diff --git a/CHANGELOG.md b/CHANGELOG.md index 55ab296f7..0f38d3e03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,9 @@ and this project adheres to Rust's notion of - `ValueCommitTrapdoor::to_bytes` - `impl Clone for orchard::tree::MerklePath` +### Changed +- Migrated to `incrementalmerkletree 0.8`. + ## [0.10.0] - 2024-10-02 ### Changed diff --git a/Cargo.lock b/Cargo.lock index 5482a493e..b053aeb79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -197,15 +197,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "bridgetree" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef977c7f8e75aa81fc589064c121ab8d32448b7939d34d58df479aa93e65ea5" -dependencies = [ - "incrementalmerkletree", -] - [[package]] name = "bumpalo" version = "3.13.0" @@ -1099,9 +1090,8 @@ dependencies = [ [[package]] name = "incrementalmerkletree" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45063fbc4b0a37837f6bfe0445f269d13d730ad0aa3b5a7f74aa7bf27a0f4df" +version = "0.8.0" +source = "git+https://github.com/zcash/incrementalmerkletree.git?rev=353cf3e9ff9621f64e2b6fabb709f4afeca487c4#353cf3e9ff9621f64e2b6fabb709f4afeca487c4" dependencies = [ "either", "proptest", @@ -1431,7 +1421,6 @@ dependencies = [ "aes", "bitvec", "blake2b_simd", - "bridgetree", "criterion", "ff", "fpe", @@ -1453,6 +1442,7 @@ dependencies = [ "rand", "reddsa", "serde", + "shardtree", "subtle", "tracing", "visibility", @@ -2014,6 +2004,17 @@ dependencies = [ "serde", ] +[[package]] +name = "shardtree" +version = "0.5.0" +source = "git+https://github.com/zcash/incrementalmerkletree.git?rev=353cf3e9ff9621f64e2b6fabb709f4afeca487c4#353cf3e9ff9621f64e2b6fabb709f4afeca487c4" +dependencies = [ + "bitflags 2.4.0", + "either", + "incrementalmerkletree", + "tracing", +] + [[package]] name = "simd-adler32" version = "0.3.7" diff --git a/Cargo.toml b/Cargo.toml index 8c014ecdf..1f1d927bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ nonempty = "0.7" serde = { version = "1.0", features = ["derive"] } subtle = "2.3" zcash_note_encryption = "0.4" -incrementalmerkletree = "0.7" +incrementalmerkletree = "0.8" zcash_spec = "0.1" zip32 = "0.1" visibility = "0.1.1" @@ -58,13 +58,13 @@ image = { version = "0.24", optional = true } plotters = { version = "0.3.0", optional = true } [dev-dependencies] -bridgetree = "0.6" criterion = "0.4" # 0.5 depends on clap 4 which has MSRV 1.70 halo2_gadgets = { version = "0.3", features = ["test-dependencies"] } hex = "0.4" proptest = "1.0.0" zcash_note_encryption = { version = "0.4", features = ["pre-zip-212"] } -incrementalmerkletree = { version = "0.7", features = ["test-dependencies"] } +incrementalmerkletree = { version = "0.8", features = ["test-dependencies"] } +shardtree = "0.5" [target.'cfg(unix)'.dev-dependencies] inferno = { version = "0.11", default-features = false, features = ["multithreaded", "nameattr"] } @@ -97,3 +97,7 @@ debug = true [profile.bench] debug = true + +[patch.crates-io] +incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree.git", rev = "353cf3e9ff9621f64e2b6fabb709f4afeca487c4" } +shardtree = { git = "https://github.com/zcash/incrementalmerkletree.git", rev = "353cf3e9ff9621f64e2b6fabb709f4afeca487c4" } diff --git a/src/pczt.rs b/src/pczt.rs index 7e079d5b4..3a727837d 100644 --- a/src/pczt.rs +++ b/src/pczt.rs @@ -288,10 +288,11 @@ pub struct Zip32Derivation { #[cfg(test)] mod tests { - use bridgetree::BridgeTree; use ff::{Field, PrimeField}; + use incrementalmerkletree::{Marking, Retention}; use pasta_curves::pallas; use rand::rngs::OsRng; + use shardtree::{store::memory::MemoryShardStore, ShardTree}; use crate::{ builder::{Builder, BundleType}, @@ -300,7 +301,7 @@ mod tests { keys::{FullViewingKey, Scope, SpendAuthorizingKey, SpendingKey}, note::{ExtractedNoteCommitment, RandomSeed, Rho}, pczt::Zip32Derivation, - tree::{MerkleHashOrchard, MerklePath, EMPTY_ROOTS}, + tree::{MerkleHashOrchard, EMPTY_ROOTS}, value::NoteValue, Note, }; @@ -371,23 +372,31 @@ mod tests { let (anchor, merkle_path) = { let cmx: ExtractedNoteCommitment = note.commitment().into(); let leaf = MerkleHashOrchard::from_cmx(&cmx); - let mut tree = BridgeTree::::new(100); - tree.append(leaf); - let position = tree.mark().unwrap(); - let root = tree.root(0).unwrap(); - let auth_path = tree.witness(position, 0).unwrap(); - let merkle_path = MerklePath::from_parts( - u64::from(position).try_into().unwrap(), - auth_path[..].try_into().unwrap(), - ); - let anchor = root.into(); - assert_eq!(anchor, merkle_path.root(cmx)); - (anchor, merkle_path) + let mut tree: ShardTree, 32, 16> = + ShardTree::new(MemoryShardStore::empty(), 100); + tree.append( + leaf, + Retention::Checkpoint { + id: 0, + marking: Marking::Marked, + }, + ) + .unwrap(); + let root = tree.root_at_checkpoint_id(&0).unwrap().unwrap(); + let position = tree.max_leaf_position(None).unwrap().unwrap(); + let merkle_path = tree + .witness_at_checkpoint_id(position, &0) + .unwrap() + .unwrap(); + assert_eq!(root, merkle_path.root(MerkleHashOrchard::from_cmx(&cmx))); + (root.into(), merkle_path) }; // Run the Creator and Constructor roles. let mut builder = Builder::new(BundleType::DEFAULT, anchor); - builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); + builder + .add_spend(fvk.clone(), note, merkle_path.into()) + .unwrap(); builder .add_output(None, recipient, NoteValue::from_raw(10_000), None) .unwrap(); diff --git a/src/tree.rs b/src/tree.rs index 046f5d924..50db8ed6e 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -289,10 +289,10 @@ pub mod testing { mod tests { use { crate::tree::{MerkleHashOrchard, EMPTY_ROOTS}, - bridgetree::{BridgeTree, Frontier as BridgeFrontier}, group::ff::PrimeField, - incrementalmerkletree::Level, + incrementalmerkletree::{frontier::Frontier, Level, Marking, MerklePath, Retention}, pasta_curves::pallas, + shardtree::{store::memory::MemoryShardStore, ShardTree}, }; #[test] @@ -303,31 +303,42 @@ mod tests { assert_eq!(tv_empty_roots[height], root.to_bytes()); } - let mut tree = BridgeTree::::new(100); + let mut tree: ShardTree, 4, 3> = + ShardTree::new(MemoryShardStore::empty(), 100); for (i, tv) in crate::test_vectors::merkle_path::test_vectors() .into_iter() .enumerate() { + let checkpoint_id = u32::try_from(i).unwrap(); let cmx = MerkleHashOrchard::from_bytes(&tv.leaves[i]).unwrap(); - tree.append(cmx); - let position = tree.mark().expect("tree is not empty"); - assert_eq!(position, (i as u64).into()); + tree.append( + cmx, + Retention::Checkpoint { + id: checkpoint_id, + marking: Marking::Marked, + }, + ) + .unwrap(); - let root = tree.root(0).unwrap(); + let root = tree.root_at_checkpoint_id(&checkpoint_id).unwrap().unwrap(); assert_eq!(root.0, pallas::Base::from_repr(tv.root).unwrap()); // Check paths for all leaves up to this point. The test vectors include paths // for not-yet-appended leaves (using UNCOMMITTED_ORCHARD as the leaf value), // but BridgeTree doesn't encode these. for j in 0..=i { + let position = j.try_into().unwrap(); assert_eq!( - tree.witness(j.try_into().unwrap(), 0).ok(), - Some( + tree.witness_at_checkpoint_id(position, &checkpoint_id) + .unwrap(), + MerklePath::from_parts( tv.paths[j] .iter() .map(|v| MerkleHashOrchard::from_bytes(v).unwrap()) - .collect() + .collect(), + position ) + .ok() ); } } @@ -392,7 +403,7 @@ mod tests { 0x9c, 0x52, 0x7f, 0x0e, ]; - let mut frontier = BridgeFrontier::::empty(); + let mut frontier: Frontier = Frontier::empty(); for commitment in commitments.iter() { let cmx = MerkleHashOrchard(pallas::Base::from_repr(*commitment).unwrap()); frontier.append(cmx); diff --git a/tests/builder.rs b/tests/builder.rs index 8ce67e92a..0bde25dd6 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -1,5 +1,4 @@ -use bridgetree::BridgeTree; -use incrementalmerkletree::Hashable; +use incrementalmerkletree::{Hashable, Marking, Retention}; use orchard::{ builder::{Builder, BundleType}, bundle::{Authorized, Flags}, @@ -7,11 +6,12 @@ use orchard::{ keys::{FullViewingKey, PreparedIncomingViewingKey, Scope, SpendAuthorizingKey, SpendingKey}, note::ExtractedNoteCommitment, note_encryption::OrchardDomain, - tree::{MerkleHashOrchard, MerklePath}, + tree::MerkleHashOrchard, value::NoteValue, Bundle, }; use rand::rngs::OsRng; +use shardtree::{store::memory::MemoryShardStore, ShardTree}; use zcash_note_encryption::try_note_decryption; fn verify_bundle(bundle: &Bundle, vk: &VerifyingKey) { @@ -91,20 +91,26 @@ fn bundle_chain() { // Use the tree with a single leaf. let cmx: ExtractedNoteCommitment = note.commitment().into(); let leaf = MerkleHashOrchard::from_cmx(&cmx); - let mut tree = BridgeTree::::new(100); - tree.append(leaf); - let position = tree.mark().unwrap(); - let root = tree.root(0).unwrap(); - let auth_path = tree.witness(position, 0).unwrap(); - let merkle_path = MerklePath::from_parts( - u64::from(position).try_into().unwrap(), - auth_path[..].try_into().unwrap(), - ); - let anchor = root.into(); - assert_eq!(anchor, merkle_path.root(cmx)); + let mut tree: ShardTree, 32, 16> = + ShardTree::new(MemoryShardStore::empty(), 100); + tree.append( + leaf, + Retention::Checkpoint { + id: 0, + marking: Marking::Marked, + }, + ) + .unwrap(); + let root = tree.root_at_checkpoint_id(&0).unwrap().unwrap(); + let position = tree.max_leaf_position(None).unwrap().unwrap(); + let merkle_path = tree + .witness_at_checkpoint_id(position, &0) + .unwrap() + .unwrap(); + assert_eq!(root, merkle_path.root(MerkleHashOrchard::from_cmx(&cmx))); - let mut builder = Builder::new(BundleType::DEFAULT, anchor); - assert_eq!(builder.add_spend(fvk, note, merkle_path), Ok(())); + let mut builder = Builder::new(BundleType::DEFAULT, root.into()); + assert_eq!(builder.add_spend(fvk, note, merkle_path.into()), Ok(())); assert_eq!( builder.add_output(None, recipient, NoteValue::from_raw(5000), None), Ok(())