From 3203c7e8ffefcb788caf5801425af344a85922bc Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Fri, 18 Oct 2024 08:47:52 -0500 Subject: [PATCH] feat: implement Frontier for Sapling witnesses --- librustzcash-wrapper/src/lib.rs | 109 ++++++++++++++++++++++++++------ src/C/Zcash.chs | 11 +++- src/ZcashHaskell/Sapling.hs | 31 +++++---- src/ZcashHaskell/Types.hs | 9 +++ 4 files changed, 128 insertions(+), 32 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 10e8df0..a0e98b6 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1369,6 +1369,31 @@ pub extern "C" fn rust_wrapper_bech32_encode( marshall_to_haskell_var(&string, out, out_len, RW); } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_sapling_frontier( + tree: *const u8, + tree_len: usize, + out: *mut u8, + out_len: &mut usize + ){ + let tree_in: Vec = marshall_from_haskell_var(tree, tree_len, RW); + let tree_reader = Cursor::new(tree_in); + let comm_tree: CommitmentTree = read_commitment_tree(tree_reader).unwrap(); + //let comm_tree: Frontier = read_frontier_v1(tree_reader).unwrap(); + let frontier: Frontier = comm_tree.to_frontier(); + match frontier.value() { + Some(f1) => { + let (pos, leaf, omm) = f1.clone().into_parts(); + let f = Hfrontier { position: ::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| x.to_bytes().to_vec()).collect()}; + marshall_to_haskell_var(&f, out, out_len, RW); + }, + None => { + let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![vec![0]]}; + marshall_to_haskell_var(&f0, out, out_len, RW); + } + } +} + #[no_mangle] pub extern "C" fn rust_wrapper_read_sapling_commitment_tree( tree: *const u8, @@ -1687,21 +1712,31 @@ 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_anchor = match sap_iw { - Ok(s_iw) => { - Some(SaplingAnchor::from(s_iw.root())) - }, - Err(_e) => { + //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 - } - }; + } 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_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) => { @@ -1746,7 +1781,6 @@ pub extern "C" fn rust_wrapper_create_transaction( } } } - let sap_input: Vec = marshall_from_haskell_var(s_input, s_input_len, RW); for s_in in sap_input { if s_in.sk.len() > 1 { let sp_key = ExtendedSpendingKey::from_bytes(&s_in.sk); @@ -1763,13 +1797,32 @@ pub extern "C" fn rust_wrapper_create_transaction( let iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); let merkle_path = iw.path().unwrap(); if net { - let _mb = main_builder.add_sapling_spend::(&sk, note, merkle_path).unwrap(); + let mb = main_builder.add_sapling_spend::(&sk, note, merkle_path); + 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_spend::(&sk, note, merkle_path).unwrap(); + let tb = test_builder.add_sapling_spend::(&sk, note, merkle_path); + match tb { + Ok(()) => { + continue; + }, + Err(_e) => { + let x = Hhex {bytes: vec![5]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } }, Err(_e) => { - continue; + let x = Hhex {bytes: vec![5]}; + marshall_to_haskell_var(&x, out, out_len, RW); } } } @@ -1786,9 +1839,27 @@ pub extern "C" fn rust_wrapper_create_transaction( let iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); let merkle_path = OrchardMerklePath::from(iw.path().unwrap()); if net { - let _mb = main_builder.add_orchard_spend::(&sp_key, note, merkle_path).unwrap(); + let mb = main_builder.add_orchard_spend::(&sp_key, note, merkle_path); + match mb { + Ok(()) => { + continue; + }, + Err(_e) => { + let x = Hhex {bytes: vec![7]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } else { - let _tb = test_builder.add_orchard_spend::(&sp_key, note, merkle_path).unwrap(); + let tb = test_builder.add_orchard_spend::(&sp_key, note, merkle_path); + match tb { + Ok(()) => { + continue; + }, + Err(_e) => { + let x = Hhex {bytes: vec![7]}; + marshall_to_haskell_var(&x, out, out_len, RW); + } + } } } } diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index beb11e2..ab4bd54 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -204,9 +204,9 @@ import ZcashHaskell.Types #} {# fun unsafe rust_wrapper_read_sapling_commitment_tree as rustWrapperReadSaplingCommitmentTree - { toBorshVar* `BS.ByteString'& + { toBorshVar* `SaplingFrontier'& , toBorshVar* `BS.ByteString'& - , getVarBuffer `Buffer HexString'& + , getVarBuffer `Buffer SaplingFrontier'& } -> `()' #} @@ -232,6 +232,13 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_read_sapling_frontier as rustWrapperReadSaplingFrontier + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer SaplingFrontier'& + } + -> `()' +#} + {# fun unsafe rust_wrapper_decode_sapling_address as rustWrapperDecodeSaplingAddress { toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer (BS.ByteString)'& diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index f145c91..4b7c286 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -21,6 +21,7 @@ import C.Zcash ( rustWrapperDecodeSaplingAddress , rustWrapperIsShielded , rustWrapperReadSaplingCommitmentTree + , rustWrapperReadSaplingFrontier , rustWrapperReadSaplingPosition , rustWrapperReadSaplingWitness , rustWrapperSaplingCheck @@ -184,21 +185,29 @@ genSaplingInternalAddress sk = res = withPureBorshVarBuffer (rustWrapperSaplingChgPaymentAddress $ getBytes sk) --- | Update a Sapling commitment tree -updateSaplingCommitmentTree :: - SaplingCommitmentTree -- ^ the base tree - -> HexString -- ^ the new note commitment - -> Maybe SaplingCommitmentTree -updateSaplingCommitmentTree tree cmu = - if BS.length (hexBytes updatedTree) > 1 - then Just $ SaplingCommitmentTree updatedTree +getSaplingFrontier :: SaplingCommitmentTree -> Maybe SaplingFrontier +getSaplingFrontier tree = + if sf_pos updatedTree > 1 + then Just updatedTree else Nothing where updatedTree = withPureBorshVarBuffer $ - rustWrapperReadSaplingCommitmentTree - (hexBytes $ sapTree tree) - (hexBytes cmu) + rustWrapperReadSaplingFrontier $ toBytes $ sapTree tree + +-- | Update a Sapling commitment tree +updateSaplingCommitmentTree :: + SaplingFrontier -- ^ the base tree + -> HexString -- ^ the new note commitment + -> Maybe SaplingFrontier +updateSaplingCommitmentTree tree cmu = + if sf_pos updatedTree > 1 + then Just updatedTree + else Nothing + where + updatedTree = + withPureBorshVarBuffer $ + rustWrapperReadSaplingCommitmentTree tree (hexBytes cmu) -- | Get the Sapling incremental witness from a commitment tree getSaplingWitness :: SaplingCommitmentTree -> Maybe SaplingWitness diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index ebf3dbf..8105d30 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -611,6 +611,15 @@ newtype SaplingCommitmentTree = SaplingCommitmentTree { sapTree :: HexString } deriving (Eq, Prelude.Show, Read) +data SaplingFrontier = SaplingFrontier + { sf_pos :: !Int64 + , sf_leaf :: !HexString + , sf_ommers :: ![BS.ByteString] + } deriving stock (Eq, Prelude.Show, GHC.Generic) + deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) + deriving anyclass (Data.Structured.Show) + deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct SaplingFrontier + -- | Type for a Sapling incremental witness newtype SaplingWitness = SaplingWitness { sapWit :: HexString