1use crate::store::{AppendableStore, Hashable, Store};
2pub use crate::tree::{
3 consistency::ConsistencyProof,
4 inclusion::AuditProof,
5 node::{Node, NodeKey},
6};
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9
10mod consistency;
11mod inclusion;
12mod node;
13
14pub(crate) type HashOutput = [u8; 32];
15
16#[derive(Clone, Debug, PartialEq, Eq, Error)]
17pub enum ProofGenerationError {
18 #[error("Index {index} not found in tree of size {tree_size}")]
19 InvalidIndex { tree_size: u64, index: u64 },
20
21 #[error("Invalid tree size {received} smaller than {expected}")]
22 InvalidTreeSize { expected: u64, received: u64 },
23
24 #[error("Failed to fetch key {0:?} from the store")]
25 KeyNotFound(NodeKey),
26}
27
28#[derive(Clone, Debug, PartialEq, Eq, Error)]
29pub enum ProofValidationError {
30 #[error("Found an unxexpected hash length (expected: {expected}, received: {received})")]
31 InvalidHashLength { expected: usize, received: usize },
32
33 #[error("Index {index} not found in tree of size {tree_size}")]
34 InvalidIndex { tree_size: u64, index: u64 },
35
36 #[error("Invalid tree size {received} smaller than {expected}")]
37 InvalidTreeSize { expected: u64, received: u64 },
38
39 #[error("Hash mismatch")]
40 HashMismatch,
41
42 #[error("Merkle path was too short")]
43 PathTooShort,
44
45 #[error("Merkle path was too long")]
46 PathTooLong,
47}
48
49#[derive(Debug, Clone)]
50
51pub struct Tree<N, L> {
52 nodes: N,
53 leafs: L,
54}
55
56impl<N, L> Tree<N, L> {
57 pub fn new(node_store: N, leaf_store: L) -> Self {
58 Self {
59 nodes: node_store,
60 leafs: leaf_store,
61 }
62 }
63
64 pub fn nodes(&self) -> &N {
65 &self.nodes
66 }
67}
68
69impl<N, L> Tree<N, L>
70where
71 N: Store<Key = NodeKey, Value = HashOutput>,
72 L: AppendableStore<Key = u64, Value: Hashable>,
73{
74 pub fn insert_entry(&self, entry: L::Value) {
75 let entry_hash = entry.hash();
76 let idx = self.leafs.append(entry);
77 let entry_key = NodeKey::leaf(idx);
78 self.nodes.insert(entry_key, entry_hash);
79
80 let end = idx + 1;
82 let mut diff = 2;
83
84 while end.is_multiple_of(diff) {
85 let start = end - diff;
86
87 let key = NodeKey { start, end };
88 let (left, right) = key.split();
89
90 let node = Node {
91 left: self.nodes.get(&left).unwrap(),
92 right: self.nodes.get(&right).unwrap(),
93 };
94
95 self.nodes.insert(key, node.hash());
96
97 diff <<= 1;
98 }
99 }
100
101 pub fn recompute_tree_head(&self) -> TreeHead {
102 let tree_size = self.leafs.len() as u64;
103 let mut current_key = NodeKey::full_range(tree_size);
104 let mut balanced_nodes = vec![];
105
106 while !current_key.is_balanced() {
107 let (left, right) = current_key.split();
108 assert!(left.is_balanced());
109 balanced_nodes.push(left);
110 current_key = right;
111 }
112
113 let mut current_node_hash = self.nodes.get(¤t_key).unwrap();
114 while let Some(left_key) = balanced_nodes.pop() {
115 let current_node = Node {
116 left: self.nodes.get(&left_key).unwrap(),
117 right: self.nodes.get(¤t_key).unwrap(),
118 };
119
120 current_key = left_key.merge(¤t_key).unwrap();
121 current_node_hash = current_node.hash();
122 self.nodes.insert(current_key.clone(), current_node_hash);
123 }
124
125 TreeHead {
126 tree_size,
127 head: current_node_hash,
128 }
129 }
130
131 pub fn get_latest_tree_head(&self) -> Option<TreeHead> {
132 let idx = self.leafs.len() as u64;
133 self.nodes
134 .get(&NodeKey::full_range(idx))
135 .map(|head| TreeHead {
136 tree_size: idx,
137 head,
138 })
139 }
140}
141
142#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
143pub struct TreeHead {
144 pub(crate) tree_size: u64,
145 pub(crate) head: HashOutput,
146}
147
148impl TreeHead {
149 pub fn tree_size(&self) -> u64 {
150 self.tree_size
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 use sha2::{Digest, Sha256};
158
159 impl Hashable for String {
160 fn hash(&self) -> HashOutput {
161 Sha256::digest(self.as_bytes()).into()
162 }
163 }
164
165 impl Hashable for HashOutput {
166 fn hash(&self) -> HashOutput {
167 Sha256::digest(self).into()
168 }
169 }
170}