From 004e2c85cd2dbb5f59ba3ee6b06937596bc49c7a Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Sun, 27 Oct 2024 06:42:04 -0500 Subject: [PATCH 01/48] feat: creation of Orchard commitment nodes --- CHANGELOG.md | 11 ++ librustzcash-wrapper/src/lib.rs | 138 ++++++++++++++++++++---- src/C/Zcash.chs | 30 ++++++ src/ZcashHaskell/Orchard.hs | 36 ++++++- src/ZcashHaskell/Types.hs | 4 +- test/Spec.hs | 181 +++++++++++++++++--------------- zcash-haskell.cabal | 2 +- 7 files changed, 292 insertions(+), 110 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bdb344..9eed57f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ 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.3.0] + +### Added + +- Function to create an Orchard hash from a note commitment +- Function to hash Orchard commitments + +### Changed + +- Modified frontiers to use `HexString` for ommers + ## [0.7.2.0] ### Changed diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 92e9319..e7b5d04 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -30,6 +30,8 @@ use secp256k1::SecretKey; use jubjub::Fr; use incrementalmerkletree::{ + Hashable, + Level, Position, frontier::{ CommitmentTree, @@ -92,7 +94,8 @@ use zcash_primitives::{ write_commitment_tree, read_incremental_witness, write_incremental_witness, - read_frontier_v1 + read_frontier_v1, + read_nonempty_frontier_v1 }, legacy::{ Script, @@ -697,7 +700,7 @@ impl ToHaskell for Hsvk { pub struct Hfrontier { position: u64, leaf: Hhex, - ommers: Vec> + ommers: Vec } impl ToHaskell for Hfrontier { @@ -1384,11 +1387,11 @@ pub extern "C" fn rust_wrapper_read_sapling_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()}; + let f = Hfrontier { position: ::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: 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]]}; + let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]}; marshall_to_haskell_var(&f0, out, out_len, RW); } } @@ -1405,17 +1408,17 @@ pub extern "C" fn rust_wrapper_read_sapling_commitment_tree( ){ let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW); let leaf = Node::from_bytes(to_array(tree_in.leaf.bytes)).unwrap(); - let mut comm_tree = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| Node::from_bytes(to_array(x.clone())).unwrap() ).collect()).unwrap(); + let mut comm_tree = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| Node::from_bytes(to_array(x.bytes.clone())).unwrap() ).collect()).unwrap(); let node_in: Vec = marshall_from_haskell_var(node, node_len, RW); let sap_note_comm = SaplingNoteCommitment::from_bytes(&to_array(node_in)); if sap_note_comm.is_some().into() { let n = Node::from_cmu(&sap_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()}; + let f = Hfrontier { position: ::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: 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]]}; + let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]}; marshall_to_haskell_var(&f0, out, out_len, RW); } } @@ -1429,7 +1432,7 @@ pub extern "C" fn rust_wrapper_read_sapling_witness( ){ let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW); let leaf = Node::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| Node::from_bytes(to_array(x.clone())).unwrap() ).collect()).unwrap(); + let frontier: Frontier = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| Node::from_bytes(to_array(x.bytes.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(); @@ -1501,23 +1504,114 @@ pub extern "C" fn rust_wrapper_read_orchard_frontier( ){ 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); + let comm_tree = read_commitment_tree(tree_reader); + //let comm_tree = read_frontier_v1(tree_reader); + //let frontier: Frontier = comm_tree.to_frontier(); + match comm_tree { + Ok::, _>(f1) => { + let frontier = f1.to_frontier(); + match frontier.value() { + Some(f2) => { + let (pos, leaf, omm) = f2.clone().into_parts(); + let f = Hfrontier { position: ::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: 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![Hhex { bytes: vec![0]}]}; + marshall_to_haskell_var(&f0, out, out_len, RW); + } + } }, - None => { - let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![vec![0]]}; + Err(_e) => { + let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]}; marshall_to_haskell_var(&f0, out, out_len, RW); } } } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_orchard_tree_anchor( + tree: *const u8, + tree_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + 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 comm_tree: NonEmptyFrontier = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap(); + let root = comm_tree.root(None); + let h = Hhex { bytes: root.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); +} +#[no_mangle] +pub extern "C" fn rust_wrapper_read_orchard_witness_anchor( + wit: *const u8, + wit_len: usize, + out: *mut u8, + out_len: &mut usize + ) { + let wit_in: Vec = marshall_from_haskell_var(wit, wit_len, RW); + let wit_reader = Cursor::new(wit_in); + let iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); + let root = iw.root(); + let h = Hhex { bytes: root.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); +} + +#[no_mangle] +pub extern "C" fn rust_wrapper_read_orchard_node( + cmx: *const u8, + cmx_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + let node_in: Vec = marshall_from_haskell_var(cmx, cmx_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()); + let h = Hhex { bytes: n.to_bytes().to_vec()}; + marshall_to_haskell_var(&h, out, out_len, RW); + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } +} + +#[no_mangle] +pub extern "C" fn rust_wrapper_combine_orchard_nodes( + level: u8, + left: *const u8, + left_len: usize, + right: *const u8, + right_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + let left_in: Vec = marshall_from_haskell_var(left, left_len, RW); + let right_in: Vec = marshall_from_haskell_var(right, right_len, RW); + let left_node = MerkleHashOrchard::from_bytes(&to_array(left_in)); + if left_node.is_some().into() { + if right_in.len() > 1 { + let right_node = MerkleHashOrchard::from_bytes(&to_array(right_in)); + if right_node.is_some().into() { + let n = MerkleHashOrchard::combine(Level::new(level), &left_node.unwrap(), &right_node.unwrap()); + let h = Hhex { bytes: n.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } + } else { + let n = MerkleHashOrchard::combine(Level::new(level), &left_node.unwrap(), &MerkleHashOrchard::empty_leaf()); + let h = Hhex { bytes: n.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + } + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } +} #[no_mangle] @@ -1534,17 +1628,17 @@ pub extern "C" fn rust_wrapper_read_orchard_commitment_tree( //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 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.bytes.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()}; + let f = Hfrontier { position: ::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: 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]]}; + let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]}; marshall_to_haskell_var(&f0, out, out_len, RW); } } @@ -1558,7 +1652,7 @@ pub extern "C" fn rust_wrapper_read_orchard_witness( ){ 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 frontier: Frontier = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.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(); diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 71c73e5..da2f86b 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -246,6 +246,36 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_read_orchard_node as rustWrapperReadOrchardNode + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + +{# fun unsafe rust_wrapper_combine_orchard_nodes as rustWrapperCombineOrchardNodes + { `Int8' + , toBorshVar* `BS.ByteString'& + , toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + +{# fun unsafe rust_wrapper_read_orchard_tree_anchor as rustWrapperReadOrchardTreeAnchor + { toBorshVar* `OrchardFrontier'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + +{# fun unsafe rust_wrapper_read_orchard_witness_anchor as rustWrapperReadOrchardWitnessAnchor + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_read_orchard_commitment_tree as rustWrapperReadOrchardCommitmentTree { toBorshVar* `OrchardFrontier'& , toBorshVar* `BS.ByteString'& diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 1bb7167..79043ea 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -18,15 +18,19 @@ module ZcashHaskell.Orchard where import C.Zcash - ( rustWrapperGenOrchardReceiver + ( rustWrapperCombineOrchardNodes + , rustWrapperGenOrchardReceiver , rustWrapperGenOrchardSpendKey , rustWrapperOrchardCheck , rustWrapperOrchardNoteDecode , rustWrapperOrchardNoteDecodeSK , rustWrapperReadOrchardCommitmentTree , rustWrapperReadOrchardFrontier + , rustWrapperReadOrchardNode , rustWrapperReadOrchardPosition + , rustWrapperReadOrchardTreeAnchor , rustWrapperReadOrchardWitness + , rustWrapperReadOrchardWitnessAnchor , rustWrapperUADecode , rustWrapperUfvkDecode , rustWrapperUpdateOrchardWitness @@ -205,6 +209,15 @@ getOrchardFrontier tree = withPureBorshVarBuffer $ rustWrapperReadOrchardFrontier $ toBytes $ orchTree tree +getOrchardTreeAnchor :: OrchardFrontier -> HexString +getOrchardTreeAnchor tree = + withPureBorshVarBuffer $ rustWrapperReadOrchardTreeAnchor tree + +getOrchardWitnessAnchor :: OrchardWitness -> HexString +getOrchardWitnessAnchor wit = + withPureBorshVarBuffer $ + rustWrapperReadOrchardWitnessAnchor $ toBytes $ orchWit wit + -- | Update a Orchard commitment tree updateOrchardCommitmentTree :: OrchardFrontier -- ^ the base tree @@ -244,6 +257,27 @@ updateOrchardWitness wit cmus = (map toBytes cmus) else wit +getOrchardNodeValue :: BS.ByteString -> Maybe HexString +getOrchardNodeValue cmx = + if BS.length (hexBytes n) > 1 + then Just n + else Nothing + where + n = withPureBorshVarBuffer $ rustWrapperReadOrchardNode cmx + +combineOrchardNodes :: Integer -> HexString -> HexString -> Maybe HexString +combineOrchardNodes level n1 n2 = + if BS.length (hexBytes r) > 1 + then Just r + else Nothing + where + r = + withPureBorshVarBuffer $ + rustWrapperCombineOrchardNodes + (fromIntegral level) + (toBytes n1) + (toBytes n2) + -- | Parse a potential Zcash address parseAddress :: BS.ByteString -> Maybe ValidAddress parseAddress t = diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index 8105d30..324216f 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -614,7 +614,7 @@ newtype SaplingCommitmentTree = SaplingCommitmentTree data SaplingFrontier = SaplingFrontier { sf_pos :: !Int64 , sf_leaf :: !HexString - , sf_ommers :: ![BS.ByteString] + , sf_ommers :: ![HexString] } deriving stock (Eq, Prelude.Show, GHC.Generic) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (Data.Structured.Show) @@ -730,7 +730,7 @@ newtype OrchardCommitmentTree = OrchardCommitmentTree data OrchardFrontier = OrchardFrontier { of_pos :: !Int64 , of_leaf :: !HexString - , of_ommers :: ![BS.ByteString] + , of_ommers :: ![HexString] } deriving stock (Eq, Prelude.Show, GHC.Generic) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (Data.Structured.Show) diff --git a/test/Spec.hs b/test/Spec.hs index ac744cb..0547e16 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -55,6 +55,7 @@ import ZcashHaskell.Sapling , genSaplingInternalAddress , genSaplingPaymentAddress , genSaplingSpendingKey + , getSaplingFrontier , getSaplingNotePosition , getSaplingWitness , getShieldedOutputs @@ -73,6 +74,7 @@ import ZcashHaskell.Types , OrchardAction(..) , OrchardBundle(..) , OrchardCommitmentTree(..) + , OrchardFrontier(..) , OrchardSpendingKey(..) , OrchardWitness(..) , Phrase(..) @@ -88,6 +90,7 @@ import ZcashHaskell.Types , SaplingAddress(..) , SaplingBundle(..) , SaplingCommitmentTree(..) + , SaplingFrontier(..) , SaplingReceiver(..) , SaplingSpendingKey(..) , SaplingWitness(..) @@ -895,33 +898,35 @@ main = do Just t' -> do let tb = zt_tBundle t' show tb `shouldNotBe` "" - describe "Sapling commitment trees" $ do - let tree = - SaplingCommitmentTree $ - hexString - "01916df07670600aefa3b412a120d6b8d9a3d2ff9466a7ec770cd52d34ddb42313001000013c60b031a5e44650059fcc7101a3f551b807ab8b3a116a5a9c7fa0f3babbe735017c0d36686294ff19d59e58b6a2ac6a7ad607a804bc202c84012d8e94f233970c0128dbde5180af5304d8577376d78297130b615a327974c10881f6d876869aea05011b80b4ca60f74dfe33c78b062df73c84b8b44dab4604db16f5b61eea40134373010c96e4cc8a6a80fba0d41e4eb3070d80769104dc33fb61133b1304c15bf9e23e000107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39" - let cmu1 = - hexString - "45e47c5df6f5c5e48aa3526e977b2d1b57eda57214e36f06128008cb17b0125f" - let cmu2 = - hexString - "426ef44b3b22e0eeda7e4d2b62bac63966572b224e50f97ee56c9490cde4910d" - let tree2 = - hexString - "01a47029e9b43722c57143a5d07681bff3e2315c9a28ad49d69e7c1f2f6e81ac160010000000000000012f4f72c03f8c937a94919a01a07f21165cc8394295291cb888ca91ed003810390107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39" - it "Commitment tree is updated correctly" $ do - let t1 = updateSaplingCommitmentTree tree cmu1 - t1 `shouldNotBe` Nothing - it "Incremental witness is generated" $ do - let t1 = updateSaplingCommitmentTree tree cmu1 - case t1 of - Nothing -> assertFailure "Failed to append node to tree" - Just t -> getSaplingWitness t `shouldNotBe` Nothing - it "Position of note is obtained" $ do - let p = - getSaplingNotePosition <$> - (getSaplingWitness =<< updateSaplingCommitmentTree tree cmu1) - p `shouldBe` Just 129405 + {- + -describe "Sapling commitment trees" $ do + - let tree = + - SaplingCommitmentTree $ + - hexString + - "01916df07670600aefa3b412a120d6b8d9a3d2ff9466a7ec770cd52d34ddb42313001000013c60b031a5e44650059fcc7101a3f551b807ab8b3a116a5a9c7fa0f3babbe735017c0d36686294ff19d59e58b6a2ac6a7ad607a804bc202c84012d8e94f233970c0128dbde5180af5304d8577376d78297130b615a327974c10881f6d876869aea05011b80b4ca60f74dfe33c78b062df73c84b8b44dab4604db16f5b61eea40134373010c96e4cc8a6a80fba0d41e4eb3070d80769104dc33fb61133b1304c15bf9e23e000107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39" + - let cmu1 = + - hexString + - "45e47c5df6f5c5e48aa3526e977b2d1b57eda57214e36f06128008cb17b0125f" + - let cmu2 = + - hexString + - "426ef44b3b22e0eeda7e4d2b62bac63966572b224e50f97ee56c9490cde4910d" + - let tree2 = + - hexString + - "01a47029e9b43722c57143a5d07681bff3e2315c9a28ad49d69e7c1f2f6e81ac160010000000000000012f4f72c03f8c937a94919a01a07f21165cc8394295291cb888ca91ed003810390107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39" + - it "Commitment tree is updated correctly" $ do + - let t1 = updateSaplingCommitmentTree tree cmu1 + - t1 `shouldNotBe` Nothing + - it "Incremental witness is generated" $ do + - let t1 = updateSaplingCommitmentTree tree cmu1 + - case t1 of + - Nothing -> assertFailure "Failed to append node to tree" + - Just t -> getSaplingWitness t `shouldNotBe` Nothing + - it "Position of note is obtained" $ do + - let p = + - getSaplingNotePosition <$> + - (getSaplingWitness =<< updateSaplingCommitmentTree tree cmu1) + - p `shouldBe` Just 129405 + -} {- describe "Orchard commitment trees" $ do let tree = OrchardCommitmentTree $ @@ -1061,18 +1066,22 @@ main = do (hexString "97e5f003d16720844ba1bd157688a7697133f4bb4a33a7c91974937a1351d7af56d16d4a10bd196ddda700fcd8be517f8f9e39a17ba0eea235d98450a626be3a998ac31f35e8e082106a31fe94da11d02b73748db4aa519df6bbf25c1d62a2cf0b192c6a486bca2632fee9e4124ce2dba6f3366a14850f6a3b784d863119f52458ed774f8d63105b4f6a3d2e09cc74e3a02ec8386213087b4c849172ded6724a45c9c12744ec4a0f86a29b803b17187df5dd5f90e71d1f3f4578d4e1496e8892") it "Sap output 1" $ do - let pos = - getSaplingNotePosition <$> - (getSaplingWitness =<< - updateSaplingCommitmentTree - tree - (fromText - "fa430c51bb108db782764cff55de9c6b11bbecd2493d2e0fa9f646428feef858")) - case pos of - Nothing -> assertFailure "couldn't get note position" - Just p -> do - let dn = decodeSaplingOutputEsk sk so1 TestNet External p - dn `shouldBe` Nothing + case getSaplingFrontier tree of + Nothing -> assertFailure "failed to read comm tree" + Just tree' -> do + let pos = + sf_pos <$> + updateSaplingCommitmentTree + tree' + (fromText + "fa430c51bb108db782764cff55de9c6b11bbecd2493d2e0fa9f646428feef858") + case pos of + Nothing -> assertFailure "couldn't get note position" + Just p -> do + let dn = + decodeSaplingOutputEsk sk so1 TestNet External $ + fromIntegral p + dn `shouldBe` Nothing it "Sap output 2" $ do case readZebraTransaction txHex2 of Nothing -> assertFailure "Failed to read Tx" @@ -1082,24 +1091,27 @@ main = do Nothing -> assertFailure "Failed to get sapling bundle" Just sB -> do let sOuts = sbOutputs sB - let pos = - getSaplingNotePosition <$> - (getSaplingWitness =<< - updateSaplingCommitmentTree - tree - (fromText - "d163c69029e8cb05d874b798c7973b3b1b1b0e04f984a252b73c848698320843")) - case pos of - Nothing -> assertFailure "couldn't get note position" - Just p -> do - let dn = - decodeSaplingOutputEsk - sk - (head . tail $ sOuts) - TestNet - External - p - dn `shouldBe` Nothing + case getSaplingFrontier tree of + Nothing -> assertFailure "Failed to read tree" + Just tree' -> do + let pos = + getSaplingNotePosition <$> + (getSaplingWitness =<< + updateSaplingCommitmentTree + tree' + (fromText + "d163c69029e8cb05d874b798c7973b3b1b1b0e04f984a252b73c848698320843")) + case pos of + Nothing -> assertFailure "couldn't get note position" + Just p -> do + let dn = + decodeSaplingOutputEsk + sk + (head . tail $ sOuts) + TestNet + External + p + dn `shouldBe` Nothing it "Decode Sapling Output from Zingo" $ do case readZebraTransaction txHex of Nothing -> assertFailure "Failed to read Tx" @@ -1112,24 +1124,26 @@ main = do Nothing -> assertFailure "Failed to get sapling bundle" Just sB -> do let sOuts = sbOutputs sB - let pos = - getSaplingNotePosition <$> - (getSaplingWitness =<< - updateSaplingCommitmentTree - tree - (fromText - "d163c69029e8cb05d874b798c7973b3b1b1b0e04f984a252b73c848698320843")) - case pos of - Nothing -> assertFailure "couldn't get note position" - Just p -> do - let dn = - decodeSaplingOutputEsk - sK' - (head . tail $ sOuts) - MainNet - External - p - dn `shouldNotBe` Nothing + case getSaplingFrontier tree of + Nothing -> assertFailure "failed to read comm tree" + Just tree' -> do + let pos = + sf_pos <$> + updateSaplingCommitmentTree + tree' + (fromText + "d163c69029e8cb05d874b798c7973b3b1b1b0e04f984a252b73c848698320843") + case pos of + Nothing -> assertFailure "couldn't get note position" + Just p -> do + let dn = + decodeSaplingOutputEsk + sK' + (head . tail $ sOuts) + MainNet + External + (fromIntegral p) + dn `shouldNotBe` Nothing describe "Generate an ExchangeAddress (MainNet) from transparent address" $ do let ta = decodeTransparentAddress "t1dMjvesbzdG41xgKaGU3HgwYJwSgbCK54e" it "Try to generate valid ExchangeAddress from Transparent Address" $ do @@ -1176,15 +1190,14 @@ main = do 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 + Just t2 -> do + case getOrchardWitness t2 of + Nothing -> assertFailure "Failed to get witness" + Just wit -> do + let uWit = updateOrchardWitness wit [cmx2, cmx3, cmx4] + Just (getOrchardWitnessAnchor uWit) `shouldBe` + getOrchardTreeAnchor <$> + finalTree describe "Witness updates" $ do it "Sapling" $ do let wit = diff --git a/zcash-haskell.cabal b/zcash-haskell.cabal index edad0f8..36ce2ae 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.2.0 +version: 0.7.3.0 synopsis: Utilities to interact with the Zcash blockchain description: Please see the README on the repo at category: Blockchain -- 2.34.1 From 2e9e6d8831cda2507d5fd893aea2b040ac11a813 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 28 Oct 2024 11:59:07 -0500 Subject: [PATCH 02/48] feat: allow combining empty Orchard leaves --- librustzcash-wrapper/src/lib.rs | 40 +++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index e7b5d04..df054c6 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1590,26 +1590,32 @@ pub extern "C" fn rust_wrapper_combine_orchard_nodes( ){ let left_in: Vec = marshall_from_haskell_var(left, left_len, RW); let right_in: Vec = marshall_from_haskell_var(right, right_len, RW); - let left_node = MerkleHashOrchard::from_bytes(&to_array(left_in)); - if left_node.is_some().into() { - if right_in.len() > 1 { - let right_node = MerkleHashOrchard::from_bytes(&to_array(right_in)); - if right_node.is_some().into() { - let n = MerkleHashOrchard::combine(Level::new(level), &left_node.unwrap(), &right_node.unwrap()); - let h = Hhex { bytes: n.to_bytes().to_vec() }; - marshall_to_haskell_var(&h, out, out_len, RW); - } else { - let h0 = Hhex { bytes: vec![0] }; - marshall_to_haskell_var(&h0, out, out_len, RW); - } - } else { - let n = MerkleHashOrchard::combine(Level::new(level), &left_node.unwrap(), &MerkleHashOrchard::empty_leaf()); + if left_in.len() > 1 { + let n = MerkleHashOrchard::combine(Level::new(level), &MerkleHashOrchard::empty_leaf(), &MerkleHashOrchard::empty_leaf()); let h = Hhex { bytes: n.to_bytes().to_vec() }; marshall_to_haskell_var(&h, out, out_len, RW); - } } else { - let h0 = Hhex { bytes: vec![0] }; - marshall_to_haskell_var(&h0, out, out_len, RW); + let left_node = MerkleHashOrchard::from_bytes(&to_array(left_in)); + if left_node.is_some().into() { + if right_in.len() > 1 { + let right_node = MerkleHashOrchard::from_bytes(&to_array(right_in)); + if right_node.is_some().into() { + let n = MerkleHashOrchard::combine(Level::new(level), &left_node.unwrap(), &right_node.unwrap()); + let h = Hhex { bytes: n.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } + } else { + let n = MerkleHashOrchard::combine(Level::new(level), &left_node.unwrap(), &MerkleHashOrchard::empty_leaf()); + let h = Hhex { bytes: n.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + } + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } } } -- 2.34.1 From b6d490d05300a9db9cdf9929baa9b984bee9f3f6 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 28 Oct 2024 12:25:34 -0500 Subject: [PATCH 03/48] fix(rust): orchard hash length check --- librustzcash-wrapper/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index df054c6..1673061 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1590,7 +1590,7 @@ pub extern "C" fn rust_wrapper_combine_orchard_nodes( ){ let left_in: Vec = marshall_from_haskell_var(left, left_len, RW); let right_in: Vec = marshall_from_haskell_var(right, right_len, RW); - if left_in.len() > 1 { + if left_in.len() == 1 { let n = MerkleHashOrchard::combine(Level::new(level), &MerkleHashOrchard::empty_leaf(), &MerkleHashOrchard::empty_leaf()); let h = Hhex { bytes: n.to_bytes().to_vec() }; marshall_to_haskell_var(&h, out, out_len, RW); -- 2.34.1 From 1492f3b6ad44f8aba2daf3e153dc792c6bab3fbf Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 29 Oct 2024 09:46:24 -0500 Subject: [PATCH 04/48] docs: add debugging to create_transaction --- librustzcash-wrapper/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 1673061..73b52cd 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1844,6 +1844,7 @@ pub extern "C" fn rust_wrapper_create_transaction( let trans_input: Vec = marshall_from_haskell_var(t_input, t_input_len, RW); for t_in in trans_input { if t_in.sk.len() > 1 { + println!("t inp: {:?}", t_in); let k = SecretKey::from_slice(&t_in.sk).unwrap(); if net { match main_builder.add_transparent_input(k, t_in.utxo.unpack(), t_in.coin.unpack()) { @@ -1866,6 +1867,7 @@ pub extern "C" fn rust_wrapper_create_transaction( } for s_in in sap_input { if s_in.sk.len() > 1 { + println!("s inp: {:?}", s_in); let sp_key = ExtendedSpendingKey::from_bytes(&s_in.sk); match sp_key { Ok(sk) => { @@ -1912,6 +1914,7 @@ pub extern "C" fn rust_wrapper_create_transaction( } for o_in in orch_input { if o_in.sk.len() > 1 { + println!("o inp: {:?}", o_in); 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 = Rho::from_bytes(&to_array(o_in.note.rho)).unwrap(); @@ -1952,6 +1955,7 @@ pub extern "C" fn rust_wrapper_create_transaction( 1 => { let recipient = TransparentAddress::PublicKeyHash(to_array(output.to)); let val = NonNegativeAmount::from_u64(output.amt).unwrap(); + println!("t out: {:?} {:?}", val, output.chg); if net { let _mb = main_builder.add_transparent_output(&recipient, val); } else { @@ -1961,6 +1965,7 @@ pub extern "C" fn rust_wrapper_create_transaction( 2 => { let recipient = TransparentAddress::ScriptHash(to_array(output.to)); let val = NonNegativeAmount::from_u64(output.amt).unwrap(); + println!("t out: {:?} {:?}", val, output.chg); if net { let _mb = main_builder.add_transparent_output(&recipient, val); } else { @@ -1972,6 +1977,7 @@ pub extern "C" fn rust_wrapper_create_transaction( let recipient = PaymentAddress::from_bytes(&to_array(output.to)).unwrap(); let val = NonNegativeAmount::from_u64(output.amt).unwrap(); let memo = MemoBytes::from_bytes(&output.memo).unwrap(); + println!("s out: {:?} {:?}", val, output.chg); if net { let _mb = main_builder.add_sapling_output::(ovk, recipient, val, memo); } else { @@ -1987,6 +1993,7 @@ pub extern "C" fn rust_wrapper_create_transaction( }; let recipient = OrchardAddress::from_raw_address_bytes(&to_array(output.to)).unwrap(); let val = output.amt; + println!("o out: {:?} {:?}", val, output.chg); let memo = MemoBytes::from_bytes(&output.memo).unwrap(); if net { let _mb = main_builder.add_orchard_output::(ovk, recipient, val, memo); -- 2.34.1 From 42da2d3a0fb876e070892fa9fc16a91a7106991f Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 29 Oct 2024 10:12:41 -0500 Subject: [PATCH 05/48] docs: add debug for fee --- librustzcash-wrapper/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 73b52cd..6abf905 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -2007,6 +2007,12 @@ pub extern "C" fn rust_wrapper_create_transaction( } } if build { + let fee_result = if net { + main_builder.get_fee(&FeeRule::standard()) + } else { + test_builder.get_fee(&FeeRule::standard()) + }; + println!("fee: {:?}", fee_result); let (spend_params_in, output_params_in) = load_sapling_parameters(); //let spend_params_in: Vec = marshall_from_haskell_var(sapspend, sapspend_len, RW); let spend_params_reader = Cursor::new(spend_params_in); -- 2.34.1 From 0ad6b9ebab1ab43e2d275883ab3742ce1e40f9a4 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 29 Oct 2024 10:31:25 -0500 Subject: [PATCH 06/48] docs: add error debug output --- librustzcash-wrapper/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 6abf905..d15036e 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -2039,6 +2039,7 @@ pub extern "C" fn rust_wrapper_create_transaction( marshall_to_haskell_var(&x, out, out_len, RW); }, Error::ChangeRequired(y1) => { + println!("change req: {:?}", y1); let x = Hhex {bytes: vec![1]}; marshall_to_haskell_var(&x, out, out_len, RW); }, -- 2.34.1 From 1e350c289c5b9332df35599a43671103d7e6f65b Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 29 Oct 2024 11:06:25 -0500 Subject: [PATCH 07/48] docs: add debug for sapling outputs --- librustzcash-wrapper/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index d15036e..a67eba0 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1914,12 +1914,12 @@ pub extern "C" fn rust_wrapper_create_transaction( } for o_in in orch_input { if o_in.sk.len() > 1 { - println!("o inp: {:?}", o_in); 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 = 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); + println!("o inp: {:?}", val); let note = Note::from_parts(pay_addr, val, rho, rseed).unwrap(); let wit_reader = Cursor::new(o_in.iw); let iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); -- 2.34.1 From a21642baeeeef51c2cbe31d64ea282ea61e26c77 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 29 Oct 2024 11:19:03 -0500 Subject: [PATCH 08/48] docs: add more Rust debug output --- librustzcash-wrapper/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index a67eba0..c243aa2 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1981,7 +1981,8 @@ pub extern "C" fn rust_wrapper_create_transaction( if net { let _mb = main_builder.add_sapling_output::(ovk, recipient, val, memo); } else { - let _tb = test_builder.add_sapling_output::(ovk, recipient, val, memo); + let tb = test_builder.add_sapling_output::(ovk, recipient, val, memo); + println!("add sap: {:?}", tb); } }, 4 => { -- 2.34.1 From 5139f9dd7bacae07aa013f7610e3ed37cb5999ab Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 29 Oct 2024 12:15:04 -0500 Subject: [PATCH 09/48] fix(rust): correct tx builder startup --- librustzcash-wrapper/src/lib.rs | 46 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index c243aa2..ade568c 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1795,43 +1795,41 @@ pub extern "C" fn rust_wrapper_create_transaction( build: bool, out: *mut u8, out_len: &mut usize){ - //let sap_wit_in: Vec = marshall_from_haskell_var(sap_wit, sap_wit_len, RW); - //let sap_wit_reader = Cursor::new(sap_wit_in); - //let sap_iw = read_commitment_tree::>, SAPLING_DEPTH>(sap_wit_reader); let sap_input: Vec = marshall_from_haskell_var(s_input, s_input_len, RW); let sap_anchor = if sap_input.is_empty() { - None + let sap_wit_in: Vec = marshall_from_haskell_var(sap_wit, sap_wit_len, RW); + let sap_wit_reader = Cursor::new(sap_wit_in); + let sap_iw = read_commitment_tree::>, SAPLING_DEPTH>(sap_wit_reader); + match sap_iw { + Ok(s_iw) => { + Some(SaplingAnchor::from(s_iw.root())) + }, + Err(_e) => { + None + } + } } else { let si = &sap_input[0]; let swit_reader = Cursor::new(&si.iw); let iw: IncrementalWitness = read_incremental_witness(swit_reader).unwrap(); Some(SaplingAnchor::from(iw.root())) }; - //let sap_anchor = match sap_iw { - //Ok(s_iw) => { - //Some(SaplingAnchor::from(s_iw.root())) - //}, - //Err(_e) => { - //None - //} - //}; //println!("{:?}", sap_anchor); - //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_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 + 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); + match orch_iw { + Ok(o_iw) => { + Some(OrchardAnchor::from(o_iw.root())) + }, + Err(_e) => { + None + } + } } else { let oi = &orch_input[0]; let wit_reader = Cursor::new(&oi.iw); -- 2.34.1 From 1694898117d3d0b211f9d3de224ca206bc30b166 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 29 Oct 2024 14:14:39 -0500 Subject: [PATCH 10/48] fix: correct transaction creation --- src/ZcashHaskell/Utils.hs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/ZcashHaskell/Utils.hs b/src/ZcashHaskell/Utils.hs index e7e1aae..e060e18 100644 --- a/src/ZcashHaskell/Utils.hs +++ b/src/ZcashHaskell/Utils.hs @@ -137,22 +137,22 @@ createTransaction sapAnchor orchAnchor tSpend sSpend oSpend outgoing znet bh bui processResult $! txResult where processResult :: HexString -> Either TxError HexString - processResult input = - if BS.length (hexBytes input) > 1 - then Right input - else case head (BS.unpack $ hexBytes input) of - 0 -> Left InsufficientFunds - 1 -> Left ChangeRequired - 2 -> Left Fee - 3 -> Left Balance - 4 -> Left TransparentBuild - 5 -> Left SaplingBuild - 6 -> Left OrchardBuild - 7 -> Left OrchardSpend - 8 -> Left OrchardRecipient - 9 -> Left SaplingBuilderNotAvailable - 10 -> Left OrchardBuilderNotAvailable - _ -> Left ZHError + processResult input + | BS.length (hexBytes input) > 1 = Right input + | otherwise = + case head (BS.unpack $ hexBytes input) of + 0 -> Left InsufficientFunds + 1 -> Left ChangeRequired + 2 -> Left Fee + 3 -> Left Balance + 4 -> Left TransparentBuild + 5 -> Left SaplingBuild + 6 -> Left OrchardBuild + 7 -> Left OrchardSpend + 8 -> Left OrchardRecipient + 9 -> Left SaplingBuilderNotAvailable + 10 -> Left OrchardBuilderNotAvailable + _ -> Left ZHError txResult = withPureBorshVarBuffer $ rustWrapperCreateTx -- 2.34.1 From 24210b1e0be8ba7319a6ec2fbbe645ae03f9143b Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 29 Oct 2024 14:55:43 -0500 Subject: [PATCH 11/48] fix: optimize create transaction --- src/ZcashHaskell/Utils.hs | 52 ++++++++++++--------------------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/src/ZcashHaskell/Utils.hs b/src/ZcashHaskell/Utils.hs index e060e18..bc3566b 100644 --- a/src/ZcashHaskell/Utils.hs +++ b/src/ZcashHaskell/Utils.hs @@ -132,40 +132,20 @@ createTransaction :: -> ZcashNet -- ^ the network to be used -> Int -- ^ target block height -> Bool -- ^ True to build, False to estimate fee - -> Either TxError HexString + -> HexString createTransaction sapAnchor orchAnchor tSpend sSpend oSpend outgoing znet bh build = - processResult $! txResult - where - processResult :: HexString -> Either TxError HexString - processResult input - | BS.length (hexBytes input) > 1 = Right input - | otherwise = - case head (BS.unpack $ hexBytes input) of - 0 -> Left InsufficientFunds - 1 -> Left ChangeRequired - 2 -> Left Fee - 3 -> Left Balance - 4 -> Left TransparentBuild - 5 -> Left SaplingBuild - 6 -> Left OrchardBuild - 7 -> Left OrchardSpend - 8 -> Left OrchardRecipient - 9 -> Left SaplingBuilderNotAvailable - 10 -> Left OrchardBuilderNotAvailable - _ -> Left ZHError - txResult = - withPureBorshVarBuffer $ - rustWrapperCreateTx - (case sapAnchor of - Nothing -> "0" - Just sA -> toBytes $ sapTree sA) - (case orchAnchor of - Nothing -> "0" - Just oA -> toBytes $ orchTree oA) - tSpend - sSpend - oSpend - outgoing - (znet == MainNet) - (fromIntegral bh) - build + withPureBorshVarBuffer $ + rustWrapperCreateTx + (case sapAnchor of + Nothing -> "0" + Just sA -> toBytes $ sapTree sA) + (case orchAnchor of + Nothing -> "0" + Just oA -> toBytes $ orchTree oA) + tSpend + sSpend + oSpend + outgoing + (znet == MainNet) + (fromIntegral bh) + build -- 2.34.1 From fa2b34e26f32b93b2adf81c1465bc6b9eba416b8 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 09:09:11 -0500 Subject: [PATCH 12/48] debuggin FFI --- librustzcash-wrapper/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index ade568c..a09f3e6 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -728,6 +728,7 @@ pub extern "C" fn rust_wrapper_f4jumble( out: *mut u8, out_len: &mut usize) { let input: Vec = marshall_from_haskell_var(input, input_len, RW); + println!("testy mc testface"); let result = f4jumble::f4jumble(&input).unwrap(); marshall_to_haskell_var(&result, out, out_len, RW); } -- 2.34.1 From f4ecfe9d11c67b8517ccabc7b6bb18b55c99dab4 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 10:23:23 -0500 Subject: [PATCH 13/48] fix: optimize FFI for large results --- src/ZcashHaskell/Utils.hs | 50 ++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/ZcashHaskell/Utils.hs b/src/ZcashHaskell/Utils.hs index bc3566b..62fb89c 100644 --- a/src/ZcashHaskell/Utils.hs +++ b/src/ZcashHaskell/Utils.hs @@ -132,20 +132,36 @@ createTransaction :: -> ZcashNet -- ^ the network to be used -> Int -- ^ target block height -> Bool -- ^ True to build, False to estimate fee - -> HexString -createTransaction sapAnchor orchAnchor tSpend sSpend oSpend outgoing znet bh build = - withPureBorshVarBuffer $ - rustWrapperCreateTx - (case sapAnchor of - Nothing -> "0" - Just sA -> toBytes $ sapTree sA) - (case orchAnchor of - Nothing -> "0" - Just oA -> toBytes $ orchTree oA) - tSpend - sSpend - oSpend - outgoing - (znet == MainNet) - (fromIntegral bh) - build + -> IO (Either TxError HexString) +createTransaction sapAnchor orchAnchor tSpend sSpend oSpend outgoing znet bh build = do + txResult <- + withBorshBufferOfInitSize 5120 $ + rustWrapperCreateTx + (case sapAnchor of + Nothing -> "0" + Just sA -> toBytes $ sapTree sA) + (case orchAnchor of + Nothing -> "0" + Just oA -> toBytes $ orchTree oA) + tSpend + sSpend + oSpend + outgoing + (znet == MainNet) + (fromIntegral bh) + build + if BS.length (hexBytes txResult) > 1 + then pure $ Right txResult + else case head (BS.unpack $ hexBytes txResult) of + 0 -> pure $ Left InsufficientFunds + 1 -> pure $ Left ChangeRequired + 2 -> pure $ Left Fee + 3 -> pure $ Left Balance + 4 -> pure $ Left TransparentBuild + 5 -> pure $ Left SaplingBuild + 6 -> pure $ Left OrchardBuild + 7 -> pure $ Left OrchardSpend + 8 -> pure $ Left OrchardRecipient + 9 -> pure $ Left SaplingBuilderNotAvailable + 10 -> pure $ Left OrchardBuilderNotAvailable + _ -> pure $ Left ZHError -- 2.34.1 From a8d4a96b8ac09cd112c260ac76234dc4801c5d18 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 10:59:20 -0500 Subject: [PATCH 14/48] fix: increase buffer size for createTransaction --- src/ZcashHaskell/Utils.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ZcashHaskell/Utils.hs b/src/ZcashHaskell/Utils.hs index 62fb89c..4b783ac 100644 --- a/src/ZcashHaskell/Utils.hs +++ b/src/ZcashHaskell/Utils.hs @@ -135,7 +135,7 @@ createTransaction :: -> IO (Either TxError HexString) createTransaction sapAnchor orchAnchor tSpend sSpend oSpend outgoing znet bh build = do txResult <- - withBorshBufferOfInitSize 5120 $ + withBorshBufferOfInitSize 10240 $ rustWrapperCreateTx (case sapAnchor of Nothing -> "0" -- 2.34.1 From b3ec3aecbd0d5555538ed8e431b430df40bb4855 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 11:15:34 -0500 Subject: [PATCH 15/48] fix: adjust FFI buffer --- src/ZcashHaskell/Utils.hs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/ZcashHaskell/Utils.hs b/src/ZcashHaskell/Utils.hs index 4b783ac..6956e3f 100644 --- a/src/ZcashHaskell/Utils.hs +++ b/src/ZcashHaskell/Utils.hs @@ -135,21 +135,22 @@ createTransaction :: -> IO (Either TxError HexString) createTransaction sapAnchor orchAnchor tSpend sSpend oSpend outgoing znet bh build = do txResult <- - withBorshBufferOfInitSize 10240 $ - rustWrapperCreateTx - (case sapAnchor of - Nothing -> "0" - Just sA -> toBytes $ sapTree sA) - (case orchAnchor of - Nothing -> "0" - Just oA -> toBytes $ orchTree oA) - tSpend - sSpend - oSpend - outgoing - (znet == MainNet) - (fromIntegral bh) - build + do print "calling FFI" + withBorshBufferOfInitSize 51200 $ + rustWrapperCreateTx + (case sapAnchor of + Nothing -> "0" + Just sA -> toBytes $ sapTree sA) + (case orchAnchor of + Nothing -> "0" + Just oA -> toBytes $ orchTree oA) + tSpend + sSpend + oSpend + outgoing + (znet == MainNet) + (fromIntegral bh) + build if BS.length (hexBytes txResult) > 1 then pure $ Right txResult else case head (BS.unpack $ hexBytes txResult) of -- 2.34.1 From c793e0c4ff9547be5b1a7663c6d21277df8876e7 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 11:42:36 -0500 Subject: [PATCH 16/48] fix(rust): remove debug messages --- librustzcash-wrapper/src/lib.rs | 110 ++++++++++++++++++++++++-------- src/ZcashHaskell/Utils.hs | 31 +++++---- 2 files changed, 97 insertions(+), 44 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index a09f3e6..a469cb8 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -20,9 +20,9 @@ use borsh::{BorshDeserialize, BorshSerialize}; use haskell_ffi::{ error::Result, - from_haskell::{marshall_from_haskell_var, marshall_from_haskell_fixed}, - to_haskell::{marshall_to_haskell_var, marshall_to_haskell_fixed}, - FromHaskell, HaskellSize, ToHaskell + from_haskell::marshall_from_haskell_var, + to_haskell::marshall_to_haskell_var, + FromHaskell, ToHaskell }; use secp256k1::SecretKey; @@ -42,8 +42,7 @@ use incrementalmerkletree::{ }; use zip32::{ - Scope as SaplingScope, - ChildIndex + Scope as SaplingScope }; @@ -728,7 +727,6 @@ pub extern "C" fn rust_wrapper_f4jumble( out: *mut u8, out_len: &mut usize) { let input: Vec = marshall_from_haskell_var(input, input_len, RW); - println!("testy mc testface"); let result = f4jumble::f4jumble(&input).unwrap(); marshall_to_haskell_var(&result, out, out_len, RW); } @@ -1843,7 +1841,7 @@ pub extern "C" fn rust_wrapper_create_transaction( let trans_input: Vec = marshall_from_haskell_var(t_input, t_input_len, RW); for t_in in trans_input { if t_in.sk.len() > 1 { - println!("t inp: {:?}", t_in); + //println!("t inp: {:?}", t_in); let k = SecretKey::from_slice(&t_in.sk).unwrap(); if net { match main_builder.add_transparent_input(k, t_in.utxo.unpack(), t_in.coin.unpack()) { @@ -1866,7 +1864,7 @@ pub extern "C" fn rust_wrapper_create_transaction( } for s_in in sap_input { if s_in.sk.len() > 1 { - println!("s inp: {:?}", s_in); + //println!("s inp: {:?}", s_in); let sp_key = ExtendedSpendingKey::from_bytes(&s_in.sk); match sp_key { Ok(sk) => { @@ -1918,7 +1916,7 @@ pub extern "C" fn rust_wrapper_create_transaction( 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); - println!("o inp: {:?}", val); + //println!("o inp: {:?}", val); let note = Note::from_parts(pay_addr, val, rho, rseed).unwrap(); let wit_reader = Cursor::new(o_in.iw); let iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); @@ -1954,21 +1952,49 @@ pub extern "C" fn rust_wrapper_create_transaction( 1 => { let recipient = TransparentAddress::PublicKeyHash(to_array(output.to)); let val = NonNegativeAmount::from_u64(output.amt).unwrap(); - println!("t out: {:?} {:?}", val, output.chg); + //println!("t out: {:?} {:?}", val, output.chg); if net { - let _mb = main_builder.add_transparent_output(&recipient, val); + let mb = main_builder.add_transparent_output(&recipient, val); + match mb { + Ok(()) => { continue; }, + Err(_e) => { + let x = Hhex {bytes: vec![4]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } else { - let _tb = test_builder.add_transparent_output(&recipient, val); + let tb = test_builder.add_transparent_output(&recipient, val); + match tb { + Ok(()) => { continue; }, + Err(_e) => { + let x = Hhex {bytes: vec![4]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } }, 2 => { let recipient = TransparentAddress::ScriptHash(to_array(output.to)); let val = NonNegativeAmount::from_u64(output.amt).unwrap(); - println!("t out: {:?} {:?}", val, output.chg); + //println!("t out: {:?} {:?}", val, output.chg); if net { - let _mb = main_builder.add_transparent_output(&recipient, val); + let mb = main_builder.add_transparent_output(&recipient, val); + match mb { + Ok(()) => { continue; }, + Err(_e) => { + let x = Hhex {bytes: vec![4]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } else { - let _tb = test_builder.add_transparent_output(&recipient, val); + let tb = test_builder.add_transparent_output(&recipient, val); + match tb { + Ok(()) => { continue; }, + Err(_e) => { + let x = Hhex {bytes: vec![4]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } }, 3 => { @@ -1976,12 +2002,26 @@ pub extern "C" fn rust_wrapper_create_transaction( let recipient = PaymentAddress::from_bytes(&to_array(output.to)).unwrap(); let val = NonNegativeAmount::from_u64(output.amt).unwrap(); let memo = MemoBytes::from_bytes(&output.memo).unwrap(); - println!("s out: {:?} {:?}", val, output.chg); + //println!("s out: {:?} {:?}", val, output.chg); if net { - let _mb = main_builder.add_sapling_output::(ovk, recipient, val, memo); + let mb = main_builder.add_sapling_output::(ovk, recipient, val, memo); + match mb { + Ok(()) => { continue; }, + Err(_e) => { + let x = Hhex {bytes: vec![5]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } else { let tb = test_builder.add_sapling_output::(ovk, recipient, val, memo); - println!("add sap: {:?}", tb); + match tb { + Ok(()) => { continue; }, + Err(_e) => { + let x = Hhex {bytes: vec![5]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } + //println!("add sap: {:?}", tb); } }, 4 => { @@ -1993,12 +2033,26 @@ pub extern "C" fn rust_wrapper_create_transaction( }; let recipient = OrchardAddress::from_raw_address_bytes(&to_array(output.to)).unwrap(); let val = output.amt; - println!("o out: {:?} {:?}", val, output.chg); + //println!("o out: {:?} {:?}", val, output.chg); let memo = MemoBytes::from_bytes(&output.memo).unwrap(); if net { - let _mb = main_builder.add_orchard_output::(ovk, recipient, val, memo); + let mb = main_builder.add_orchard_output::(ovk, recipient, val, memo); + match mb { + Ok(()) => { continue; }, + Err(_e) => { + let x = Hhex {bytes: vec![6]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } else { - let _tb = test_builder.add_orchard_output::(ovk, recipient, val, memo); + let tb = test_builder.add_orchard_output::(ovk, recipient, val, memo); + match tb { + Ok(()) => { continue; }, + Err(_e) => { + let x = Hhex {bytes: vec![6]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } }, _ => { @@ -2007,12 +2061,12 @@ pub extern "C" fn rust_wrapper_create_transaction( } } if build { - let fee_result = if net { - main_builder.get_fee(&FeeRule::standard()) - } else { - test_builder.get_fee(&FeeRule::standard()) - }; - println!("fee: {:?}", fee_result); + //let fee_result = if net { + //main_builder.get_fee(&FeeRule::standard()) + //} else { + //test_builder.get_fee(&FeeRule::standard()) + //}; + //println!("fee: {:?}", fee_result); let (spend_params_in, output_params_in) = load_sapling_parameters(); //let spend_params_in: Vec = marshall_from_haskell_var(sapspend, sapspend_len, RW); let spend_params_reader = Cursor::new(spend_params_in); @@ -2039,7 +2093,7 @@ pub extern "C" fn rust_wrapper_create_transaction( marshall_to_haskell_var(&x, out, out_len, RW); }, Error::ChangeRequired(y1) => { - println!("change req: {:?}", y1); + //println!("change req: {:?}", y1); let x = Hhex {bytes: vec![1]}; marshall_to_haskell_var(&x, out, out_len, RW); }, diff --git a/src/ZcashHaskell/Utils.hs b/src/ZcashHaskell/Utils.hs index 6956e3f..ee0a0d9 100644 --- a/src/ZcashHaskell/Utils.hs +++ b/src/ZcashHaskell/Utils.hs @@ -135,22 +135,21 @@ createTransaction :: -> IO (Either TxError HexString) createTransaction sapAnchor orchAnchor tSpend sSpend oSpend outgoing znet bh build = do txResult <- - do print "calling FFI" - withBorshBufferOfInitSize 51200 $ - rustWrapperCreateTx - (case sapAnchor of - Nothing -> "0" - Just sA -> toBytes $ sapTree sA) - (case orchAnchor of - Nothing -> "0" - Just oA -> toBytes $ orchTree oA) - tSpend - sSpend - oSpend - outgoing - (znet == MainNet) - (fromIntegral bh) - build + withBorshBufferOfInitSize 51200 $ + rustWrapperCreateTx + (case sapAnchor of + Nothing -> "0" + Just sA -> toBytes $ sapTree sA) + (case orchAnchor of + Nothing -> "0" + Just oA -> toBytes $ orchTree oA) + tSpend + sSpend + oSpend + outgoing + (znet == MainNet) + (fromIntegral bh) + build if BS.length (hexBytes txResult) > 1 then pure $ Right txResult else case head (BS.unpack $ hexBytes txResult) of -- 2.34.1 From 33085a46bff80d63a2fb81a0fa2db705765c9ee0 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 11:44:56 -0500 Subject: [PATCH 17/48] docs: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eed57f..3f3a7e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Modified frontiers to use `HexString` for ommers +- Optimized `createTransaction` ## [0.7.2.0] -- 2.34.1 From f6b8a772770f492221dc99281016d7090f981e63 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 13:23:46 -0500 Subject: [PATCH 18/48] feat: add function to test empty trees --- librustzcash-wrapper/src/lib.rs | 14 +++++++++++++- src/C/Zcash.chs | 7 +++++++ src/ZcashHaskell/Orchard.hs | 4 ++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index a469cb8..d011e65 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -36,7 +36,8 @@ use incrementalmerkletree::{ frontier::{ CommitmentTree, Frontier, - NonEmptyFrontier + NonEmptyFrontier, + PathFiller }, witness::IncrementalWitness }; @@ -1618,6 +1619,17 @@ pub extern "C" fn rust_wrapper_combine_orchard_nodes( } } +#[no_mangle] +pub extern "C" fn rust_wrapper_get_orchard_root( + level: u8, + out: *mut u8, + out_len: &mut usize + ){ + let tree: CommitmentTree = CommitmentTree::empty(); + let root = tree.root_at_depth(level, PathFiller::empty()); + let h = Hhex { bytes: root.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); +} #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_commitment_tree( diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index da2f86b..abb7435 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -276,6 +276,13 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_get_orchard_root as rustWrapperGetOrchardRootTest + { `Int8' + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_read_orchard_commitment_tree as rustWrapperReadOrchardCommitmentTree { toBorshVar* `OrchardFrontier'& , toBorshVar* `BS.ByteString'& diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 79043ea..170e177 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -218,6 +218,10 @@ getOrchardWitnessAnchor wit = withPureBorshVarBuffer $ rustWrapperReadOrchardWitnessAnchor $ toBytes $ orchWit wit +getOrchardRootTest :: Int -> HexString +getOrchardRootTest level = + withPureBorshVarBuffer $ rustWrapperGetOrchardRootTest $ fromIntegral level + -- | Update a Orchard commitment tree updateOrchardCommitmentTree :: OrchardFrontier -- ^ the base tree -- 2.34.1 From 52c3faa7d4d676945464a47ce352548d850c28e8 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 14:21:48 -0500 Subject: [PATCH 19/48] feat: function to test orchard trees --- src/ZcashHaskell/Orchard.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 170e177..4cb8b9e 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -21,6 +21,7 @@ import C.Zcash ( rustWrapperCombineOrchardNodes , rustWrapperGenOrchardReceiver , rustWrapperGenOrchardSpendKey + , rustWrapperGetOrchardRootTest , rustWrapperOrchardCheck , rustWrapperOrchardNoteDecode , rustWrapperOrchardNoteDecodeSK -- 2.34.1 From 96ee5f417944b1f1719b5613d2d7cdb9a6f8160b Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 15:24:06 -0500 Subject: [PATCH 20/48] feat: new function to test tree with one node --- librustzcash-wrapper/src/lib.rs | 22 ++++++++++++++++++++++ src/C/Zcash.chs | 8 ++++++++ src/ZcashHaskell/Orchard.hs | 5 +++++ 3 files changed, 35 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index d011e65..3b060fd 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1631,6 +1631,28 @@ pub extern "C" fn rust_wrapper_get_orchard_root( marshall_to_haskell_var(&h, out, out_len, RW); } +#[no_mangle] +pub extern "C" fn rust_wrapper_orchard_add_node( + node: *const u8, + node_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + let mut tree: CommitmentTree = CommitmentTree::empty(); + 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()); + tree.append(n); + let root = tree.root(); + let h = Hhex { bytes: root.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } +} + #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_commitment_tree( tree: *const u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index abb7435..915058f 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -311,6 +311,14 @@ import ZcashHaskell.Types -> `Word64' #} +{# fun unsafe rust_wrapper_orchard_add_node as rustWrapperOrchardAddNodeTest + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' + +#} + {# fun unsafe rust_wrapper_update_sapling_witness as rustWrapperUpdateSaplingWitness { toBorshVar* `BS.ByteString'& , toBorshVar* `[BS.ByteString]'& diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 4cb8b9e..7e30158 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -22,6 +22,7 @@ import C.Zcash , rustWrapperGenOrchardReceiver , rustWrapperGenOrchardSpendKey , rustWrapperGetOrchardRootTest + , rustWrapperOrchardAddNodeTest , rustWrapperOrchardCheck , rustWrapperOrchardNoteDecode , rustWrapperOrchardNoteDecodeSK @@ -223,6 +224,10 @@ getOrchardRootTest :: Int -> HexString getOrchardRootTest level = withPureBorshVarBuffer $ rustWrapperGetOrchardRootTest $ fromIntegral level +addOrchardNodeGetRoot :: BS.ByteString -> HexString +addOrchardNodeGetRoot n = + withPureBorshVarBuffer $ rustWrapperOrchardAddNodeTest n + -- | Update a Orchard commitment tree updateOrchardCommitmentTree :: OrchardFrontier -- ^ the base tree -- 2.34.1 From 1938e162f46ce7c879ccb3aa5e3eb6bbf7e63969 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 30 Oct 2024 16:24:02 -0500 Subject: [PATCH 21/48] feat: update root testing functions --- librustzcash-wrapper/src/lib.rs | 18 +++++++++++++----- src/C/Zcash.chs | 3 ++- src/ZcashHaskell/Orchard.hs | 6 +++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 3b060fd..1b22434 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1626,13 +1626,14 @@ pub extern "C" fn rust_wrapper_get_orchard_root( out_len: &mut usize ){ let tree: CommitmentTree = CommitmentTree::empty(); - let root = tree.root_at_depth(level, PathFiller::empty()); + let root = tree.root(); let h = Hhex { bytes: root.to_bytes().to_vec() }; marshall_to_haskell_var(&h, out, out_len, RW); } #[no_mangle] pub extern "C" fn rust_wrapper_orchard_add_node( + level: u8, node: *const u8, node_len: usize, out: *mut u8, @@ -1643,10 +1644,17 @@ pub extern "C" fn rust_wrapper_orchard_add_node( 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()); - tree.append(n); - let root = tree.root(); - let h = Hhex { bytes: root.to_bytes().to_vec() }; - marshall_to_haskell_var(&h, out, out_len, RW); + match tree.append(n) { + Ok(()) => { + let root = tree.root_at_depth(level, PathFiller::empty()); + let h = Hhex { bytes: root.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + }, + Err(_) => { + 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); diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 915058f..fda259a 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -312,7 +312,8 @@ import ZcashHaskell.Types #} {# fun unsafe rust_wrapper_orchard_add_node as rustWrapperOrchardAddNodeTest - { toBorshVar* `BS.ByteString'& + { `Int8' + , toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer HexString'& } -> `()' diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 7e30158..3fdb25a 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -224,9 +224,9 @@ getOrchardRootTest :: Int -> HexString getOrchardRootTest level = withPureBorshVarBuffer $ rustWrapperGetOrchardRootTest $ fromIntegral level -addOrchardNodeGetRoot :: BS.ByteString -> HexString -addOrchardNodeGetRoot n = - withPureBorshVarBuffer $ rustWrapperOrchardAddNodeTest n +addOrchardNodeGetRoot :: Int -> BS.ByteString -> HexString +addOrchardNodeGetRoot l n = + withPureBorshVarBuffer $ rustWrapperOrchardAddNodeTest (fromIntegral l) n -- | Update a Orchard commitment tree updateOrchardCommitmentTree :: -- 2.34.1 From 92cc2aabe4e7bb675b97af7f23fb9bdf0b984aab Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Thu, 31 Oct 2024 09:28:34 -0500 Subject: [PATCH 22/48] modify tree root validation --- librustzcash-wrapper/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 1b22434..d90351e 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1538,8 +1538,8 @@ pub extern "C" fn rust_wrapper_read_orchard_tree_anchor( ){ 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 comm_tree: NonEmptyFrontier = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap(); - let root = comm_tree.root(None); + let comm_tree: Frontier = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap(); + let root = comm_tree.root(); let h = Hhex { bytes: root.to_bytes().to_vec() }; marshall_to_haskell_var(&h, out, out_len, RW); } -- 2.34.1 From c94bce3c25840a65282ec51dba1a00924db761cc Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Thu, 31 Oct 2024 10:11:35 -0500 Subject: [PATCH 23/48] add validation of frontier and tree --- librustzcash-wrapper/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index d90351e..93b96ee 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1514,7 +1514,13 @@ pub extern "C" fn rust_wrapper_read_orchard_frontier( Some(f2) => { let (pos, leaf, omm) = f2.clone().into_parts(); let f = Hfrontier { position: ::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: x.to_bytes().to_vec()}).collect()}; - marshall_to_haskell_var(&f, out, out_len, RW); + let comm_tree2: Frontier = Frontier::from_parts(Position::from(f.position), MerkleHashOrchard::from_bytes(&to_array(f.leaf.bytes.clone())).unwrap(), f.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap(); + if f1.root() == comm_tree2.root() { + marshall_to_haskell_var(&f, out, out_len, RW); + } else { + let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]}; + marshall_to_haskell_var(&f0, out, out_len, RW); + } }, None => { let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]}; -- 2.34.1 From 8f03811fcad2e18aa814ac11e457b887ce4e7e53 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Thu, 31 Oct 2024 13:36:28 -0500 Subject: [PATCH 24/48] feat: add orchard comm tree parts functionality --- librustzcash-wrapper/src/lib.rs | 67 +++++++++++++++++++++++++++++++++ src/C/Zcash.chs | 7 ++++ src/ZcashHaskell/Orchard.hs | 20 ++++++++++ src/ZcashHaskell/Types.hs | 15 ++++++++ 4 files changed, 109 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 93b96ee..926aa42 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -717,6 +717,27 @@ impl FromHaskell for Hfrontier { } } +#[derive(BorshSerialize, BorshDeserialize)] +pub struct Htree { + left: Hhex, + right: Hhex, + parents: Vec +} + +impl ToHaskell for Htree { + fn to_haskell(&self, writer: &mut W, _tag: PhantomData) -> Result<()> { + self.serialize(writer)?; + Ok(()) + } +} + +impl FromHaskell for Htree { + fn from_haskell(buf: &mut &[u8], _tag: PhantomData) -> Result { + let x = Htree::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())) } @@ -1550,6 +1571,52 @@ pub extern "C" fn rust_wrapper_read_orchard_tree_anchor( marshall_to_haskell_var(&h, out, out_len, RW); } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_orchard_commitment_tree_parts( + 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 = read_commitment_tree(tree_reader); + match comm_tree { + Ok::, _>(c1) => { + let left = match c1.left() { + Some(x) => { + Hhex { bytes: x.to_bytes().to_vec() } + }, + None => { + Hhex { bytes: vec![0] } + } + }; + let right = match c1.right() { + Some(x) => { + Hhex { bytes: x.to_bytes().to_vec() } + }, + None => { + Hhex { bytes: vec![0] } + } + }; + let parents = c1.parents().iter().map(|x| match x { + Some(y) => { + Hhex { bytes: y.to_bytes().to_vec() } + }, + None => { + Hhex { bytes: vec![0] } + } + }).collect(); + let ht = Htree { left, right, parents}; + marshall_to_haskell_var(&ht, out, out_len, RW); + }, + Err(_e) => { + let ht0 = Htree { left: Hhex { bytes: vec![0] } , right: Hhex { bytes: vec![0] }, parents: vec![Hhex { bytes: vec![0] }]}; + marshall_to_haskell_var(&ht0, out, out_len, RW); + } + } +} + #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_witness_anchor( wit: *const u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index fda259a..6e721de 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -291,6 +291,13 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_read_orchard_commitment_tree_parts as rustWrapperReadOrchardTreeParts + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer OrchardRawTree'& + } + -> `()' +#} + {# 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 3fdb25a..6a21eb8 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -31,6 +31,7 @@ import C.Zcash , rustWrapperReadOrchardNode , rustWrapperReadOrchardPosition , rustWrapperReadOrchardTreeAnchor + , rustWrapperReadOrchardTreeParts , rustWrapperReadOrchardWitness , rustWrapperReadOrchardWitnessAnchor , rustWrapperUADecode @@ -228,6 +229,25 @@ addOrchardNodeGetRoot :: Int -> BS.ByteString -> HexString addOrchardNodeGetRoot l n = withPureBorshVarBuffer $ rustWrapperOrchardAddNodeTest (fromIntegral l) n +getOrchardTreeParts :: OrchardCommitmentTree -> Maybe OrchardTree +getOrchardTreeParts h = + if isBlank (ort_left tree) && isBlank (ort_right tree) + then Nothing + else Just $ + OrchardTree + (parseHex $ ort_left tree) + (parseHex $ ort_right tree) + (map parseHex (ort_parents tree)) + where + isBlank h = (BS.length $ hexBytes $ h) == 1 + parseHex h = + if (BS.length $ hexBytes $ h) > 1 + then Just h + else Nothing + tree = + withPureBorshVarBuffer $ + rustWrapperReadOrchardTreeParts $ toBytes $ orchTree h + -- | Update a Orchard commitment tree updateOrchardCommitmentTree :: OrchardFrontier -- ^ the base tree diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index 324216f..afa6a81 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -727,6 +727,21 @@ newtype OrchardCommitmentTree = OrchardCommitmentTree { orchTree :: HexString } deriving (Eq, Prelude.Show, Read) +data OrchardRawTree = OrchardRawTree + { ort_left :: !HexString + , ort_right :: !HexString + , ort_parents :: ![HexString] + } deriving stock (Eq, Prelude.Show, GHC.Generic) + deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) + deriving anyclass (Data.Structured.Show) + deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardRawTree + +data OrchardTree = OrchardTree + { ot_left :: !(Maybe HexString) + , ot_right :: !(Maybe HexString) + , ot_parents :: ![Maybe HexString] + } deriving (Eq, Prelude.Show, Read) + data OrchardFrontier = OrchardFrontier { of_pos :: !Int64 , of_leaf :: !HexString -- 2.34.1 From 1cdd1d75fad541d300aa5842213410e2d6b35821 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Fri, 1 Nov 2024 08:07:29 -0500 Subject: [PATCH 25/48] add validation of orchard anchor --- librustzcash-wrapper/src/lib.rs | 20 ++++++++++++++------ src/C/Zcash.chs | 2 +- src/ZcashHaskell/Orchard.hs | 5 +++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 926aa42..a234c82 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1563,12 +1563,20 @@ pub extern "C" fn rust_wrapper_read_orchard_tree_anchor( out: *mut u8, out_len: &mut usize ){ - 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 comm_tree: Frontier = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap(); - let root = comm_tree.root(); - let h = Hhex { bytes: root.to_bytes().to_vec() }; - marshall_to_haskell_var(&h, out, out_len, RW); + let tree_in: Vec = marshall_from_haskell_var(tree, tree_len, RW); + let tree_reader = Cursor::new(tree_in); + let comm_tree = read_commitment_tree(tree_reader); + match comm_tree { + Ok::, _>(c1) => { + let root = c1.root(); + let h = Hhex { bytes: root.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + }, + Err(_) => { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } + } } #[no_mangle] diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 6e721de..9c485d2 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -263,7 +263,7 @@ import ZcashHaskell.Types #} {# fun unsafe rust_wrapper_read_orchard_tree_anchor as rustWrapperReadOrchardTreeAnchor - { toBorshVar* `OrchardFrontier'& + { toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer HexString'& } -> `()' diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 6a21eb8..e99e9e3 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -212,9 +212,10 @@ getOrchardFrontier tree = withPureBorshVarBuffer $ rustWrapperReadOrchardFrontier $ toBytes $ orchTree tree -getOrchardTreeAnchor :: OrchardFrontier -> HexString +getOrchardTreeAnchor :: OrchardCommitmentTree -> HexString getOrchardTreeAnchor tree = - withPureBorshVarBuffer $ rustWrapperReadOrchardTreeAnchor tree + withPureBorshVarBuffer $ + rustWrapperReadOrchardTreeAnchor $ toBytes $ orchTree tree getOrchardWitnessAnchor :: OrchardWitness -> HexString getOrchardWitnessAnchor wit = -- 2.34.1 From 70927645e774d53dd04650d68d996670033a8ef1 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Fri, 1 Nov 2024 15:44:32 -0500 Subject: [PATCH 26/48] feat: add `MerklePath` --- src/ZcashHaskell/Types.hs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index afa6a81..f87444d 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -722,6 +722,14 @@ instance FromJSON OrchardAction where a <- obj .: "spendAuthSig" pure $ OrchardAction n r c ephKey encText outText cval a +data MerklePath = MerklePath + { mp_position :: !Int64 + , mp_path :: ![HexString] + } deriving stock (Eq, Prelude.Show, GHC.Generic) + deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) + deriving anyclass (Data.Structured.Show) + deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct MerklePath + -- | Type for a Orchard note commitment tree newtype OrchardCommitmentTree = OrchardCommitmentTree { orchTree :: HexString -- 2.34.1 From b748cba3103c23ff90937c905f7a94c30bb31628 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 4 Nov 2024 14:55:44 -0600 Subject: [PATCH 27/48] feat: add Merkle path tests for orchard --- librustzcash-wrapper/src/lib.rs | 43 +++++++++++++++++++++++++++++++++ src/C/Zcash.chs | 8 ++++++ src/ZcashHaskell/Orchard.hs | 5 ++++ 3 files changed, 56 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index a234c82..9054ed0 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -738,6 +738,26 @@ impl FromHaskell for Htree { } } +#[derive(BorshSerialize, BorshDeserialize)] +pub struct Hpath { + position: u32, + path: Vec +} + +impl ToHaskell for Hpath { + fn to_haskell(&self, writer: &mut W, _tag: PhantomData) -> Result<()> { + self.serialize(writer)?; + Ok(()) + } +} + +impl FromHaskell for Hpath { + fn from_haskell(buf: &mut &[u8], _tag: PhantomData) -> Result { + let x = Hpath::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())) } @@ -1659,6 +1679,29 @@ pub extern "C" fn rust_wrapper_read_orchard_node( } } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_orchard_path_anchor( + path: *const u8, + path_len: usize, + cmx: *const u8, + cmx_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + let path_in: Hpath = marshall_from_haskell_var(path, path_len, RW); + let cmx_in: Vec = marshall_from_haskell_var(cmx, cmx_len, RW); + let mk_path = orchard::tree::MerklePath::from_parts(path_in.position, to_array(path_in.path.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap()).collect())); + let nc = ExtractedNoteCommitment::from_bytes(&to_array(cmx_in)); + if nc.is_some().into() { + let anchor = mk_path.root(nc.unwrap()); + let h = Hhex { bytes: anchor.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } +} + #[no_mangle] pub extern "C" fn rust_wrapper_combine_orchard_nodes( level: u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 9c485d2..a896a10 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -276,6 +276,14 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_read_orchard_path_anchor as rustWrapperReadOrchardPathAnchor + { toBorshVar* `MerklePath'& + , toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_get_orchard_root as rustWrapperGetOrchardRootTest { `Int8' , getVarBuffer `Buffer HexString'& diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index e99e9e3..7991138 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -29,6 +29,7 @@ import C.Zcash , rustWrapperReadOrchardCommitmentTree , rustWrapperReadOrchardFrontier , rustWrapperReadOrchardNode + , rustWrapperReadOrchardPathAnchor , rustWrapperReadOrchardPosition , rustWrapperReadOrchardTreeAnchor , rustWrapperReadOrchardTreeParts @@ -249,6 +250,10 @@ getOrchardTreeParts h = withPureBorshVarBuffer $ rustWrapperReadOrchardTreeParts $ toBytes $ orchTree h +getOrchardPathAnchor :: HexString -> MerklePath -> HexString +getOrchardPathAnchor hex p = + withPureBorshVarBuffer $ rustWrapperReadOrchardPathAnchor p (hexBytes hex) + -- | Update a Orchard commitment tree updateOrchardCommitmentTree :: OrchardFrontier -- ^ the base tree -- 2.34.1 From 1ec6d2df5b09d259ebfbccade4255f13f66233a4 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 4 Nov 2024 15:41:27 -0600 Subject: [PATCH 28/48] feat(rust): add marshalling for Hhex --- librustzcash-wrapper/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 9054ed0..7657829 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -272,6 +272,12 @@ impl ToHaskell for Hhex { } } +impl FromHaskell for Hhex { + fn from_haskell(buf: &mut &[u8], _tag: PhantomData) -> Result { + let x = Hhex::deserialize(buf)?; + Ok(x) + } +} #[derive(Debug, BorshSerialize, BorshDeserialize)] pub struct Haction { -- 2.34.1 From 9008010db7dc36a88602ff936ddfa38ea684b40d Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 4 Nov 2024 18:38:55 -0600 Subject: [PATCH 29/48] feat: update position size --- src/ZcashHaskell/Types.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index f87444d..8b8a90b 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -723,7 +723,7 @@ instance FromJSON OrchardAction where pure $ OrchardAction n r c ephKey encText outText cval a data MerklePath = MerklePath - { mp_position :: !Int64 + { mp_position :: !Int32 , mp_path :: ![HexString] } deriving stock (Eq, Prelude.Show, GHC.Generic) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) -- 2.34.1 From ef8dba474e263f330f7ab173bcea4e40c3e30803 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 5 Nov 2024 14:35:19 -0600 Subject: [PATCH 30/48] feat: add sapling node creation --- librustzcash-wrapper/src/lib.rs | 19 +++++++++++++++++++ src/C/Zcash.chs | 7 +++++++ src/ZcashHaskell/Sapling.hs | 9 +++++++++ 3 files changed, 35 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 7657829..feeb16c 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1542,6 +1542,25 @@ pub extern "C" fn rust_wrapper_update_sapling_witness( } } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_sapling_node( + cmu: *const u8, + cmu_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + let node_in: Vec = marshall_from_haskell_var(cmu, cmu_len, RW); + let sapling_note_comm = SaplingNoteCommitment::from_bytes(&to_array(node_in)); + if sapling_note_comm.is_some().into() { + let n = Node::from_cmu(&sapling_note_comm.unwrap()); + let h = Hhex { bytes: n.to_bytes().to_vec()}; + marshall_to_haskell_var(&h, out, out_len, RW); + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } +} + #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_frontier( tree: *const u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index a896a10..48e3189 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -246,6 +246,13 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_read_sapling_node as rustWrapperReadSaplingNode + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_read_orchard_node as rustWrapperReadOrchardNode { toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer HexString'& diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index e15bf4f..8cbe12c 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -22,6 +22,7 @@ import C.Zcash , rustWrapperIsShielded , rustWrapperReadSaplingCommitmentTree , rustWrapperReadSaplingFrontier + , rustWrapperReadSaplingNode , rustWrapperReadSaplingPosition , rustWrapperReadSaplingWitness , rustWrapperSaplingCheck @@ -185,6 +186,14 @@ genSaplingInternalAddress sk = res = withPureBorshVarBuffer (rustWrapperSaplingChgPaymentAddress $ getBytes sk) +getSaplingNodeValue :: BS.ByteString -> Maybe HexString +getSaplingNodeValue cmu = + if BS.length (hexBytes n) > 1 + then Just n + else Nothing + where + n = withPureBorshVarBuffer $ rustWrapperReadSaplingNode cmu + getSaplingFrontier :: SaplingCommitmentTree -> Maybe SaplingFrontier getSaplingFrontier tree = if sf_pos updatedTree > 1 -- 2.34.1 From 93622f445615ae89490be63fa09324fb8bd370f6 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 5 Nov 2024 15:35:56 -0600 Subject: [PATCH 31/48] feat: add Sapling node combinator --- CHANGELOG.md | 6 +++++ librustzcash-wrapper/src/lib.rs | 41 +++++++++++++++++++++++++++++++++ src/C/Zcash.chs | 9 ++++++++ src/ZcashHaskell/Sapling.hs | 14 ++++++++++- zcash-haskell.cabal | 2 +- 5 files changed, 70 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cbfed3..c817ca1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ 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.5.0] + +### Added + +- Sapling commitment node functions + ## [0.7.4.0] ### Added diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index feeb16c..8170650 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1561,6 +1561,47 @@ pub extern "C" fn rust_wrapper_read_sapling_node( } } +#[no_mangle] +pub extern "C" fn rust_wrapper_combine_sapling_nodes( + level: u8, + left: *const u8, + left_len: usize, + right: *const u8, + right_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + let left_in: Vec = marshall_from_haskell_var(left, left_len, RW); + let right_in: Vec = marshall_from_haskell_var(right, right_len, RW); + if left_in.len() == 1 { + let n = Node::combine(Level::new(level), &Node::empty_leaf(), &Node::empty_leaf()); + let h = Hhex { bytes: n.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + } else { + let left_node = Node::from_bytes(to_array(left_in)); + if left_node.is_some().into() { + if right_in.len() > 1 { + let right_node = Node::from_bytes(to_array(right_in)); + if right_node.is_some().into() { + let n = Node::combine(Level::new(level), &left_node.unwrap(), &right_node.unwrap()); + let h = Hhex { bytes: n.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } + } else { + let n = Node::combine(Level::new(level), &left_node.unwrap(), &Node::empty_leaf()); + let h = Hhex { bytes: n.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + } + } else { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } + } +} + #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_frontier( tree: *const u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 48e3189..06b486a 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -253,6 +253,15 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_combine_sapling_nodes as rustWrapperCombineSaplingNodes + { `Int8' + , toBorshVar* `BS.ByteString'& + , toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_read_orchard_node as rustWrapperReadOrchardNode { toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer HexString'& diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index 8cbe12c..c7fe8e2 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -18,7 +18,8 @@ module ZcashHaskell.Sapling where import C.Zcash - ( rustWrapperDecodeSaplingAddress + ( rustWrapperCombineSaplingNodes + , rustWrapperDecodeSaplingAddress , rustWrapperIsShielded , rustWrapperReadSaplingCommitmentTree , rustWrapperReadSaplingFrontier @@ -39,6 +40,7 @@ import Data.Aeson import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as C import Data.HexString (HexString(..), fromText, hexString, toBytes, toText) +import Data.Int (Int8) import qualified Data.Text as T import Data.Word import Foreign.Rust.Marshall.Variable @@ -194,6 +196,16 @@ getSaplingNodeValue cmu = where n = withPureBorshVarBuffer $ rustWrapperReadSaplingNode cmu +combineSaplingNodes :: Int8 -> HexString -> HexString -> Maybe HexString +combineSaplingNodes level n1 n2 = + if BS.length (hexBytes r) > 1 + then Just r + else Nothing + where + r = + withPureBorshVarBuffer $ + rustWrapperCombineSaplingNodes level (toBytes n1) (toBytes n2) + getSaplingFrontier :: SaplingCommitmentTree -> Maybe SaplingFrontier getSaplingFrontier tree = if sf_pos updatedTree > 1 diff --git a/zcash-haskell.cabal b/zcash-haskell.cabal index 3216af8..c1d1d82 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.4.0 +version: 0.7.5.0 synopsis: Utilities to interact with the Zcash blockchain description: Please see the README on the repo at category: Blockchain -- 2.34.1 From 00782b80c07993d877174b352d1d0c7b07651179 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 6 Nov 2024 07:29:48 -0600 Subject: [PATCH 32/48] feat: add sapling tree root test --- librustzcash-wrapper/src/lib.rs | 12 ++++++++++++ src/C/Zcash.chs | 7 +++++++ src/ZcashHaskell/Sapling.hs | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 8170650..7a03a49 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1602,6 +1602,18 @@ pub extern "C" fn rust_wrapper_combine_sapling_nodes( } } +#[no_mangle] +pub extern "C" fn rust_wrapper_get_sapling_root( + level: u8, + out: *mut u8, + out_len: &mut usize + ){ + let tree: CommitmentTree = CommitmentTree::empty(); + let root = tree.root(); + let h = Hhex { bytes: root.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); +} + #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_frontier( tree: *const u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 06b486a..8e8947b 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -262,6 +262,13 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_get_sapling_root as rustWrapperGetSaplingRootTest + { `Int8' + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_read_orchard_node as rustWrapperReadOrchardNode { toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer HexString'& diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index c7fe8e2..362a8e9 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -20,6 +20,7 @@ module ZcashHaskell.Sapling where import C.Zcash ( rustWrapperCombineSaplingNodes , rustWrapperDecodeSaplingAddress + , rustWrapperGetSaplingRootTest , rustWrapperIsShielded , rustWrapperReadSaplingCommitmentTree , rustWrapperReadSaplingFrontier @@ -206,6 +207,10 @@ combineSaplingNodes level n1 n2 = withPureBorshVarBuffer $ rustWrapperCombineSaplingNodes level (toBytes n1) (toBytes n2) +getSaplingRootTest :: Int8 -> HexString +getSaplingRootTest level = + withPureBorshVarBuffer $ rustWrapperGetSaplingRootTest level + getSaplingFrontier :: SaplingCommitmentTree -> Maybe SaplingFrontier getSaplingFrontier tree = if sf_pos updatedTree > 1 -- 2.34.1 From a13eab17d7b5765d820f96f81ec177893e79b263 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 6 Nov 2024 13:17:58 -0600 Subject: [PATCH 33/48] feat: add sapling commitment trees --- librustzcash-wrapper/src/lib.rs | 46 +++++++++++++++++++++++++++++++++ src/C/Zcash.chs | 7 +++++ src/ZcashHaskell/Sapling.hs | 20 ++++++++++++++ src/ZcashHaskell/Types.hs | 15 +++++++++++ 4 files changed, 88 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 7a03a49..903c256 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1614,6 +1614,52 @@ pub extern "C" fn rust_wrapper_get_sapling_root( marshall_to_haskell_var(&h, out, out_len, RW); } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_sapling_commitment_tree_parts( + 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 = read_commitment_tree(tree_reader); + match comm_tree { + Ok::, _>(c1) => { + let left = match c1.left() { + Some(x) => { + Hhex { bytes: x.to_bytes().to_vec() } + }, + None => { + Hhex { bytes: vec![0] } + } + }; + let right = match c1.right() { + Some(x) => { + Hhex { bytes: x.to_bytes().to_vec() } + }, + None => { + Hhex { bytes: vec![0] } + } + }; + let parents = c1.parents().iter().map(|x| match x { + Some(y) => { + Hhex { bytes: y.to_bytes().to_vec() } + }, + None => { + Hhex { bytes: vec![0] } + } + }).collect(); + let ht = Htree { left, right, parents}; + marshall_to_haskell_var(&ht, out, out_len, RW); + }, + Err(_e) => { + let ht0 = Htree { left: Hhex { bytes: vec![0] } , right: Hhex { bytes: vec![0] }, parents: vec![Hhex { bytes: vec![0] }]}; + marshall_to_haskell_var(&ht0, out, out_len, RW); + } + } +} + #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_frontier( tree: *const u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 8e8947b..0bcdf6d 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -269,6 +269,13 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_read_sapling_commitment_tree_parts as rustWrapperReadSaplingTreeParts + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer SaplingRawTree'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_read_orchard_node as rustWrapperReadOrchardNode { toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer HexString'& diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index 362a8e9..f0b743c 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -26,6 +26,7 @@ import C.Zcash , rustWrapperReadSaplingFrontier , rustWrapperReadSaplingNode , rustWrapperReadSaplingPosition + , rustWrapperReadSaplingTreeParts , rustWrapperReadSaplingWitness , rustWrapperSaplingCheck , rustWrapperSaplingChgPaymentAddress @@ -211,6 +212,25 @@ getSaplingRootTest :: Int8 -> HexString getSaplingRootTest level = withPureBorshVarBuffer $ rustWrapperGetSaplingRootTest level +getSaplingTreeParts :: SaplingCommitmentTree -> Maybe SaplingTree +getSaplingTreeParts h = + if isBlank (srt_left tree) && isBlank (srt_right tree) + then Nothing + else Just $ + SaplingTree + (parseHex $ srt_left tree) + (parseHex $ srt_right tree) + (map parseHex (srt_parents tree)) + where + isBlank h = (BS.length $ hexBytes $ h) == 1 + parseHex h = + if (BS.length $ hexBytes $ h) > 1 + then Just h + else Nothing + tree = + withPureBorshVarBuffer $ + rustWrapperReadSaplingTreeParts $ toBytes $ sapTree h + getSaplingFrontier :: SaplingCommitmentTree -> Maybe SaplingFrontier getSaplingFrontier tree = if sf_pos updatedTree > 1 diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index 8b8a90b..0226ea1 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -611,6 +611,21 @@ newtype SaplingCommitmentTree = SaplingCommitmentTree { sapTree :: HexString } deriving (Eq, Prelude.Show, Read) +data SaplingRawTree = SaplingRawTree + { srt_left :: !HexString + , srt_right :: !HexString + , srt_parents :: ![HexString] + } deriving stock (Eq, Prelude.Show, GHC.Generic) + deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) + deriving anyclass (Data.Structured.Show) + deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct SaplingRawTree + +data SaplingTree = SaplingTree + { ot_left :: !(Maybe HexString) + , ot_right :: !(Maybe HexString) + , ot_parents :: ![Maybe HexString] + } deriving (Eq, Prelude.Show, Read) + data SaplingFrontier = SaplingFrontier { sf_pos :: !Int64 , sf_leaf :: !HexString -- 2.34.1 From 4c3a188c32330c1a12a5e01d3083bd523292bb5f Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 6 Nov 2024 14:02:24 -0600 Subject: [PATCH 34/48] fix: sapling tree field names --- src/ZcashHaskell/Types.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index 0226ea1..ada4a58 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -621,9 +621,9 @@ data SaplingRawTree = SaplingRawTree deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct SaplingRawTree data SaplingTree = SaplingTree - { ot_left :: !(Maybe HexString) - , ot_right :: !(Maybe HexString) - , ot_parents :: ![Maybe HexString] + { st_left :: !(Maybe HexString) + , st_right :: !(Maybe HexString) + , st_parents :: ![Maybe HexString] } deriving (Eq, Prelude.Show, Read) data SaplingFrontier = SaplingFrontier -- 2.34.1 From 1dcc549bd5f59290897ce21b40a60c3d7cd4644c Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 6 Nov 2024 15:48:50 -0600 Subject: [PATCH 35/48] feat: add sapling tree anchor function --- librustzcash-wrapper/src/lib.rs | 23 +++++++++++++++++++++++ src/C/Zcash.chs | 7 +++++++ src/ZcashHaskell/Sapling.hs | 6 ++++++ 3 files changed, 36 insertions(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 903c256..2c1b644 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1660,6 +1660,29 @@ pub extern "C" fn rust_wrapper_read_sapling_commitment_tree_parts( } } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_sapling_tree_anchor( + 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 = read_commitment_tree(tree_reader); + match comm_tree { + Ok::, _>(c1) => { + let root = c1.root(); + let h = Hhex { bytes: root.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, out, out_len, RW); + }, + Err(_) => { + let h0 = Hhex { bytes: vec![0] }; + marshall_to_haskell_var(&h0, out, out_len, RW); + } + } +} + #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_frontier( tree: *const u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 0bcdf6d..6d915bb 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -276,6 +276,13 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_read_sapling_tree_anchor as rustWrapperReadSaplingTreeAnchor + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_read_orchard_node as rustWrapperReadOrchardNode { toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer HexString'& diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index f0b743c..87b21f7 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -26,6 +26,7 @@ import C.Zcash , rustWrapperReadSaplingFrontier , rustWrapperReadSaplingNode , rustWrapperReadSaplingPosition + , rustWrapperReadSaplingTreeAnchor , rustWrapperReadSaplingTreeParts , rustWrapperReadSaplingWitness , rustWrapperSaplingCheck @@ -231,6 +232,11 @@ getSaplingTreeParts h = withPureBorshVarBuffer $ rustWrapperReadSaplingTreeParts $ toBytes $ sapTree h +getSaplingTreeAnchor :: SaplingCommitmentTree -> HexString +getSaplingTreeAnchor tree = + withPureBorshVarBuffer $ + rustWrapperReadSaplingTreeAnchor $ toBytes $ sapTree tree + getSaplingFrontier :: SaplingCommitmentTree -> Maybe SaplingFrontier getSaplingFrontier tree = if sf_pos updatedTree > 1 -- 2.34.1 From 8244ffa1cec822a6e0db108ec72ed5f268297eee Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Thu, 7 Nov 2024 12:13:52 -0600 Subject: [PATCH 36/48] feat: add sapling merkle path test --- CHANGELOG.md | 1 + librustzcash-wrapper/src/lib.rs | 31 +++++++++++++++++++++++++++++++ src/C/Zcash.chs | 8 ++++++++ src/ZcashHaskell/Sapling.hs | 5 +++++ 4 files changed, 45 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c817ca1..5c1328f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Sapling commitment node functions +- Sapling Merkle path test ## [0.7.4.0] diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 2c1b644..165b144 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1683,6 +1683,37 @@ pub extern "C" fn rust_wrapper_read_sapling_tree_anchor( } } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_sapling_path_anchor( + path: *const u8, + path_len: usize, + cmx: *const u8, + cmx_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + let path_in: Hpath = marshall_from_haskell_var(path, path_len, RW); + let cmx_in: Vec = marshall_from_haskell_var(cmx, cmx_len, RW); + let mk_path = sapling_crypto::MerklePath::from_parts(path_in.path.iter().map(|x| Node::from_bytes(to_array(x.bytes.clone())).unwrap()).collect(), Position::from(u64::from(path_in.position))); + match mk_path { + Ok(mp1) => { + let nc = SaplingNoteCommitment::from_bytes(&to_array(cmx_in)); + if nc.is_some().into() { + let anchor = mp1.root(Node::from_cmu(&nc.unwrap())); + let h = Hhex { bytes: anchor.to_bytes().to_vec() }; + marshall_to_haskell_var(&h, 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); + } + } +} + #[no_mangle] pub extern "C" fn rust_wrapper_read_orchard_frontier( tree: *const u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 6d915bb..fde4550 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -283,6 +283,14 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_read_sapling_path_anchor as rustWrapperReadSaplingPathAnchor + { toBorshVar* `MerklePath'& + , toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_read_orchard_node as rustWrapperReadOrchardNode { toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer HexString'& diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index 87b21f7..1347778 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -25,6 +25,7 @@ import C.Zcash , rustWrapperReadSaplingCommitmentTree , rustWrapperReadSaplingFrontier , rustWrapperReadSaplingNode + , rustWrapperReadSaplingPathAnchor , rustWrapperReadSaplingPosition , rustWrapperReadSaplingTreeAnchor , rustWrapperReadSaplingTreeParts @@ -237,6 +238,10 @@ getSaplingTreeAnchor tree = withPureBorshVarBuffer $ rustWrapperReadSaplingTreeAnchor $ toBytes $ sapTree tree +getSaplingPathAnchor :: HexString -> MerklePath -> HexString +getSaplingPathAnchor hex p = + withPureBorshVarBuffer $ rustWrapperReadSaplingPathAnchor p (hexBytes hex) + getSaplingFrontier :: SaplingCommitmentTree -> Maybe SaplingFrontier getSaplingFrontier tree = if sf_pos updatedTree > 1 -- 2.34.1 From 20851a4e48f768a492796fb828f16ae9745931dc Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Thu, 7 Nov 2024 12:54:22 -0600 Subject: [PATCH 37/48] fix(rust): account for empty leaf in sapling path --- librustzcash-wrapper/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 165b144..6c4095f 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1694,7 +1694,12 @@ pub extern "C" fn rust_wrapper_read_sapling_path_anchor( ){ let path_in: Hpath = marshall_from_haskell_var(path, path_len, RW); let cmx_in: Vec = marshall_from_haskell_var(cmx, cmx_len, RW); - let mk_path = sapling_crypto::MerklePath::from_parts(path_in.path.iter().map(|x| Node::from_bytes(to_array(x.bytes.clone())).unwrap()).collect(), Position::from(u64::from(path_in.position))); + let mk_path = sapling_crypto::MerklePath::from_parts(path_in.path.iter().map(|x| + if x.bytes.len() > 1 { + Node::from_bytes(to_array(x.bytes.clone())).unwrap() + } else { + Node::empty_leaf() + }).collect(), Position::from(u64::from(path_in.position))); match mk_path { Ok(mp1) => { let nc = SaplingNoteCommitment::from_bytes(&to_array(cmx_in)); -- 2.34.1 From 1ce7dc24feb8fc7063a49e3fd9f8e5e0512cba2f Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 11 Nov 2024 11:21:24 -0600 Subject: [PATCH 38/48] feat: Implement transaction creation with new trees --- librustzcash-wrapper/src/lib.rs | 70 ++++++++++++--------------------- src/ZcashHaskell/Types.hs | 4 +- src/ZcashHaskell/Utils.hs | 12 ++---- 3 files changed, 31 insertions(+), 55 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 6c4095f..1e99fbe 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -570,11 +570,11 @@ impl Hspend { } } -#[derive(Debug, BorshSerialize, BorshDeserialize)] +#[derive(BorshSerialize, BorshDeserialize)] pub struct HsaplingInput { sk: Vec, note: Hnote, - iw: Vec + iw: Hpath } impl FromHaskell for HsaplingInput { @@ -585,11 +585,11 @@ impl FromHaskell for HsaplingInput { } -#[derive(Debug, BorshSerialize, BorshDeserialize)] +#[derive(BorshSerialize, BorshDeserialize)] pub struct HorchardInput { sk: Vec, note: Hnote, - iw: Vec + iw: Hpath } impl FromHaskell for HorchardInput { @@ -2144,47 +2144,25 @@ pub extern "C" fn rust_wrapper_create_transaction( out: *mut u8, out_len: &mut usize){ let sap_input: Vec = marshall_from_haskell_var(s_input, s_input_len, RW); - let sap_anchor = - if sap_input.is_empty() { - let sap_wit_in: Vec = marshall_from_haskell_var(sap_wit, sap_wit_len, RW); - let sap_wit_reader = Cursor::new(sap_wit_in); - let sap_iw = read_commitment_tree::>, SAPLING_DEPTH>(sap_wit_reader); - match sap_iw { - Ok(s_iw) => { - Some(SaplingAnchor::from(s_iw.root())) - }, - Err(_e) => { - None - } - } + let sap_anchor_in: Vec = marshall_from_haskell_var(sap_wit, sap_wit_len, RW); + let sap_anchor = SaplingAnchor::from_bytes(to_array(sap_anchor_in)); + let sapling_anchor = + if sap_anchor.is_some().into() { + Some(sap_anchor.unwrap()) } else { - let si = &sap_input[0]; - let swit_reader = Cursor::new(&si.iw); - let iw: IncrementalWitness = read_incremental_witness(swit_reader).unwrap(); - Some(SaplingAnchor::from(iw.root())) + None }; //println!("{:?}", sap_anchor); let orch_input: Vec = marshall_from_haskell_var(o_input, o_input_len, RW); - let orch_anchor = - if orch_input.is_empty() { - 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); - match orch_iw { - Ok(o_iw) => { - Some(OrchardAnchor::from(o_iw.root())) - }, - Err(_e) => { - None - } - } + let orch_anchor_in : Vec = marshall_from_haskell_var(orch_wit, orch_wit_len, RW); + let orch_anchor = OrchardAnchor::from_bytes(to_array(orch_anchor_in)); + let orchard_anchor = + if orch_anchor.is_some().into() { + Some(orch_anchor.unwrap()) } 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())) + None }; - let build_config = BuildConfig::Standard {sapling_anchor: sap_anchor, orchard_anchor: orch_anchor}; + let build_config = BuildConfig::Standard {sapling_anchor, orchard_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); let trans_input: Vec = marshall_from_haskell_var(t_input, t_input_len, RW); @@ -2224,9 +2202,13 @@ pub extern "C" fn rust_wrapper_create_transaction( Rseed::AfterZip212(to_array(s_in.note.rseed.bytes)) }; let note = SaplingNote::from_parts(pay_addr, SaplingNoteValue::from_raw(s_in.note.note), rseed); - let wit_reader = Cursor::new(s_in.iw); - let iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); - let merkle_path = iw.path().unwrap(); + let mk_path = sapling_crypto::MerklePath::from_parts(s_in.iw.path.iter().map(|x| + if x.bytes.len() > 1 { + Node::from_bytes(to_array(x.bytes.clone())).unwrap() + } else { + Node::empty_leaf() + }).collect(), Position::from(u64::from(s_in.iw.position))); + let merkle_path = mk_path.unwrap(); if net { let mb = main_builder.add_sapling_spend::(&sk, note, merkle_path); match mb { @@ -2267,9 +2249,7 @@ pub extern "C" fn rust_wrapper_create_transaction( let val = NoteValue::from_raw(o_in.note.note); //println!("o inp: {:?}", val); let note = Note::from_parts(pay_addr, val, rho, rseed).unwrap(); - let wit_reader = Cursor::new(o_in.iw); - let iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); - let merkle_path = OrchardMerklePath::from(iw.path().unwrap()); + let merkle_path = orchard::tree::MerklePath::from_parts(o_in.iw.position, to_array(o_in.iw.path.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap()).collect())); if net { let mb = main_builder.add_orchard_spend::(&sp_key, note, merkle_path); match mb { diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index ada4a58..1c55a73 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -812,7 +812,7 @@ data TransparentTxSpend = TransparentTxSpend data SaplingTxSpend = SaplingTxSpend { ss_sk :: !BS.ByteString , ss_note :: !DecodedNote - , ss_iw :: !BS.ByteString + , ss_iw :: !MerklePath } deriving stock (Eq, Prelude.Show, GHC.Generic) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (Data.Structured.Show) @@ -821,7 +821,7 @@ data SaplingTxSpend = SaplingTxSpend data OrchardTxSpend = OrchardTxSpend { ss_sk :: !BS.ByteString , ss_note :: !DecodedNote - , ss_iw :: !BS.ByteString + , ss_iw :: !MerklePath } deriving stock (Eq, Prelude.Show, GHC.Generic) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (Data.Structured.Show) diff --git a/src/ZcashHaskell/Utils.hs b/src/ZcashHaskell/Utils.hs index ee0a0d9..03db2b5 100644 --- a/src/ZcashHaskell/Utils.hs +++ b/src/ZcashHaskell/Utils.hs @@ -123,8 +123,8 @@ readZebraTransaction hex = rawTx = (withPureBorshVarBuffer . rustWrapperTxRead) $ hexBytes hex createTransaction :: - Maybe SaplingCommitmentTree -- ^ to obtain the Sapling anchor - -> Maybe OrchardCommitmentTree -- ^ to obtain the Orchard anchor + HexString -- ^ to obtain the Sapling anchor + -> HexString -- ^ to obtain the Orchard anchor -> [TransparentTxSpend] -- ^ the list of transparent notes to spend -> [SaplingTxSpend] -- ^ the list of Sapling notes to spend -> [OrchardTxSpend] -- ^ the list of Orchard notes to spend @@ -137,12 +137,8 @@ createTransaction sapAnchor orchAnchor tSpend sSpend oSpend outgoing znet bh bui txResult <- withBorshBufferOfInitSize 51200 $ rustWrapperCreateTx - (case sapAnchor of - Nothing -> "0" - Just sA -> toBytes $ sapTree sA) - (case orchAnchor of - Nothing -> "0" - Just oA -> toBytes $ orchTree oA) + (hexBytes sapAnchor) + (hexBytes orchAnchor) tSpend sSpend oSpend -- 2.34.1 From 58951db64a0927d0004b2c33b573ae04c1cd0ef8 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 12 Nov 2024 14:32:23 -0600 Subject: [PATCH 39/48] docs: add debugging --- librustzcash-wrapper/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 1e99fbe..64908d7 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -2418,6 +2418,7 @@ pub extern "C" fn rust_wrapper_create_transaction( Err(e) => { match e { Error::InsufficientFunds(y) => { + println!("ins funds: {:?}", y); let x = Hhex {bytes: vec![0]}; marshall_to_haskell_var(&x, out, out_len, RW); }, -- 2.34.1 From 42f3e3a7fd03b279a1c968e632df8adef846deea Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 12 Nov 2024 14:53:59 -0600 Subject: [PATCH 40/48] docs: add debugging --- librustzcash-wrapper/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 64908d7..9b446f6 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -2247,7 +2247,7 @@ pub extern "C" fn rust_wrapper_create_transaction( 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); - //println!("o inp: {:?}", val); + println!("o inp: {:?}", val); let note = Note::from_parts(pay_addr, val, rho, rseed).unwrap(); let merkle_path = orchard::tree::MerklePath::from_parts(o_in.iw.position, to_array(o_in.iw.path.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap()).collect())); if net { -- 2.34.1 From 107e1fa6e5f479a795d279546ec1c90ed49b7d3a Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 12 Nov 2024 14:56:41 -0600 Subject: [PATCH 41/48] add debugging --- librustzcash-wrapper/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 9b446f6..04eb794 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -2152,7 +2152,7 @@ pub extern "C" fn rust_wrapper_create_transaction( } else { None }; - //println!("{:?}", sap_anchor); + println!("{:?}", sapling_anchor); let orch_input: Vec = marshall_from_haskell_var(o_input, o_input_len, RW); let orch_anchor_in : Vec = marshall_from_haskell_var(orch_wit, orch_wit_len, RW); let orch_anchor = OrchardAnchor::from_bytes(to_array(orch_anchor_in)); @@ -2162,6 +2162,7 @@ pub extern "C" fn rust_wrapper_create_transaction( } else { None }; + println!("{:?}", orchard_anchor); let build_config = BuildConfig::Standard {sapling_anchor, orchard_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); -- 2.34.1 From 442d2adfad2154dca02a50e368a3e6b13560d67b Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 12 Nov 2024 15:10:47 -0600 Subject: [PATCH 42/48] update anchors for builder --- librustzcash-wrapper/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 04eb794..0433ee7 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -2145,20 +2145,20 @@ pub extern "C" fn rust_wrapper_create_transaction( out_len: &mut usize){ let sap_input: Vec = marshall_from_haskell_var(s_input, s_input_len, RW); let sap_anchor_in: Vec = marshall_from_haskell_var(sap_wit, sap_wit_len, RW); - let sap_anchor = SaplingAnchor::from_bytes(to_array(sap_anchor_in)); + let sap_anchor = Node::from_bytes(to_array(sap_anchor_in)); let sapling_anchor = if sap_anchor.is_some().into() { - Some(sap_anchor.unwrap()) + Some(SaplingAnchor::from(sap_anchor.unwrap())) } else { None }; println!("{:?}", sapling_anchor); let orch_input: Vec = marshall_from_haskell_var(o_input, o_input_len, RW); let orch_anchor_in : Vec = marshall_from_haskell_var(orch_wit, orch_wit_len, RW); - let orch_anchor = OrchardAnchor::from_bytes(to_array(orch_anchor_in)); + let orch_anchor = MerkleHashOrchard::from_bytes(&to_array(orch_anchor_in)); let orchard_anchor = if orch_anchor.is_some().into() { - Some(orch_anchor.unwrap()) + Some(OrchardAnchor::from(orch_anchor.unwrap())) } else { None }; -- 2.34.1 From a5898d04f8a43bb99e210b13e6909bf79eb570af Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 12 Nov 2024 15:40:58 -0600 Subject: [PATCH 43/48] add debugging --- librustzcash-wrapper/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 0433ee7..24912ba 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -2363,7 +2363,7 @@ pub extern "C" fn rust_wrapper_create_transaction( }; let recipient = OrchardAddress::from_raw_address_bytes(&to_array(output.to)).unwrap(); let val = output.amt; - //println!("o out: {:?} {:?}", val, output.chg); + println!("o out: {:?} {:?}", val, output.chg); let memo = MemoBytes::from_bytes(&output.memo).unwrap(); if net { let mb = main_builder.add_orchard_output::(ovk, recipient, val, memo); -- 2.34.1 From 0171b5ec5af08852f87ec46cd4bb618f5330f570 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 12 Nov 2024 16:01:53 -0600 Subject: [PATCH 44/48] add debugging --- librustzcash-wrapper/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 24912ba..1549e16 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -2255,9 +2255,11 @@ pub extern "C" fn rust_wrapper_create_transaction( let mb = main_builder.add_orchard_spend::(&sp_key, note, merkle_path); match mb { Ok(()) => { + println!("added orchard inp: {:?}", val); continue; }, - Err(_e) => { + Err(e) => { + println!("failed orchard inp: {:?}", e); let x = Hhex {bytes: vec![7]}; marshall_to_haskell_var(&x, out, out_len, RW); } -- 2.34.1 From 5ce29d096d0f747e824280b6a472033689481657 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 12 Nov 2024 16:22:56 -0600 Subject: [PATCH 45/48] add debugging --- librustzcash-wrapper/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 1549e16..e13fffb 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -2268,9 +2268,11 @@ pub extern "C" fn rust_wrapper_create_transaction( let tb = test_builder.add_orchard_spend::(&sp_key, note, merkle_path); match tb { Ok(()) => { + println!("added orchard inp: {:?}", val); continue; }, - Err(_e) => { + Err(e) => { + println!("failed orchard inp: {:?}", e); let x = Hhex {bytes: vec![7]}; marshall_to_haskell_var(&x, out, out_len, RW); } -- 2.34.1 From 952ceeda4bc779fd46c876c5bb6df9844abb0e9a Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 13 Nov 2024 12:57:08 -0600 Subject: [PATCH 46/48] upgrade rust deps --- librustzcash-wrapper/Cargo.lock | 61 +++++++++++++++++---------------- librustzcash-wrapper/Cargo.toml | 12 +++---- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/librustzcash-wrapper/Cargo.lock b/librustzcash-wrapper/Cargo.lock index 604eeee..0c20ffb 100644 --- a/librustzcash-wrapper/Cargo.lock +++ b/librustzcash-wrapper/Cargo.lock @@ -60,9 +60,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.21.2" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -757,9 +757,9 @@ dependencies = [ [[package]] name = "incrementalmerkletree" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75346da3bd8e3d8891d02508245ed2df34447ca6637e343829f8d08986e9cde2" +checksum = "d45063fbc4b0a37837f6bfe0445f269d13d730ad0aa3b5a7f74aa7bf27a0f4df" dependencies = [ "either", ] @@ -987,9 +987,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "orchard" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc7bde644aeb980be296cd908c6650894dc8541deb56f9f5294c52ed7ca568f" +checksum = "4f18e997fa121de5c73e95cdc7e8512ae43b7de38904aeea5e5713cc48f3c0ba" dependencies = [ "aes", "bitvec", @@ -1379,9 +1379,9 @@ dependencies = [ [[package]] name = "sapling-crypto" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e379398fffad84e49f9a45a05635fc004f66086e65942dbf4eb95332c26d2a" +checksum = "cfff8cfce16aeb38da50b8e2ed33c9018f30552beff2210c266662a021b17f38" dependencies = [ "aes", "bellman", @@ -1488,9 +1488,9 @@ dependencies = [ [[package]] name = "shardtree" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78222845cd8bbe5eb95687407648ff17693a35de5e8abaa39a4681fb21e033f9" +checksum = "b5f2390975ebfe8838f9e861f7a588123d49a7a7a0a08568ea831d8ad53fc9b4" dependencies = [ "bitflags 2.4.2", "either", @@ -1883,9 +1883,9 @@ dependencies = [ [[package]] name = "zcash_address" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d26f21381dc220836dd8d2a9a10dbe85928a26232b011bc6a42b611789b743" +checksum = "4ff95eac82f71286a79c750e674550d64fb2b7aadaef7b89286b2917f645457d" dependencies = [ "bech32 0.9.1", "bs58 0.5.0", @@ -1896,9 +1896,9 @@ dependencies = [ [[package]] name = "zcash_client_backend" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e3a0f3e5d7f299d8b7ef3237697630989c31ab1b162824c99c1cd8bc83715e" +checksum = "cbeeede366fdb642710d3c59fc2090489affd075f66db53ed11bb7138d2d0258" dependencies = [ "base64", "bech32 0.9.1", @@ -1924,7 +1924,7 @@ dependencies = [ "tonic-build", "tracing", "which", - "zcash_address 0.4.0", + "zcash_address 0.6.0", "zcash_encoding", "zcash_keys", "zcash_note_encryption", @@ -1946,9 +1946,9 @@ dependencies = [ [[package]] name = "zcash_keys" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712faf4070107ab0b2828d0eda6aeaf4c3cb02564109832d95b97ad3467c95a5" +checksum = "e8162c94957f1e379b8e2fb30f97b95cfa93ac9c6bc02895946ca6392d1abb81" dependencies = [ "bech32 0.9.1", "blake2b_simd", @@ -1963,7 +1963,7 @@ dependencies = [ "secrecy", "subtle", "tracing", - "zcash_address 0.4.0", + "zcash_address 0.6.0", "zcash_encoding", "zcash_primitives", "zcash_protocol", @@ -1985,9 +1985,9 @@ dependencies = [ [[package]] name = "zcash_primitives" -version = "0.16.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f044bc9cf2887ec408196fbafb44749e5581f57cc18d8da7aabaeb60cc40c64" +checksum = "6ab47d526d7fd6f88b3a2854ad81b54757a80c2aeadd1d8b06f690556af9743c" dependencies = [ "aes", "bip32", @@ -2014,7 +2014,7 @@ dependencies = [ "sha2 0.10.6", "subtle", "tracing", - "zcash_address 0.4.0", + "zcash_address 0.6.0", "zcash_encoding", "zcash_note_encryption", "zcash_protocol", @@ -2024,9 +2024,9 @@ dependencies = [ [[package]] name = "zcash_protocol" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f35eac659fdbba614333d119217c5963c0d7cea43aee33176c4f2f95e5460d8d" +checksum = "6bc22b9155b2c7eb20105cd06de170d188c1bc86489b92aa3fda7b8da8d96acf" dependencies = [ "document-features", "memuse", @@ -2034,9 +2034,9 @@ dependencies = [ [[package]] name = "zcash_spec" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a3bf58b673cb3dacd8ae09ba345998923a197ab0da70d6239d8e8838949e9b" +checksum = "9cede95491c2191d3e278cab76e097a44b17fde8d6ca0d4e3a22cf4807b2d857" dependencies = [ "blake2b_simd", ] @@ -2063,24 +2063,25 @@ dependencies = [ [[package]] name = "zip32" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4226d0aee9c9407c27064dfeec9d7b281c917de3374e1e5a2e2cfad9e09de19e" +checksum = "92022ac1e47c7b78f9cee29efac8a1a546e189506f3bb5ad46d525be7c519bf6" dependencies = [ "blake2b_simd", "memuse", "subtle", + "zcash_spec", ] [[package]] name = "zip321" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc85f862f7be64fb0d46f9eb5b82ad54e58cde314fa979d5bae591bc0143693" +checksum = "1f3e613defb0940acef1f54774b51c7f48f2fa705613dd800870dc69f35cd2ea" dependencies = [ "base64", "nom", "percent-encoding", - "zcash_address 0.4.0", + "zcash_address 0.6.0", "zcash_protocol", ] diff --git a/librustzcash-wrapper/Cargo.toml b/librustzcash-wrapper/Cargo.toml index 208022f..350ecb2 100644 --- a/librustzcash-wrapper/Cargo.toml +++ b/librustzcash-wrapper/Cargo.toml @@ -11,15 +11,15 @@ f4jumble = "0.1" zcash_address = "0.2.0" borsh = "0.10" bech32 = "0.11" -orchard = "0.9.0" +orchard = "0.10.0" zcash_note_encryption = "0.4.0" -zcash_primitives = { version = "0.16.0", features = ["transparent-inputs"]} -zcash_client_backend = "0.13.0" -sapling-crypto = "0.2" -zip32 = "0.1.0" +zcash_primitives = { version = "0.19.0", features = ["transparent-inputs"]} +zcash_client_backend = "0.14.0" +sapling-crypto = "0.3" +zip32 = "0.1.2" proc-macro2 = "1.0.66" nonempty = "0.7.0" -incrementalmerkletree = "0.6.0" +incrementalmerkletree = "0.7.0" secp256k1 = "0.27.0" jubjub = "0.10.0" rand_core = { version = "0.6.4", features = ["getrandom"]} -- 2.34.1 From c205bc6cf53b1c511b421e399b84b9038eec8114 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 13 Nov 2024 13:10:10 -0600 Subject: [PATCH 47/48] remove debugging --- librustzcash-wrapper/src/lib.rs | 34 ++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index e13fffb..563ac5f 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1873,7 +1873,13 @@ pub extern "C" fn rust_wrapper_read_orchard_path_anchor( ){ let path_in: Hpath = marshall_from_haskell_var(path, path_len, RW); let cmx_in: Vec = marshall_from_haskell_var(cmx, cmx_len, RW); - let mk_path = orchard::tree::MerklePath::from_parts(path_in.position, to_array(path_in.path.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap()).collect())); + let mk_path = orchard::tree::MerklePath::from_parts(path_in.position, to_array(path_in.path.iter().map(|x| + if x.bytes.len() > 1 { + MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() + } else { + MerkleHashOrchard::empty_leaf() + } + ).collect())); let nc = ExtractedNoteCommitment::from_bytes(&to_array(cmx_in)); if nc.is_some().into() { let anchor = mk_path.root(nc.unwrap()); @@ -2152,7 +2158,7 @@ pub extern "C" fn rust_wrapper_create_transaction( } else { None }; - println!("{:?}", sapling_anchor); + //println!("{:?}", sapling_anchor); let orch_input: Vec = marshall_from_haskell_var(o_input, o_input_len, RW); let orch_anchor_in : Vec = marshall_from_haskell_var(orch_wit, orch_wit_len, RW); let orch_anchor = MerkleHashOrchard::from_bytes(&to_array(orch_anchor_in)); @@ -2162,7 +2168,7 @@ pub extern "C" fn rust_wrapper_create_transaction( } else { None }; - println!("{:?}", orchard_anchor); + //println!("{:?}", orchard_anchor); let build_config = BuildConfig::Standard {sapling_anchor, orchard_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); @@ -2248,18 +2254,24 @@ pub extern "C" fn rust_wrapper_create_transaction( 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); - println!("o inp: {:?}", val); + //println!("o inp: {:?}", val); let note = Note::from_parts(pay_addr, val, rho, rseed).unwrap(); - let merkle_path = orchard::tree::MerklePath::from_parts(o_in.iw.position, to_array(o_in.iw.path.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap()).collect())); + let merkle_path = orchard::tree::MerklePath::from_parts(o_in.iw.position, to_array(o_in.iw.path.iter().map(|x| + if x.bytes.len() > 1 { + MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() + } else { + MerkleHashOrchard::empty_leaf() + } + ).collect())); if net { let mb = main_builder.add_orchard_spend::(&sp_key, note, merkle_path); match mb { Ok(()) => { - println!("added orchard inp: {:?}", val); + //println!("added orchard inp: {:?}", val); continue; }, Err(e) => { - println!("failed orchard inp: {:?}", e); + //println!("failed orchard inp: {:?}", e); let x = Hhex {bytes: vec![7]}; marshall_to_haskell_var(&x, out, out_len, RW); } @@ -2268,11 +2280,11 @@ pub extern "C" fn rust_wrapper_create_transaction( let tb = test_builder.add_orchard_spend::(&sp_key, note, merkle_path); match tb { Ok(()) => { - println!("added orchard inp: {:?}", val); + //println!("added orchard inp: {:?}", val); continue; }, Err(e) => { - println!("failed orchard inp: {:?}", e); + //println!("failed orchard inp: {:?}", e); let x = Hhex {bytes: vec![7]}; marshall_to_haskell_var(&x, out, out_len, RW); } @@ -2367,7 +2379,7 @@ pub extern "C" fn rust_wrapper_create_transaction( }; let recipient = OrchardAddress::from_raw_address_bytes(&to_array(output.to)).unwrap(); let val = output.amt; - println!("o out: {:?} {:?}", val, output.chg); + //println!("o out: {:?} {:?}", val, output.chg); let memo = MemoBytes::from_bytes(&output.memo).unwrap(); if net { let mb = main_builder.add_orchard_output::(ovk, recipient, val, memo); @@ -2423,7 +2435,7 @@ pub extern "C" fn rust_wrapper_create_transaction( Err(e) => { match e { Error::InsufficientFunds(y) => { - println!("ins funds: {:?}", y); + //println!("ins funds: {:?}", y); let x = Hhex {bytes: vec![0]}; marshall_to_haskell_var(&x, out, out_len, RW); }, -- 2.34.1 From db92676ca4dd281b55ea4dd5ce4fc08d2348e0f2 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Fri, 15 Nov 2024 12:46:35 -0600 Subject: [PATCH 48/48] docs: update changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c1328f..ed642a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Sapling commitment node functions - Sapling Merkle path test +### Changed + +- Upgraded Rust dependencies to latest versions: + - `zcash_primitives` 0.19.0 + - `zcash_client_backend` 0.14.0 + - `orchard` 0.10.0 + - `sapling-crypto` 0.3.0 + - `incrementalmerkletree` 0.7.0 + - `zip32` 0.1.2 + ## [0.7.4.0] ### Added -- 2.34.1