Merge branch 'main' into next
This commit is contained in:
commit
0514a8316a
6 changed files with 134 additions and 80 deletions
|
@ -1,20 +0,0 @@
|
|||
# Documentation available at editorconfig.org
|
||||
|
||||
root=true
|
||||
|
||||
[*]
|
||||
ident_style = space
|
||||
ident_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.rs]
|
||||
max_line_length = 100
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.yml]
|
||||
ident_size = 2
|
|
@ -1,34 +0,0 @@
|
|||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.6.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-json
|
||||
- id: check-toml
|
||||
- id: pretty-format-json
|
||||
- id: check-added-large-files
|
||||
- id: check-case-conflict
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-merge-conflict
|
||||
- id: detect-private-key
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: lint
|
||||
name: Make lint
|
||||
stages: [commit]
|
||||
language: rust
|
||||
entry: make lint
|
||||
- id: doc
|
||||
name: Make doc
|
||||
stages: [commit]
|
||||
language: rust
|
||||
entry: make doc
|
||||
- id: check
|
||||
name: Make check
|
||||
stages: [commit]
|
||||
language: rust
|
||||
entry: make check
|
|
@ -7,9 +7,10 @@
|
|||
- [BREAKING] Updated Winterfell dependency to v0.12 (#374).
|
||||
- Added debug-only duplicate column check in `build_subtree` (#378).
|
||||
|
||||
## 0.13.3 (2025-02-12)
|
||||
## 0.13.3 (2025-02-18)
|
||||
|
||||
- Implement `PartialSmt` (#372).
|
||||
- Implement `PartialSmt` (#372, #381).
|
||||
- Fix panic in `PartialMmr::untrack` (#382).
|
||||
|
||||
## 0.13.2 (2025-01-24)
|
||||
|
||||
|
|
33
Cargo.lock
generated
33
Cargo.lock
generated
|
@ -120,9 +120,9 @@ checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
|||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.5.5"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e"
|
||||
checksum = "1230237285e3e10cde447185e8975408ae24deaa67205ce684805c25bc0c7937"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
|
@ -160,9 +160,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.12"
|
||||
version = "1.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "755717a7de9ec452bf7f3f1a3099085deabd7f2962b861dae91ecd7a365903d2"
|
||||
checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
|
@ -204,9 +204,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.28"
|
||||
version = "4.5.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff"
|
||||
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -214,9 +214,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.27"
|
||||
version = "4.5.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
|
||||
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -972,9 +972,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.16.0"
|
||||
version = "3.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
|
||||
checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
|
@ -1016,9 +1016,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||
|
||||
[[package]]
|
||||
name = "unarray"
|
||||
|
@ -1275,6 +1275,15 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
|
|
|
@ -341,16 +341,13 @@ impl PartialMmr {
|
|||
pub fn untrack(&mut self, leaf_pos: usize) {
|
||||
let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
|
||||
|
||||
self.nodes.remove(&idx.sibling());
|
||||
|
||||
// `idx` represent the element that can be computed by the authentication path, because
|
||||
// these elements can be computed they are not saved for the authentication of the current
|
||||
// target. In other words, if the idx is present it was added for the authentication of
|
||||
// another element, and no more elements should be removed otherwise it would remove that
|
||||
// element's authentication data.
|
||||
while !self.nodes.contains_key(&idx) {
|
||||
while self.nodes.remove(&idx.sibling()).is_some() && !self.nodes.contains_key(&idx) {
|
||||
idx = idx.parent();
|
||||
self.nodes.remove(&idx.sibling());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -949,4 +946,32 @@ mod tests {
|
|||
|
||||
assert_eq!(partial_mmr, decoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_partial_mmr_untrack() {
|
||||
// build the MMR
|
||||
let mmr: Mmr = LEAVES.into();
|
||||
|
||||
// get path and node for position 1
|
||||
let node1 = mmr.get(1).unwrap();
|
||||
let proof1 = mmr.open(1).unwrap();
|
||||
|
||||
// get path and node for position 2
|
||||
let node2 = mmr.get(2).unwrap();
|
||||
let proof2 = mmr.open(2).unwrap();
|
||||
|
||||
// create partial MMR and add authentication path to nodes at position 1 and 2
|
||||
let mut partial_mmr: PartialMmr = mmr.peaks().into();
|
||||
partial_mmr.track(1, node1, &proof1.merkle_path).unwrap();
|
||||
partial_mmr.track(2, node2, &proof2.merkle_path).unwrap();
|
||||
|
||||
// untrack nodes at positions 1 and 2
|
||||
partial_mmr.untrack(1);
|
||||
partial_mmr.untrack(2);
|
||||
|
||||
// nodes should not longer be tracked
|
||||
assert!(!partial_mmr.is_tracked(1));
|
||||
assert!(!partial_mmr.is_tracked(2));
|
||||
assert_eq!(partial_mmr.nodes().count(), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,17 +138,25 @@ impl PartialSmt {
|
|||
Ok(previous_value)
|
||||
}
|
||||
|
||||
/// Adds a leaf and its merkle path to this [`PartialSmt`] and returns the value that
|
||||
/// was previously present at this key, if any.
|
||||
/// Adds an [`SmtProof`] to this [`PartialSmt`].
|
||||
///
|
||||
/// If this function was called, the `key` can subsequently be updated to a new value and
|
||||
/// produce a correct new tree root.
|
||||
/// This is a convenience method which calls [`Self::add_path`] on the proof. See its
|
||||
/// documentation for details on errors.
|
||||
pub fn add_proof(&mut self, proof: SmtProof) -> Result<(), MerkleError> {
|
||||
let (path, leaf) = proof.into_parts();
|
||||
self.add_path(leaf, path)
|
||||
}
|
||||
|
||||
/// Adds a leaf and its merkle path to this [`PartialSmt`].
|
||||
///
|
||||
/// If this function was called, any key that is part of the `leaf` can subsequently be updated
|
||||
/// to a new value and produce a correct new tree root.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if:
|
||||
/// - the new root after the insertion of the leaf and the path does not match the existing root
|
||||
/// (except if the tree was previously empty). If an error is returned, the tree is left in an
|
||||
/// (except when the first leaf is added). If an error is returned, the tree is left in an
|
||||
/// inconsistent state.
|
||||
pub fn add_path(&mut self, leaf: SmtLeaf, path: MerklePath) -> Result<(), MerkleError> {
|
||||
let mut current_index = leaf.index().index;
|
||||
|
@ -193,9 +201,10 @@ impl PartialSmt {
|
|||
|
||||
// Check the newly added merkle path is consistent with the existing tree. If not, the
|
||||
// merkle path was invalid or computed from another tree.
|
||||
// We skip this check if the root is empty since this indicates we're adding the first
|
||||
// merkle path in which case we have to update the tree root to the root from the path.
|
||||
if self.root() != Smt::EMPTY_ROOT && self.root() != node_hash_at_current_index {
|
||||
//
|
||||
// We skip this check if we have just inserted the first leaf since we assume that leaf's
|
||||
// root is correct and all subsequent leaves that will be added must have the same root.
|
||||
if self.0.num_leaves() != 1 && self.root() != node_hash_at_current_index {
|
||||
return Err(MerkleError::ConflictingRoots {
|
||||
expected_root: self.root(),
|
||||
actual_root: node_hash_at_current_index,
|
||||
|
@ -358,4 +367,68 @@ mod tests {
|
|||
assert_eq!(partial.get_leaf(&key1).unwrap(), full.get_leaf(&key1));
|
||||
assert_eq!(partial.get_leaf(&key2).unwrap(), full.get_leaf(&key2));
|
||||
}
|
||||
|
||||
/// Tests that adding proofs to a partial SMT whose roots are not the same will result in an
|
||||
/// error.
|
||||
///
|
||||
/// This test uses only empty values in the partial SMT.
|
||||
#[test]
|
||||
fn partial_smt_root_mismatch_on_empty_values() {
|
||||
let key0 = RpoDigest::from(Word::from(rand_array()));
|
||||
let key1 = RpoDigest::from(Word::from(rand_array()));
|
||||
let key2 = RpoDigest::from(Word::from(rand_array()));
|
||||
|
||||
let value0 = EMPTY_WORD;
|
||||
let value1 = Word::from(rand_array());
|
||||
let value2 = EMPTY_WORD;
|
||||
|
||||
let kv_pairs = vec![(key0, value0)];
|
||||
|
||||
let mut full = Smt::with_entries(kv_pairs).unwrap();
|
||||
// This proof will be stale after we insert another value.
|
||||
let stale_proof0 = full.open(&key0);
|
||||
|
||||
// Insert a non-empty value so the root actually changes.
|
||||
full.insert(key1, value1);
|
||||
full.insert(key2, value2);
|
||||
|
||||
let proof2 = full.open(&key2);
|
||||
|
||||
let mut partial = PartialSmt::new();
|
||||
|
||||
partial.add_proof(stale_proof0).unwrap();
|
||||
let err = partial.add_proof(proof2).unwrap_err();
|
||||
assert_matches!(err, MerkleError::ConflictingRoots { .. });
|
||||
}
|
||||
|
||||
/// Tests that adding proofs to a partial SMT whose roots are not the same will result in an
|
||||
/// error.
|
||||
///
|
||||
/// This test uses only non-empty values in the partial SMT.
|
||||
#[test]
|
||||
fn partial_smt_root_mismatch_on_non_empty_values() {
|
||||
let key0 = RpoDigest::from(Word::from(rand_array()));
|
||||
let key1 = RpoDigest::from(Word::from(rand_array()));
|
||||
let key2 = RpoDigest::from(Word::from(rand_array()));
|
||||
|
||||
let value0 = Word::from(rand_array());
|
||||
let value1 = Word::from(rand_array());
|
||||
let value2 = Word::from(rand_array());
|
||||
|
||||
let kv_pairs = vec![(key0, value0), (key1, value1)];
|
||||
|
||||
let mut full = Smt::with_entries(kv_pairs).unwrap();
|
||||
// This proof will be stale after we insert another value.
|
||||
let stale_proof0 = full.open(&key0);
|
||||
|
||||
full.insert(key2, value2);
|
||||
|
||||
let proof2 = full.open(&key2);
|
||||
|
||||
let mut partial = PartialSmt::new();
|
||||
|
||||
partial.add_proof(stale_proof0).unwrap();
|
||||
let err = partial.add_proof(proof2).unwrap_err();
|
||||
assert_matches!(err, MerkleError::ConflictingRoots { .. });
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue