pessimistic_proof/local_exit_tree/
data.rs1use agglayer_primitives::{keccak::keccak256_combine, Digest};
2use agglayer_tries::utils::{empty_hash_array_at_height, empty_hash_at_height};
3use serde::{Deserialize, Serialize};
4use serde_with::serde_as;
5use unified_bridge::{LETMerkleProof, LocalExitTreeError};
6
7#[serde_as]
9#[derive(Clone, Debug, Serialize, Deserialize)]
10pub struct LocalExitTreeData<const TREE_DEPTH: usize = 32> {
11 #[serde_as(as = "[_; TREE_DEPTH]")]
20 pub layers: [Vec<Digest>; TREE_DEPTH],
21}
22
23impl<const TREE_DEPTH: usize> Default for LocalExitTreeData<TREE_DEPTH> {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl<const TREE_DEPTH: usize> LocalExitTreeData<TREE_DEPTH> {
30 const MAX_NUM_LEAVES: u32 = ((1u64 << TREE_DEPTH) - 1) as u32;
31
32 pub fn new() -> Self {
34 LocalExitTreeData {
35 layers: std::array::from_fn(|_| Vec::new()),
36 }
37 }
38
39 pub fn from_leaves(leaves: impl Iterator<Item = Digest>) -> Result<Self, LocalExitTreeError> {
41 let mut tree = Self::new();
42
43 for leaf in leaves {
44 tree.add_leaf(leaf)?;
45 }
46
47 Ok(tree)
48 }
49
50 pub fn add_leaf(&mut self, leaf: Digest) -> Result<u32, LocalExitTreeError> {
52 let leaf_index = self.layers[0].len();
53
54 if leaf_index >= Self::MAX_NUM_LEAVES as usize {
55 return Err(LocalExitTreeError::LeafIndexOverflow);
56 }
57 self.layers[0].push(leaf);
58 let mut index = leaf_index;
59 let mut entry = leaf;
60 for height in 0..TREE_DEPTH - 1 {
61 let sibling = self.get(height, index ^ 1)?;
62 entry = if index & 1 == 1 {
63 keccak256_combine([&sibling, &entry])
64 } else {
65 keccak256_combine([&entry, &sibling])
66 };
67 index >>= 1;
68 if index < self.layers[height + 1].len() {
69 self.layers[height + 1][index] = entry;
70 } else {
71 self.layers[height + 1].push(entry);
72 }
73 }
74
75 leaf_index
76 .try_into()
77 .map_err(|_| LocalExitTreeError::LeafIndexOverflow)
78 }
79
80 pub fn get(&self, height: usize, index: usize) -> Result<Digest, LocalExitTreeError> {
81 if index >= 1 << (TREE_DEPTH - height) {
82 return Err(LocalExitTreeError::IndexOutOfBounds);
83 }
84 Ok(*self.layers[height]
85 .get(index)
86 .unwrap_or(&empty_hash_array_at_height::<TREE_DEPTH>()[height]))
87 }
88
89 pub fn is_empty(&self) -> bool {
90 self.layers[0].is_empty()
91 }
92
93 pub fn get_root(&self) -> Digest {
95 let empty_hash = empty_hash_at_height::<TREE_DEPTH>();
96 let get_last_layer = |i| self.layers[TREE_DEPTH - 1].get(i).unwrap_or(&empty_hash);
97 keccak256_combine([get_last_layer(0), get_last_layer(1)])
98 }
99
100 pub fn get_proof(
101 &self,
102 leaf_index: u32,
103 ) -> Result<LETMerkleProof<TREE_DEPTH>, LocalExitTreeError> {
104 let leaf_index: usize = leaf_index
105 .try_into()
106 .map_err(|_| LocalExitTreeError::LeafIndexOverflow)?;
107 if leaf_index >= self.layers[0].len() {
108 return Err(LocalExitTreeError::IndexOutOfBounds);
109 }
110 let mut siblings = [Default::default(); TREE_DEPTH];
111 let mut index = leaf_index;
112
113 for (height, sibling) in siblings.iter_mut().enumerate().take(TREE_DEPTH) {
114 *sibling = self.get(height, index ^ 1)?;
115 index >>= 1;
116 }
117
118 Ok(LETMerkleProof { siblings })
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use rand::{random, rng, Rng};
125
126 use crate::local_exit_tree::{data::LocalExitTreeData, LocalExitTree, LocalExitTreeError};
127
128 const TREE_DEPTH: usize = 32;
129
130 fn compare_let_data_let_frontier(num_leaves: usize) {
131 let leaves = (0..num_leaves).map(|_| random()).collect::<Vec<_>>();
132 let local_exit_tree_frontier: LocalExitTree<TREE_DEPTH> =
133 LocalExitTree::from_leaves(leaves.iter().cloned()).unwrap();
134 let local_exit_tree_data: LocalExitTreeData<TREE_DEPTH> =
135 LocalExitTreeData::from_leaves(leaves.into_iter()).unwrap();
136 assert_eq!(
137 local_exit_tree_frontier.get_root(),
138 local_exit_tree_data.get_root()
139 );
140 }
141
142 #[test]
143 fn test_data_vs_frontier_empty() {
144 compare_let_data_let_frontier(0)
145 }
146
147 #[test]
148 fn test_data_vs_frontier_root() {
149 let num_leaves = rng().random_range(1..100.min(1 << TREE_DEPTH));
150 compare_let_data_let_frontier(num_leaves)
151 }
152
153 #[test]
154 fn test_data_vs_frontier_add_leaf() -> Result<(), LocalExitTreeError> {
155 let num_leaves = rng().random_range(1usize..100.min(1 << TREE_DEPTH));
156 let leaves = (0..num_leaves).map(|_| random()).collect::<Vec<_>>();
157 let mut local_exit_tree_data: LocalExitTreeData<TREE_DEPTH> =
158 LocalExitTreeData::from_leaves(leaves.into_iter())?;
159 let mut local_exit_tree_frontier: LocalExitTree<TREE_DEPTH> =
160 LocalExitTree::try_from(&local_exit_tree_data)?;
161 assert_eq!(
162 local_exit_tree_data.get_root(),
163 local_exit_tree_frontier.get_root()
164 );
165 let leaf = random();
166 local_exit_tree_data.add_leaf(leaf)?;
167 local_exit_tree_frontier.add_leaf(leaf)?;
168 assert_eq!(
169 local_exit_tree_data.get_root(),
170 local_exit_tree_frontier.get_root()
171 );
172 Ok(())
173 }
174
175 #[test]
176 fn test_merkle_proofs() {
177 let num_leaves = rng().random_range(1..=100.min(1 << TREE_DEPTH));
178 let leaves = (0..num_leaves).map(|_| random()).collect::<Vec<_>>();
179 let leaf_index = rng().random_range(0..num_leaves);
180 let leaf = leaves[leaf_index];
181 let local_exit_tree_data: LocalExitTreeData<TREE_DEPTH> =
182 LocalExitTreeData::from_leaves(leaves.into_iter()).unwrap();
183 let root = local_exit_tree_data.get_root();
184 let proof = local_exit_tree_data.get_proof(leaf_index as u32).unwrap();
185 assert!(proof.verify(leaf, leaf_index as u32, root));
186 }
187}