light_concurrent_merkle_tree/
changelog.rs1use std::ops::{Deref, DerefMut};
2
3use light_bounded_vec::BoundedVec;
4
5use crate::errors::ConcurrentMerkleTreeError;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
8#[repr(transparent)]
9pub struct ChangelogPath<const HEIGHT: usize>(pub [Option<[u8; 32]>; HEIGHT]);
10
11impl<const HEIGHT: usize> ChangelogPath<HEIGHT> {
12 pub fn from_fn<F>(cb: F) -> Self
13 where
14 F: FnMut(usize) -> Option<[u8; 32]>,
15 {
16 Self(std::array::from_fn(cb))
17 }
18
19 pub fn eq_to(&self, other: BoundedVec<[u8; 32]>) -> bool {
29 if other.len() != HEIGHT {
30 return false;
31 }
32
33 for i in 0..HEIGHT {
34 let changelog_node = self.0[i];
35 let path_node = other[i];
36 match changelog_node {
37 Some(changelog_node) => {
38 if changelog_node != path_node {
39 return false;
40 }
41 }
42 None => break,
43 }
44 }
45
46 true
47 }
48
49 pub fn eq_to_vec(&self, other: Vec<[u8; 32]>) -> bool {
50 if other.len() != HEIGHT {
51 return false;
52 }
53
54 for (i, path_node) in other.iter().enumerate() {
55 let changelog_node = self.0[i];
56 match changelog_node {
57 Some(changelog_node) => {
58 if changelog_node != *path_node {
59 return false;
60 }
61 }
62 None => break,
63 }
64 }
65
66 true
67 }
68}
69
70impl<const HEIGHT: usize> Default for ChangelogPath<HEIGHT> {
71 fn default() -> Self {
72 Self([None; HEIGHT])
73 }
74}
75
76impl<const HEIGHT: usize> Deref for ChangelogPath<HEIGHT> {
77 type Target = [Option<[u8; 32]>; HEIGHT];
78
79 fn deref(&self) -> &Self::Target {
80 &self.0
81 }
82}
83
84impl<const HEIGHT: usize> DerefMut for ChangelogPath<HEIGHT> {
85 fn deref_mut(&mut self) -> &mut Self::Target {
86 &mut self.0
87 }
88}
89
90#[derive(Clone, Debug, PartialEq, Eq)]
91#[repr(C)]
92pub struct ChangelogEntry<const HEIGHT: usize> {
93 pub path: ChangelogPath<HEIGHT>,
95 pub index: u64,
97}
98
99pub type ChangelogEntry22 = ChangelogEntry<22>;
100pub type ChangelogEntry26 = ChangelogEntry<26>;
101pub type ChangelogEntry32 = ChangelogEntry<32>;
102pub type ChangelogEntry40 = ChangelogEntry<40>;
103
104impl<const HEIGHT: usize> ChangelogEntry<HEIGHT> {
105 pub fn new(path: ChangelogPath<HEIGHT>, index: usize) -> Self {
106 let index = index as u64;
107 Self { path, index }
108 }
109
110 pub fn default_with_index(index: usize) -> Self {
111 Self {
112 path: ChangelogPath::default(),
113 index: index as u64,
114 }
115 }
116
117 pub fn index(&self) -> usize {
118 self.index as usize
119 }
120
121 fn intersection_index(&self, leaf_index: usize) -> usize {
135 let padding = 64 - HEIGHT;
136 let common_path_len = ((leaf_index ^ self.index()) << padding).leading_zeros() as usize;
137 (HEIGHT - 1) - common_path_len
138 }
139
140 pub fn update_proof(
141 &self,
142 leaf_index: usize,
143 proof: &mut BoundedVec<[u8; 32]>,
144 ) -> Result<(), ConcurrentMerkleTreeError> {
145 if leaf_index != self.index() {
146 let intersection_index = self.intersection_index(leaf_index);
147 if let Some(node) = self.path[intersection_index] {
148 proof[intersection_index] = node;
149 }
150 } else {
151 return Err(ConcurrentMerkleTreeError::CannotUpdateLeaf);
156 }
157
158 Ok(())
159 }
160}