From af9806d72df6c551b5e61eb19d7a605011d32b1d Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Thu, 25 Apr 2024 19:56:29 -0500 Subject: [PATCH] Add witness update functionality --- CHANGELOG.md | 15 ++++++-- librustzcash-wrapper/src/lib.rs | 68 +++++++++++++++++++++++++++++++++ src/C/Zcash.chs | 16 ++++++++ src/ZcashHaskell/Orchard.hs | 7 ++++ src/ZcashHaskell/Sapling.hs | 42 +++++++++++--------- zcash-haskell.cabal | 2 +- 6 files changed, 127 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70317db..7c13f62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,21 @@ 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.5.4] + +### Added + +- Functions to update Sapling witnesses. +- Functions to update Orchard witnesses. + ## [0.5.5.3] ### Added -- Added unction to generate an ExchangeAddress in Human Readable Format Using a TransparentAddress in HRF - `encodeExchangeAddress` a function to create a ExchangeAddress in HRF - `decodeExchangeAddress` a function to obtaina a TransparentAddress object from an ExchangeAddress in HRF -- Added new type ExchangeAddress +- Added function to generate an `ExchangeAddress` in Human Readable Format Using a `TransparentAddress` in HRF +- `encodeExchangeAddress` a function to create a `ExchangeAddress` in HRF +- `decodeExchangeAddress` a function to obtain a `TransparentAddress` object from an `ExchangeAddress` in HRF +- Added new type `ExchangeAddress` ### Fixed diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 67a7447..985c3c4 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -1251,6 +1251,40 @@ pub extern "C" fn rust_wrapper_read_sapling_position( return u64::from(pos); } +#[no_mangle] +pub extern "C" fn rust_wrapper_update_sapling_witness( + wit: *const u8, + wit_len: usize, + cmus: *const u8, + cmus_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 mut iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); + let cmu: Vec> = marshall_from_haskell_var(cmus, cmus_len, RW); + for c in cmu { + let sap_note_comm = SaplingNoteCommitment::from_bytes(&to_array(c)); + if sap_note_comm.is_some().into() { + let n = Node::from_cmu(&sap_note_comm.unwrap()); + iw.append(n); + } + } + let mut out_bytes: Vec = Vec::new(); + let result = write_incremental_witness(&iw, &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_orchard_commitment_tree( tree: *const u8, @@ -1340,6 +1374,40 @@ pub extern "C" fn rust_wrapper_read_orchard_position( } } +#[no_mangle] +pub extern "C" fn rust_wrapper_update_orchard_witness( + wit: *const u8, + wit_len: usize, + cm: *const u8, + cm_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 mut iw: IncrementalWitness = read_incremental_witness(wit_reader).unwrap(); + let cmu: Vec> = marshall_from_haskell_var(cm, cm_len, RW); + for c in cmu { + let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(c)); + if orchard_note_comm.is_some().into() { + let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap()); + iw.append(n); + } + let mut out_bytes: Vec = Vec::new(); + let result = write_incremental_witness(&iw, &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_decode_sapling_address( sapling: *const u8, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index a4bfb9d..0300865 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -259,3 +259,19 @@ import ZcashHaskell.Types } -> `Word64' #} + +{# fun unsafe rust_wrapper_update_sapling_witness as rustWrapperUpdateSaplingWitness + { toBorshVar* `BS.ByteString'& + , toBorshVar* `[BS.ByteString]'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + +{# fun unsafe rust_wrapper_update_orchard_witness as rustWrapperUpdateOrchardWitness + { toBorshVar* `BS.ByteString'& + , toBorshVar* `[BS.ByteString]'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 7e6fc6c..d7c3e38 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -28,6 +28,7 @@ import C.Zcash , rustWrapperReadOrchardWitness , rustWrapperUADecode , rustWrapperUfvkDecode + , rustWrapperUpdateOrchardWitness ) import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as C @@ -219,3 +220,9 @@ getOrchardWitness tree = getOrchardNotePosition :: OrchardWitness -> Integer getOrchardNotePosition = fromIntegral . rustWrapperReadOrchardPosition . hexBytes . orchWit + +updateOrchardWitness :: OrchardWitness -> [HexString] -> OrchardWitness +updateOrchardWitness wit cmus = + OrchardWitness $ + withPureBorshVarBuffer $ + rustWrapperUpdateOrchardWitness (toBytes $ orchWit wit) (map toBytes cmus) diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index 6e3c7b0..1b4e3bc 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -18,11 +18,11 @@ module ZcashHaskell.Sapling where import C.Zcash - ( rustWrapperIsShielded + ( rustWrapperDecodeSaplingAddress + , rustWrapperIsShielded , rustWrapperReadSaplingCommitmentTree , rustWrapperReadSaplingPosition , rustWrapperReadSaplingWitness - , rustWrapperDecodeSaplingAddress , rustWrapperSaplingCheck , rustWrapperSaplingChgPaymentAddress , rustWrapperSaplingDecodeEsk @@ -31,18 +31,19 @@ import C.Zcash , rustWrapperSaplingSpendingkey , rustWrapperSaplingVkDecode , rustWrapperTxParse + , rustWrapperUpdateSaplingWitness ) import Data.Aeson import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as C -import qualified Data.Text as T import Data.HexString (HexString(..), fromText, hexString, toBytes, toText) +import qualified Data.Text as T import Data.Word import Foreign.Rust.Marshall.Variable ( withPureBorshVarBuffer , withPureBorshVarBuffer ) -import ZcashHaskell.Types +import ZcashHaskell.Types import ZcashHaskell.Utils (decodeBech32, encodeBech32, encodeBech32m) -- | Check if given bytesting is a valid encoded shielded address @@ -192,32 +193,37 @@ getSaplingNotePosition :: SaplingWitness -> Integer getSaplingNotePosition = fromIntegral . rustWrapperReadSaplingPosition . hexBytes . sapWit +updateSaplingWitness :: SaplingWitness -> [HexString] -> SaplingWitness +updateSaplingWitness wit cmus = + SaplingWitness $ + withPureBorshVarBuffer $ + rustWrapperUpdateSaplingWitness (toBytes $ sapWit wit) (map toBytes cmus) + -- | Encode a SaplingReceiver into HRF text encodeSaplingAddress :: ZcashNet -> SaplingReceiver -> Maybe T.Text -encodeSaplingAddress net sr = do +encodeSaplingAddress net sr = do case net of - MainNet -> - Just $ encodeBech32 (C.pack sapPaymentAddressHrp) (getBytes sr) + MainNet -> Just $ encodeBech32 (C.pack sapPaymentAddressHrp) (getBytes sr) TestNet -> Just $ encodeBech32 (C.pack sapTestPaymentAddressHrp) (getBytes sr) -- | Helper to get de Nework Id from FFI response -getNetId:: [Word8] -> ZcashNet -getNetId [x] = do - case x of +getNetId :: [Word8] -> ZcashNet +getNetId [x] = do + case x of 1 -> MainNet - 2 -> TestNet + 2 -> TestNet -- | decode a Sapling address decodeSaplingAddress :: BS.ByteString -> Maybe SaplingAddress -decodeSaplingAddress sapling_address = do +decodeSaplingAddress sapling_address = do if BS.length sa > 1 then do let sa0 = BS.unpack sa - Just $ SaplingAddress (getNetId (take 1 sa0)) - $ SaplingReceiver (BS.pack (drop 1 sa0)) + Just $ + SaplingAddress (getNetId (take 1 sa0)) $ + SaplingReceiver (BS.pack (drop 1 sa0)) else Nothing - where - sa = - withPureBorshVarBuffer $ - rustWrapperDecodeSaplingAddress sapling_address + where + sa = + withPureBorshVarBuffer $ rustWrapperDecodeSaplingAddress sapling_address diff --git a/zcash-haskell.cabal b/zcash-haskell.cabal index be2387f..e8bff8c 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.5.3 +version: 0.5.5.4 synopsis: Utilities to interact with the Zcash blockchain description: Please see the README on the repo at category: Blockchain -- 2.34.1