From dea960c2acf7479eeb42845c07b482449d538aae Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Fri, 15 Nov 2024 18:48:36 +0000 Subject: [PATCH] Functions to handle commitment tree nodes for Sapling and Orchard (#100) This PR includes the functions for hashing commitment nodes for both Sapling and Orchard. It also includes functions to validate tree roots and Merkle paths. Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/100 Co-authored-by: Rene Vergara Co-committed-by: Rene Vergara --- CHANGELOG.md | 17 ++ librustzcash-wrapper/Cargo.lock | 61 +++---- librustzcash-wrapper/Cargo.toml | 12 +- librustzcash-wrapper/src/lib.rs | 273 ++++++++++++++++++++++++++------ src/C/Zcash.chs | 45 ++++++ src/ZcashHaskell/Sapling.hs | 59 ++++++- src/ZcashHaskell/Types.hs | 19 ++- src/ZcashHaskell/Utils.hs | 12 +- zcash-haskell.cabal | 2 +- 9 files changed, 403 insertions(+), 97 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cbfed3..ed642a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ 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 +- 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 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"]} diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 7657829..563ac5f 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 { @@ -1542,6 +1542,183 @@ 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_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_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_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_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_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| + 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)); + 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, @@ -1696,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()); @@ -1967,47 +2150,26 @@ 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 = Node::from_bytes(to_array(sap_anchor_in)); + let sapling_anchor = + if sap_anchor.is_some().into() { + Some(SaplingAnchor::from(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); + //println!("{:?}", sapling_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 = MerkleHashOrchard::from_bytes(&to_array(orch_anchor_in)); + let orchard_anchor = + if orch_anchor.is_some().into() { + Some(OrchardAnchor::from(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}; + //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); let trans_input: Vec = marshall_from_haskell_var(t_input, t_input_len, RW); @@ -2047,9 +2209,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 { @@ -2090,16 +2256,22 @@ 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| + 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); 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); } @@ -2108,9 +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); 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); } @@ -2261,6 +2435,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); }, diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index a896a10..fde4550 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -246,6 +246,51 @@ import ZcashHaskell.Types -> `()' #} +{# fun unsafe rust_wrapper_read_sapling_node as rustWrapperReadSaplingNode + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + +{# fun unsafe rust_wrapper_combine_sapling_nodes as rustWrapperCombineSaplingNodes + { `Int8' + , toBorshVar* `BS.ByteString'& + , toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + +{# fun unsafe rust_wrapper_get_sapling_root as rustWrapperGetSaplingRootTest + { `Int8' + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + +{# fun unsafe rust_wrapper_read_sapling_commitment_tree_parts as rustWrapperReadSaplingTreeParts + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer SaplingRawTree'& + } + -> `()' +#} + +{# fun unsafe rust_wrapper_read_sapling_tree_anchor as rustWrapperReadSaplingTreeAnchor + { toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer HexString'& + } + -> `()' +#} + +{# 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 e15bf4f..1347778 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -18,11 +18,17 @@ module ZcashHaskell.Sapling where import C.Zcash - ( rustWrapperDecodeSaplingAddress + ( rustWrapperCombineSaplingNodes + , rustWrapperDecodeSaplingAddress + , rustWrapperGetSaplingRootTest , rustWrapperIsShielded , rustWrapperReadSaplingCommitmentTree , rustWrapperReadSaplingFrontier + , rustWrapperReadSaplingNode + , rustWrapperReadSaplingPathAnchor , rustWrapperReadSaplingPosition + , rustWrapperReadSaplingTreeAnchor + , rustWrapperReadSaplingTreeParts , rustWrapperReadSaplingWitness , rustWrapperSaplingCheck , rustWrapperSaplingChgPaymentAddress @@ -38,6 +44,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 @@ -185,6 +192,56 @@ 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 + +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) + +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 + +getSaplingTreeAnchor :: SaplingCommitmentTree -> HexString +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 diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index 8b8a90b..1c55a73 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 + { st_left :: !(Maybe HexString) + , st_right :: !(Maybe HexString) + , st_parents :: ![Maybe HexString] + } deriving (Eq, Prelude.Show, Read) + data SaplingFrontier = SaplingFrontier { sf_pos :: !Int64 , sf_leaf :: !HexString @@ -797,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) @@ -806,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 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