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 <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
This commit is contained in:
Rene Vergara 2024-11-15 18:48:36 +00:00 committed by Vergara Technologies LLC
parent 62cda9cc15
commit dea960c2ac
Signed by: Vergara Technologies LLC
GPG key ID: 99DB473BB4715618
9 changed files with 403 additions and 97 deletions

View file

@ -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/), 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). 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] ## [0.7.4.0]
### Added ### Added

View file

@ -60,9 +60,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.21.2" version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
@ -757,9 +757,9 @@ dependencies = [
[[package]] [[package]]
name = "incrementalmerkletree" name = "incrementalmerkletree"
version = "0.6.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75346da3bd8e3d8891d02508245ed2df34447ca6637e343829f8d08986e9cde2" checksum = "d45063fbc4b0a37837f6bfe0445f269d13d730ad0aa3b5a7f74aa7bf27a0f4df"
dependencies = [ dependencies = [
"either", "either",
] ]
@ -987,9 +987,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]] [[package]]
name = "orchard" name = "orchard"
version = "0.9.0" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dc7bde644aeb980be296cd908c6650894dc8541deb56f9f5294c52ed7ca568f" checksum = "4f18e997fa121de5c73e95cdc7e8512ae43b7de38904aeea5e5713cc48f3c0ba"
dependencies = [ dependencies = [
"aes", "aes",
"bitvec", "bitvec",
@ -1379,9 +1379,9 @@ dependencies = [
[[package]] [[package]]
name = "sapling-crypto" name = "sapling-crypto"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15e379398fffad84e49f9a45a05635fc004f66086e65942dbf4eb95332c26d2a" checksum = "cfff8cfce16aeb38da50b8e2ed33c9018f30552beff2210c266662a021b17f38"
dependencies = [ dependencies = [
"aes", "aes",
"bellman", "bellman",
@ -1488,9 +1488,9 @@ dependencies = [
[[package]] [[package]]
name = "shardtree" name = "shardtree"
version = "0.4.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78222845cd8bbe5eb95687407648ff17693a35de5e8abaa39a4681fb21e033f9" checksum = "b5f2390975ebfe8838f9e861f7a588123d49a7a7a0a08568ea831d8ad53fc9b4"
dependencies = [ dependencies = [
"bitflags 2.4.2", "bitflags 2.4.2",
"either", "either",
@ -1883,9 +1883,9 @@ dependencies = [
[[package]] [[package]]
name = "zcash_address" name = "zcash_address"
version = "0.4.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6d26f21381dc220836dd8d2a9a10dbe85928a26232b011bc6a42b611789b743" checksum = "4ff95eac82f71286a79c750e674550d64fb2b7aadaef7b89286b2917f645457d"
dependencies = [ dependencies = [
"bech32 0.9.1", "bech32 0.9.1",
"bs58 0.5.0", "bs58 0.5.0",
@ -1896,9 +1896,9 @@ dependencies = [
[[package]] [[package]]
name = "zcash_client_backend" name = "zcash_client_backend"
version = "0.13.0" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e3a0f3e5d7f299d8b7ef3237697630989c31ab1b162824c99c1cd8bc83715e" checksum = "cbeeede366fdb642710d3c59fc2090489affd075f66db53ed11bb7138d2d0258"
dependencies = [ dependencies = [
"base64", "base64",
"bech32 0.9.1", "bech32 0.9.1",
@ -1924,7 +1924,7 @@ dependencies = [
"tonic-build", "tonic-build",
"tracing", "tracing",
"which", "which",
"zcash_address 0.4.0", "zcash_address 0.6.0",
"zcash_encoding", "zcash_encoding",
"zcash_keys", "zcash_keys",
"zcash_note_encryption", "zcash_note_encryption",
@ -1946,9 +1946,9 @@ dependencies = [
[[package]] [[package]]
name = "zcash_keys" name = "zcash_keys"
version = "0.3.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712faf4070107ab0b2828d0eda6aeaf4c3cb02564109832d95b97ad3467c95a5" checksum = "e8162c94957f1e379b8e2fb30f97b95cfa93ac9c6bc02895946ca6392d1abb81"
dependencies = [ dependencies = [
"bech32 0.9.1", "bech32 0.9.1",
"blake2b_simd", "blake2b_simd",
@ -1963,7 +1963,7 @@ dependencies = [
"secrecy", "secrecy",
"subtle", "subtle",
"tracing", "tracing",
"zcash_address 0.4.0", "zcash_address 0.6.0",
"zcash_encoding", "zcash_encoding",
"zcash_primitives", "zcash_primitives",
"zcash_protocol", "zcash_protocol",
@ -1985,9 +1985,9 @@ dependencies = [
[[package]] [[package]]
name = "zcash_primitives" name = "zcash_primitives"
version = "0.16.0" version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f044bc9cf2887ec408196fbafb44749e5581f57cc18d8da7aabaeb60cc40c64" checksum = "6ab47d526d7fd6f88b3a2854ad81b54757a80c2aeadd1d8b06f690556af9743c"
dependencies = [ dependencies = [
"aes", "aes",
"bip32", "bip32",
@ -2014,7 +2014,7 @@ dependencies = [
"sha2 0.10.6", "sha2 0.10.6",
"subtle", "subtle",
"tracing", "tracing",
"zcash_address 0.4.0", "zcash_address 0.6.0",
"zcash_encoding", "zcash_encoding",
"zcash_note_encryption", "zcash_note_encryption",
"zcash_protocol", "zcash_protocol",
@ -2024,9 +2024,9 @@ dependencies = [
[[package]] [[package]]
name = "zcash_protocol" name = "zcash_protocol"
version = "0.2.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f35eac659fdbba614333d119217c5963c0d7cea43aee33176c4f2f95e5460d8d" checksum = "6bc22b9155b2c7eb20105cd06de170d188c1bc86489b92aa3fda7b8da8d96acf"
dependencies = [ dependencies = [
"document-features", "document-features",
"memuse", "memuse",
@ -2034,9 +2034,9 @@ dependencies = [
[[package]] [[package]]
name = "zcash_spec" name = "zcash_spec"
version = "0.1.0" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7a3bf58b673cb3dacd8ae09ba345998923a197ab0da70d6239d8e8838949e9b" checksum = "9cede95491c2191d3e278cab76e097a44b17fde8d6ca0d4e3a22cf4807b2d857"
dependencies = [ dependencies = [
"blake2b_simd", "blake2b_simd",
] ]
@ -2063,24 +2063,25 @@ dependencies = [
[[package]] [[package]]
name = "zip32" name = "zip32"
version = "0.1.1" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4226d0aee9c9407c27064dfeec9d7b281c917de3374e1e5a2e2cfad9e09de19e" checksum = "92022ac1e47c7b78f9cee29efac8a1a546e189506f3bb5ad46d525be7c519bf6"
dependencies = [ dependencies = [
"blake2b_simd", "blake2b_simd",
"memuse", "memuse",
"subtle", "subtle",
"zcash_spec",
] ]
[[package]] [[package]]
name = "zip321" name = "zip321"
version = "0.1.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dc85f862f7be64fb0d46f9eb5b82ad54e58cde314fa979d5bae591bc0143693" checksum = "1f3e613defb0940acef1f54774b51c7f48f2fa705613dd800870dc69f35cd2ea"
dependencies = [ dependencies = [
"base64", "base64",
"nom", "nom",
"percent-encoding", "percent-encoding",
"zcash_address 0.4.0", "zcash_address 0.6.0",
"zcash_protocol", "zcash_protocol",
] ]

View file

@ -11,15 +11,15 @@ f4jumble = "0.1"
zcash_address = "0.2.0" zcash_address = "0.2.0"
borsh = "0.10" borsh = "0.10"
bech32 = "0.11" bech32 = "0.11"
orchard = "0.9.0" orchard = "0.10.0"
zcash_note_encryption = "0.4.0" zcash_note_encryption = "0.4.0"
zcash_primitives = { version = "0.16.0", features = ["transparent-inputs"]} zcash_primitives = { version = "0.19.0", features = ["transparent-inputs"]}
zcash_client_backend = "0.13.0" zcash_client_backend = "0.14.0"
sapling-crypto = "0.2" sapling-crypto = "0.3"
zip32 = "0.1.0" zip32 = "0.1.2"
proc-macro2 = "1.0.66" proc-macro2 = "1.0.66"
nonempty = "0.7.0" nonempty = "0.7.0"
incrementalmerkletree = "0.6.0" incrementalmerkletree = "0.7.0"
secp256k1 = "0.27.0" secp256k1 = "0.27.0"
jubjub = "0.10.0" jubjub = "0.10.0"
rand_core = { version = "0.6.4", features = ["getrandom"]} rand_core = { version = "0.6.4", features = ["getrandom"]}

View file

@ -570,11 +570,11 @@ impl Hspend {
} }
} }
#[derive(Debug, BorshSerialize, BorshDeserialize)] #[derive(BorshSerialize, BorshDeserialize)]
pub struct HsaplingInput { pub struct HsaplingInput {
sk: Vec<u8>, sk: Vec<u8>,
note: Hnote, note: Hnote,
iw: Vec<u8> iw: Hpath
} }
impl<RW> FromHaskell<RW> for HsaplingInput { impl<RW> FromHaskell<RW> for HsaplingInput {
@ -585,11 +585,11 @@ impl<RW> FromHaskell<RW> for HsaplingInput {
} }
#[derive(Debug, BorshSerialize, BorshDeserialize)] #[derive(BorshSerialize, BorshDeserialize)]
pub struct HorchardInput { pub struct HorchardInput {
sk: Vec<u8>, sk: Vec<u8>,
note: Hnote, note: Hnote,
iw: Vec<u8> iw: Hpath
} }
impl<RW> FromHaskell<RW> for HorchardInput { impl<RW> FromHaskell<RW> 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<u8> = 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<u8> = marshall_from_haskell_var(left, left_len, RW);
let right_in: Vec<u8> = 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<Node, 32> = 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<u8> = 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::<CommitmentTree<Node, 32>, _>(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<u8> = 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::<CommitmentTree<Node, 32>, _>(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<u8> = 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] #[no_mangle]
pub extern "C" fn rust_wrapper_read_orchard_frontier( pub extern "C" fn rust_wrapper_read_orchard_frontier(
tree: *const u8, 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 path_in: Hpath = marshall_from_haskell_var(path, path_len, RW);
let cmx_in: Vec<u8> = marshall_from_haskell_var(cmx, cmx_len, RW); let cmx_in: Vec<u8> = 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)); let nc = ExtractedNoteCommitment::from_bytes(&to_array(cmx_in));
if nc.is_some().into() { if nc.is_some().into() {
let anchor = mk_path.root(nc.unwrap()); let anchor = mk_path.root(nc.unwrap());
@ -1967,47 +2150,26 @@ pub extern "C" fn rust_wrapper_create_transaction(
out: *mut u8, out: *mut u8,
out_len: &mut usize){ out_len: &mut usize){
let sap_input: Vec<HsaplingInput> = marshall_from_haskell_var(s_input, s_input_len, RW); let sap_input: Vec<HsaplingInput> = marshall_from_haskell_var(s_input, s_input_len, RW);
let sap_anchor = let sap_anchor_in: Vec<u8> = marshall_from_haskell_var(sap_wit, sap_wit_len, RW);
if sap_input.is_empty() { let sap_anchor = Node::from_bytes(to_array(sap_anchor_in));
let sap_wit_in: Vec<u8> = marshall_from_haskell_var(sap_wit, sap_wit_len, RW); let sapling_anchor =
let sap_wit_reader = Cursor::new(sap_wit_in); if sap_anchor.is_some().into() {
let sap_iw = read_commitment_tree::<Node, Cursor<Vec<u8>>, SAPLING_DEPTH>(sap_wit_reader); Some(SaplingAnchor::from(sap_anchor.unwrap()))
match sap_iw {
Ok(s_iw) => {
Some(SaplingAnchor::from(s_iw.root()))
},
Err(_e) => {
None
}
}
} else { } else {
let si = &sap_input[0]; None
let swit_reader = Cursor::new(&si.iw);
let iw: IncrementalWitness<Node, SAPLING_DEPTH> = read_incremental_witness(swit_reader).unwrap();
Some(SaplingAnchor::from(iw.root()))
}; };
//println!("{:?}", sap_anchor); //println!("{:?}", sapling_anchor);
let orch_input: Vec<HorchardInput> = marshall_from_haskell_var(o_input, o_input_len, RW); let orch_input: Vec<HorchardInput> = marshall_from_haskell_var(o_input, o_input_len, RW);
let orch_anchor = let orch_anchor_in : Vec<u8> = marshall_from_haskell_var(orch_wit, orch_wit_len, RW);
if orch_input.is_empty() { let orch_anchor = MerkleHashOrchard::from_bytes(&to_array(orch_anchor_in));
let orch_wit_in: Vec<u8> = marshall_from_haskell_var(orch_wit, orch_wit_len, RW); let orchard_anchor =
let orch_wit_reader = Cursor::new(orch_wit_in); if orch_anchor.is_some().into() {
let orch_iw = read_commitment_tree::<MerkleHashOrchard, Cursor<Vec<u8>>, 32>(orch_wit_reader); Some(OrchardAnchor::from(orch_anchor.unwrap()))
match orch_iw {
Ok(o_iw) => {
Some(OrchardAnchor::from(o_iw.root()))
},
Err(_e) => {
None
}
}
} else { } else {
let oi = &orch_input[0]; None
let wit_reader = Cursor::new(&oi.iw);
let iw: IncrementalWitness<MerkleHashOrchard, 32> = read_incremental_witness(wit_reader).unwrap();
Some(OrchardAnchor::from(iw.root()))
}; };
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 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 mut test_builder = Builder::new(TestNetwork, BlockHeight::from(bl_height), build_config);
let trans_input: Vec<HtransparentInput> = marshall_from_haskell_var(t_input, t_input_len, RW); let trans_input: Vec<HtransparentInput> = 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)) 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 note = SaplingNote::from_parts(pay_addr, SaplingNoteValue::from_raw(s_in.note.note), rseed);
let wit_reader = Cursor::new(s_in.iw); let mk_path = sapling_crypto::MerklePath::from_parts(s_in.iw.path.iter().map(|x|
let iw: IncrementalWitness<Node, SAPLING_DEPTH> = read_incremental_witness(wit_reader).unwrap(); if x.bytes.len() > 1 {
let merkle_path = iw.path().unwrap(); 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 { if net {
let mb = main_builder.add_sapling_spend::<String>(&sk, note, merkle_path); let mb = main_builder.add_sapling_spend::<String>(&sk, note, merkle_path);
match mb { match mb {
@ -2090,16 +2256,22 @@ pub extern "C" fn rust_wrapper_create_transaction(
let val = NoteValue::from_raw(o_in.note.note); 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 note = Note::from_parts(pay_addr, val, rho, rseed).unwrap();
let wit_reader = Cursor::new(o_in.iw); let merkle_path = orchard::tree::MerklePath::from_parts(o_in.iw.position, to_array(o_in.iw.path.iter().map(|x|
let iw: IncrementalWitness<MerkleHashOrchard, 32> = read_incremental_witness(wit_reader).unwrap(); if x.bytes.len() > 1 {
let merkle_path = OrchardMerklePath::from(iw.path().unwrap()); MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap()
} else {
MerkleHashOrchard::empty_leaf()
}
).collect()));
if net { if net {
let mb = main_builder.add_orchard_spend::<String>(&sp_key, note, merkle_path); let mb = main_builder.add_orchard_spend::<String>(&sp_key, note, merkle_path);
match mb { match mb {
Ok(()) => { Ok(()) => {
//println!("added orchard inp: {:?}", val);
continue; continue;
}, },
Err(_e) => { Err(e) => {
//println!("failed orchard inp: {:?}", e);
let x = Hhex {bytes: vec![7]}; let x = Hhex {bytes: vec![7]};
marshall_to_haskell_var(&x, out, out_len, RW); 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::<String>(&sp_key, note, merkle_path); let tb = test_builder.add_orchard_spend::<String>(&sp_key, note, merkle_path);
match tb { match tb {
Ok(()) => { Ok(()) => {
//println!("added orchard inp: {:?}", val);
continue; continue;
}, },
Err(_e) => { Err(e) => {
//println!("failed orchard inp: {:?}", e);
let x = Hhex {bytes: vec![7]}; let x = Hhex {bytes: vec![7]};
marshall_to_haskell_var(&x, out, out_len, RW); marshall_to_haskell_var(&x, out, out_len, RW);
} }
@ -2261,6 +2435,7 @@ pub extern "C" fn rust_wrapper_create_transaction(
Err(e) => { Err(e) => {
match e { match e {
Error::InsufficientFunds(y) => { Error::InsufficientFunds(y) => {
//println!("ins funds: {:?}", y);
let x = Hhex {bytes: vec![0]}; let x = Hhex {bytes: vec![0]};
marshall_to_haskell_var(&x, out, out_len, RW); marshall_to_haskell_var(&x, out, out_len, RW);
}, },

View file

@ -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 {# fun unsafe rust_wrapper_read_orchard_node as rustWrapperReadOrchardNode
{ toBorshVar* `BS.ByteString'& { toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'& , getVarBuffer `Buffer HexString'&

View file

@ -18,11 +18,17 @@
module ZcashHaskell.Sapling where module ZcashHaskell.Sapling where
import C.Zcash import C.Zcash
( rustWrapperDecodeSaplingAddress ( rustWrapperCombineSaplingNodes
, rustWrapperDecodeSaplingAddress
, rustWrapperGetSaplingRootTest
, rustWrapperIsShielded , rustWrapperIsShielded
, rustWrapperReadSaplingCommitmentTree , rustWrapperReadSaplingCommitmentTree
, rustWrapperReadSaplingFrontier , rustWrapperReadSaplingFrontier
, rustWrapperReadSaplingNode
, rustWrapperReadSaplingPathAnchor
, rustWrapperReadSaplingPosition , rustWrapperReadSaplingPosition
, rustWrapperReadSaplingTreeAnchor
, rustWrapperReadSaplingTreeParts
, rustWrapperReadSaplingWitness , rustWrapperReadSaplingWitness
, rustWrapperSaplingCheck , rustWrapperSaplingCheck
, rustWrapperSaplingChgPaymentAddress , rustWrapperSaplingChgPaymentAddress
@ -38,6 +44,7 @@ import Data.Aeson
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C import qualified Data.ByteString.Char8 as C
import Data.HexString (HexString(..), fromText, hexString, toBytes, toText) import Data.HexString (HexString(..), fromText, hexString, toBytes, toText)
import Data.Int (Int8)
import qualified Data.Text as T import qualified Data.Text as T
import Data.Word import Data.Word
import Foreign.Rust.Marshall.Variable import Foreign.Rust.Marshall.Variable
@ -185,6 +192,56 @@ genSaplingInternalAddress sk =
res = res =
withPureBorshVarBuffer (rustWrapperSaplingChgPaymentAddress $ getBytes sk) 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 :: SaplingCommitmentTree -> Maybe SaplingFrontier
getSaplingFrontier tree = getSaplingFrontier tree =
if sf_pos updatedTree > 1 if sf_pos updatedTree > 1

View file

@ -611,6 +611,21 @@ newtype SaplingCommitmentTree = SaplingCommitmentTree
{ sapTree :: HexString { sapTree :: HexString
} deriving (Eq, Prelude.Show, Read) } 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 data SaplingFrontier = SaplingFrontier
{ sf_pos :: !Int64 { sf_pos :: !Int64
, sf_leaf :: !HexString , sf_leaf :: !HexString
@ -797,7 +812,7 @@ data TransparentTxSpend = TransparentTxSpend
data SaplingTxSpend = SaplingTxSpend data SaplingTxSpend = SaplingTxSpend
{ ss_sk :: !BS.ByteString { ss_sk :: !BS.ByteString
, ss_note :: !DecodedNote , ss_note :: !DecodedNote
, ss_iw :: !BS.ByteString , ss_iw :: !MerklePath
} deriving stock (Eq, Prelude.Show, GHC.Generic) } deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)
@ -806,7 +821,7 @@ data SaplingTxSpend = SaplingTxSpend
data OrchardTxSpend = OrchardTxSpend data OrchardTxSpend = OrchardTxSpend
{ ss_sk :: !BS.ByteString { ss_sk :: !BS.ByteString
, ss_note :: !DecodedNote , ss_note :: !DecodedNote
, ss_iw :: !BS.ByteString , ss_iw :: !MerklePath
} deriving stock (Eq, Prelude.Show, GHC.Generic) } deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)

View file

@ -123,8 +123,8 @@ readZebraTransaction hex =
rawTx = (withPureBorshVarBuffer . rustWrapperTxRead) $ hexBytes hex rawTx = (withPureBorshVarBuffer . rustWrapperTxRead) $ hexBytes hex
createTransaction :: createTransaction ::
Maybe SaplingCommitmentTree -- ^ to obtain the Sapling anchor HexString -- ^ to obtain the Sapling anchor
-> Maybe OrchardCommitmentTree -- ^ to obtain the Orchard anchor -> HexString -- ^ to obtain the Orchard anchor
-> [TransparentTxSpend] -- ^ the list of transparent notes to spend -> [TransparentTxSpend] -- ^ the list of transparent notes to spend
-> [SaplingTxSpend] -- ^ the list of Sapling notes to spend -> [SaplingTxSpend] -- ^ the list of Sapling notes to spend
-> [OrchardTxSpend] -- ^ the list of Orchard 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 <- txResult <-
withBorshBufferOfInitSize 51200 $ withBorshBufferOfInitSize 51200 $
rustWrapperCreateTx rustWrapperCreateTx
(case sapAnchor of (hexBytes sapAnchor)
Nothing -> "0" (hexBytes orchAnchor)
Just sA -> toBytes $ sapTree sA)
(case orchAnchor of
Nothing -> "0"
Just oA -> toBytes $ orchTree oA)
tSpend tSpend
sSpend sSpend
oSpend oSpend

View file

@ -5,7 +5,7 @@ cabal-version: 3.0
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
name: zcash-haskell name: zcash-haskell
version: 0.7.4.0 version: 0.7.5.0
synopsis: Utilities to interact with the Zcash blockchain synopsis: Utilities to interact with the Zcash blockchain
description: Please see the README on the repo at <https://git.vergara.tech/Vergara_Tech/zcash-haskell#readme> description: Please see the README on the repo at <https://git.vergara.tech/Vergara_Tech/zcash-haskell#readme>
category: Blockchain category: Blockchain