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:
parent
62cda9cc15
commit
dea960c2ac
9 changed files with 403 additions and 97 deletions
17
CHANGELOG.md
17
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
|
||||
|
|
61
librustzcash-wrapper/Cargo.lock
generated
61
librustzcash-wrapper/Cargo.lock
generated
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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"]}
|
||||
|
|
|
@ -570,11 +570,11 @@ impl Hspend {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||
#[derive(BorshSerialize, BorshDeserialize)]
|
||||
pub struct HsaplingInput {
|
||||
sk: Vec<u8>,
|
||||
note: Hnote,
|
||||
iw: Vec<u8>
|
||||
iw: Hpath
|
||||
}
|
||||
|
||||
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 {
|
||||
sk: Vec<u8>,
|
||||
note: Hnote,
|
||||
iw: Vec<u8>
|
||||
iw: Hpath
|
||||
}
|
||||
|
||||
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]
|
||||
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<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));
|
||||
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<HsaplingInput> = marshall_from_haskell_var(s_input, s_input_len, RW);
|
||||
let sap_anchor =
|
||||
if sap_input.is_empty() {
|
||||
let sap_wit_in: Vec<u8> = 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::<Node, Cursor<Vec<u8>>, 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<u8> = 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<Node, SAPLING_DEPTH> = read_incremental_witness(swit_reader).unwrap();
|
||||
Some(SaplingAnchor::from(iw.root()))
|
||||
None
|
||||
};
|
||||
//println!("{:?}", sap_anchor);
|
||||
//println!("{:?}", sapling_anchor);
|
||||
let orch_input: Vec<HorchardInput> = marshall_from_haskell_var(o_input, o_input_len, RW);
|
||||
let orch_anchor =
|
||||
if orch_input.is_empty() {
|
||||
let orch_wit_in: Vec<u8> = 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::<MerkleHashOrchard, Cursor<Vec<u8>>, 32>(orch_wit_reader);
|
||||
match orch_iw {
|
||||
Ok(o_iw) => {
|
||||
Some(OrchardAnchor::from(o_iw.root()))
|
||||
},
|
||||
Err(_e) => {
|
||||
None
|
||||
}
|
||||
}
|
||||
let orch_anchor_in : Vec<u8> = 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<MerkleHashOrchard, 32> = 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<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))
|
||||
};
|
||||
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<Node, SAPLING_DEPTH> = 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::<String>(&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<MerkleHashOrchard, 32> = 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::<String>(&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::<String>(&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);
|
||||
},
|
||||
|
|
|
@ -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'&
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <https://git.vergara.tech/Vergara_Tech/zcash-haskell#readme>
|
||||
category: Blockchain
|
||||
|
|
Loading…
Reference in a new issue