diff --git a/CHANGELOG.md b/CHANGELOG.md index fc440977b..63e89e6e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to Rust's notion of ### Changed - MSRV is now 1.66 -- Migrated to `nonempty 0.11`. +- Migrated to `nonempty 0.11`, `incrementalmerkletree 0.8`, `shardtree 0.6`, `zip32 0.1.3`. ## [0.10.1] - 2024-12-16 @@ -31,6 +31,8 @@ and this project adheres to Rust's notion of - `ValueCommitTrapdoor::to_bytes` - `impl Clone for orchard::tree::MerklePath` +### Changed + ## [0.10.0] - 2024-10-02 ### Changed diff --git a/Cargo.lock b/Cargo.lock index 2d318a3e1..1b888d713 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" @@ -1122,9 +1113,8 @@ dependencies = [ [[package]] name = "incrementalmerkletree" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216c71634ac6f6ed13c2102d64354c0a04dcbdc30e31692c5972d3974d8b6d97" +version = "0.8.1" +source = "git+https://github.com/zcash/incrementalmerkletree?rev=3b21d2123edde31d6abfbce19db77fe923cdfaab#3b21d2123edde31d6abfbce19db77fe923cdfaab" dependencies = [ "either", "proptest", @@ -1451,7 +1441,6 @@ dependencies = [ "aes", "bitvec", "blake2b_simd", - "bridgetree", "core2", "criterion", "ff", @@ -1475,6 +1464,7 @@ dependencies = [ "rand", "reddsa", "serde", + "shardtree", "sinsemilla", "subtle", "tracing", @@ -2037,6 +2027,17 @@ dependencies = [ "serde", ] +[[package]] +name = "shardtree" +version = "0.6.0" +source = "git+https://github.com/zcash/incrementalmerkletree?rev=3b21d2123edde31d6abfbce19db77fe923cdfaab#3b21d2123edde31d6abfbce19db77fe923cdfaab" +dependencies = [ + "bitflags 2.4.0", + "either", + "incrementalmerkletree", + "tracing", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -2580,9 +2581,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", ] @@ -2609,13 +2610,14 @@ dependencies = [ [[package]] name = "zip32" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d724a63be4dfb50b7f3617e542984e22e4b4a5b8ca5de91f55613152885e6b22" +checksum = "2e9943793abf9060b68e1889012dafbd5523ab5b125c0fcc24802d69182f2ac9" dependencies = [ "blake2b_simd", "memuse", "subtle", + "zcash_spec", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 24b3388e5..67ec4977c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,9 +42,9 @@ serde = { version = "1.0", default-features = false, features = ["derive"] } sinsemilla = "0.1" subtle = { version = "2.3", default-features = false } zcash_note_encryption = "0.4" -incrementalmerkletree = { version = "0.7", default-features = false } +incrementalmerkletree = "0.8.1" zcash_spec = "0.1" -zip32 = { version = "0.1", default-features = false } +zip32 = { version = "0.1.3", default-features = false } visibility = "0.1.1" # Circuit @@ -65,13 +65,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.1", features = ["test-dependencies"] } +shardtree = "0.6" [target.'cfg(unix)'.dev-dependencies] inferno = { version = "0.11", default-features = false, features = ["multithreaded", "nameattr"] } @@ -106,3 +106,7 @@ debug = true [profile.bench] debug = true + +[patch.crates-io] +incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "3b21d2123edde31d6abfbce19db77fe923cdfaab" } +shardtree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "3b21d2123edde31d6abfbce19db77fe923cdfaab" } diff --git a/src/pczt.rs b/src/pczt.rs index 4381c7c3e..a7422ca39 100644 --- a/src/pczt.rs +++ b/src/pczt.rs @@ -332,10 +332,11 @@ impl 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}, @@ -344,7 +345,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, }; @@ -415,23 +416,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 57fdae308..dee5b3ac8 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -290,10 +290,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] @@ -304,31 +304,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() ); } } @@ -393,7 +404,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(())