diff --git a/Cargo.lock b/Cargo.lock index 11a21fba..3c0ac1d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common", + "crypto-common 0.1.6", "generic-array", ] @@ -453,15 +453,16 @@ dependencies = [ [[package]] name = "bip32" -version = "0.5.3" +version = "0.6.0-pre.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db40d3dfbeab4e031d78c844642fa0caa0b0db11ce1607ac9d2986dff1405c69" +checksum = "143f5327f23168716be068f8e1014ba2ea16a6c91e8777bc8927da7b51e1df1f" dependencies = [ "bs58", "hmac", "rand_core 0.6.4", - "ripemd", - "sha2", + "ripemd 0.2.0-pre.4", + "secp256k1", + "sha2 0.11.0-pre.4", "subtle", "zeroize", ] @@ -511,7 +512,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -545,6 +546,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.11.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd016a0ddc7cb13661bf5576073ce07330a693f8608a1320b4e20561cc12cdc" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bls12_381" version = "0.8.0" @@ -558,13 +568,22 @@ dependencies = [ "subtle", ] +[[package]] +name = "bounded-vec" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09dc0086e469182132244e9b8d313a0742e1132da43a08c24b9dd3c18e0faf3a" +dependencies = [ + "thiserror 2.0.11", +] + [[package]] name = "bs58" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "sha2", + "sha2 0.10.8", "tinyvec", ] @@ -676,7 +695,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.6", "inout", "zeroize", ] @@ -872,6 +891,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b8ce8218c97789f16356e7896b3714f26c2ee1079b79c0b7ae7064bb9089fa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "ctr" version = "0.9.2" @@ -890,7 +918,7 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest", + "digest 0.10.7", "fiat-crypto", "rand_core 0.6.4", "rustc_version", @@ -1021,8 +1049,19 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.0-pre.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2e3d6615d99707295a9673e889bf363a04b2a466bd320c65a72536f7577379" +dependencies = [ + "block-buffer 0.11.0-rc.3", + "crypto-common 0.2.0-rc.1", "subtle", ] @@ -1092,7 +1131,7 @@ dependencies = [ "curve25519-dalek", "ed25519", "serde", - "sha2", + "sha2 0.10.8", "subtle", "zeroize", ] @@ -1115,6 +1154,12 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "equihash" version = "0.2.0" @@ -1291,7 +1336,7 @@ dependencies = [ "frost-core", "frost-rerandomized", "rand_core 0.6.4", - "sha2", + "sha2 0.10.8", ] [[package]] @@ -1567,6 +1612,26 @@ dependencies = [ "uint", ] +[[package]] +name = "halo2_gadgets" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45824ce0dd12e91ec0c68ebae2a7ed8ae19b70946624c849add59f1d1a62a143" +dependencies = [ + "arrayvec", + "bitvec", + "ff", + "group", + "halo2_poseidon", + "halo2_proofs", + "lazy_static", + "pasta_curves", + "rand 0.8.5", + "sinsemilla", + "subtle", + "uint", +] + [[package]] name = "halo2_legacy_pdqsort" version = "0.1.0" @@ -1587,14 +1652,15 @@ dependencies = [ [[package]] name = "halo2_proofs" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b867a8d9bbb85fca76fff60652b5cd19b853a1c4d0665cb89bee68b18d2caf0" +checksum = "05713f117155643ce10975e0bee44a274bcda2f4bb5ef29a999ad67c1fa8d4d3" dependencies = [ "blake2b_simd", "ff", "group", "halo2_legacy_pdqsort", + "indexmap 1.9.3", "maybe-rayon", "pasta_curves", "rand_core 0.6.4", @@ -1686,11 +1752,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hmac" -version = "0.12.1" +version = "0.13.0-pre.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "e4b1fb14e4df79f9406b434b60acef9f45c26c50062cccf1346c6103b8c47d58" dependencies = [ - "digest", + "digest 0.11.0-pre.9", ] [[package]] @@ -1748,6 +1814,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d35805454dc9f8662a98d6d61886ffe26bd465f5960e0e55345c70d5c0d2a9" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.6.0" @@ -1976,9 +2051,9 @@ dependencies = [ [[package]] name = "incrementalmerkletree" -version = "0.7.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216c71634ac6f6ed13c2102d64354c0a04dcbdc30e31692c5972d3974d8b6d97" +checksum = "30821f91f0fa8660edca547918dc59812893b497d07c1144f326f07fdd94aba9" dependencies = [ "either", "proptest", @@ -1988,9 +2063,9 @@ dependencies = [ [[package]] name = "incrementalmerkletree-testing" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc7fb094e413bc6daea7b30a6f2c749e47fd07e98691c6ef3b3423d4ef4b7fb6" +checksum = "ad20fb6cf815e76ce9b9eca74f347740ab99059fe4b5e4a002403d0441a02983" dependencies = [ "incrementalmerkletree", "proptest", @@ -2134,9 +2209,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libloading" @@ -2170,6 +2245,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" version = "0.7.4" @@ -2361,9 +2442,9 @@ dependencies = [ [[package]] name = "nonempty" -version = "0.7.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" +checksum = "549e471b99ccaf2f89101bec68f4d244457d5a95a9c3d0672e9564124397741d" [[package]] name = "nu-ansi-term" @@ -2454,8 +2535,8 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orchard" -version = "0.10.1" -source = "git+https://github.com/conradoplg/orchard.git?rev=f0c88b78a1d70d55ce6bb480566d132e57d5607b#f0c88b78a1d70d55ce6bb480566d132e57d5607b" +version = "0.11.0" +source = "git+https://github.com/conradoplg/orchard.git?rev=4d001c5b6ad15373e68a5923d5868fbe42daba96#4d001c5b6ad15373e68a5923d5868fbe42daba96" dependencies = [ "aes", "bitvec", @@ -2465,7 +2546,7 @@ dependencies = [ "fpe", "getset", "group", - "halo2_gadgets", + "halo2_gadgets 0.3.1", "halo2_poseidon", "halo2_proofs", "hex", @@ -2546,6 +2627,35 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pczt" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20367012e2faad5dd99ad6fcb1efcc3332e8ac83a7653854c3ae3889c517197c" +dependencies = [ + "blake2b_simd", + "bls12_381", + "document-features", + "ff", + "getset", + "jubjub", + "nonempty", + "orchard", + "pasta_curves", + "postcard", + "rand_core 0.6.4", + "redjubjub", + "sapling-crypto", + "secp256k1", + "serde", + "serde_with", + "zcash_note_encryption", + "zcash_primitives", + "zcash_protocol", + "zcash_script", + "zcash_transparent", +] + [[package]] name = "pem" version = "3.0.4" @@ -2662,7 +2772,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -2738,9 +2848,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" dependencies = [ "bytes", "prost-derive", @@ -2748,9 +2858,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" dependencies = [ "heck 0.5.0", "itertools 0.14.0", @@ -2768,9 +2878,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" dependencies = [ "anyhow", "itertools 0.14.0", @@ -2781,9 +2891,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" dependencies = [ "prost", ] @@ -2874,13 +2984,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.1", - "zerocopy 0.8.18", + "rand_core 0.9.3", ] [[package]] @@ -2900,7 +3009,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.1", + "rand_core 0.9.3", ] [[package]] @@ -2914,12 +3023,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.1", - "zerocopy 0.8.18", ] [[package]] @@ -3002,13 +3110,12 @@ dependencies = [ [[package]] name = "redjubjub" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a60db2c3bc9c6fd1e8631fee75abc008841d27144be744951d6b9b75f9b569c" +checksum = "89b0ac1bc6bb3696d2c6f52cff8fba57238b81da8c0214ee6cd146eb8fde364e" dependencies = [ "rand_core 0.6.4", "reddsa 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde", "thiserror 1.0.69", "zeroize", ] @@ -3150,7 +3257,16 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "ripemd" +version = "0.2.0-pre.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48cf93482ea998ad1302c42739bc73ab3adc574890c373ec89710e219357579" +dependencies = [ + "digest 0.11.0-pre.9", ] [[package]] @@ -3186,7 +3302,7 @@ dependencies = [ "http", "mime", "mime_guess", - "rand 0.9.0", + "rand 0.9.2", "thiserror 2.0.11", ] @@ -3226,7 +3342,20 @@ dependencies = [ "bitflags 2.8.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.8.0", + "errno", + "libc", + "linux-raw-sys 0.11.0", "windows-sys 0.59.0", ] @@ -3314,9 +3443,9 @@ checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "sapling-crypto" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c2acdbbab83d554fc2dceea5f7d6d3da71e57adb18a6c80b8901bd0eee54b0" +checksum = "f9d3c081c83f1dc87403d9d71a06f52301c0aa9ea4c17da2a3435bbf493ffba4" dependencies = [ "aes", "bellman", @@ -3324,7 +3453,7 @@ dependencies = [ "blake2b_simd", "blake2s_simd", "bls12_381", - "byteorder", + "core2", "document-features", "ff", "fpe", @@ -3361,6 +3490,24 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "secp256k1" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -3531,7 +3678,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -3542,7 +3689,18 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0-pre.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "540c0893cce56cdbcfebcec191ec8e0f470dd1889b6e7a0b503e310a94a168f5" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.11.0-pre.9", ] [[package]] @@ -3556,9 +3714,9 @@ dependencies = [ [[package]] name = "shardtree" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5f2390975ebfe8838f9e861f7a588123d49a7a7a0a08568ea831d8ad53fc9b4" +checksum = "637e95dcd06bc1bb3f86ed9db1e1832a70125f32daae071ef37dcb7701b7d4fe" dependencies = [ "bitflags 2.8.0", "either", @@ -3637,7 +3795,7 @@ dependencies = [ "curve25519-dalek", "rand_core 0.6.4", "rustc_version", - "sha2", + "sha2 0.10.8", "subtle", ] @@ -3785,7 +3943,7 @@ dependencies = [ "fastrand", "getrandom 0.3.1", "once_cell", - "rustix", + "rustix 0.38.44", "windows-sys 0.59.0", ] @@ -3999,9 +4157,21 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.12.3" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" +checksum = "4c40aaccc9f9eccf2cd82ebc111adc13030d23e887244bc9cfa5d1d636049de3" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "tonic-prost-build" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a16cba4043dc3ff43fcb3f96b4c5c154c64cbd18ca8dce2ab2c6a451d058a2" dependencies = [ "prettyplease", "proc-macro2", @@ -4009,6 +4179,8 @@ dependencies = [ "prost-types", "quote", "syn 2.0.98", + "tempfile", + "tonic-build", ] [[package]] @@ -4199,7 +4371,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common", + "crypto-common 0.1.6", "subtle", ] @@ -4251,7 +4423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" dependencies = [ "getrandom 0.3.1", - "rand 0.9.0", + "rand 0.9.2", "serde", ] @@ -4461,18 +4633,17 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.44", ] [[package]] name = "which" -version = "6.0.3" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" dependencies = [ - "either", - "home", - "rustix", + "env_home", + "rustix 1.1.2", "winsafe", ] @@ -4759,7 +4930,7 @@ dependencies = [ "ed25519", "ed25519-dalek", "rand 0.8.5", - "sha2", + "sha2 0.10.8", "x25519-dalek", "zeroize", ] @@ -4810,11 +4981,12 @@ dependencies = [ "base64 0.22.1", "clap", "eyre", - "halo2_gadgets", + "halo2_gadgets 0.4.0", "halo2_proofs", "hex", "lazy_static", "orchard", + "pczt", "rand 0.8.5", "rand_core 0.6.4", "sapling-crypto", @@ -4829,13 +5001,14 @@ dependencies = [ "zcash_primitives", "zcash_proofs", "zcash_protocol", + "zcash_transparent", ] [[package]] name = "zcash_address" -version = "0.6.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b955fe87f2d9052e3729bdbeb0e94975355f4fe39f7d26aea9457bec6a0bb55" +checksum = "ee4491dddd232de02df42481757054dc19c8bc51cf709cfec58feebfef7c3c9a" dependencies = [ "bech32", "bs58", @@ -4847,9 +5020,9 @@ dependencies = [ [[package]] name = "zcash_client_backend" -version = "0.16.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a187ad05cdfe13707c07e6aedca8026b34921d081decfd0b43aac1efd438a7" +checksum = "5493217c813ba1f7ef4e6b6bf846f4e4cd57b6a070d679c9f15d2477e12d1464" dependencies = [ "base64 0.22.1", "bech32", @@ -4857,11 +5030,11 @@ dependencies = [ "bs58", "crossbeam-channel", "document-features", + "getset", "group", "hex", "incrementalmerkletree", "memuse", - "nom", "nonempty", "orchard", "pasta_curves", @@ -4874,24 +5047,27 @@ dependencies = [ "shardtree", "subtle", "time", - "tonic-build", + "time-core", + "tonic-prost-build", "tracing", - "which 6.0.3", + "which 8.0.0", "zcash_address", "zcash_encoding", "zcash_keys", "zcash_note_encryption", "zcash_primitives", "zcash_protocol", + "zcash_script", + "zcash_transparent", "zip32", "zip321", ] [[package]] name = "zcash_encoding" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3654116ae23ab67dd1f849b01f8821a8a156f884807ff665eac109bf28306c4d" +checksum = "bca38087e6524e5f51a5b0fb3fc18f36d7b84bf67b2056f494ca0c281590953d" dependencies = [ "core2", "nonempty", @@ -4899,9 +5075,9 @@ dependencies = [ [[package]] name = "zcash_keys" -version = "0.6.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad3cf576c6e6094cd03f446fcb83ad241ec315a088593cd50940f135cb03ce1" +checksum = "c115531caa1b7ca5ccd82dc26dbe3ba44b7542e928a3f77cd04abbe3cde4a4f2" dependencies = [ "bech32", "blake2b_simd", @@ -4941,15 +5117,16 @@ dependencies = [ [[package]] name = "zcash_primitives" -version = "0.21.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b45f3ca3a9df34fcdbf036c2c814417bb417bde742812abc09d744bb3d7ed72" +checksum = "d0e6912efdae984166ec0dc580049699026795328dcea4fc8cc077d51fce350c" dependencies = [ - "aes", "bip32", "blake2b_simd", + "block-buffer 0.11.0-rc.3", "bs58", - "byteorder", + "core2", + "crypto-common 0.2.0-rc.1", "document-features", "equihash", "ff", @@ -4965,15 +5142,16 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "redjubjub", - "ripemd", + "ripemd 0.1.3", "sapling-crypto", - "sha2", + "sha2 0.10.8", "subtle", "tracing", "zcash_address", "zcash_encoding", "zcash_note_encryption", "zcash_protocol", + "zcash_script", "zcash_spec", "zcash_transparent", "zip32", @@ -4981,9 +5159,9 @@ dependencies = [ [[package]] name = "zcash_proofs" -version = "0.21.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5826910c516675eca1f34b3557e159f4e35a4a1711b39fa4f01fb0adb9a9c24" +checksum = "43a2c13bb673d542608a0e6502ac5494136e7ce4ce97e92dd239489b2523eed9" dependencies = [ "bellman", "blake2b_simd", @@ -5005,9 +5183,9 @@ dependencies = [ [[package]] name = "zcash_protocol" -version = "0.4.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cb36b15b5a1be70b30c32ce40372dead6561df8a467e297f96b892873a63a2" +checksum = "deb4c8d0530fd7a3d65358010f1e0a1ccfe6cc5f1ad63447af089ccc82ae9edf" dependencies = [ "core2", "document-features", @@ -5018,34 +5196,54 @@ dependencies = [ "proptest", ] +[[package]] +name = "zcash_script" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bed6cf5b2b4361105d4ea06b2752f0c8af4641756c7fbc9858a80af186c234f" +dependencies = [ + "bip32", + "bitflags 2.8.0", + "bounded-vec", + "hex", + "ripemd 0.1.3", + "secp256k1", + "sha1", + "sha2 0.10.8", + "thiserror 2.0.11", +] + [[package]] name = "zcash_spec" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cede95491c2191d3e278cab76e097a44b17fde8d6ca0d4e3a22cf4807b2d857" +checksum = "ded3f58b93486aa79b85acba1001f5298f27a46489859934954d262533ee2915" dependencies = [ "blake2b_simd", ] [[package]] name = "zcash_transparent" -version = "0.1.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0512e8e02af804e852fbbc4bd5db35a9037bc253d2ce396506293a6e7dd745" +checksum = "91df4a3a377d478f94e4a00ff36a4963dc641ccd8ed2455554b8cb6914721562" dependencies = [ "bip32", "blake2b_simd", "bs58", "core2", + "document-features", "getset", "hex", "proptest", - "ripemd", - "sha2", + "ripemd 0.1.3", + "secp256k1", + "sha2 0.10.8", "subtle", "zcash_address", "zcash_encoding", "zcash_protocol", + "zcash_script", "zcash_spec", "zip32", ] @@ -5057,16 +5255,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2" -dependencies = [ - "zerocopy-derive 0.8.18", + "zerocopy-derive", ] [[package]] @@ -5080,17 +5269,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "zerocopy-derive" -version = "0.8.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] - [[package]] name = "zerofrom" version = "0.1.5" @@ -5157,10 +5335,11 @@ dependencies = [ [[package]] name = "zip32" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9943793abf9060b68e1889012dafbd5523ab5b125c0fcc24802d69182f2ac9" +checksum = "b64bf5186a8916f7a48f2a98ef599bf9c099e2458b36b819e393db1c0e768c4b" dependencies = [ + "bech32", "blake2b_simd", "memuse", "subtle", @@ -5169,9 +5348,9 @@ dependencies = [ [[package]] name = "zip321" -version = "0.2.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3e613defb0940acef1f54774b51c7f48f2fa705613dd800870dc69f35cd2ea" +checksum = "3090953750ce1d56aa213710765eb14997868f463c45dae115cf1ebe09fe39eb" dependencies = [ "base64 0.22.1", "nom", diff --git a/Cargo.toml b/Cargo.toml index d6b34a39..e46c2cbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,13 +27,14 @@ frost-rerandomized = "2.0.0-rc.0" frostd = { path = "frostd" } futures = "0.3.31" futures-util = "0.3.31" -halo2_gadgets = "0.3.0" -halo2_proofs = "0.3.0" +halo2_gadgets = "0.4.0" +halo2_proofs = "0.3.2" hex = "0.4.3" itertools = "0.14.0" lazy_static = "1.5.0" message-io = "0.18" -orchard = "0.10.1" +orchard = "0.11.0" +pczt = "0.5" postcard = "1.1.1" rand = "0.8.5" rand_core = "0.6.4" @@ -43,7 +44,7 @@ regex = "1.11.1" reqwest = { version = "0.12.12", default-features = false } rpassword = "7.3.1" rustls = "0.23.21" -sapling-crypto = "0.4.0" +sapling-crypto = "0.5.0" serde = "1.0.204" serde-hex = "0.1.0" serde_json = "1.0.138" @@ -60,16 +61,18 @@ tracing = "0.1" tracing-subscriber = "0.3" uuid = "1.11.0" xeddsa = "1.0.2" -zcash_address = "0.6.2" -zcash_client_backend = "0.16.0" -zcash_encoding = "0.2.2" -zcash_keys = "0.6.0" -zcash_primitives = "0.21.0" -zcash_proofs = "0.21.0" -zcash_protocol = "0.4.3" +zcash_address = "0.10.1" +zcash_client_backend = "0.21.0" +zcash_encoding = "0.3.0" +zcash_keys = "0.12.0" +zcash_primitives = "0.26.1" +zcash_proofs = "0.26.1" +zcash_protocol = "0.7.1" +zcash_transparent = "0.6" zeroize = "1.8.1" [patch.crates-io] -# TODO: remove this when https://github.com/zcash/orchard/issues/430 is fully -# addressed and a new release is made -orchard = { git = "https://github.com/conradoplg/orchard.git", rev = "f0c88b78a1d70d55ce6bb480566d132e57d5607b" } +# TODO: remove this when https://github.com/zcash/orchard/pull/475 is merged, +# and a all ECC crates are updated to point to the orchard version that includes +# it. +orchard = { git = "https://github.com/conradoplg/orchard.git", rev = "4d001c5b6ad15373e68a5923d5868fbe42daba96" } diff --git a/zcash-sign/Cargo.toml b/zcash-sign/Cargo.toml index 73796e2e..21b5945c 100644 --- a/zcash-sign/Cargo.toml +++ b/zcash-sign/Cargo.toml @@ -12,6 +12,7 @@ halo2_proofs = { workspace = true } hex = { workspace = true } lazy_static = { workspace = true } orchard = { workspace = true, features = ["unstable-frost"] } +pczt = { workspace = true, features = ["signer"] } rand = { workspace = true } rand_core = { workspace = true } sapling-crypto = { workspace = true } @@ -26,3 +27,4 @@ zcash_keys = { workspace = true, features = ["test-dependencies", "orchard"] } zcash_primitives = { workspace = true } zcash_proofs = { workspace = true, features = ["bundled-prover"] } zcash_protocol = { workspace = true } +zcash_transparent = { workspace = true, features = ["transparent-inputs"] } \ No newline at end of file diff --git a/zcash-sign/src/args.rs b/zcash-sign/src/args.rs index c29b68a8..8f9bb10e 100644 --- a/zcash-sign/src/args.rs +++ b/zcash-sign/src/args.rs @@ -14,6 +14,10 @@ pub(crate) enum Command { /// The SpendValidatingKey (VerifyingKey in FROST) to use #[arg(short, long)] ak: String, + /// The network the address will be generated for: "main" or "test" (default: "main") + #[arg(short, long)] + #[arg(default_value = "main")] + network: String, /// Whether to generate a dummy Sapling key along with the Orchard key. /// Require for Ywallet use since it does not support Orchard-only keys. /// DANGER: make sure to not send to the Sapling address, or your @@ -31,8 +35,14 @@ pub(crate) enum Command { #[arg(short = 'o', long)] tx: String, - /// The UnifiedFullViewingKey generated previously, in hex format + /// The UnifiedFullViewingKey generated previously, in hex format. + /// Not required for PCZTs, only for Ywallet transaction plans. + #[arg(short, long)] + ufvk: Option, + + /// The network the address will be generated for: "main" or "test" (default: "main") #[arg(short, long)] - ufvk: String, + #[arg(default_value = "main")] + network: String, }, } diff --git a/zcash-sign/src/lib.rs b/zcash-sign/src/lib.rs index 087d77f1..73ccbbe5 100644 --- a/zcash-sign/src/lib.rs +++ b/zcash-sign/src/lib.rs @@ -1,6 +1,7 @@ mod generate; mod sign; +pub(crate) mod sign_ywallet; pub mod transaction_plan; pub use generate::generate; -pub use sign::sign; +pub use sign::{sign, Input}; diff --git a/zcash-sign/src/main.rs b/zcash-sign/src/main.rs index 794bd514..4925024b 100644 --- a/zcash-sign/src/main.rs +++ b/zcash-sign/src/main.rs @@ -2,18 +2,16 @@ mod args; use std::{error::Error, fs}; -use base64::{prelude::BASE64_STANDARD, Engine as _}; use clap::Parser as _; use eyre::eyre; +use pczt::Pczt; use rand::{thread_rng, RngCore}; use orchard::keys::{Scope, SpendValidatingKey}; use sapling_crypto::zip32::ExtendedSpendingKey; use zcash_client_backend::address::UnifiedAddress; use zcash_keys::keys::UnifiedFullViewingKey; -use zcash_protocol::consensus::MainNetwork; - -use zcash_sign::transaction_plan::TransactionPlan; +use zcash_protocol::consensus::{self}; use args::{Args, Command}; @@ -21,10 +19,16 @@ fn generate(args: &Command) -> Result<(), Box> { let Command::Generate { ak, danger_dummy_sapling, + network, } = args else { panic!("invalid Command"); }; + let params: consensus::Network = match network.as_str() { + "main" => consensus::Network::MainNetwork, + "test" => consensus::Network::TestNetwork, + _ => Err(eyre!("Invalid network: {}", network))?, + }; let ak = hex::decode(ak.trim()).unwrap(); let ak = SpendValidatingKey::from_bytes(&ak).ok_or(eyre!("Invalid ak"))?; @@ -37,7 +41,7 @@ fn generate(args: &Command) -> Result<(), Box> { let unified_address = UnifiedAddress::from_receivers(Some(orchard_address), None, None) .expect("must work with a shielded address"); // TODO: make params selectable - let unified_address_str = unified_address.encode(&MainNetwork); + let unified_address_str = unified_address.encode(¶ms); println!("Orchard-only unified address: {unified_address_str:?}"); @@ -51,7 +55,7 @@ fn generate(args: &Command) -> Result<(), Box> { }; let ufvk = UnifiedFullViewingKey::new(sapling_fvk, Some(fvk.clone())).unwrap(); - let ufvk_str = ufvk.encode(&MainNetwork); + let ufvk_str = ufvk.encode(¶ms); println!("Unified Full Viewing Key: {ufvk_str:?}"); @@ -63,26 +67,32 @@ fn sign(args: &Command) -> Result<(), Box> { tx_plan, ufvk, tx: tx_path, + network, } = args else { panic!("invalid Command") }; - // TODO: make configurable - let network = MainNetwork; + let params: consensus::Network = match network.as_str() { + "main" => consensus::Network::MainNetwork, + "test" => consensus::Network::TestNetwork, + _ => Err(eyre!("Invalid network: {}", network))?, + }; - let tx_plan = fs::read_to_string(tx_plan)?; - let tx_plan: TransactionPlan = serde_json::from_str(&tx_plan)?; + let tx_plan = fs::read(tx_plan)?; + let input = match Pczt::parse(&tx_plan) { + Ok(pczt) => zcash_sign::Input::Pczt(pczt), + Err(_) => zcash_sign::Input::YwalletTxPlan(serde_json::from_slice(&tx_plan)?), + }; - let ufvk = UnifiedFullViewingKey::decode(&network, ufvk.trim()).unwrap(); + let ufvk = ufvk + .clone() + .map(|ufvk_str| UnifiedFullViewingKey::decode(¶ms, ufvk_str.trim()).unwrap()); let mut rng = thread_rng(); - let tx = zcash_sign::sign(&mut rng, &tx_plan, &ufvk)?; - - let mut tx_bytes = vec![]; - tx.write(&mut tx_bytes).unwrap(); + let tx_bytes = zcash_sign::sign(&mut rng, params, &input, ufvk.as_ref())?; - fs::write(tx_path, BASE64_STANDARD.encode(&tx_bytes))?; + fs::write(tx_path, tx_bytes)?; println!("Tx written to {tx_path}"); Ok(()) diff --git a/zcash-sign/src/sign.rs b/zcash-sign/src/sign.rs index 50d4ce4d..ded9f004 100644 --- a/zcash-sign/src/sign.rs +++ b/zcash-sign/src/sign.rs @@ -1,275 +1,121 @@ use std::error::Error; use eyre::eyre; -use lazy_static::lazy_static; +use pczt::{roles::low_level_signer::Signer, Pczt}; use rand_core::{CryptoRng, RngCore}; use halo2_proofs::pasta::group::ff::PrimeField; use orchard::{ - builder::MaybeSigned, - bundle::Flags, - circuit::ProvingKey, - keys::{Scope, SpendValidatingKey}, - note::Rho, primitives::redpallas::{self, SpendAuth}, value::NoteValue, - Address, Anchor, }; -use sapling_crypto::PaymentAddress; use zcash_keys::keys::UnifiedFullViewingKey; -use zcash_primitives::transaction::{ - components::transparent::builder::TransparentBuilder, - sighash::{signature_hash, SignableInput}, - txid::TxIdDigester, - Transaction, TransactionData, -}; -use zcash_primitives::transaction::{ - components::{amount::NonNegativeAmount, sapling::zip212_enforcement}, - TxVersion, -}; -use zcash_proofs::prover::LocalTxProver; -use zcash_protocol::{ - consensus::{BlockHeight, BranchId, MainNetwork}, - value::ZatBalance as Amount, -}; +use zcash_primitives::transaction::{sighash::SignableInput, txid::TxIdDigester}; +use zcash_primitives::transaction::{sighash_v5::v5_signature_hash, TxVersion}; -use crate::transaction_plan::{ - Destination, Hasher, OrchardHasher, Source, TransactionPlan, Witness, -}; +use crate::transaction_plan::TransactionPlan; -lazy_static! { - pub static ref ORCHARD_ROOTS: Vec<[u8; 32]> = { - let h = OrchardHasher::new(); - h.empty_roots(32) - }; +pub enum Input { + YwalletTxPlan(TransactionPlan), + Pczt(Pczt), } /// Sign a transaction plan with externally-generated signatures. /// TODO: make this non-interactive by possibly using a callback pub fn sign( - mut rng: &mut (impl RngCore + CryptoRng), - tx_plan: &TransactionPlan, - ufvk: &UnifiedFullViewingKey, -) -> Result> { - // TODO: make params selectable - let network = MainNetwork; - - let orchard_fvk = ufvk - .orchard() - .ok_or(eyre!("UFVK must have an Orchard component"))?; - let orchard_fvk_hex = hex::encode(orchard_fvk.to_bytes()); - let orchard_ovk = orchard_fvk.clone().to_ovk(Scope::External); - - if tx_plan.orchard_fvk != orchard_fvk_hex { - return Err( - eyre!("Key does not match the key used to create the given transaction plan").into(), - ); - } - - let mut transparent_builder = TransparentBuilder::empty(); - let mut sapling_builder = sapling_crypto::builder::Builder::new( - zip212_enforcement(&network, BlockHeight::from_u32(tx_plan.anchor_height)), - sapling_crypto::builder::BundleType::DEFAULT, - sapling_crypto::Anchor::empty_tree(), - ); - - let orchard_anchor: Anchor = - orchard::tree::MerkleHashOrchard::from_bytes(&tx_plan.orchard_anchor) - .unwrap() - .into(); - let mut orchard_builder = orchard::builder::Builder::new( - orchard::builder::BundleType::Transactional { - flags: Flags::ENABLED, - bundle_required: false, - }, - orchard_anchor, - ); - - for spend in tx_plan.spends.iter() { - match &spend.source { - Source::Transparent { .. } => { - return Err(eyre!("Only Orchard inputs are supported").into()) - } - Source::Sapling { .. } => return Err(eyre!("Only Orchard inputs are supported").into()), - Source::Orchard { - id_note, - diversifier, - rho, - rseed, - witness, - } => { - let diversifier = orchard::keys::Diversifier::from_bytes(*diversifier); - let sender_address = orchard_fvk.address(diversifier, Scope::External); - let value = NoteValue::from_raw(spend.amount); - let rho = Rho::from_bytes(rho).unwrap(); - let rseed = orchard::note::RandomSeed::from_bytes(*rseed, &rho).unwrap(); - let note = orchard::Note::from_parts(sender_address, value, rho, rseed).unwrap(); - let witness = Witness::from_bytes(*id_note, witness)?; - let auth_path: Vec<_> = witness - .auth_path(32, &ORCHARD_ROOTS, &OrchardHasher::new()) - .iter() - .map(|n| orchard::tree::MerkleHashOrchard::from_bytes(n).unwrap()) - .collect(); - let merkle_path = orchard::tree::MerklePath::from_parts( - witness.position as u32, - auth_path.try_into().unwrap(), - ); - orchard_builder - .add_spend(orchard_fvk.clone(), note, merkle_path) - .map_err(|e| eyre!(e.to_string()))?; - } + rng: impl RngCore + CryptoRng, + network: zcash_protocol::consensus::Network, + tx_plan: &Input, + _ufvk: Option<&UnifiedFullViewingKey>, +) -> Result, Box> { + match tx_plan { + Input::YwalletTxPlan(_plan) => { + #[cfg(false)] + sign_ywallet(rng, network, plan, ufvk); + Err(eyre!("Ywallet signing is disabled"))? } + Input::Pczt(pczt) => sign_pczt(rng, network, pczt), } +} - for output in tx_plan.outputs.iter() { - let value = NonNegativeAmount::from_u64(output.amount).unwrap(); - match &output.destination { - Destination::Transparent(_addr) => { - let transparent_address = output.destination.transparent(); - transparent_builder - .add_output(&transparent_address, value) - .map_err(|e| eyre!(e.to_string()))?; - } - Destination::Sapling(addr) => { - let sapling_address = PaymentAddress::from_bytes(addr).unwrap(); - // TODO: use ovk if Sapling support is added? - sapling_builder - .add_output( - None, - sapling_address, - sapling_crypto::value::NoteValue::from_raw(value.into()), - Some(*output.memo.as_array()), - ) - .map_err(|e| eyre!(e.to_string()))?; - } - Destination::Orchard(addr) => { - let orchard_address = Address::from_raw_address_bytes(addr).unwrap(); - orchard_builder - .add_output( - Some(orchard_ovk.clone()), - orchard_address, - NoteValue::from_raw(output.amount), - Some(*output.memo.as_array()), - ) - .map_err(|e| eyre!(e.to_string()))?; +fn sign_pczt( + _rng: impl RngCore + CryptoRng, + _network: zcash_protocol::consensus::Network, + pczt: &Pczt, +) -> Result, Box> { + let sighash = match pczt.clone().into_effects() { + None => Err(eyre!( + "Not enough information to build the transaction's effects" + ))?, + Some(tx_data) => { + let txid_parts = tx_data.digest(TxIdDigester); + if matches!(tx_data.version(), TxVersion::V5) + && (tx_data.sapling_bundle().is_some() || tx_data.orchard_bundle().is_some()) + { + v5_signature_hash(&tx_data, &SignableInput::Shielded, &txid_parts) + } else { + Err(eyre!( + "Only version 5 transactions with shielded components are supported" + ))? } } - } + }; - let transparent_bundle = transparent_builder.build(); - let sapling_bundle = sapling_builder - .build::(&[], &mut rng) + println!("SIGHASH: {}", hex::encode(sighash)); + + let signer = Signer::new(pczt.clone()); + + let mut alphas = vec![]; + signer + .sign_orchard_with(|_pczt, bundle, _| { + alphas = bundle + .actions() + .iter() + .enumerate() + // TODO: remove unwrap + .filter_map(|(idx, a)| { + // TODO: improve dummy detection (check rk instead) + if a.spend().value().unwrap() != NoteValue::default() { + Some((idx, a.spend().alpha().unwrap())) + } else { + None + } + }) + .collect::>(); + Ok::<_, orchard::pczt::ParseError>(()) + }) .unwrap(); - let orchard_bundle = orchard_builder.build(&mut rng).unwrap(); - let prover = LocalTxProver::bundled(); - - // TODO: allow specifying a progress notifier - // TODO: allow returning sapling metadata - let sapling_bundle = sapling_bundle - .map(|(bundle, _sapling_meta)| bundle.create_proofs(&prover, &prover, &mut rng, ())); - - let orchard_bundle = orchard_bundle.map(|(b, _m)| b); - - let consensus_branch_id = - BranchId::for_height(&network, BlockHeight::from_u32(tx_plan.anchor_height)); - let version = TxVersion::suggested_for_branch(consensus_branch_id); - - let unauthed_tx: TransactionData = - TransactionData::from_parts( - version, - consensus_branch_id, - 0, - BlockHeight::from_u32(tx_plan.expiry_height), - transparent_bundle, - None, - sapling_bundle, - orchard_bundle, - ); - - let txid_parts = unauthed_tx.digest(TxIdDigester); - let sig_hash = signature_hash(&unauthed_tx, &SignableInput::Shielded, &txid_parts); - let sig_hash: [u8; 32] = *sig_hash.as_ref(); - - println!("SIGHASH: {}", hex::encode(sig_hash)); - - // There are no transaprent inputs to sign, but we need to move the Bundle - // to the Authorized state, which we do by calling `apply_signatures()` - // (which does not take arguments since the transparent-inputs feature is - // not enabled) - let transparent_bundle = unauthed_tx.transparent_bundle().map(|tb| { - tb.clone() - .apply_signatures(|_| [0; 32], &Default::default()) - .unwrap() - }); - - // There are no Sapling spends to sign, but we need to move the Bundle to - // the Authorized state, which we do by applying an empty vector of - // signatures. - let sapling_bundle = unauthed_tx.sapling_bundle().map(|sb| { - sb.clone() - .apply_signatures(&mut rng, sig_hash, &[]) - .unwrap() - }); - - let proving_key = ProvingKey::build(); - - let orchard_bundle = unauthed_tx.orchard_bundle().map(|ob| { - let proven = ob.clone().create_proof(&proving_key, &mut rng).unwrap(); - let proven = proven.prepare(&mut rng, sig_hash); - - let expected_ak: SpendValidatingKey = orchard_fvk.clone().into(); - - let mut alphas = Vec::new(); - let proven = proven.map_authorization( - &mut rng, - |_rng, _partial, maybe| { - if let MaybeSigned::SigningMetadata(parts) = &maybe { - if *parts.ak() == expected_ak { - alphas.push(parts.alpha()); - } - } - maybe - }, - |_rng, auth| auth, + let mut signatures = vec![]; + for (idx, alpha) in alphas.iter() { + println!( + "Randomizer #{}: {}", + idx, + hex::encode::<&[u8]>(alpha.to_repr().as_ref()) ); + let mut buffer = String::new(); + let stdin = std::io::stdin(); + println!("Input hex-encoded signature #{idx}: "); + stdin.read_line(&mut buffer).unwrap(); + let signature = hex::decode(buffer.trim()).unwrap(); + let signature: [u8; 64] = signature.try_into().unwrap(); + let signature = redpallas::Signature::::from(signature); + signatures.push((*idx, signature)); + } - let mut signatures = Vec::new(); - - for (i, alpha) in alphas.iter().enumerate() { - println!( - "Randomizer #{}: {}", - i, - hex::encode(alpha.to_repr().as_ref()) - ); - let mut buffer = String::new(); - let stdin = std::io::stdin(); - println!("Input hex-encoded signature #{i}: "); - stdin.read_line(&mut buffer).unwrap(); - let signature = hex::decode(buffer.trim()).unwrap(); - let signature: [u8; 64] = signature.try_into().unwrap(); - let signature = redpallas::Signature::::from(signature); - signatures.push(signature); - } - - proven - .append_signatures(&signatures) - .unwrap() - .finalize() - .unwrap() - }); + let signer = Signer::new(pczt.clone()); + let signer = signer + .sign_orchard_with(|_pczt, bundle, _| { + for (idx, signature) in signatures.into_iter() { + let action = &mut bundle.actions_mut()[idx]; + action + .apply_signature(sighash.as_bytes().try_into().unwrap(), signature) + .unwrap(); + } + Ok::<_, orchard::pczt::ParseError>(()) + }) + .map_err(|e| eyre!("Error signing: {:?}", e))?; + let pczt = signer.finish(); - let tx_data: TransactionData = - TransactionData::from_parts( - version, - consensus_branch_id, - 0, - BlockHeight::from_u32(tx_plan.expiry_height), - transparent_bundle, - None, - sapling_bundle, - orchard_bundle, - ); - let tx = tx_data.freeze().unwrap(); - Ok(tx) + Ok(pczt.serialize()) } diff --git a/zcash-sign/src/sign_ywallet.rs b/zcash-sign/src/sign_ywallet.rs new file mode 100644 index 00000000..e8979c73 --- /dev/null +++ b/zcash-sign/src/sign_ywallet.rs @@ -0,0 +1,276 @@ +#![cfg(false)] + +use std::error::Error; + +use base64::{prelude::BASE64_STANDARD, Engine as _}; +use eyre::eyre; +use lazy_static::lazy_static; +use pczt::{roles::low_level_signer::Signer, Pczt}; +use rand_core::{CryptoRng, RngCore}; + +use halo2_proofs::pasta::group::ff::PrimeField; +use orchard::{ + builder::MaybeSigned, + bundle::Flags, + circuit::ProvingKey, + keys::{Scope, SpendValidatingKey}, + note::Rho, + primitives::redpallas::{self, SpendAuth}, + value::NoteValue, + Address, Anchor, +}; +use sapling_crypto::PaymentAddress; +use zcash_keys::keys::UnifiedFullViewingKey; +use zcash_primitives::transaction::{ + components::sapling::zip212_enforcement, sighash_v5::v5_signature_hash, TxVersion, +}; +use zcash_primitives::transaction::{ + components::transparent::builder::TransparentBuilder, + sighash::{signature_hash, SignableInput}, + txid::TxIdDigester, + TransactionData, +}; +use zcash_proofs::prover::LocalTxProver; +use zcash_protocol::{ + consensus::{BlockHeight, BranchId}, + value::{ZatBalance as Amount, Zatoshis}, +}; + +use crate::transaction_plan::{ + Destination, Hasher, OrchardHasher, Source, TransactionPlan, Witness, +}; + +lazy_static! { + pub static ref ORCHARD_ROOTS: Vec<[u8; 32]> = { + let h = OrchardHasher::new(); + h.empty_roots(32) + }; +} + +fn sign_ywallet( + mut rng: impl RngCore + CryptoRng, + network: zcash_protocol::consensus::Network, + tx_plan: &TransactionPlan, + ufvk: &UnifiedFullViewingKey, +) -> Result, Box> { + let orchard_fvk = ufvk + .orchard() + .ok_or(eyre!("UFVK must have an Orchard component"))?; + let orchard_fvk_hex = hex::encode(orchard_fvk.to_bytes()); + let orchard_ovk = orchard_fvk.clone().to_ovk(Scope::External); + + if tx_plan.orchard_fvk != orchard_fvk_hex { + return Err( + eyre!("Key does not match the key used to create the given transaction plan").into(), + ); + } + + let mut transparent_builder = TransparentBuilder::empty(); + let mut sapling_builder = sapling_crypto::builder::Builder::new( + zip212_enforcement(&network, BlockHeight::from_u32(tx_plan.anchor_height)), + sapling_crypto::builder::BundleType::DEFAULT, + sapling_crypto::Anchor::empty_tree(), + ); + + let orchard_anchor: Anchor = + orchard::tree::MerkleHashOrchard::from_bytes(&tx_plan.orchard_anchor) + .unwrap() + .into(); + let mut orchard_builder = orchard::builder::Builder::new( + orchard::builder::BundleType::Transactional { + flags: Flags::ENABLED, + bundle_required: false, + }, + orchard_anchor, + ); + + for spend in tx_plan.spends.iter() { + match &spend.source { + Source::Transparent { .. } => { + return Err(eyre!("Only Orchard inputs are supported").into()) + } + Source::Sapling { .. } => return Err(eyre!("Only Orchard inputs are supported").into()), + Source::Orchard { + id_note, + diversifier, + rho, + rseed, + witness, + } => { + let diversifier = orchard::keys::Diversifier::from_bytes(*diversifier); + let sender_address = orchard_fvk.address(diversifier, Scope::External); + let value = NoteValue::from_raw(spend.amount); + let rho = Rho::from_bytes(rho).unwrap(); + let rseed = orchard::note::RandomSeed::from_bytes(*rseed, &rho).unwrap(); + let note = orchard::Note::from_parts(sender_address, value, rho, rseed).unwrap(); + let witness = Witness::from_bytes(*id_note, witness)?; + let auth_path: Vec<_> = witness + .auth_path(32, &ORCHARD_ROOTS, &OrchardHasher::new()) + .iter() + .map(|n| orchard::tree::MerkleHashOrchard::from_bytes(n).unwrap()) + .collect(); + let merkle_path = orchard::tree::MerklePath::from_parts( + witness.position as u32, + auth_path.try_into().unwrap(), + ); + orchard_builder + .add_spend(orchard_fvk.clone(), note, merkle_path) + .map_err(|e| eyre!(e.to_string()))?; + } + } + } + + for output in tx_plan.outputs.iter() { + let value = Zatoshis::from_u64(output.amount).unwrap(); + match &output.destination { + Destination::Transparent(_addr) => { + let transparent_address = output.destination.transparent(); + transparent_builder + .add_output(&transparent_address, value) + .map_err(|e| eyre!(e.to_string()))?; + } + Destination::Sapling(addr) => { + let sapling_address = PaymentAddress::from_bytes(addr).unwrap(); + // TODO: use ovk if Sapling support is added? + sapling_builder + .add_output( + None, + sapling_address, + sapling_crypto::value::NoteValue::from_raw(value.into()), + *output.memo.as_array(), + ) + .map_err(|e| eyre!(e.to_string()))?; + } + Destination::Orchard(addr) => { + let orchard_address = Address::from_raw_address_bytes(addr).unwrap(); + orchard_builder + .add_output( + Some(orchard_ovk.clone()), + orchard_address, + NoteValue::from_raw(output.amount), + *output.memo.as_array(), + ) + .map_err(|e| eyre!(e.to_string()))?; + } + } + } + + let transparent_bundle = transparent_builder.build(); + let sapling_bundle = sapling_builder + .build::(&[], &mut rng) + .unwrap(); + let orchard_bundle = orchard_builder.build(&mut rng).unwrap(); + + let prover = LocalTxProver::bundled(); + + // TODO: allow specifying a progress notifier + // TODO: allow returning sapling metadata + let sapling_bundle = sapling_bundle + .map(|(bundle, _sapling_meta)| bundle.create_proofs(&prover, &prover, &mut rng, ())); + + let orchard_bundle = orchard_bundle.map(|(b, _m)| b); + + let consensus_branch_id = + BranchId::for_height(&network, BlockHeight::from_u32(tx_plan.anchor_height)); + let version = TxVersion::suggested_for_branch(consensus_branch_id); + + let unauthed_tx: TransactionData = + TransactionData::from_parts( + version, + consensus_branch_id, + 0, + BlockHeight::from_u32(tx_plan.expiry_height), + transparent_bundle, + None, + sapling_bundle, + orchard_bundle, + ); + + let txid_parts = unauthed_tx.digest(TxIdDigester); + let sig_hash = signature_hash(&unauthed_tx, &SignableInput::Shielded, &txid_parts); + let sig_hash: [u8; 32] = *sig_hash.as_ref(); + + println!("SIGHASH: {}", hex::encode(sig_hash)); + + // There are no transaprent inputs to sign, but we need to move the Bundle + // to the Authorized state, which we do by calling `apply_signatures()` + // (which does not take arguments since the transparent-inputs feature is + // not enabled) + let transparent_bundle = unauthed_tx.transparent_bundle().map(|tb| { + tb.clone() + .apply_signatures(|_| [0; 32], &Default::default()) + .unwrap() + }); + + // There are no Sapling spends to sign, but we need to move the Bundle to + // the Authorized state, which we do by applying an empty vector of + // signatures. + let sapling_bundle = unauthed_tx.sapling_bundle().map(|sb| { + sb.clone() + .apply_signatures(&mut rng, sig_hash, &[]) + .unwrap() + }); + + let proving_key = ProvingKey::build(); + + let orchard_bundle = unauthed_tx.orchard_bundle().map(|ob| { + let proven = ob.clone().create_proof(&proving_key, &mut rng).unwrap(); + let proven = proven.prepare(&mut rng, sig_hash); + + let expected_ak: SpendValidatingKey = orchard_fvk.clone().into(); + + let mut alphas = Vec::new(); + let proven = proven.map_authorization( + &mut rng, + |_rng, _partial, maybe| { + if let MaybeSigned::SigningMetadata(parts) = &maybe { + if *parts.ak() == expected_ak { + alphas.push(parts.alpha()); + } + } + maybe + }, + |_rng, auth| auth, + ); + + let mut signatures = Vec::new(); + + for (i, alpha) in alphas.iter().enumerate() { + println!( + "Randomizer #{}: {}", + i, + hex::encode::<&[u8]>(alpha.to_repr().as_ref()) + ); + let mut buffer = String::new(); + let stdin = std::io::stdin(); + println!("Input hex-encoded signature #{i}: "); + stdin.read_line(&mut buffer).unwrap(); + let signature = hex::decode(buffer.trim()).unwrap(); + let signature: [u8; 64] = signature.try_into().unwrap(); + let signature = redpallas::Signature::::from(signature); + signatures.push(signature); + } + + proven + .append_signatures(&signatures) + .unwrap() + .finalize() + .unwrap() + }); + + let tx_data: TransactionData = + TransactionData::from_parts( + version, + consensus_branch_id, + 0, + BlockHeight::from_u32(tx_plan.expiry_height), + transparent_bundle, + None, + sapling_bundle, + orchard_bundle, + ); + let tx = tx_data.freeze().unwrap(); + let mut tx_bytes = vec![]; + tx.write(&mut tx_bytes).unwrap(); + Ok(BASE64_STANDARD.encode(&tx_bytes).as_bytes().to_vec()) +}