Functions to create and manage Orchard commitment trees #99

Merged
pitmutt merged 30 commits from rav001 into milestone2 2024-11-05 18:28:46 +00:00
7 changed files with 292 additions and 110 deletions
Showing only changes of commit 004e2c85cd - Show all commits

View file

@ -5,6 +5,17 @@ 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.3.0]
### Added
- Function to create an Orchard hash from a note commitment
- Function to hash Orchard commitments
### Changed
- Modified frontiers to use `HexString` for ommers
## [0.7.2.0] ## [0.7.2.0]
### Changed ### Changed

View file

@ -30,6 +30,8 @@ use secp256k1::SecretKey;
use jubjub::Fr; use jubjub::Fr;
use incrementalmerkletree::{ use incrementalmerkletree::{
Hashable,
Level,
Position, Position,
frontier::{ frontier::{
CommitmentTree, CommitmentTree,
@ -92,7 +94,8 @@ use zcash_primitives::{
write_commitment_tree, write_commitment_tree,
read_incremental_witness, read_incremental_witness,
write_incremental_witness, write_incremental_witness,
read_frontier_v1 read_frontier_v1,
read_nonempty_frontier_v1
}, },
legacy::{ legacy::{
Script, Script,
@ -697,7 +700,7 @@ impl<RW> ToHaskell<RW> for Hsvk {
pub struct Hfrontier { pub struct Hfrontier {
position: u64, position: u64,
leaf: Hhex, leaf: Hhex,
ommers: Vec<Vec<u8>> ommers: Vec<Hhex>
} }
impl<RW> ToHaskell<RW> for Hfrontier { impl<RW> ToHaskell<RW> for Hfrontier {
@ -1384,11 +1387,11 @@ pub extern "C" fn rust_wrapper_read_sapling_frontier(
match frontier.value() { match frontier.value() {
Some(f1) => { Some(f1) => {
let (pos, leaf, omm) = f1.clone().into_parts(); let (pos, leaf, omm) = f1.clone().into_parts();
let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| x.to_bytes().to_vec()).collect()}; let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: x.to_bytes().to_vec()}).collect()};
marshall_to_haskell_var(&f, out, out_len, RW); marshall_to_haskell_var(&f, out, out_len, RW);
}, },
None => { None => {
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![vec![0]]}; let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
marshall_to_haskell_var(&f0, out, out_len, RW); marshall_to_haskell_var(&f0, out, out_len, RW);
} }
} }
@ -1405,17 +1408,17 @@ pub extern "C" fn rust_wrapper_read_sapling_commitment_tree(
){ ){
let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW); let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW);
let leaf = Node::from_bytes(to_array(tree_in.leaf.bytes)).unwrap(); let leaf = Node::from_bytes(to_array(tree_in.leaf.bytes)).unwrap();
let mut comm_tree = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| Node::from_bytes(to_array(x.clone())).unwrap() ).collect()).unwrap(); let mut comm_tree = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| Node::from_bytes(to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
let node_in: Vec<u8> = marshall_from_haskell_var(node, node_len, RW); let node_in: Vec<u8> = marshall_from_haskell_var(node, node_len, RW);
let sap_note_comm = SaplingNoteCommitment::from_bytes(&to_array(node_in)); let sap_note_comm = SaplingNoteCommitment::from_bytes(&to_array(node_in));
if sap_note_comm.is_some().into() { if sap_note_comm.is_some().into() {
let n = Node::from_cmu(&sap_note_comm.unwrap()); let n = Node::from_cmu(&sap_note_comm.unwrap());
comm_tree.append(n); comm_tree.append(n);
let (pos, leaf, omm) = comm_tree.into_parts(); let (pos, leaf, omm) = comm_tree.into_parts();
let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| x.to_bytes().to_vec()).collect()}; let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: x.to_bytes().to_vec()}).collect()};
marshall_to_haskell_var(&f, out, out_len, RW); marshall_to_haskell_var(&f, out, out_len, RW);
} else { } else {
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![vec![0]]}; let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
marshall_to_haskell_var(&f0, out, out_len, RW); marshall_to_haskell_var(&f0, out, out_len, RW);
} }
} }
@ -1429,7 +1432,7 @@ pub extern "C" fn rust_wrapper_read_sapling_witness(
){ ){
let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW); let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW);
let leaf = Node::from_bytes(to_array(tree_in.leaf.bytes)).unwrap(); let leaf = Node::from_bytes(to_array(tree_in.leaf.bytes)).unwrap();
let frontier: Frontier<Node, SAPLING_DEPTH> = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| Node::from_bytes(to_array(x.clone())).unwrap() ).collect()).unwrap(); let frontier: Frontier<Node, SAPLING_DEPTH> = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| Node::from_bytes(to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
let ct: CommitmentTree<Node, SAPLING_DEPTH> = CommitmentTree::from_frontier(&frontier); let ct: CommitmentTree<Node, SAPLING_DEPTH> = CommitmentTree::from_frontier(&frontier);
let inc_wit = IncrementalWitness::from_tree(ct); let inc_wit = IncrementalWitness::from_tree(ct);
let mut out_bytes: Vec<u8> = Vec::new(); let mut out_bytes: Vec<u8> = Vec::new();
@ -1501,23 +1504,114 @@ pub extern "C" fn rust_wrapper_read_orchard_frontier(
){ ){
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW); let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
let tree_reader = Cursor::new(tree_in); let tree_reader = Cursor::new(tree_in);
let comm_tree: CommitmentTree<MerkleHashOrchard, 32> = read_commitment_tree(tree_reader).unwrap(); let comm_tree = read_commitment_tree(tree_reader);
//let comm_tree: Frontier<MerkleHashOrchard, 32> = read_frontier_v1(tree_reader).unwrap(); //let comm_tree = read_frontier_v1(tree_reader);
let frontier: Frontier<MerkleHashOrchard, 32> = comm_tree.to_frontier(); //let frontier: Frontier<MerkleHashOrchard, 32> = comm_tree.to_frontier();
match frontier.value() { match comm_tree {
Some(f1) => { Ok::<CommitmentTree<MerkleHashOrchard, 32>, _>(f1) => {
let (pos, leaf, omm) = f1.clone().into_parts(); let frontier = f1.to_frontier();
let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| x.to_bytes().to_vec()).collect()}; match frontier.value() {
marshall_to_haskell_var(&f, out, out_len, RW); Some(f2) => {
let (pos, leaf, omm) = f2.clone().into_parts();
let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: x.to_bytes().to_vec()}).collect()};
marshall_to_haskell_var(&f, out, out_len, RW);
},
None => {
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
marshall_to_haskell_var(&f0, out, out_len, RW);
}
}
}, },
None => { Err(_e) => {
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![vec![0]]}; let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
marshall_to_haskell_var(&f0, out, out_len, RW); marshall_to_haskell_var(&f0, out, out_len, RW);
} }
} }
} }
#[no_mangle]
pub extern "C" fn rust_wrapper_read_orchard_tree_anchor(
tree: *const u8,
tree_len: usize,
out: *mut u8,
out_len: &mut usize
){
let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW);
let leaf = MerkleHashOrchard::from_bytes(&to_array(tree_in.leaf.bytes)).unwrap();
let comm_tree: NonEmptyFrontier<MerkleHashOrchard> = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
let root = comm_tree.root(None);
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_orchard_witness_anchor(
wit: *const u8,
wit_len: usize,
out: *mut u8,
out_len: &mut usize
) {
let wit_in: Vec<u8> = marshall_from_haskell_var(wit, wit_len, RW);
let wit_reader = Cursor::new(wit_in);
let iw: IncrementalWitness<MerkleHashOrchard, 32> = read_incremental_witness(wit_reader).unwrap();
let root = iw.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_orchard_node(
cmx: *const u8,
cmx_len: usize,
out: *mut u8,
out_len: &mut usize
){
let node_in: Vec<u8> = marshall_from_haskell_var(cmx, cmx_len, RW);
let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(node_in));
if orchard_note_comm.is_some().into() {
let n = MerkleHashOrchard::from_cmx(&orchard_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_orchard_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);
let left_node = MerkleHashOrchard::from_bytes(&to_array(left_in));
if left_node.is_some().into() {
if right_in.len() > 1 {
let right_node = MerkleHashOrchard::from_bytes(&to_array(right_in));
if right_node.is_some().into() {
let n = MerkleHashOrchard::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 = MerkleHashOrchard::combine(Level::new(level), &left_node.unwrap(), &MerkleHashOrchard::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] #[no_mangle]
@ -1534,17 +1628,17 @@ pub extern "C" fn rust_wrapper_read_orchard_commitment_tree(
//let mut comm_tree: CommitmentTree<MerkleHashOrchard, 32> = read_commitment_tree(tree_reader).unwrap(); //let mut comm_tree: CommitmentTree<MerkleHashOrchard, 32> = read_commitment_tree(tree_reader).unwrap();
//let mut comm_tree: Frontier<MerkleHashOrchard, 32> = read_frontier_v1(tree_reader).unwrap(); //let mut comm_tree: Frontier<MerkleHashOrchard, 32> = read_frontier_v1(tree_reader).unwrap();
let leaf = MerkleHashOrchard::from_bytes(&to_array(tree_in.leaf.bytes)).unwrap(); let leaf = MerkleHashOrchard::from_bytes(&to_array(tree_in.leaf.bytes)).unwrap();
let mut comm_tree: NonEmptyFrontier<MerkleHashOrchard> = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.clone())).unwrap() ).collect()).unwrap(); let mut comm_tree: NonEmptyFrontier<MerkleHashOrchard> = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
let node_in: Vec<u8> = marshall_from_haskell_var(node, node_len, RW); let node_in: Vec<u8> = marshall_from_haskell_var(node, node_len, RW);
let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(node_in)); let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(node_in));
if orchard_note_comm.is_some().into() { if orchard_note_comm.is_some().into() {
let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap()); let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap());
comm_tree.append(n); comm_tree.append(n);
let (pos, leaf, omm) = comm_tree.into_parts(); let (pos, leaf, omm) = comm_tree.into_parts();
let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| x.to_bytes().to_vec()).collect()}; let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: x.to_bytes().to_vec()}).collect()};
marshall_to_haskell_var(&f, out, out_len, RW); marshall_to_haskell_var(&f, out, out_len, RW);
} else { } else {
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![vec![0]]}; let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
marshall_to_haskell_var(&f0, out, out_len, RW); marshall_to_haskell_var(&f0, out, out_len, RW);
} }
} }
@ -1558,7 +1652,7 @@ pub extern "C" fn rust_wrapper_read_orchard_witness(
){ ){
let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW); let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW);
let leaf = MerkleHashOrchard::from_bytes(&to_array(tree_in.leaf.bytes)).unwrap(); let leaf = MerkleHashOrchard::from_bytes(&to_array(tree_in.leaf.bytes)).unwrap();
let frontier: Frontier<MerkleHashOrchard, 32> = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.clone())).unwrap() ).collect()).unwrap(); let frontier: Frontier<MerkleHashOrchard, 32> = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
let ct: CommitmentTree<MerkleHashOrchard, 32> = CommitmentTree::from_frontier(&frontier); let ct: CommitmentTree<MerkleHashOrchard, 32> = CommitmentTree::from_frontier(&frontier);
let inc_wit = IncrementalWitness::from_tree(ct); let inc_wit = IncrementalWitness::from_tree(ct);
let mut out_bytes: Vec<u8> = Vec::new(); let mut out_bytes: Vec<u8> = Vec::new();

View file

@ -246,6 +246,36 @@ import ZcashHaskell.Types
-> `()' -> `()'
#} #}
{# fun unsafe rust_wrapper_read_orchard_node as rustWrapperReadOrchardNode
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_combine_orchard_nodes as rustWrapperCombineOrchardNodes
{ `Int8'
, toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_read_orchard_tree_anchor as rustWrapperReadOrchardTreeAnchor
{ toBorshVar* `OrchardFrontier'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_read_orchard_witness_anchor as rustWrapperReadOrchardWitnessAnchor
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_read_orchard_commitment_tree as rustWrapperReadOrchardCommitmentTree {# fun unsafe rust_wrapper_read_orchard_commitment_tree as rustWrapperReadOrchardCommitmentTree
{ toBorshVar* `OrchardFrontier'& { toBorshVar* `OrchardFrontier'&
, toBorshVar* `BS.ByteString'& , toBorshVar* `BS.ByteString'&

View file

@ -18,15 +18,19 @@
module ZcashHaskell.Orchard where module ZcashHaskell.Orchard where
import C.Zcash import C.Zcash
( rustWrapperGenOrchardReceiver ( rustWrapperCombineOrchardNodes
, rustWrapperGenOrchardReceiver
, rustWrapperGenOrchardSpendKey , rustWrapperGenOrchardSpendKey
, rustWrapperOrchardCheck , rustWrapperOrchardCheck
, rustWrapperOrchardNoteDecode , rustWrapperOrchardNoteDecode
, rustWrapperOrchardNoteDecodeSK , rustWrapperOrchardNoteDecodeSK
, rustWrapperReadOrchardCommitmentTree , rustWrapperReadOrchardCommitmentTree
, rustWrapperReadOrchardFrontier , rustWrapperReadOrchardFrontier
, rustWrapperReadOrchardNode
, rustWrapperReadOrchardPosition , rustWrapperReadOrchardPosition
, rustWrapperReadOrchardTreeAnchor
, rustWrapperReadOrchardWitness , rustWrapperReadOrchardWitness
, rustWrapperReadOrchardWitnessAnchor
, rustWrapperUADecode , rustWrapperUADecode
, rustWrapperUfvkDecode , rustWrapperUfvkDecode
, rustWrapperUpdateOrchardWitness , rustWrapperUpdateOrchardWitness
@ -205,6 +209,15 @@ getOrchardFrontier tree =
withPureBorshVarBuffer $ withPureBorshVarBuffer $
rustWrapperReadOrchardFrontier $ toBytes $ orchTree tree rustWrapperReadOrchardFrontier $ toBytes $ orchTree tree
getOrchardTreeAnchor :: OrchardFrontier -> HexString
getOrchardTreeAnchor tree =
withPureBorshVarBuffer $ rustWrapperReadOrchardTreeAnchor tree
getOrchardWitnessAnchor :: OrchardWitness -> HexString
getOrchardWitnessAnchor wit =
withPureBorshVarBuffer $
rustWrapperReadOrchardWitnessAnchor $ toBytes $ orchWit wit
-- | Update a Orchard commitment tree -- | Update a Orchard commitment tree
updateOrchardCommitmentTree :: updateOrchardCommitmentTree ::
OrchardFrontier -- ^ the base tree OrchardFrontier -- ^ the base tree
@ -244,6 +257,27 @@ updateOrchardWitness wit cmus =
(map toBytes cmus) (map toBytes cmus)
else wit else wit
getOrchardNodeValue :: BS.ByteString -> Maybe HexString
getOrchardNodeValue cmx =
if BS.length (hexBytes n) > 1
then Just n
else Nothing
where
n = withPureBorshVarBuffer $ rustWrapperReadOrchardNode cmx
combineOrchardNodes :: Integer -> HexString -> HexString -> Maybe HexString
combineOrchardNodes level n1 n2 =
if BS.length (hexBytes r) > 1
then Just r
else Nothing
where
r =
withPureBorshVarBuffer $
rustWrapperCombineOrchardNodes
(fromIntegral level)
(toBytes n1)
(toBytes n2)
-- | Parse a potential Zcash address -- | Parse a potential Zcash address
parseAddress :: BS.ByteString -> Maybe ValidAddress parseAddress :: BS.ByteString -> Maybe ValidAddress
parseAddress t = parseAddress t =

View file

@ -614,7 +614,7 @@ newtype SaplingCommitmentTree = SaplingCommitmentTree
data SaplingFrontier = SaplingFrontier data SaplingFrontier = SaplingFrontier
{ sf_pos :: !Int64 { sf_pos :: !Int64
, sf_leaf :: !HexString , sf_leaf :: !HexString
, sf_ommers :: ![BS.ByteString] , sf_ommers :: ![HexString]
} 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)
@ -730,7 +730,7 @@ newtype OrchardCommitmentTree = OrchardCommitmentTree
data OrchardFrontier = OrchardFrontier data OrchardFrontier = OrchardFrontier
{ of_pos :: !Int64 { of_pos :: !Int64
, of_leaf :: !HexString , of_leaf :: !HexString
, of_ommers :: ![BS.ByteString] , of_ommers :: ![HexString]
} 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

@ -55,6 +55,7 @@ import ZcashHaskell.Sapling
, genSaplingInternalAddress , genSaplingInternalAddress
, genSaplingPaymentAddress , genSaplingPaymentAddress
, genSaplingSpendingKey , genSaplingSpendingKey
, getSaplingFrontier
, getSaplingNotePosition , getSaplingNotePosition
, getSaplingWitness , getSaplingWitness
, getShieldedOutputs , getShieldedOutputs
@ -73,6 +74,7 @@ import ZcashHaskell.Types
, OrchardAction(..) , OrchardAction(..)
, OrchardBundle(..) , OrchardBundle(..)
, OrchardCommitmentTree(..) , OrchardCommitmentTree(..)
, OrchardFrontier(..)
, OrchardSpendingKey(..) , OrchardSpendingKey(..)
, OrchardWitness(..) , OrchardWitness(..)
, Phrase(..) , Phrase(..)
@ -88,6 +90,7 @@ import ZcashHaskell.Types
, SaplingAddress(..) , SaplingAddress(..)
, SaplingBundle(..) , SaplingBundle(..)
, SaplingCommitmentTree(..) , SaplingCommitmentTree(..)
, SaplingFrontier(..)
, SaplingReceiver(..) , SaplingReceiver(..)
, SaplingSpendingKey(..) , SaplingSpendingKey(..)
, SaplingWitness(..) , SaplingWitness(..)
@ -895,33 +898,35 @@ main = do
Just t' -> do Just t' -> do
let tb = zt_tBundle t' let tb = zt_tBundle t'
show tb `shouldNotBe` "" show tb `shouldNotBe` ""
describe "Sapling commitment trees" $ do {-
let tree = -describe "Sapling commitment trees" $ do
SaplingCommitmentTree $ - let tree =
hexString - SaplingCommitmentTree $
"01916df07670600aefa3b412a120d6b8d9a3d2ff9466a7ec770cd52d34ddb42313001000013c60b031a5e44650059fcc7101a3f551b807ab8b3a116a5a9c7fa0f3babbe735017c0d36686294ff19d59e58b6a2ac6a7ad607a804bc202c84012d8e94f233970c0128dbde5180af5304d8577376d78297130b615a327974c10881f6d876869aea05011b80b4ca60f74dfe33c78b062df73c84b8b44dab4604db16f5b61eea40134373010c96e4cc8a6a80fba0d41e4eb3070d80769104dc33fb61133b1304c15bf9e23e000107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39" - hexString
let cmu1 = - "01916df07670600aefa3b412a120d6b8d9a3d2ff9466a7ec770cd52d34ddb42313001000013c60b031a5e44650059fcc7101a3f551b807ab8b3a116a5a9c7fa0f3babbe735017c0d36686294ff19d59e58b6a2ac6a7ad607a804bc202c84012d8e94f233970c0128dbde5180af5304d8577376d78297130b615a327974c10881f6d876869aea05011b80b4ca60f74dfe33c78b062df73c84b8b44dab4604db16f5b61eea40134373010c96e4cc8a6a80fba0d41e4eb3070d80769104dc33fb61133b1304c15bf9e23e000107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
hexString - let cmu1 =
"45e47c5df6f5c5e48aa3526e977b2d1b57eda57214e36f06128008cb17b0125f" - hexString
let cmu2 = - "45e47c5df6f5c5e48aa3526e977b2d1b57eda57214e36f06128008cb17b0125f"
hexString - let cmu2 =
"426ef44b3b22e0eeda7e4d2b62bac63966572b224e50f97ee56c9490cde4910d" - hexString
let tree2 = - "426ef44b3b22e0eeda7e4d2b62bac63966572b224e50f97ee56c9490cde4910d"
hexString - let tree2 =
"01a47029e9b43722c57143a5d07681bff3e2315c9a28ad49d69e7c1f2f6e81ac160010000000000000012f4f72c03f8c937a94919a01a07f21165cc8394295291cb888ca91ed003810390107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39" - hexString
it "Commitment tree is updated correctly" $ do - "01a47029e9b43722c57143a5d07681bff3e2315c9a28ad49d69e7c1f2f6e81ac160010000000000000012f4f72c03f8c937a94919a01a07f21165cc8394295291cb888ca91ed003810390107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
let t1 = updateSaplingCommitmentTree tree cmu1 - it "Commitment tree is updated correctly" $ do
t1 `shouldNotBe` Nothing - let t1 = updateSaplingCommitmentTree tree cmu1
it "Incremental witness is generated" $ do - t1 `shouldNotBe` Nothing
let t1 = updateSaplingCommitmentTree tree cmu1 - it "Incremental witness is generated" $ do
case t1 of - let t1 = updateSaplingCommitmentTree tree cmu1
Nothing -> assertFailure "Failed to append node to tree" - case t1 of
Just t -> getSaplingWitness t `shouldNotBe` Nothing - Nothing -> assertFailure "Failed to append node to tree"
it "Position of note is obtained" $ do - Just t -> getSaplingWitness t `shouldNotBe` Nothing
let p = - it "Position of note is obtained" $ do
getSaplingNotePosition <$> - let p =
(getSaplingWitness =<< updateSaplingCommitmentTree tree cmu1) - getSaplingNotePosition <$>
p `shouldBe` Just 129405 - (getSaplingWitness =<< updateSaplingCommitmentTree tree cmu1)
- p `shouldBe` Just 129405
-}
{- describe "Orchard commitment trees" $ do {- describe "Orchard commitment trees" $ do
let tree = let tree =
OrchardCommitmentTree $ OrchardCommitmentTree $
@ -1061,18 +1066,22 @@ main = do
(hexString (hexString
"97e5f003d16720844ba1bd157688a7697133f4bb4a33a7c91974937a1351d7af56d16d4a10bd196ddda700fcd8be517f8f9e39a17ba0eea235d98450a626be3a998ac31f35e8e082106a31fe94da11d02b73748db4aa519df6bbf25c1d62a2cf0b192c6a486bca2632fee9e4124ce2dba6f3366a14850f6a3b784d863119f52458ed774f8d63105b4f6a3d2e09cc74e3a02ec8386213087b4c849172ded6724a45c9c12744ec4a0f86a29b803b17187df5dd5f90e71d1f3f4578d4e1496e8892") "97e5f003d16720844ba1bd157688a7697133f4bb4a33a7c91974937a1351d7af56d16d4a10bd196ddda700fcd8be517f8f9e39a17ba0eea235d98450a626be3a998ac31f35e8e082106a31fe94da11d02b73748db4aa519df6bbf25c1d62a2cf0b192c6a486bca2632fee9e4124ce2dba6f3366a14850f6a3b784d863119f52458ed774f8d63105b4f6a3d2e09cc74e3a02ec8386213087b4c849172ded6724a45c9c12744ec4a0f86a29b803b17187df5dd5f90e71d1f3f4578d4e1496e8892")
it "Sap output 1" $ do it "Sap output 1" $ do
let pos = case getSaplingFrontier tree of
getSaplingNotePosition <$> Nothing -> assertFailure "failed to read comm tree"
(getSaplingWitness =<< Just tree' -> do
updateSaplingCommitmentTree let pos =
tree sf_pos <$>
(fromText updateSaplingCommitmentTree
"fa430c51bb108db782764cff55de9c6b11bbecd2493d2e0fa9f646428feef858")) tree'
case pos of (fromText
Nothing -> assertFailure "couldn't get note position" "fa430c51bb108db782764cff55de9c6b11bbecd2493d2e0fa9f646428feef858")
Just p -> do case pos of
let dn = decodeSaplingOutputEsk sk so1 TestNet External p Nothing -> assertFailure "couldn't get note position"
dn `shouldBe` Nothing Just p -> do
let dn =
decodeSaplingOutputEsk sk so1 TestNet External $
fromIntegral p
dn `shouldBe` Nothing
it "Sap output 2" $ do it "Sap output 2" $ do
case readZebraTransaction txHex2 of case readZebraTransaction txHex2 of
Nothing -> assertFailure "Failed to read Tx" Nothing -> assertFailure "Failed to read Tx"
@ -1082,24 +1091,27 @@ main = do
Nothing -> assertFailure "Failed to get sapling bundle" Nothing -> assertFailure "Failed to get sapling bundle"
Just sB -> do Just sB -> do
let sOuts = sbOutputs sB let sOuts = sbOutputs sB
let pos = case getSaplingFrontier tree of
getSaplingNotePosition <$> Nothing -> assertFailure "Failed to read tree"
(getSaplingWitness =<< Just tree' -> do
updateSaplingCommitmentTree let pos =
tree getSaplingNotePosition <$>
(fromText (getSaplingWitness =<<
"d163c69029e8cb05d874b798c7973b3b1b1b0e04f984a252b73c848698320843")) updateSaplingCommitmentTree
case pos of tree'
Nothing -> assertFailure "couldn't get note position" (fromText
Just p -> do "d163c69029e8cb05d874b798c7973b3b1b1b0e04f984a252b73c848698320843"))
let dn = case pos of
decodeSaplingOutputEsk Nothing -> assertFailure "couldn't get note position"
sk Just p -> do
(head . tail $ sOuts) let dn =
TestNet decodeSaplingOutputEsk
External sk
p (head . tail $ sOuts)
dn `shouldBe` Nothing TestNet
External
p
dn `shouldBe` Nothing
it "Decode Sapling Output from Zingo" $ do it "Decode Sapling Output from Zingo" $ do
case readZebraTransaction txHex of case readZebraTransaction txHex of
Nothing -> assertFailure "Failed to read Tx" Nothing -> assertFailure "Failed to read Tx"
@ -1112,24 +1124,26 @@ main = do
Nothing -> assertFailure "Failed to get sapling bundle" Nothing -> assertFailure "Failed to get sapling bundle"
Just sB -> do Just sB -> do
let sOuts = sbOutputs sB let sOuts = sbOutputs sB
let pos = case getSaplingFrontier tree of
getSaplingNotePosition <$> Nothing -> assertFailure "failed to read comm tree"
(getSaplingWitness =<< Just tree' -> do
updateSaplingCommitmentTree let pos =
tree sf_pos <$>
(fromText updateSaplingCommitmentTree
"d163c69029e8cb05d874b798c7973b3b1b1b0e04f984a252b73c848698320843")) tree'
case pos of (fromText
Nothing -> assertFailure "couldn't get note position" "d163c69029e8cb05d874b798c7973b3b1b1b0e04f984a252b73c848698320843")
Just p -> do case pos of
let dn = Nothing -> assertFailure "couldn't get note position"
decodeSaplingOutputEsk Just p -> do
sK' let dn =
(head . tail $ sOuts) decodeSaplingOutputEsk
MainNet sK'
External (head . tail $ sOuts)
p MainNet
dn `shouldNotBe` Nothing External
(fromIntegral p)
dn `shouldNotBe` Nothing
describe "Generate an ExchangeAddress (MainNet) from transparent address" $ do describe "Generate an ExchangeAddress (MainNet) from transparent address" $ do
let ta = decodeTransparentAddress "t1dMjvesbzdG41xgKaGU3HgwYJwSgbCK54e" let ta = decodeTransparentAddress "t1dMjvesbzdG41xgKaGU3HgwYJwSgbCK54e"
it "Try to generate valid ExchangeAddress from Transparent Address" $ do it "Try to generate valid ExchangeAddress from Transparent Address" $ do
@ -1176,15 +1190,14 @@ main = do
Just t1 -> Just t1 ->
case updateOrchardCommitmentTree t1 cmx1 of case updateOrchardCommitmentTree t1 cmx1 of
Nothing -> assertFailure "Failed to update frontier with cmx" Nothing -> assertFailure "Failed to update frontier with cmx"
Just t2 -> Just t2 -> do
case updateOrchardCommitmentTree t2 cmx2 of case getOrchardWitness t2 of
Nothing -> assertFailure "Failed to update frontier with cmx" Nothing -> assertFailure "Failed to get witness"
Just t3 -> Just wit -> do
case updateOrchardCommitmentTree t3 cmx3 of let uWit = updateOrchardWitness wit [cmx2, cmx3, cmx4]
Nothing -> Just (getOrchardWitnessAnchor uWit) `shouldBe`
assertFailure "Failed to update frontier with cmx" getOrchardTreeAnchor <$>
Just t4 -> finalTree
updateOrchardCommitmentTree t4 cmx4 `shouldBe` finalTree
describe "Witness updates" $ do describe "Witness updates" $ do
it "Sapling" $ do it "Sapling" $ do
let wit = let wit =

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.2.0 version: 0.7.3.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