arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/merkle/delta.rs
src/merkle/delta.rsRaw
  1use super::{
  2    BTreeMap, KvMap, MerkleError, MerkleStore, NodeIndex, RpoDigest, StoreNode, Vec, Word,
  3};
  4use crate::utils::collections::Diff;
  5
  6#[cfg(test)]
  7use super::{empty_roots::EMPTY_WORD, Felt, SimpleSmt};
  8
  9// MERKLE STORE DELTA
 10// ================================================================================================
 11
 12/// [MerkleStoreDelta] stores a vector of ([RpoDigest], [MerkleTreeDelta]) tuples where the
 13/// [RpoDigest] represents the root of the Merkle tree and [MerkleTreeDelta] represents the
 14/// differences between the initial and final Merkle tree states.
 15#[derive(Default, Debug, Clone, PartialEq, Eq)]
 16pub struct MerkleStoreDelta(pub Vec<(RpoDigest, MerkleTreeDelta)>);
 17
 18// MERKLE TREE DELTA
 19// ================================================================================================
 20
 21/// [MerkleDelta] stores the differences between the initial and final Merkle tree states.
 22///
 23/// The differences are represented as follows:
 24/// - depth: the depth of the merkle tree.
 25/// - cleared_slots: indexes of slots where values were set to [ZERO; 4].
 26/// - updated_slots: index-value pairs of slots where values were set to non [ZERO; 4] values.
 27#[cfg(not(test))]
 28#[derive(Debug, Clone, PartialEq, Eq)]
 29pub struct MerkleTreeDelta {
 30    depth: u8,
 31    cleared_slots: Vec<u64>,
 32    updated_slots: Vec<(u64, Word)>,
 33}
 34
 35impl MerkleTreeDelta {
 36    // CONSTRUCTOR
 37    // --------------------------------------------------------------------------------------------
 38    pub fn new(depth: u8) -> Self {
 39        Self {
 40            depth,
 41            cleared_slots: Vec::new(),
 42            updated_slots: Vec::new(),
 43        }
 44    }
 45
 46    // ACCESSORS
 47    // --------------------------------------------------------------------------------------------
 48    /// Returns the depth of the Merkle tree the [MerkleDelta] is associated with.
 49    pub fn depth(&self) -> u8 {
 50        self.depth
 51    }
 52
 53    /// Returns the indexes of slots where values were set to [ZERO; 4].
 54    pub fn cleared_slots(&self) -> &[u64] {
 55        &self.cleared_slots
 56    }
 57
 58    /// Returns the index-value pairs of slots where values were set to non [ZERO; 4] values.
 59    pub fn updated_slots(&self) -> &[(u64, Word)] {
 60        &self.updated_slots
 61    }
 62
 63    // MODIFIERS
 64    // --------------------------------------------------------------------------------------------
 65    /// Adds a slot index to the list of cleared slots.
 66    pub fn add_cleared_slot(&mut self, index: u64) {
 67        self.cleared_slots.push(index);
 68    }
 69
 70    /// Adds a slot index and a value to the list of updated slots.
 71    pub fn add_updated_slot(&mut self, index: u64, value: Word) {
 72        self.updated_slots.push((index, value));
 73    }
 74}
 75
 76/// Extracts a [MerkleDelta] object by comparing the leaves of two Merkle trees specifies by
 77/// their roots and depth.
 78pub fn merkle_tree_delta<T: KvMap<RpoDigest, StoreNode>>(
 79    tree_root_1: RpoDigest,
 80    tree_root_2: RpoDigest,
 81    depth: u8,
 82    merkle_store: &MerkleStore<T>,
 83) -> Result<MerkleTreeDelta, MerkleError> {
 84    if tree_root_1 == tree_root_2 {
 85        return Ok(MerkleTreeDelta::new(depth));
 86    }
 87
 88    let tree_1_leaves: BTreeMap<NodeIndex, RpoDigest> =
 89        merkle_store.non_empty_leaves(tree_root_1, depth).collect();
 90    let tree_2_leaves: BTreeMap<NodeIndex, RpoDigest> =
 91        merkle_store.non_empty_leaves(tree_root_2, depth).collect();
 92    let diff = tree_1_leaves.diff(&tree_2_leaves);
 93
 94    // TODO: Refactor this diff implementation to prevent allocation of both BTree and Vec.
 95    Ok(MerkleTreeDelta {
 96        depth,
 97        cleared_slots: diff.removed.into_iter().map(|index| index.value()).collect(),
 98        updated_slots: diff
 99            .updated
100            .into_iter()
101            .map(|(index, leaf)| (index.value(), *leaf))
102            .collect(),
103    })
104}
105
106// INTERNALS
107// --------------------------------------------------------------------------------------------
108#[cfg(test)]
109#[derive(Debug, Clone, PartialEq, Eq)]
110pub struct MerkleTreeDelta {
111    pub depth: u8,
112    pub cleared_slots: Vec<u64>,
113    pub updated_slots: Vec<(u64, Word)>,
114}
115
116// MERKLE DELTA
117// ================================================================================================
118#[test]
119fn test_compute_merkle_delta() {
120    let entries = vec![
121        (10, [Felt::new(0), Felt::new(1), Felt::new(2), Felt::new(3)]),
122        (15, [Felt::new(4), Felt::new(5), Felt::new(6), Felt::new(7)]),
123        (20, [Felt::new(8), Felt::new(9), Felt::new(10), Felt::new(11)]),
124        (31, [Felt::new(12), Felt::new(13), Felt::new(14), Felt::new(15)]),
125    ];
126    let simple_smt = SimpleSmt::with_leaves(30, entries.clone()).unwrap();
127    let mut store: MerkleStore = (&simple_smt).into();
128    let root = simple_smt.root();
129
130    // add a new node
131    let new_value = [Felt::new(16), Felt::new(17), Felt::new(18), Felt::new(19)];
132    let new_index = NodeIndex::new(simple_smt.depth(), 32).unwrap();
133    let root = store.set_node(root, new_index, new_value.into()).unwrap().root;
134
135    // update an existing node
136    let update_value = [Felt::new(20), Felt::new(21), Felt::new(22), Felt::new(23)];
137    let update_idx = NodeIndex::new(simple_smt.depth(), entries[0].0).unwrap();
138    let root = store.set_node(root, update_idx, update_value.into()).unwrap().root;
139
140    // remove a node
141    let remove_idx = NodeIndex::new(simple_smt.depth(), entries[1].0).unwrap();
142    let root = store.set_node(root, remove_idx, EMPTY_WORD.into()).unwrap().root;
143
144    let merkle_delta =
145        merkle_tree_delta(simple_smt.root(), root, simple_smt.depth(), &store).unwrap();
146    let expected_merkle_delta = MerkleTreeDelta {
147        depth: simple_smt.depth(),
148        cleared_slots: vec![remove_idx.value()],
149        updated_slots: vec![(update_idx.value(), update_value), (new_index.value(), new_value)],
150    };
151
152    assert_eq!(merkle_delta, expected_merkle_delta);
153}