1use sha2::{Digest, Sha256};
7
8#[derive(Debug, thiserror::Error)]
10pub enum MerkleAccumulatorError {
11 #[error("Invalid accumulator proof")]
12 InvalidProof,
13 #[error("Hash mismatch")]
14 HashMismatch,
15 #[error("Empty accumulator")]
16 EmptyAccumulator,
17}
18
19pub type MerkleAccumulatorResult<T> = Result<T, MerkleAccumulatorError>;
21
22#[derive(Clone, Debug)]
24pub struct Leaf {
25 pub hash: [u8; 32],
27 pub index: u64,
29 pub data: Vec<u8>,
31}
32
33#[derive(Clone, Debug)]
35pub enum MerkleNode {
36 Leaf(Leaf),
38 Internal {
40 hash: [u8; 32],
41 left: Box<MerkleNode>,
42 right: Box<MerkleNode>,
43 },
44 Empty,
46}
47
48impl MerkleNode {
49 pub fn hash(&self) -> [u8; 32] {
51 match self {
52 MerkleNode::Leaf(leaf) => leaf.hash,
53 MerkleNode::Internal { hash, .. } => *hash,
54 MerkleNode::Empty => Self::empty_hash(),
55 }
56 }
57
58 pub fn empty_hash() -> [u8; 32] {
60 let digest = Sha256::digest(b"");
62 digest.into()
63 }
64
65 pub fn compute_internal_hash(left_hash: [u8; 32], right_hash: [u8; 32]) -> [u8; 32] {
67 let mut hasher = Sha256::new();
69 hasher.update(left_hash);
70 hasher.update(right_hash);
71 hasher.finalize().into()
72 }
73}
74
75#[derive(Clone, Debug)]
77pub struct MerkleAccumulator {
78 root: MerkleNode,
80 num_leaves: u64,
82}
83
84impl Default for MerkleAccumulator {
85 fn default() -> Self {
86 Self {
87 root: MerkleNode::Empty,
88 num_leaves: 0,
89 }
90 }
91}
92
93impl MerkleAccumulator {
94 pub fn new() -> Self {
96 Self {
97 root: MerkleNode::Empty,
98 num_leaves: 0,
99 }
100 }
101
102 pub fn from_leaves(leaves: &[[u8; 32]]) -> Self {
104 if leaves.is_empty() {
105 return Self::new();
106 }
107
108 let leaf_nodes: Vec<MerkleNode> = leaves
110 .iter()
111 .enumerate()
112 .map(|(i, &hash)| {
113 MerkleNode::Leaf(Leaf {
114 hash,
115 index: i as u64,
116 data: Vec::new(),
117 })
118 })
119 .collect();
120
121 let root = Self::build_tree(&leaf_nodes);
123
124 Self {
125 root,
126 num_leaves: leaves.len() as u64,
127 }
128 }
129
130 fn build_tree(nodes: &[MerkleNode]) -> MerkleNode {
132 if nodes.is_empty() {
133 return MerkleNode::Empty;
134 }
135
136 if nodes.len() == 1 {
137 return nodes[0].clone();
138 }
139
140 let mut current_level = nodes.to_vec();
142
143 while current_level.len() > 1 {
144 let mut next_level = Vec::new();
145
146 for i in (0..current_level.len()).step_by(2) {
147 let left = current_level[i].clone();
148 let right = if i + 1 < current_level.len() {
149 current_level[i + 1].clone()
150 } else {
151 current_level[i].clone()
153 };
154
155 let left_hash = left.hash();
156 let right_hash = right.hash();
157 let internal_hash = MerkleNode::compute_internal_hash(left_hash, right_hash);
158
159 next_level.push(MerkleNode::Internal {
160 hash: internal_hash,
161 left: Box::new(left),
162 right: Box::new(right),
163 });
164 }
165
166 current_level = next_level;
167 }
168
169 current_level[0].clone()
170 }
171
172 pub fn root_hash(&self) -> [u8; 32] {
174 self.root.hash()
175 }
176
177 pub fn num_leaves(&self) -> u64 {
179 self.num_leaves
180 }
181
182 pub fn verify_proof(&self, leaf_hash: [u8; 32], index: u64, proof: &[MerkleProofItem]) -> bool {
184 if proof.is_empty() {
185 return self.root_hash() == leaf_hash && self.num_leaves == 1;
187 }
188
189 let computed_root = Self::compute_root_from_leaf(leaf_hash, index, proof);
191 computed_root == self.root_hash()
192 }
193
194 fn compute_root_from_leaf(
196 leaf_hash: [u8; 32],
197 index: u64,
198 proof: &[MerkleProofItem],
199 ) -> [u8; 32] {
200 let mut current_hash = leaf_hash;
201 let mut _current_index = index;
202
203 for item in proof {
204 match item {
205 MerkleProofItem::Left { hash } => {
206 current_hash = MerkleNode::compute_internal_hash(*hash, current_hash);
208 }
209 MerkleProofItem::Right { hash } => {
210 current_hash = MerkleNode::compute_internal_hash(current_hash, *hash);
212 }
213 }
214 _current_index /= 2;
215 }
216
217 current_hash
218 }
219}
220
221#[derive(Clone, Debug)]
223pub enum MerkleProofItem {
224 Left { hash: [u8; 32] },
226 Right { hash: [u8; 32] },
228}
229
230#[derive(Clone, Debug)]
232pub struct StateProof {
233 pub address: [u8; 32],
235 pub resource_type: String,
237 pub exists: bool,
239 pub data: Option<Vec<u8>>,
241 pub accumulator_proof: Vec<MerkleProofItem>,
243 pub version: u64,
245 pub leaf_hash: [u8; 32],
247}
248
249impl StateProof {
250 pub fn new(
252 address: [u8; 32],
253 resource_type: String,
254 exists: bool,
255 data: Option<Vec<u8>>,
256 accumulator_proof: Vec<MerkleProofItem>,
257 version: u64,
258 leaf_hash: [u8; 32],
259 ) -> Self {
260 Self {
261 address,
262 resource_type,
263 exists,
264 data,
265 accumulator_proof,
266 version,
267 leaf_hash,
268 }
269 }
270
271 pub fn compute_leaf_hash(&self) -> [u8; 32] {
273 let mut hasher = Sha256::new();
274 hasher.update(b"APTOS::STATE::LEAF");
275 hasher.update(self.address);
276 hasher.update(self.resource_type.as_bytes());
277 if self.exists {
278 hasher.update(b"EXISTS");
279 if let Some(data) = &self.data {
280 hasher.update(data);
281 }
282 } else {
283 hasher.update(b"NOT_EXISTS");
284 }
285 hasher.finalize().into()
286 }
287
288 pub fn verify(&self, expected_root: [u8; 32]) -> bool {
290 let leaf_hash = self.compute_leaf_hash();
291
292 if leaf_hash != self.leaf_hash {
294 return false;
295 }
296
297 let computed_root = MerkleAccumulator::compute_root_from_leaf(
299 leaf_hash,
300 0, &self.accumulator_proof,
302 );
303
304 computed_root == expected_root
305 }
306}
307
308#[derive(Clone, Debug)]
310pub struct TransactionProof {
311 pub version: u64,
313 pub hash: [u8; 32],
315 pub state_change_hash: [u8; 32],
317 pub event_root_hash: [u8; 32],
319 pub state_checkpoint_hash: Option<[u8; 32]>,
321 pub epoch: u64,
323 pub round: u64,
325 pub ledger_proof: Vec<MerkleProofItem>,
327}
328
329impl TransactionProof {
330 #[allow(clippy::too_many_arguments)]
332 pub fn new(
333 version: u64,
334 hash: [u8; 32],
335 state_change_hash: [u8; 32],
336 event_root_hash: [u8; 32],
337 state_checkpoint_hash: Option<[u8; 32]>,
338 epoch: u64,
339 round: u64,
340 ledger_proof: Vec<MerkleProofItem>,
341 ) -> Self {
342 Self {
343 version,
344 hash,
345 state_change_hash,
346 event_root_hash,
347 state_checkpoint_hash,
348 epoch,
349 round,
350 ledger_proof,
351 }
352 }
353}
354
355#[derive(Clone, Debug)]
357pub struct EventProof {
358 pub hash: [u8; 32],
360 pub index: u64,
362 pub event_proof: Vec<MerkleProofItem>,
364}
365
366impl EventProof {
367 pub fn new(hash: [u8; 32], index: u64, event_proof: Vec<MerkleProofItem>) -> Self {
369 Self {
370 hash,
371 index,
372 event_proof,
373 }
374 }
375
376 pub fn verify(&self, event_root: [u8; 32]) -> bool {
378 let computed_root =
379 MerkleAccumulator::compute_root_from_leaf(self.hash, self.index, &self.event_proof);
380
381 computed_root == event_root
382 }
383}
384
385#[derive(Clone, Debug)]
387pub struct LedgerProof {
388 pub version: u64,
390 pub root_hash: [u8; 32],
392 pub chain_id: u64,
394 pub epoch: u64,
396 pub proof: Vec<MerkleProofItem>,
398}
399
400impl LedgerProof {
401 pub fn new(
403 version: u64,
404 root_hash: [u8; 32],
405 chain_id: u64,
406 epoch: u64,
407 proof: Vec<MerkleProofItem>,
408 ) -> Self {
409 Self {
410 version,
411 root_hash,
412 chain_id,
413 epoch,
414 proof,
415 }
416 }
417
418 pub fn verify(&self) -> bool {
420 self.root_hash != [0u8; 32]
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use super::*;
429
430 #[test]
431 fn test_merkle_accumulator_empty() {
432 let acc = MerkleAccumulator::new();
433 assert_eq!(acc.num_leaves(), 0);
434 assert_ne!(acc.root_hash(), [0u8; 32]); }
436
437 #[test]
438 fn test_merkle_accumulator_single_leaf() {
439 let leaves = [[1u8; 32]];
440 let acc = MerkleAccumulator::from_leaves(&leaves);
441 assert_eq!(acc.num_leaves(), 1);
442 assert_eq!(acc.root_hash(), leaves[0]);
443 }
444
445 #[test]
446 fn test_merkle_accumulator_two_leaves() {
447 let leaves = [[1u8; 32], [2u8; 32]];
448 let acc = MerkleAccumulator::from_leaves(&leaves);
449 assert_eq!(acc.num_leaves(), 2);
450 assert_ne!(acc.root_hash(), [0u8; 32]);
451 }
452
453 #[test]
454 fn test_merkle_node_compute_internal_hash() {
455 let left = [1u8; 32];
456 let right = [2u8; 32];
457 let hash = MerkleNode::compute_internal_hash(left, right);
458 assert_ne!(hash, [0u8; 32]);
459 }
460
461 #[test]
462 fn test_state_proof_leaf_hash() {
463 let proof = StateProof::new(
464 [1u8; 32],
465 "CSV::Seal".to_string(),
466 true,
467 Some(vec![1, 2, 3]),
468 vec![],
469 100,
470 [0u8; 32],
471 );
472 let hash = proof.compute_leaf_hash();
473 assert_eq!(hash.len(), 32);
474 }
475
476 #[test]
477 fn test_ledger_proof_verification() {
478 let proof = LedgerProof::new(100, [1u8; 32], 1, 1, vec![]);
479 assert!(proof.verify());
480 }
481}