From 48afd8159585b29587dbcb5e4d5cf3a3a1b2b820 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 30 Sep 2024 12:05:00 -0500 Subject: [PATCH 1/3] feat!: migrate Orchard commitment trees to Frontier --- CHANGELOG.md | 12 +- librustzcash-wrapper/Cargo.lock | 286 ++++++++++++-------------------- librustzcash-wrapper/Cargo.toml | 13 +- librustzcash-wrapper/src/lib.rs | 122 +++++++++----- src/C/Zcash.chs | 11 +- src/ZcashHaskell/Orchard.hs | 31 ++-- src/ZcashHaskell/Types.hs | 9 + test/Spec.hs | 41 ++++- zcash-haskell.cabal | 2 +- 9 files changed, 283 insertions(+), 244 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a27c7a7..9a68512 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.7.1.0] + +### Added + +- Type `OrchardFrontier` + +### Changed + +- Modified Orchard commitment trees functions to use Frontier + ## [0.7.0.2] -## Changed +### Changed - Modified witness update functions to skip the process if no commitments are present diff --git a/librustzcash-wrapper/Cargo.lock b/librustzcash-wrapper/Cargo.lock index e74b7c7..604eeee 100644 --- a/librustzcash-wrapper/Cargo.lock +++ b/librustzcash-wrapper/Cargo.lock @@ -66,9 +66,9 @@ checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "base64ct" -version = "1.0.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bech32" @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "bip0039" -version = "0.10.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef0f0152ec5cf17f49a5866afaa3439816207fd4f0a224c0211ffaf5e278426" +checksum = "568b6890865156d9043af490d4c4081c385dd68ea10acd6ca15733d511e6b51c" dependencies = [ "hmac", "pbkdf2", @@ -132,6 +132,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "bip32" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b" +dependencies = [ + "bs58 0.5.0", + "hmac", + "rand_core", + "ripemd", + "secp256k1", + "sha2 0.10.6", + "subtle", + "zeroize", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -318,12 +334,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "bumpalo" -version = "3.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" - [[package]] name = "byteorder" version = "1.4.3" @@ -709,19 +719,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "hdwallet" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a03ba7d4c9ea41552cd4351965ff96883e629693ae85005c501bb4b9e1c48a7" -dependencies = [ - "lazy_static", - "rand_core", - "ring", - "secp256k1", - "thiserror", -] - [[package]] name = "heck" version = "0.4.1" @@ -760,9 +757,9 @@ dependencies = [ [[package]] name = "incrementalmerkletree" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1872810fb725b06b8c153dde9e86f3ec26747b9b60096da7a869883b549cbe" +checksum = "75346da3bd8e3d8891d02508245ed2df34447ca6637e343829f8d08986e9cde2" dependencies = [ "either", ] @@ -815,15 +812,6 @@ dependencies = [ "either", ] -[[package]] -name = "js-sys" -version = "0.3.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "jubjub" version = "0.10.0" @@ -999,9 +987,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "orchard" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb255c3ffdccd3c84fe9ebed72aef64fdc72e6a3e4180dd411002d47abaad42" +checksum = "4dc7bde644aeb980be296cd908c6650894dc8541deb56f9f5294c52ed7ca568f" dependencies = [ "aes", "bitvec", @@ -1022,6 +1010,7 @@ dependencies = [ "serde", "subtle", "tracing", + "visibility", "zcash_note_encryption", "zcash_spec", "zip32", @@ -1038,9 +1027,9 @@ dependencies = [ [[package]] name = "password-hash" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", "rand_core", @@ -1064,9 +1053,9 @@ dependencies = [ [[package]] name = "pbkdf2" -version = "0.10.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest 0.10.7", "password-hash", @@ -1147,9 +1136,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", "prost-derive", @@ -1157,9 +1146,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.12.3" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", "heck", @@ -1174,14 +1163,13 @@ dependencies = [ "regex", "syn 2.0.32", "tempfile", - "which", ] [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", "itertools", @@ -1192,9 +1180,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.12.3" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" dependencies = [ "prost", ] @@ -1341,21 +1329,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - [[package]] name = "ripemd" version = "0.1.3" @@ -1384,6 +1357,7 @@ name = "rustzcash-wrapper" version = "0.1.0" dependencies = [ "bech32 0.11.0", + "bip0039", "borsh 0.10.3", "f4jumble", "haskell-ffi", @@ -1405,9 +1379,9 @@ dependencies = [ [[package]] name = "sapling-crypto" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f4270033afcb0c74c5c7d59c73cfd1040367f67f224fe7ed9a919ae618f1b7" +checksum = "15e379398fffad84e49f9a45a05635fc004f66086e65942dbf4eb95332c26d2a" dependencies = [ "aes", "bellman", @@ -1443,9 +1417,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "secp256k1" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4124a35fe33ae14259c490fd70fa199a32b9ce9502f2ee6bc4f81ec06fa65894" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ "secp256k1-sys", ] @@ -1514,9 +1488,9 @@ dependencies = [ [[package]] name = "shardtree" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf20c7a2747d9083092e3a3eeb9a7ed75577ae364896bebbc5e0bdcd4e97735" +checksum = "78222845cd8bbe5eb95687407648ff17693a35de5e8abaa39a4681fb21e033f9" dependencies = [ "bitflags 2.4.2", "either", @@ -1649,13 +1623,14 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.10.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d021fc044c18582b9a2408cd0dd05b1596e3ecdb5c4df822bb0183545683889" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" dependencies = [ "prettyplease", "proc-macro2", "prost-build", + "prost-types", "quote", "syn 2.0.32", ] @@ -1718,9 +1693,9 @@ checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -1735,18 +1710,23 @@ dependencies = [ "subtle", ] -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "visibility" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + [[package]] name = "wagyu-zcash-parameters" version = "0.2.0" @@ -1803,70 +1783,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.32", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "web-sys" -version = "0.3.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "which" version = "4.4.0" @@ -1878,28 +1794,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-sys" version = "0.48.0" @@ -1989,21 +1883,22 @@ dependencies = [ [[package]] name = "zcash_address" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bce173f1d9ed4f806e310bc3a873301531e7a6dc209928584d6404e3f8228ef4" +checksum = "a6d26f21381dc220836dd8d2a9a10dbe85928a26232b011bc6a42b611789b743" dependencies = [ "bech32 0.9.1", "bs58 0.5.0", "f4jumble", "zcash_encoding", + "zcash_protocol", ] [[package]] name = "zcash_client_backend" -version = "0.11.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001ec65dc2828ee648dc6d29f0944d7a877fe68ad06e001a203c11770ab1b3d4" +checksum = "80e3a0f3e5d7f299d8b7ef3237697630989c31ab1b162824c99c1cd8bc83715e" dependencies = [ "base64", "bech32 0.9.1", @@ -2029,19 +1924,21 @@ dependencies = [ "tonic-build", "tracing", "which", - "zcash_address 0.3.1", + "zcash_address 0.4.0", "zcash_encoding", "zcash_keys", "zcash_note_encryption", "zcash_primitives", + "zcash_protocol", "zip32", + "zip321", ] [[package]] name = "zcash_encoding" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03391b81727875efa6ac0661a20883022b6fba92365dc121c48fa9b00c5aac0" +checksum = "052d8230202f0a018cd9b5d1b56b94cd25e18eccc2d8665073bcea8261ab87fc" dependencies = [ "byteorder", "nonempty", @@ -2049,11 +1946,12 @@ dependencies = [ [[package]] name = "zcash_keys" -version = "0.1.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f22d3407fdd6992b49f037f23862ab376be6013be6f2d0bc85948a635edc1f5" +checksum = "712faf4070107ab0b2828d0eda6aeaf4c3cb02564109832d95b97ad3467c95a5" dependencies = [ "bech32 0.9.1", + "blake2b_simd", "bls12_381", "bs58 0.5.0", "document-features", @@ -2062,11 +1960,13 @@ dependencies = [ "nonempty", "rand_core", "sapling-crypto", + "secrecy", "subtle", "tracing", - "zcash_address 0.3.1", + "zcash_address 0.4.0", "zcash_encoding", "zcash_primitives", + "zcash_protocol", "zip32", ] @@ -2085,20 +1985,20 @@ dependencies = [ [[package]] name = "zcash_primitives" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9070e084570bb78aed4f8d71fd6254492e62c87a5d01e084183980e98117092d" +checksum = "5f044bc9cf2887ec408196fbafb44749e5581f57cc18d8da7aabaeb60cc40c64" dependencies = [ "aes", - "bip0039", + "bip32", "blake2b_simd", + "bs58 0.5.0", "byteorder", "document-features", "equihash", "ff", "fpe", "group", - "hdwallet", "hex", "incrementalmerkletree", "jubjub", @@ -2114,13 +2014,24 @@ dependencies = [ "sha2 0.10.6", "subtle", "tracing", - "zcash_address 0.3.1", + "zcash_address 0.4.0", "zcash_encoding", "zcash_note_encryption", + "zcash_protocol", "zcash_spec", "zip32", ] +[[package]] +name = "zcash_protocol" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f35eac659fdbba614333d119217c5963c0d7cea43aee33176c4f2f95e5460d8d" +dependencies = [ + "document-features", + "memuse", +] + [[package]] name = "zcash_spec" version = "0.1.0" @@ -2160,3 +2071,16 @@ dependencies = [ "memuse", "subtle", ] + +[[package]] +name = "zip321" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc85f862f7be64fb0d46f9eb5b82ad54e58cde314fa979d5bae591bc0143693" +dependencies = [ + "base64", + "nom", + "percent-encoding", + "zcash_address 0.4.0", + "zcash_protocol", +] diff --git a/librustzcash-wrapper/Cargo.toml b/librustzcash-wrapper/Cargo.toml index abb27b5..208022f 100644 --- a/librustzcash-wrapper/Cargo.toml +++ b/librustzcash-wrapper/Cargo.toml @@ -11,19 +11,20 @@ f4jumble = "0.1" zcash_address = "0.2.0" borsh = "0.10" bech32 = "0.11" -orchard = "0.7.1" +orchard = "0.9.0" zcash_note_encryption = "0.4.0" -zcash_primitives = { version = "0.14.0", features = ["transparent-inputs"]} -zcash_client_backend = "0.11.1" -sapling-crypto = "0.1.3" +zcash_primitives = { version = "0.16.0", features = ["transparent-inputs"]} +zcash_client_backend = "0.13.0" +sapling-crypto = "0.2" zip32 = "0.1.0" proc-macro2 = "1.0.66" nonempty = "0.7.0" -incrementalmerkletree = "0.5.0" -secp256k1 = "0.26.0" +incrementalmerkletree = "0.6.0" +secp256k1 = "0.27.0" jubjub = "0.10.0" rand_core = { version = "0.6.4", features = ["getrandom"]} wagyu-zcash-parameters = "0.2.0" +bip0039 = "0.12.0" [features] diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index be36e38..63c4d2b 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -30,7 +30,12 @@ use secp256k1::SecretKey; use jubjub::Fr; use incrementalmerkletree::{ - frontier::CommitmentTree, + Position, + frontier::{ + CommitmentTree, + Frontier, + NonEmptyFrontier + }, witness::IncrementalWitness }; @@ -79,18 +84,20 @@ use sapling_crypto::{ } }; +use bip0039::{Count, Mnemonic, English}; + use zcash_primitives::{ merkle_tree::{ read_commitment_tree, write_commitment_tree, read_incremental_witness, - write_incremental_witness + write_incremental_witness, + read_frontier_v1 }, legacy::{ Script, TransparentAddress }, - zip339::{Count, Mnemonic}, transaction::{ Transaction, fees::zip317::FeeRule, @@ -147,7 +154,7 @@ use orchard::{ }, Action, keys::{SpendingKey, FullViewingKey, PreparedIncomingViewingKey, Scope}, - note::{RandomSeed, Note, Nullifier, TransmittedNoteCiphertext, ExtractedNoteCommitment}, + note::{Rho, RandomSeed, Note, Nullifier, TransmittedNoteCiphertext, ExtractedNoteCommitment}, note_encryption::OrchardDomain, primitives::redpallas::{VerificationKey, SpendAuth, Signature}, tree::{ @@ -686,6 +693,27 @@ impl ToHaskell for Hsvk { } } +#[derive(BorshSerialize, BorshDeserialize)] +pub struct Hfrontier { + position: u64, + leaf: Hhex, + ommers: Vec> +} + +impl ToHaskell for Hfrontier { + fn to_haskell(&self, writer: &mut W, _tag: PhantomData) -> Result<()> { + self.serialize(writer)?; + Ok(()) + } +} + +impl FromHaskell for Hfrontier { + fn from_haskell(buf: &mut &[u8], _tag: PhantomData) -> Result { + let x = Hfrontier::deserialize(buf)?; + Ok(x) + } +} + fn to_array(v: Vec) -> [T; N] { v.try_into().unwrap_or_else(|v: Vec| panic!("Expected a Vec of length {} but it was {}", N, v.len())) } @@ -1026,7 +1054,7 @@ pub extern "C" fn rust_wrapper_orchard_note_decrypt( ValueCommitment::from_bytes(&to_array(note_input.cv.bytes)).unwrap(), Signature::from(to_array(note_input.auth.bytes))); let fvk_array = to_array(fvk_input); - let domain = OrchardDomain::for_nullifier(*action.nullifier()); + let domain = OrchardDomain::for_action(&action); let dec_fvk = FullViewingKey::from_bytes(&fvk_array); match dec_fvk { Some(fvk) => { @@ -1073,7 +1101,7 @@ pub extern "C" fn rust_wrapper_orchard_note_decrypt_sk( ValueCommitment::from_bytes(&to_array(note_input.cv.bytes)).unwrap(), Signature::from(to_array(note_input.auth.bytes))); let sk_array = to_array(sk_input); - let domain = OrchardDomain::for_nullifier(*action.nullifier()); + let domain = OrchardDomain::for_action(&action); let dec_sk = SpendingKey::from_bytes(sk_array).unwrap(); let fvk = FullViewingKey::from(&dec_sk); let ivk = if external { @@ -1186,7 +1214,7 @@ pub extern "C" fn rust_wrapper_gen_seed_phrase( out: *mut u8, out_len: &mut usize ){ - let mnemonic = Mnemonic::generate(Count::Words24); + let mnemonic: Mnemonic = Mnemonic::generate(Count::Words24); let seed = mnemonic.phrase().as_bytes().to_vec(); marshall_to_haskell_var(&seed, out, out_len, RW); } @@ -1199,7 +1227,7 @@ pub extern "C" fn rust_wrapper_recover_seed( out_len: &mut usize ){ let phrase: String = marshall_from_haskell_var(input, input_len, RW); - let mnemonic = Mnemonic::from_phrase(phrase); + let mnemonic = >::from_phrase(phrase); match mnemonic { Ok(m) => { let s = m.to_seed("").to_vec(); @@ -1456,6 +1484,34 @@ pub extern "C" fn rust_wrapper_update_sapling_witness( } } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_orchard_frontier( + tree: *const u8, + tree_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + let tree_in: Vec = marshall_from_haskell_var(tree, tree_len, RW); + let tree_reader = Cursor::new(tree_in); + let comm_tree: CommitmentTree = read_commitment_tree(tree_reader).unwrap(); + //let comm_tree: Frontier = read_frontier_v1(tree_reader).unwrap(); + let frontier: Frontier = comm_tree.to_frontier(); + match frontier.value() { + Some(f1) => { + let (pos, leaf, omm) = f1.clone().into_parts(); + let f = Hfrontier { position: ::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| x.to_bytes().to_vec()).collect()}; + marshall_to_haskell_var(&f, out, out_len, RW); + }, + None => { + let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![vec![0]]}; + marshall_to_haskell_var(&f0, out, out_len, RW); + } + } +} + + + + #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_commitment_tree( tree: *const u8, @@ -1465,37 +1521,23 @@ pub extern "C" fn rust_wrapper_read_orchard_commitment_tree( out: *mut u8, out_len: &mut usize ){ - let tree_in: Vec = marshall_from_haskell_var(tree, tree_len, RW); - let tree_reader = Cursor::new(tree_in); - let ct = read_commitment_tree::>, 32>(tree_reader); - match ct { - Ok(mut comm_tree) => { - let node_in: Vec = marshall_from_haskell_var(node, node_len, RW); - let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(node_in)); - if orchard_note_comm.is_some().into() { - let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap()); - comm_tree.append(n); - let mut out_bytes: Vec = Vec::new(); - let result = write_commitment_tree(&comm_tree, &mut out_bytes ); - match result { - Ok(()) => { - let h = Hhex { bytes: out_bytes}; - marshall_to_haskell_var(&h, out, out_len, RW); - }, - Err(_e) => { - let h0 = Hhex { bytes: vec![0]}; - marshall_to_haskell_var(&h0, out, out_len, RW); - } - } - } else { - let h0 = Hhex { bytes: vec![0]}; - marshall_to_haskell_var(&h0, out, out_len, RW); - } - }, - Err(_e) => { - let h0 = Hhex { bytes: vec![0]}; - marshall_to_haskell_var(&h0, out, out_len, RW); - } + let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW); + //let tree_reader = Cursor::new(tree_in); + //let mut comm_tree: CommitmentTree = read_commitment_tree(tree_reader).unwrap(); + //let mut comm_tree: Frontier = read_frontier_v1(tree_reader).unwrap(); + let leaf = MerkleHashOrchard::from_bytes(&to_array(tree_in.leaf.bytes)).unwrap(); + let mut comm_tree: NonEmptyFrontier = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.clone())).unwrap() ).collect()).unwrap(); + let node_in: Vec = marshall_from_haskell_var(node, node_len, RW); + let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(node_in)); + if orchard_note_comm.is_some().into() { + let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap()); + comm_tree.append(n); + let (pos, leaf, omm) = comm_tree.into_parts(); + let f = Hfrontier { position: ::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| x.to_bytes().to_vec()).collect()}; + marshall_to_haskell_var(&f, out, out_len, RW); + } else { + let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![vec![0]]}; + marshall_to_haskell_var(&f0, out, out_len, RW); } } @@ -1726,7 +1768,7 @@ pub extern "C" fn rust_wrapper_create_transaction( if o_in.sk.len() > 1 { let sp_key = SpendingKey::from_bytes(o_in.sk[0..32].try_into().unwrap()).unwrap(); let pay_addr = OrchardAddress::from_raw_address_bytes(&to_array(o_in.note.recipient)).unwrap(); - let rho = Nullifier::from_bytes(&to_array(o_in.note.rho)).unwrap(); + let rho = Rho::from_bytes(&to_array(o_in.note.rho)).unwrap(); let rseed = RandomSeed::from_bytes(to_array(o_in.note.rseed.bytes), &rho).unwrap(); let val = NoteValue::from_raw(o_in.note.note); let note = Note::from_parts(pay_addr, val, rho, rseed).unwrap(); diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index bc75ee4..884d0e6 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -240,9 +240,16 @@ import ZcashHaskell.Types #} {# fun unsafe rust_wrapper_read_orchard_commitment_tree as rustWrapperReadOrchardCommitmentTree - { toBorshVar* `BS.ByteString'& + { toBorshVar* `OrchardFrontier'& , toBorshVar* `BS.ByteString'& - , getVarBuffer `Buffer HexString'& + , getVarBuffer `Buffer OrchardFrontier'& + } + -> `()' +#} + +{# fun unsafe rust_wrapper_read_orchard_frontier as rustWrapperReadOrchardFrontier + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer OrchardFrontier'& } -> `()' #} diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index d975c2a..a4ef75a 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -24,6 +24,7 @@ import C.Zcash , rustWrapperOrchardNoteDecode , rustWrapperOrchardNoteDecodeSK , rustWrapperReadOrchardCommitmentTree + , rustWrapperReadOrchardFrontier , rustWrapperReadOrchardPosition , rustWrapperReadOrchardWitness , rustWrapperUADecode @@ -194,21 +195,29 @@ decryptOrchardActionSK sk scope oa = withPureBorshVarBuffer $ rustWrapperOrchardNoteDecodeSK (getBytes sk) oa (scope == External) --- | Update a Orchard commitment tree -updateOrchardCommitmentTree :: - OrchardCommitmentTree -- ^ the base tree - -> HexString -- ^ the new note commitment - -> Maybe OrchardCommitmentTree -updateOrchardCommitmentTree tree cmx = - if BS.length (hexBytes updatedTree) > 1 - then Just $ OrchardCommitmentTree updatedTree +getOrchardFrontier :: OrchardCommitmentTree -> Maybe OrchardFrontier +getOrchardFrontier tree = + if of_pos updatedTree > 1 + then Just updatedTree else Nothing where updatedTree = withPureBorshVarBuffer $ - rustWrapperReadOrchardCommitmentTree - (hexBytes $ orchTree tree) - (hexBytes cmx) + rustWrapperReadOrchardFrontier $ toBytes $ orchTree tree + +-- | Update a Orchard commitment tree +updateOrchardCommitmentTree :: + OrchardFrontier -- ^ the base tree + -> HexString -- ^ the new note commitment + -> Maybe OrchardFrontier +updateOrchardCommitmentTree tree cmx = + if of_pos updatedTree > 1 + then Just updatedTree + else Nothing + where + updatedTree = + withPureBorshVarBuffer $ + rustWrapperReadOrchardCommitmentTree tree (hexBytes cmx) -- | Get the Orchard incremental witness from a commitment tree getOrchardWitness :: OrchardCommitmentTree -> Maybe OrchardWitness diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index 1647b42..0fc44c3 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -708,6 +708,15 @@ newtype OrchardCommitmentTree = OrchardCommitmentTree { orchTree :: HexString } deriving (Eq, Prelude.Show, Read) +data OrchardFrontier = OrchardFrontier + { of_pos :: !Int64 + , of_leaf :: !HexString + , of_ommers :: ![BS.ByteString] + } deriving stock (Eq, Prelude.Show, GHC.Generic) + deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) + deriving anyclass (Data.Structured.Show) + deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardFrontier + -- | Type for a Sapling incremental witness newtype OrchardWitness = OrchardWitness { orchWit :: HexString diff --git a/test/Spec.hs b/test/Spec.hs index ac4581e..ac744cb 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -922,7 +922,7 @@ main = do getSaplingNotePosition <$> (getSaplingWitness =<< updateSaplingCommitmentTree tree cmu1) p `shouldBe` Just 129405 - describe "Orchard commitment trees" $ do + {- describe "Orchard commitment trees" $ do let tree = OrchardCommitmentTree $ hexString @@ -942,7 +942,7 @@ main = do let p = getOrchardNotePosition <$> (getOrchardWitness =<< updateOrchardCommitmentTree tree cmx) - p `shouldBe` Just 39432 + p `shouldBe` Just 39432 -} describe "Extract Sapling Address - UA Valid" $ do let sr = getSaplingFromUA @@ -1148,6 +1148,43 @@ main = do Just addr -> do let eadr = decodeExchangeAddress (E.encodeUtf8 addr) eadr `shouldNotBe` Nothing + describe "Tree updates" $ do + it "Orchard" $ do + let tree = + OrchardCommitmentTree $ + hexString + "0136a7886d7d73bc1845223165fd9cb0cef02046c707e8f88a7f61564720bd0f3501dca1fbdd7b5ba92a0809af5e85874626ce0db14d0532a48e41dde6f0f81b46011f0001fb48c27bd07e68f27aba47cd6e93fa961e0ef8c63f993963a614e56855d2013c0001ea572db9c5c2d24c7ad9132ae32b27179466bf67a580d59901d13b281d3f530b01c160348f10b9ad893d9731317ebe36ac8665e01c52cbe15a56aa9b72e4e6c41e000001cd7695156de2debdc5b13ea84d32e4e3ac020fb0aa7cd372c57ce765103bd70401746e6bc066a10e7f80a9ff8993dcb25c819edd64f2ca10ac248ef7848d41450500011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000" + let cmx1 = + hexString + "1712ead46028d4349e234abf59e94e0640fe7a0829e2e2e17e1a931631810400" + let cmx2 = + hexString + "39f5ad39817fb432fa07c5feb3a957189fbe7662a4b5555ca95093b6d853cf07" + let cmx3 = + hexString + "84f7fbc4b9f87215c653078d7fdd90756c3ba370c745065167da9eb73a65a83f" + let cmx4 = + hexString + "e55ad64e1ea2b261893fdea6ad0509b66e5f62d3142f351298c7135c4498d429" + let finalTree = + getOrchardFrontier $ + OrchardCommitmentTree $ + hexString + "0184f7fbc4b9f87215c653078d7fdd90756c3ba370c745065167da9eb73a65a83f01e55ad64e1ea2b261893fdea6ad0509b66e5f62d3142f351298c7135c4498d4291f0000014b1a76d3820087b26cd087ca84e17f3067a25ebed82ad23a93fa485affb5530b01ea572db9c5c2d24c7ad9132ae32b27179466bf67a580d59901d13b281d3f530b01c160348f10b9ad893d9731317ebe36ac8665e01c52cbe15a56aa9b72e4e6c41e000001cd7695156de2debdc5b13ea84d32e4e3ac020fb0aa7cd372c57ce765103bd70401746e6bc066a10e7f80a9ff8993dcb25c819edd64f2ca10ac248ef7848d41450500011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000" + case getOrchardFrontier tree of + Nothing -> assertFailure "Failed to get frontier" + Just t1 -> + case updateOrchardCommitmentTree t1 cmx1 of + Nothing -> assertFailure "Failed to update frontier with cmx" + Just t2 -> + case updateOrchardCommitmentTree t2 cmx2 of + Nothing -> assertFailure "Failed to update frontier with cmx" + Just t3 -> + case updateOrchardCommitmentTree t3 cmx3 of + Nothing -> + assertFailure "Failed to update frontier with cmx" + Just t4 -> + updateOrchardCommitmentTree t4 cmx4 `shouldBe` finalTree describe "Witness updates" $ do it "Sapling" $ do let wit = diff --git a/zcash-haskell.cabal b/zcash-haskell.cabal index a3288b5..bcec9de 100644 --- a/zcash-haskell.cabal +++ b/zcash-haskell.cabal @@ -5,7 +5,7 @@ cabal-version: 3.0 -- see: https://github.com/sol/hpack name: zcash-haskell -version: 0.7.0.2 +version: 0.7.1.0 synopsis: Utilities to interact with the Zcash blockchain description: Please see the README on the repo at category: Blockchain -- 2.34.1 From 38e4131daaebd45bfe005e753b0b5716a4481d89 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 30 Sep 2024 13:18:47 -0500 Subject: [PATCH 2/3] feat!: update Orchard witness calculation Now uses Frontier --- librustzcash-wrapper/src/lib.rs | 7 ++++--- src/C/Zcash.chs | 2 +- src/ZcashHaskell/Orchard.hs | 6 ++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 63c4d2b..6034424 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1548,9 +1548,10 @@ pub extern "C" fn rust_wrapper_read_orchard_witness( out: *mut u8, out_len: &mut usize ){ - let tree_in: Vec = marshall_from_haskell_var(tree, tree_len, RW); - let tree_reader = Cursor::new(tree_in); - let ct: CommitmentTree = read_commitment_tree(tree_reader).unwrap(); + let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW); + let leaf = MerkleHashOrchard::from_bytes(&to_array(tree_in.leaf.bytes)).unwrap(); + let frontier: Frontier = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.clone())).unwrap() ).collect()).unwrap(); + let ct: CommitmentTree = CommitmentTree::from_frontier(&frontier); let inc_wit = IncrementalWitness::from_tree(ct); let mut out_bytes: Vec = Vec::new(); let result = write_incremental_witness(&inc_wit, &mut out_bytes); diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 884d0e6..beb11e2 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -255,7 +255,7 @@ import ZcashHaskell.Types #} {# fun unsafe rust_wrapper_read_orchard_witness as rustWrapperReadOrchardWitness - { toBorshVar* `BS.ByteString'& + { toBorshVar* `OrchardFrontier'& , getVarBuffer `Buffer HexString'& } -> `()' diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index a4ef75a..1bb7167 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -220,15 +220,13 @@ updateOrchardCommitmentTree tree cmx = rustWrapperReadOrchardCommitmentTree tree (hexBytes cmx) -- | Get the Orchard incremental witness from a commitment tree -getOrchardWitness :: OrchardCommitmentTree -> Maybe OrchardWitness +getOrchardWitness :: OrchardFrontier -> Maybe OrchardWitness getOrchardWitness tree = if BS.length (hexBytes wit) > 1 then Just $ OrchardWitness wit else Nothing where - wit = - withPureBorshVarBuffer $ - rustWrapperReadOrchardWitness (hexBytes $ orchTree tree) + wit = withPureBorshVarBuffer $ rustWrapperReadOrchardWitness tree -- | Get the Sapling note position from a witness getOrchardNotePosition :: OrchardWitness -> Integer -- 2.34.1 From 3969490283420af0bb193590a1e5d4b6828cc2f9 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 30 Sep 2024 14:50:54 -0500 Subject: [PATCH 3/3] feat: Use the notes to determine anchors --- librustzcash-wrapper/src/lib.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 6034424..10e8df0 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1702,14 +1702,24 @@ pub extern "C" fn rust_wrapper_create_transaction( let orch_wit_in: Vec = marshall_from_haskell_var(orch_wit, orch_wit_len, RW); let orch_wit_reader = Cursor::new(orch_wit_in); let orch_iw = read_commitment_tree::>, 32>(orch_wit_reader); - let orch_anchor = match orch_iw { - Ok(o_iw) => { - Some(OrchardAnchor::from(o_iw.root())) - }, - Err(_e) => { + let orch_input: Vec = marshall_from_haskell_var(o_input, o_input_len, RW); + //let orch_anchor = match orch_iw { + //Ok(o_iw) => { + //Some(OrchardAnchor::from(o_iw.root())) + //}, + //Err(_e) => { + //None + //} + //}; + let orch_anchor = + if orch_input.is_empty() { None - } - }; + } else { + let oi = &orch_input[0]; + let wit_reader = Cursor::new(&oi.iw); + let iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); + Some(OrchardAnchor::from(iw.root())) + }; let build_config = BuildConfig::Standard {sapling_anchor: sap_anchor, orchard_anchor: orch_anchor}; let mut main_builder = Builder::new(MainNetwork, BlockHeight::from(bl_height), build_config); let mut test_builder = Builder::new(TestNetwork, BlockHeight::from(bl_height), build_config); @@ -1764,7 +1774,6 @@ pub extern "C" fn rust_wrapper_create_transaction( } } } - let orch_input: Vec = marshall_from_haskell_var(o_input, o_input_len, RW); for o_in in orch_input { if o_in.sk.len() > 1 { let sp_key = SpendingKey::from_bytes(o_in.sk[0..32].try_into().unwrap()).unwrap(); -- 2.34.1