Skip to content

Commit 7bfc2ed

Browse files
feat!: Commit to leaf count when bagging peaks
Co-authored-by: sword-smith <thor@neptune.cash>
1 parent 01d0aa2 commit 7bfc2ed

File tree

4 files changed

+84
-126
lines changed

4 files changed

+84
-126
lines changed

twenty-first/src/mock/mmr/mock_mmr.rs

Lines changed: 41 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ use itertools::Itertools;
22

33
use crate::math::digest::Digest;
44
use crate::prelude::Tip5;
5+
use crate::util_types::mmr::mmr_accumulator::bag_peaks;
56
use crate::util_types::mmr::mmr_accumulator::MmrAccumulator;
67
use crate::util_types::mmr::mmr_membership_proof::MmrMembershipProof;
78
use crate::util_types::mmr::mmr_trait::LeafMutation;
89
use crate::util_types::mmr::mmr_trait::Mmr;
910
use crate::util_types::mmr::shared_advanced;
1011
use crate::util_types::mmr::shared_basic;
11-
use crate::util_types::shared::bag_peaks;
1212

1313
/// MockMmr is available for feature `mock` and for unit tests.
1414
///
@@ -29,14 +29,13 @@ use crate::util_types::shared::bag_peaks;
2929
/// wrapper to this data structure.
3030
#[derive(Debug, Clone)]
3131
pub struct MockMmr {
32-
digests: MyVec<Digest>,
32+
leafs: MyVec<Digest>,
3333
}
3434

3535
impl Mmr for MockMmr {
3636
/// Calculate the root for the entire MMR
3737
fn bag_peaks(&self) -> Digest {
38-
let peaks: Vec<Digest> = self.peaks();
39-
bag_peaks(&peaks)
38+
bag_peaks(&self.peaks(), self.num_leafs())
4039
}
4140

4241
/// Return the digests of the peaks of the MMR
@@ -49,7 +48,7 @@ impl Mmr for MockMmr {
4948
/// 1, the `digests` contain must always contain at least one
5049
/// element: a dummy digest.
5150
fn is_empty(&self) -> bool {
52-
self.digests.len() == 1
51+
self.leafs.len() == 1
5352
}
5453

5554
/// Return the number of leafs in the tree
@@ -68,7 +67,7 @@ impl Mmr for MockMmr {
6867
/// retrieving a membership proof for a leaf. And the archival and accumulator MMR share
6968
/// this interface.
7069
fn append(&mut self, new_leaf: Digest) -> MmrMembershipProof {
71-
let node_index = self.digests.len();
70+
let node_index = self.leafs.len();
7271
let leaf_index = shared_advanced::node_index_to_leaf_index(node_index).unwrap();
7372
self.append_raw(new_leaf);
7473
self.prove_membership(leaf_index)
@@ -149,7 +148,7 @@ impl MockMmr {
149148
/// Create a new MockMmr
150149
pub fn new(pv: Vec<Digest>) -> Self {
151150
let mut ret = Self {
152-
digests: MyVec::from(pv),
151+
leafs: MyVec::from(pv),
153152
};
154153
ret.fix_dummy();
155154
ret
@@ -161,47 +160,47 @@ impl MockMmr {
161160
/// this data structure can be set to the default vector, which
162161
/// is the empty vector. This method fixes that.
163162
pub fn fix_dummy(&mut self) {
164-
if self.digests.len() == 0 {
165-
self.digests.push(Digest::default());
163+
if self.leafs.len() == 0 {
164+
self.leafs.push(Digest::default());
166165
}
167166
}
168167

169168
/// Get a leaf from the MMR, will panic if index is out of range
170169
pub fn get_leaf(&self, leaf_index: u64) -> Digest {
171170
let node_index = shared_advanced::leaf_index_to_node_index(leaf_index);
172-
self.digests.get(node_index)
171+
self.leafs.get(node_index)
173172
}
174173

175174
/// Update a hash in the existing MockMmr
176175
pub fn mutate_leaf_raw(&mut self, leaf_index: u64, new_leaf: Digest) {
177176
// 1. change the leaf value
178177
let mut node_index = shared_advanced::leaf_index_to_node_index(leaf_index);
179-
self.digests.set(node_index, new_leaf);
178+
self.leafs.set(node_index, new_leaf);
180179

181180
// 2. Calculate hash changes for all parents
182181
let mut parent_index = shared_advanced::parent(node_index);
183182
let mut acc_hash = new_leaf;
184183

185184
// While parent exists in MMR, update parent
186-
while parent_index < self.digests.len() {
185+
while parent_index < self.leafs.len() {
187186
let (right_lineage_count, height) =
188187
shared_advanced::right_lineage_length_and_own_height(node_index);
189188
acc_hash = if right_lineage_count != 0 {
190189
// node is right child
191190
Tip5::hash_pair(
192-
self.digests
191+
self.leafs
193192
.get(shared_advanced::left_sibling(node_index, height)),
194193
acc_hash,
195194
)
196195
} else {
197196
// node is left child
198197
Tip5::hash_pair(
199198
acc_hash,
200-
self.digests
199+
self.leafs
201200
.get(shared_advanced::right_sibling(node_index, height)),
202201
)
203202
};
204-
self.digests.set(parent_index, acc_hash);
203+
self.leafs.set(parent_index, acc_hash);
205204
node_index = parent_index;
206205
parent_index = shared_advanced::parent(parent_index);
207206
}
@@ -221,7 +220,7 @@ impl MockMmr {
221220
let node_index = shared_advanced::leaf_index_to_node_index(leaf_index);
222221
let mut top_height: i32 = -1;
223222
let mut parent_index = node_index;
224-
while parent_index < self.digests.len() {
223+
while parent_index < self.leafs.len() {
225224
parent_index = shared_advanced::parent(parent_index);
226225
top_height += 1;
227226
}
@@ -235,14 +234,14 @@ impl MockMmr {
235234
if right_ancestor_count != 0 {
236235
// index is right child
237236
let left_sibling_index = shared_advanced::left_sibling(index, index_height);
238-
authentication_path.push(self.digests.get(left_sibling_index));
237+
authentication_path.push(self.leafs.get(left_sibling_index));
239238

240239
// parent of right child is index + 1
241240
index += 1;
242241
} else {
243242
// index is left child
244243
let right_sibling_index = shared_advanced::right_sibling(index, index_height);
245-
authentication_path.push(self.digests.get(right_sibling_index));
244+
authentication_path.push(self.leafs.get(right_sibling_index));
246245

247246
// parent of left child:
248247
index += 1 << (index_height + 1);
@@ -268,21 +267,21 @@ impl MockMmr {
268267
// 5. Take left child of sibling, continue until a node in tree is found
269268
let mut peaks_and_heights: Vec<(Digest, u32)> = vec![];
270269
let (mut top_peak, mut top_height) =
271-
shared_advanced::leftmost_ancestor(self.digests.len() - 1);
272-
if top_peak > self.digests.len() - 1 {
270+
shared_advanced::leftmost_ancestor(self.leafs.len() - 1);
271+
if top_peak > self.leafs.len() - 1 {
273272
top_peak = shared_basic::left_child(top_peak, top_height);
274273
top_height -= 1;
275274
}
276275

277-
peaks_and_heights.push((self.digests.get(top_peak), top_height));
276+
peaks_and_heights.push((self.leafs.get(top_peak), top_height));
278277
let mut height = top_height;
279278
let mut candidate = shared_advanced::right_sibling(top_peak, height);
280279
'outer: while height > 0 {
281-
'_inner: while candidate > self.digests.len() && height > 0 {
280+
'_inner: while candidate > self.leafs.len() && height > 0 {
282281
candidate = shared_basic::left_child(candidate, height);
283282
height -= 1;
284-
if candidate < self.digests.len() {
285-
peaks_and_heights.push((self.digests.get(candidate), height));
283+
if candidate < self.leafs.len() {
284+
peaks_and_heights.push((self.leafs.get(candidate), height));
286285
candidate = shared_advanced::right_sibling(candidate, height);
287286
continue 'outer;
288287
}
@@ -294,15 +293,15 @@ impl MockMmr {
294293

295294
/// Append an element to the MockMmr
296295
pub fn append_raw(&mut self, new_leaf: Digest) {
297-
let node_index = self.digests.len();
298-
self.digests.push(new_leaf);
296+
let node_index = self.leafs.len();
297+
self.leafs.push(new_leaf);
299298
let (right_parent_count, own_height) =
300299
shared_advanced::right_lineage_length_and_own_height(node_index);
301300

302301
// This function could be rewritten with a while-loop instead of being recursive.
303302
if right_parent_count != 0 {
304303
let left_sibling_hash = self
305-
.digests
304+
.leafs
306305
.get(shared_advanced::left_sibling(node_index, own_height));
307306
let parent_hash: Digest = Tip5::hash_pair(left_sibling_hash, new_leaf);
308307
self.append_raw(parent_hash);
@@ -315,11 +314,11 @@ impl MockMmr {
315314
return None;
316315
}
317316

318-
let node_index = self.digests.len() - 1;
319-
let mut ret = self.digests.pop().unwrap();
317+
let node_index = self.leafs.len() - 1;
318+
let mut ret = self.leafs.pop().unwrap();
320319
let (_, mut height) = shared_advanced::right_lineage_length_and_own_height(node_index);
321320
while height > 0 {
322-
ret = self.digests.pop().unwrap();
321+
ret = self.leafs.pop().unwrap();
323322
height -= 1;
324323
}
325324

@@ -367,55 +366,22 @@ impl<T: Clone> MyVec<T> {
367366
mod mmr_test {
368367
use itertools::*;
369368
use rand::random;
370-
use test_strategy::proptest;
371369

372370
use super::*;
373371
use crate::math::b_field_element::BFieldElement;
374372
use crate::math::other::*;
375373
use crate::math::tip5::Tip5;
376374
use crate::mock::mmr::*;
377-
use crate::util_types::merkle_tree::merkle_tree_test::MerkleTreeToTest;
378-
use crate::util_types::merkle_tree::*;
379375
use crate::util_types::mmr::mmr_accumulator::MmrAccumulator;
380-
use crate::util_types::mmr::shared_advanced::get_peak_heights;
381376
use crate::util_types::mmr::shared_advanced::get_peak_heights_and_peak_node_indices;
382377

383378
impl MockMmr {
384379
/// Return the number of nodes in all the trees in the MMR
385380
fn count_nodes(&mut self) -> u64 {
386-
self.digests.len() - 1
381+
self.leafs.len() - 1
387382
}
388383
}
389384

390-
/// Calculate a Merkle root from a list of digests of arbitrary length.
391-
pub fn root_from_arbitrary_number_of_digests(digests: &[Digest]) -> Digest {
392-
let mut trees = vec![];
393-
let mut num_processed_digests = 0;
394-
for tree_height in get_peak_heights(digests.len() as u64) {
395-
let num_leafs_in_tree = 1 << tree_height;
396-
let leaf_digests =
397-
&digests[num_processed_digests..num_processed_digests + num_leafs_in_tree];
398-
let tree = MerkleTree::par_new(leaf_digests).unwrap();
399-
num_processed_digests += num_leafs_in_tree;
400-
trees.push(tree);
401-
}
402-
let roots = trees.iter().map(|t| t.root()).collect_vec();
403-
bag_peaks(&roots)
404-
}
405-
406-
#[test]
407-
fn computing_mmr_root_for_no_leafs_produces_some_digest() {
408-
root_from_arbitrary_number_of_digests(&[]);
409-
}
410-
411-
#[proptest(cases = 30)]
412-
fn mmr_root_of_arbitrary_number_of_leafs_is_merkle_root_when_number_of_leafs_is_a_power_of_two(
413-
test_tree: MerkleTreeToTest,
414-
) {
415-
let root = root_from_arbitrary_number_of_digests(test_tree.tree.leafs());
416-
assert_eq!(test_tree.tree.root(), root);
417-
}
418-
419385
#[test]
420386
fn empty_mmr_behavior_test() {
421387
let mut archival_mmr: MockMmr = get_empty_mock_ammr();
@@ -428,8 +394,7 @@ mod mmr_test {
428394
assert_eq!(archival_mmr.bag_peaks(), accumulator_mmr.bag_peaks());
429395
assert_eq!(
430396
archival_mmr.bag_peaks(),
431-
root_from_arbitrary_number_of_digests(&[]),
432-
"Bagged peaks for empty MMR must agree with MT root finder"
397+
MmrAccumulator::new_from_leafs(vec![]).bag_peaks(),
433398
);
434399
assert_eq!(0, archival_mmr.count_nodes());
435400
assert!(accumulator_mmr.is_empty());
@@ -587,10 +552,10 @@ mod mmr_test {
587552
// modified MMR, and verify that the two MMRs are equivalent
588553

589554
let archival_mmr_new: MockMmr = get_mock_ammr_from_digests(leaf_hashes);
590-
assert_eq!(archival_mmr.digests.len(), archival_mmr_new.digests.len());
555+
assert_eq!(archival_mmr.leafs.len(), archival_mmr_new.leafs.len());
591556

592557
for i in 0..leaf_count {
593-
assert_eq!(archival_mmr.digests.get(i), archival_mmr_new.digests.get(i));
558+
assert_eq!(archival_mmr.leafs.get(i), archival_mmr_new.leafs.get(i));
594559
}
595560
}
596561

@@ -603,10 +568,8 @@ mod mmr_test {
603568
archival_mmr_small.bag_peaks(),
604569
accumulator_mmr_small.bag_peaks()
605570
);
606-
assert_eq!(
607-
archival_mmr_small.bag_peaks(),
608-
bag_peaks(&accumulator_mmr_small.peaks())
609-
);
571+
572+
// bagged peaks must never correspond to any peak
610573
assert!(!accumulator_mmr_small
611574
.peaks()
612575
.iter()
@@ -874,13 +837,9 @@ mod mmr_test {
874837
assert_eq!(peak_count, actual_peak_count);
875838

876839
// Verify that MMR root from odd number of digests and MMR bagged peaks agree
877-
let mmra_root = mmr.bag_peaks();
878-
let mt_root = root_from_arbitrary_number_of_digests(&input_hashes);
879-
880-
assert_eq!(
881-
mmra_root, mt_root,
882-
"MMRA bagged peaks and MT root must agree"
883-
);
840+
let mock_mmr_root = mmr.bag_peaks();
841+
let mmra_root = MmrAccumulator::new_from_leafs(input_hashes.clone()).bag_peaks();
842+
assert_eq!(mock_mmr_root, mmra_root);
884843

885844
// Get an authentication path for **all** values in MMR,
886845
// verify that it is valid
@@ -989,12 +948,9 @@ mod mmr_test {
989948
assert_eq!(peak_count, original_peaks_and_heights.len() as u64);
990949

991950
// Verify that MMR root from odd number of digests and MMR bagged peaks agree
992-
let mmra_root = mmr.bag_peaks();
993-
let mt_root = root_from_arbitrary_number_of_digests(&input_digests);
994-
assert_eq!(
995-
mmra_root, mt_root,
996-
"MMRA bagged peaks and MT root must agree"
997-
);
951+
let mock_mmr_root = mmr.bag_peaks();
952+
let mmra_root = MmrAccumulator::new_from_leafs(input_digests.clone()).bag_peaks();
953+
assert_eq!(mock_mmr_root, mmra_root);
998954

999955
// Get an authentication path for **all** values in MMR,
1000956
// verify that it is valid

twenty-first/src/util_types.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
pub mod merkle_tree;
22
pub mod mmr;
3-
pub mod shared;
43
pub mod sponge;

0 commit comments

Comments
 (0)