From 27b291c49a64542232fea2b966835229bfc281b2 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 10 Apr 2024 07:06:04 -0500 Subject: [PATCH 1/3] Add function to append nodes to commitment tree --- librustzcash-wrapper/src/lib.rs | 46 ++++++++++++++++++++++++++++++++- src/C/Zcash.chs | 8 ++++++ src/ZcashHaskell/Sapling.hs | 17 +++++++++++- test/Spec.hs | 19 ++++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index d5533f5..ad70b02 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -6,7 +6,8 @@ use std::{ marker::PhantomData, io::{ Write, - Cursor + Cursor, + Error }, }; @@ -28,6 +29,10 @@ use incrementalmerkletree::frontier::CommitmentTree; use zip32; use zcash_primitives::{ + merkle_tree::{ + read_commitment_tree, + write_commitment_tree + }, zip32::{ Scope as SaplingScope, ChildIndex, @@ -57,6 +62,7 @@ use zcash_primitives::{ MerklePath, NOTE_COMMITMENT_TREE_DEPTH as SAPLING_DEPTH, PaymentAddress, + note::ExtractedNoteCommitment as SaplingNoteCommitment, keys::{ PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey, ExpandedSpendingKey, @@ -187,6 +193,14 @@ pub struct Hhex { bytes: Vec } +impl ToHaskell for Hhex { + fn to_haskell(&self, writer: &mut W, _tag: PhantomData) -> Result<()> { + self.serialize(writer)?; + Ok(()) + } +} + + #[derive(BorshSerialize, BorshDeserialize)] pub struct Haction { nf: Hhex, @@ -1129,3 +1143,33 @@ pub extern "C" fn rust_wrapper_derive_orchard_receiver( marshall_to_haskell_var(&o_rec.to_raw_address_bytes().to_vec(), out, out_len, RW); } + +#[no_mangle] +pub extern "C" fn rust_wrapper_read_commitment_tree( + tree: *const u8, + tree_len: usize, + node: *const u8, + node_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 mut ct: CommitmentTree = read_commitment_tree(tree_reader).unwrap(); + + let node_in: Vec = marshall_from_haskell_var(node, node_len, RW); + let n = Node::from_cmu(&SaplingNoteCommitment::from_bytes(&to_array(node_in)).unwrap()); + ct.append(n); + let mut out_bytes: Vec = Vec::new(); + let result = write_commitment_tree(&ct, &mut out_bytes ); + match result { + Ok(()) => { + let h = Hhex { bytes: out_bytes}; + marshall_to_haskell_var(&h, out, out_len, RW); + }, + Err(_e) => { + let h0 = Hhex { bytes: vec![0]}; + marshall_to_haskell_var(&h0, out, out_len, RW); + } + } +} diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index ea2f9ea..f131d40 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -200,3 +200,11 @@ import ZcashHaskell.Types } -> `()' #} + +{# fun unsafe rust_wrapper_read_commitment_tree as rustWrapperReadSaplingCommitmentTree + { toBorshVar* `BS.ByteString'& + , toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer (BS.ByteString)'& + } + -> `()' +#} diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index ef287d6..8153034 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -19,6 +19,7 @@ module ZcashHaskell.Sapling where import C.Zcash ( rustWrapperIsShielded + , rustWrapperReadSaplingCommitmentTree , rustWrapperSaplingCheck , rustWrapperSaplingChgPaymentAddress , rustWrapperSaplingDecodeEsk @@ -30,7 +31,7 @@ import C.Zcash ) import Data.Aeson import qualified Data.ByteString as BS -import Data.HexString (HexString(..), fromText, toBytes, toText) +import Data.HexString (HexString(..), fromText, hexString, toBytes, toText) import Data.Word import Foreign.Rust.Marshall.Variable ( withPureBorshVarBuffer @@ -166,3 +167,17 @@ genSaplingInternalAddress sk = where res = withPureBorshVarBuffer (rustWrapperSaplingChgPaymentAddress $ getBytes sk) + +-- | Update a Sapling commitment tree +updateSaplingCommitmentTree :: + HexString -- ^ the base tree + -> HexString -- ^ the new note commitment + -> Maybe HexString +updateSaplingCommitmentTree tree cmu = + if BS.length updatedTree > 1 + then Just $ HexString updatedTree + else Nothing + where + updatedTree = + withPureBorshVarBuffer $ + rustWrapperReadSaplingCommitmentTree (hexBytes tree) (hexBytes cmu) diff --git a/test/Spec.hs b/test/Spec.hs index 6db774b..95320b9 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -54,6 +54,7 @@ import ZcashHaskell.Sapling , isValidSaplingViewingKey , isValidShieldedAddress , matchSaplingAddress + , updateSaplingCommitmentTree ) import ZcashHaskell.Transparent import ZcashHaskell.Types @@ -844,6 +845,24 @@ main = do let tb = zt_tBundle t' print tb show tb `shouldNotBe` "" + describe "Sapling commitment trees" $ do + let tree = + 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 + case t1 of + Nothing -> assertFailure "Tree 1 failed" + Just t2 -> updateSaplingCommitmentTree t2 cmu2 `shouldBe` Just tree2 -- | Properties prop_PhraseLength :: Property From 0f19e376dcf24849b9a92b525e1f6852d9b04e88 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Thu, 11 Apr 2024 16:01:29 -0500 Subject: [PATCH 2/3] Add Sapling commitment tree functionality --- CHANGELOG.md | 7 +++ librustzcash-wrapper/src/lib.rs | 77 +++++++++++++++++++++++++++------ src/C/Zcash.chs | 19 +++++++- src/ZcashHaskell/Sapling.hs | 32 +++++++++++--- src/ZcashHaskell/Types.hs | 10 +++++ test/Spec.hs | 17 ++++++-- zcash-haskell.cabal | 2 +- 7 files changed, 139 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80e6446..d271b2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,15 @@ 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.5.4.1] + +### Added + +- Functions to handle Sapling commitment trees, incremental witnesses and note positions + ## [0.5.4.0] +### Added - Function to decode Orchard actions with a spending key - Functions for Bech32 encoding - Function to encode a Sapling address diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 9fc6c59..559ca5d 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -24,14 +24,19 @@ use haskell_ffi::{ FromHaskell, HaskellSize, ToHaskell }; -use incrementalmerkletree::frontier::CommitmentTree; +use incrementalmerkletree::{ + frontier::CommitmentTree, + witness::IncrementalWitness +}; use zip32; use zcash_primitives::{ merkle_tree::{ read_commitment_tree, - write_commitment_tree + write_commitment_tree, + read_incremental_witness, + write_incremental_witness }, zip32::{ Scope as SaplingScope, @@ -1146,7 +1151,23 @@ pub extern "C" fn rust_wrapper_derive_orchard_receiver( } #[no_mangle] -pub extern "C" fn rust_wrapper_read_commitment_tree( +pub extern "C" fn rust_wrapper_bech32_encode( + hr: *const u8, + hr_len: usize, + b: *const u8, + b_len: usize, + out: *mut u8, + out_len: &mut usize + ) { + let hr: String = marshall_from_haskell_var(hr, hr_len, RW); + let hrp = Hrp::parse(&hr).unwrap(); + let b: Vec = marshall_from_haskell_var(b, b_len, RW); + let string = bech32::encode::(hrp, &b).unwrap(); + marshall_to_haskell_var(&string, out, out_len, RW); +} + +#[no_mangle] +pub extern "C" fn rust_wrapper_read_sapling_commitment_tree( tree: *const u8, tree_len: usize, node: *const u8, @@ -1176,18 +1197,46 @@ pub extern "C" fn rust_wrapper_read_commitment_tree( } #[no_mangle] -pub extern "C" fn rust_wrapper_bech32_encode( - hr: *const u8, - hr_len: usize, - b: *const u8, - b_len: usize, +pub extern "C" fn rust_wrapper_read_sapling_witness( + tree: *const u8, + tree_len: usize, out: *mut u8, out_len: &mut usize - ) { - let hr: String = marshall_from_haskell_var(hr, hr_len, RW); - let hrp = Hrp::parse(&hr).unwrap(); - let b: Vec = marshall_from_haskell_var(b, b_len, RW); - let string = bech32::encode::(hrp, &b).unwrap(); - marshall_to_haskell_var(&string, out, out_len, RW); + ){ + let tree_in: Vec = marshall_from_haskell_var(tree, tree_len, RW); + let tree_reader = Cursor::new(tree_in); + let ct: CommitmentTree = read_commitment_tree(tree_reader).unwrap(); + let inc_wit = IncrementalWitness::from_tree(ct); + let mut out_bytes: Vec = Vec::new(); + let result = write_incremental_witness(&inc_wit, &mut out_bytes); + match result { + Ok(()) => { + let h = Hhex { bytes: out_bytes}; + marshall_to_haskell_var(&h, out, out_len, RW); + }, + Err(_e) => { + let h0 = Hhex { bytes: vec![0]}; + marshall_to_haskell_var(&h0, out, out_len, RW); + } + } } +#[no_mangle] +pub extern "C" fn rust_wrapper_read_sapling_position( + wit: *const u8, + wit_len: usize, + ) -> u64 { + 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 path = iw.path(); + match path { + Some(p) => { + let pos = p.position(); + return u64::from(pos); + }, + None => { + return 0; + } + } +} diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 4f7818e..37537c8 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -21,6 +21,7 @@ import qualified Data.Text as T import Data.Word import Data.Int import Data.Structured +import Data.HexString (HexString(..)) import Foreign.C.Types import Foreign.Rust.Marshall.External import Foreign.Rust.Marshall.Fixed @@ -201,14 +202,27 @@ import ZcashHaskell.Types -> `()' #} -{# fun unsafe rust_wrapper_read_commitment_tree as rustWrapperReadSaplingCommitmentTree +{# fun unsafe rust_wrapper_read_sapling_commitment_tree as rustWrapperReadSaplingCommitmentTree { toBorshVar* `BS.ByteString'& , toBorshVar* `BS.ByteString'& - , getVarBuffer `Buffer (BS.ByteString)'& + , getVarBuffer `Buffer HexString'& } -> `()' #} +{# fun unsafe rust_wrapper_read_sapling_witness as rustWrapperReadSaplingWitness + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + +{# fun pure unsafe rust_wrapper_read_sapling_position as rustWrapperReadSaplingPosition + { toBorshVar* `BS.ByteString'& + } + -> `Word64' +#} + {# fun unsafe rust_wrapper_bech32_encode as rustWrapperBech32Encode { toBorshVar* `BS.ByteString'& , toBorshVar* `BS.ByteString'& @@ -216,3 +230,4 @@ import ZcashHaskell.Types } -> `()' #} + diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index 8153034..f737622 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -20,6 +20,8 @@ module ZcashHaskell.Sapling where import C.Zcash ( rustWrapperIsShielded , rustWrapperReadSaplingCommitmentTree + , rustWrapperReadSaplingPosition + , rustWrapperReadSaplingWitness , rustWrapperSaplingCheck , rustWrapperSaplingChgPaymentAddress , rustWrapperSaplingDecodeEsk @@ -43,8 +45,10 @@ import ZcashHaskell.Types , DecodedNote(..) , RawData(..) , RawTxResponse(..) + , SaplingCommitmentTree(..) , SaplingReceiver(..) , SaplingSpendingKey(..) + , SaplingWitness(..) , Scope(..) , Seed(..) , ShieldedOutput(..) @@ -170,14 +174,32 @@ genSaplingInternalAddress sk = -- | Update a Sapling commitment tree updateSaplingCommitmentTree :: - HexString -- ^ the base tree + SaplingCommitmentTree -- ^ the base tree -> HexString -- ^ the new note commitment - -> Maybe HexString + -> Maybe SaplingCommitmentTree updateSaplingCommitmentTree tree cmu = - if BS.length updatedTree > 1 - then Just $ HexString updatedTree + if BS.length (hexBytes updatedTree) > 1 + then Just $ SaplingCommitmentTree updatedTree else Nothing where updatedTree = withPureBorshVarBuffer $ - rustWrapperReadSaplingCommitmentTree (hexBytes tree) (hexBytes cmu) + rustWrapperReadSaplingCommitmentTree + (hexBytes $ sapTree tree) + (hexBytes cmu) + +-- | Get the Sapling incremental witness from a commitment tree +getSaplingWitness :: SaplingCommitmentTree -> Maybe SaplingWitness +getSaplingWitness tree = + if BS.length (hexBytes wit) > 1 + then Just $ SaplingWitness wit + else Nothing + where + wit = + withPureBorshVarBuffer $ + rustWrapperReadSaplingWitness (hexBytes $ sapTree tree) + +-- | Get the Sapling note position from a witness +getSaplingNotePosition :: SaplingWitness -> Integer +getSaplingNotePosition = + fromIntegral . rustWrapperReadSaplingPosition . hexBytes . sapWit diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index 0320479..aeca505 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -519,6 +519,16 @@ instance FromJSON ShieldedOutput where p <- obj .: "proof" pure $ ShieldedOutput cv cmu ephKey encText outText p +-- | Type for a Sapling note commitment tree +newtype SaplingCommitmentTree = SaplingCommitmentTree + { sapTree :: HexString + } deriving (Eq, Prelude.Show, Read) + +-- | Type for a Sapling incremental witness +newtype SaplingWitness = SaplingWitness + { sapWit :: HexString + } deriving (Eq, Prelude.Show, Read) + -- * Orchard -- | A spending key for Orchard newtype OrchardSpendingKey = diff --git a/test/Spec.hs b/test/Spec.hs index a6b7665..10b6da6 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -50,6 +50,8 @@ import ZcashHaskell.Sapling , genSaplingInternalAddress , genSaplingPaymentAddress , genSaplingSpendingKey + , getSaplingNotePosition + , getSaplingWitness , getShieldedOutputs , isValidSaplingViewingKey , isValidShieldedAddress @@ -72,6 +74,7 @@ import ZcashHaskell.Types , RawTxOut(..) , RawTxResponse(..) , RawZebraTx(..) + , SaplingCommitmentTree(..) , SaplingReceiver(..) , SaplingSpendingKey(..) , Scope(..) @@ -843,10 +846,10 @@ main = do Nothing -> assertFailure "Couldn't decode" Just t' -> do let tb = zt_tBundle t' - print tb show tb `shouldNotBe` "" describe "Sapling commitment trees" $ do let tree = + SaplingCommitmentTree $ hexString "01916df07670600aefa3b412a120d6b8d9a3d2ff9466a7ec770cd52d34ddb42313001000013c60b031a5e44650059fcc7101a3f551b807ab8b3a116a5a9c7fa0f3babbe735017c0d36686294ff19d59e58b6a2ac6a7ad607a804bc202c84012d8e94f233970c0128dbde5180af5304d8577376d78297130b615a327974c10881f6d876869aea05011b80b4ca60f74dfe33c78b062df73c84b8b44dab4604db16f5b61eea40134373010c96e4cc8a6a80fba0d41e4eb3070d80769104dc33fb61133b1304c15bf9e23e000107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39" let cmu1 = @@ -859,10 +862,18 @@ main = do 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 "Tree 1 failed" - Just t2 -> updateSaplingCommitmentTree t2 cmu2 `shouldBe` Just tree2 + 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 "Extract Sapling Address - UA Valid" $ do let sr = getSaplingFromUA diff --git a/zcash-haskell.cabal b/zcash-haskell.cabal index 2e0cae2..fea4200 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.5.4.0 +version: 0.5.4.1 synopsis: Utilities to interact with the Zcash blockchain description: Please see the README on the repo at category: Blockchain From 6a2849aae0f574bd0dfdc4dbce2b9de3f2691f56 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Fri, 12 Apr 2024 13:15:41 -0500 Subject: [PATCH 3/3] Add Sapling nullifier calculation to decoding --- librustzcash-wrapper/src/lib.rs | 32 +++++++++++++++++--------------- src/C/Zcash.chs | 1 + src/ZcashHaskell/Sapling.hs | 4 +++- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 559ca5d..81f7235 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -240,7 +240,8 @@ impl Haction { pub struct Hnote { note: u64, recipient: Vec, - memo: Vec + memo: Vec, + nullifier: Vec } impl ToHaskell for Hnote { @@ -732,6 +733,7 @@ pub extern "C" fn rust_wrapper_sapling_esk_decrypt( note_len: usize, external: bool, net: bool, + pos: u64, out: *mut u8, out_len: &mut usize ){ @@ -759,24 +761,24 @@ pub extern "C" fn rust_wrapper_sapling_esk_decrypt( else {zcash_note_encryption::try_note_decryption(&test_domain, &pivk, &action2)}; match result { Some((n, r, m)) => { - //let nullifier = n.nf(&nk, MerklePath.position()); - let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec() }; + let nullifier = n.nf(&nk, pos); + let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec(), nullifier: nullifier.to_vec() }; marshall_to_haskell_var(&hn, out, out_len, RW); }, None => { - let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]}; + let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]}; marshall_to_haskell_var(&hn0, out, out_len, RW); } } }, Err(_e1) => { - let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] }; + let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0] }; marshall_to_haskell_var(&hn0, out, out_len, RW); } } }, Err(_e) => { - let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] }; + let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0] }; marshall_to_haskell_var(&hn0, out, out_len, RW); } } @@ -806,23 +808,23 @@ pub extern "C" fn rust_wrapper_sapling_note_decrypt_v2( let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action3); match result { Some((n, r, m)) => { - let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec()}; + let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec(), nullifier: vec![0]}; marshall_to_haskell_var(&hn, out, out_len, RW); } None => { - let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]}; + let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]}; marshall_to_haskell_var(&hn0, out, out_len, RW); } } }, Err(_e1) => { - let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] }; + let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] , nullifier: vec![0]}; marshall_to_haskell_var(&hn0, out, out_len, RW); } } } Err(_e) => { - let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]}; + let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]}; marshall_to_haskell_var(&hn0, out, out_len, RW); } } @@ -856,17 +858,17 @@ pub extern "C" fn rust_wrapper_orchard_note_decrypt( let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action); match result { Some((n, r, m)) => { - let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec()}; + let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec(), nullifier: vec![0]}; marshall_to_haskell_var(&hn, out, out_len, RW); } None => { - let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]}; + let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]}; marshall_to_haskell_var(&hn0, out, out_len, RW); } } }, None => { - let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]}; + let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]}; marshall_to_haskell_var(&hn0, out, out_len, RW); } } @@ -904,11 +906,11 @@ pub extern "C" fn rust_wrapper_orchard_note_decrypt_sk( let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action); match result { Some((n, r, m)) => { - let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec()}; + let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec(), nullifier: vec![0]}; marshall_to_haskell_var(&hn, out, out_len, RW); } None => { - let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]}; + let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]}; marshall_to_haskell_var(&hn0, out, out_len, RW); } } diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 37537c8..4b08f78 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -107,6 +107,7 @@ import ZcashHaskell.Types , toBorshVar* `BS.ByteString'& , `Bool' , `Bool' + , `Word64' , getVarBuffer `Buffer DecodedNote'& } -> `()' diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index f737622..a108eaa 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -121,8 +121,9 @@ decodeSaplingOutputEsk :: -> ShieldedOutput -> ZcashNet -> Scope + -> Integer -> Maybe DecodedNote -decodeSaplingOutputEsk key out znet scope = +decodeSaplingOutputEsk key out znet scope pos = case a_value decodedAction of 0 -> Nothing _ -> Just decodedAction @@ -134,6 +135,7 @@ decodeSaplingOutputEsk key out znet scope = (serializeShieldedOutput out) (znet == MainNet) (scope == External) + (fromIntegral pos) -- | Attempts to obtain a sapling SpendingKey using a HDSeed genSaplingSpendingKey :: Seed -> CoinType -> Int -> Maybe SaplingSpendingKey