Skip to content

Commit

Permalink
Merge pull request #35 from yangby-cryptape/pr/verify-incremental
Browse files Browse the repository at this point in the history
feat: verify a old root and all incremental items after it
  • Loading branch information
jjyr authored Jul 18, 2023
2 parents 8206b58 + 34a6cbb commit e68de73
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 1 deletion.
59 changes: 58 additions & 1 deletion src/mmr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
use crate::borrow::Cow;
use crate::collections::VecDeque;
use crate::helper::{get_peak_map, get_peaks, parent_offset, pos_height_in_tree, sibling_offset};
use crate::helper::{
get_peak_map, get_peaks, leaf_index_to_mmr_size, leaf_index_to_pos, parent_offset,
pos_height_in_tree, sibling_offset,
};
use crate::mmr_store::{MMRBatch, MMRStoreReadOps, MMRStoreWriteOps};
use crate::vec;
use crate::vec::Vec;
Expand Down Expand Up @@ -291,6 +294,60 @@ impl<T: Clone + PartialEq, M: Merge<Item = T>> MerkleProof<T, M> {
self.calculate_root(leaves)
.map(|calculated_root| calculated_root == root)
}

/// Verifies a old root and all incremental leaves.
///
/// If this method returns `true`, it means the following assertion are true:
/// - The old root could be generated in the history of the current MMR.
/// - All incremental leaves are on the current MMR.
/// - The MMR, which could generate the old root, appends all incremental leaves, becomes the
/// current MMR.
pub fn verify_incremental(&self, root: T, prev_root: T, incremental: Vec<T>) -> Result<bool> {
let current_leaves_count = get_peak_map(self.mmr_size);
if current_leaves_count <= incremental.len() as u64 {
return Err(Error::CorruptedProof);
}
// Test if previous root is correct.
let prev_leaves_count = current_leaves_count - incremental.len() as u64;
let prev_peaks_positions = {
let prev_index = prev_leaves_count - 1;
let prev_mmr_size = leaf_index_to_mmr_size(prev_index);
let prev_peaks_positions = get_peaks(prev_mmr_size);
if prev_peaks_positions.len() != self.proof.len() {
return Err(Error::CorruptedProof);
}
prev_peaks_positions
};
let current_peaks_positions = get_peaks(self.mmr_size);

let mut reverse_index = prev_peaks_positions.len() - 1;
for (i, position) in prev_peaks_positions.iter().enumerate() {
if *position < current_peaks_positions[i] {
reverse_index = i;
break;
}
}
let mut prev_peaks: Vec<_> = self.proof_items().to_vec();
let mut reverse_peaks = prev_peaks.split_off(reverse_index);
reverse_peaks.reverse();
prev_peaks.extend(reverse_peaks);

let calculated_prev_root = bagging_peaks_hashes::<T, M>(prev_peaks)?;
if calculated_prev_root != prev_root {
return Ok(false);
}

// Test if incremental leaves are correct.
let leaves = incremental
.into_iter()
.enumerate()
.map(|(index, leaf)| {
let pos = leaf_index_to_pos(prev_leaves_count + index as u64);
(pos, leaf)
})
.collect();
self.verify(root, leaves)
}
}

fn calculate_peak_root<'a, T: 'a, M: Merge<Item = T>, I: Iterator<Item = &'a T>>(
Expand Down
1 change: 1 addition & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod test_accumulate_headers;
mod test_helper;
mod test_incremental;
mod test_mmr;
mod test_sequence;

Expand Down
51 changes: 51 additions & 0 deletions src/tests/test_incremental.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use proptest::proptest;

use super::{MergeNumberHash, NumberHash};
use crate::util::{MemMMR, MemStore};

proptest! {
#[test]
fn test_incremental(start in 1u32..500, steps in 1usize..50, turns in 10usize..20) {
test_incremental_with_params(start, steps, turns);
}
}

fn test_incremental_with_params(start: u32, steps: usize, turns: usize) {
let store = MemStore::default();
let mut mmr = MemMMR::<_, MergeNumberHash>::new(0, &store);

let mut curr = 0;

let _positions: Vec<u64> = (0u32..start)
.map(|_| {
let pos = mmr.push(NumberHash::from(curr)).unwrap();
curr += 1;
pos
})
.collect();
mmr.commit().expect("commit changes");

for turn in 0..turns {
let prev_root = mmr.get_root().expect("get root");
let (positions, leaves) = (0..steps).fold(
(Vec::new(), Vec::new()),
|(mut positions, mut leaves), _| {
let leaf = NumberHash::from(curr);
let pos = mmr.push(leaf.clone()).unwrap();
curr += 1;
positions.push(pos);
leaves.push(leaf);
(positions, leaves)
},
);
mmr.commit().expect("commit changes");
let proof = mmr.gen_proof(positions).expect("gen proof");
let root = mmr.get_root().expect("get root");
let result = proof.verify_incremental(root, prev_root, leaves).unwrap();
assert!(
result,
"start: {}, steps: {}, turn: {}, curr: {}",
start, steps, turn, curr
);
}
}

0 comments on commit e68de73

Please sign in to comment.