mithril_stm/merkle_tree/
commitment.rs1use std::marker::PhantomData;
2
3use blake2::digest::{Digest, FixedOutput};
4use serde::{Deserialize, Serialize};
5
6use crate::error::MerkleTreeError;
7use crate::merkle_tree::{MerkleBatchPath, MerklePath, MerkleTreeLeaf, parent, sibling};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct MerkleTreeCommitment<D: Digest> {
14 pub root: Vec<u8>,
16 hasher: PhantomData<D>,
17}
18
19impl<D: Digest + FixedOutput> MerkleTreeCommitment<D> {
20 pub(crate) fn new(root: Vec<u8>) -> Self {
21 MerkleTreeCommitment {
22 root,
23 hasher: PhantomData,
24 }
25 }
26
27 pub(crate) fn verify_leaf_membership_from_path(
31 &self,
32 val: &MerkleTreeLeaf,
33 proof: &MerklePath<D>,
34 ) -> Result<(), MerkleTreeError<D>>
35 where
36 D: FixedOutput + Clone,
37 {
38 let mut idx = proof.index;
39
40 let mut h = D::digest(val.to_bytes()).to_vec();
41 for p in &proof.values {
42 if (idx & 0b1) == 0 {
43 h = D::new().chain_update(h).chain_update(p).finalize().to_vec();
44 } else {
45 h = D::new().chain_update(p).chain_update(h).finalize().to_vec();
46 }
47 idx >>= 1;
48 }
49
50 if h == self.root {
51 return Ok(());
52 }
53 Err(MerkleTreeError::PathInvalid(proof.clone()))
54 }
55
56 #[deprecated(
60 since = "0.5.0",
61 note = "Use `verify_leaf_membership_from_path` instead"
62 )]
63 pub fn check(
64 &self,
65 val: &MerkleTreeLeaf,
66 proof: &MerklePath<D>,
67 ) -> Result<(), MerkleTreeError<D>>
68 where
69 D: FixedOutput + Clone,
70 {
71 Self::verify_leaf_membership_from_path(self, val, proof)
72 }
73
74 fn concatenate_with_message(&self, msg: &[u8]) -> Vec<u8>
77 where
78 D: Digest,
79 {
80 let mut msgp = msg.to_vec();
81 let mut bytes = self.root.clone();
82 msgp.append(&mut bytes);
83
84 msgp
85 }
86
87 #[deprecated(since = "0.5.0", note = "Use `concatenate_with_message` instead")]
90 pub fn concat_with_msg(&self, msg: &[u8]) -> Vec<u8>
91 where
92 D: Digest,
93 {
94 Self::concatenate_with_message(self, msg)
95 }
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct MerkleTreeBatchCommitment<D: Digest> {
104 pub root: Vec<u8>,
106 nr_leaves: usize,
107 hasher: PhantomData<D>,
108}
109
110impl<D: Digest> MerkleTreeBatchCommitment<D> {
111 pub(crate) fn new(root: Vec<u8>, nr_leaves: usize) -> Self {
112 Self {
113 root,
114 nr_leaves,
115 hasher: Default::default(),
116 }
117 }
118
119 #[cfg(test)]
120 pub(crate) fn get_number_of_leaves(&self) -> usize {
122 self.nr_leaves
123 }
124
125 pub(crate) fn concatenate_with_message(&self, msg: &[u8]) -> Vec<u8> {
129 let mut msgp = msg.to_vec();
130 let mut bytes = self.root.clone();
131 msgp.append(&mut bytes);
132
133 msgp
134 }
135
136 #[deprecated(since = "0.5.0", note = "Use `concatenate_with_message` instead")]
140 pub fn concat_with_msg(&self, msg: &[u8]) -> Vec<u8> {
141 Self::concatenate_with_message(self, msg)
142 }
143
144 pub(crate) fn verify_leaves_membership_from_batch_path(
152 &self,
153 batch_val: &[MerkleTreeLeaf],
154 proof: &MerkleBatchPath<D>,
155 ) -> Result<(), MerkleTreeError<D>>
156 where
157 D: FixedOutput + Clone,
158 {
159 if batch_val.len() != proof.indices.len() {
160 return Err(MerkleTreeError::BatchPathInvalid(proof.clone()));
161 }
162 let mut ordered_indices: Vec<usize> = proof.indices.clone();
163 ordered_indices.sort_unstable();
164
165 if ordered_indices != proof.indices {
166 return Err(MerkleTreeError::BatchPathInvalid(proof.clone()));
167 }
168
169 let nr_nodes = self.nr_leaves + self.nr_leaves.next_power_of_two() - 1;
170
171 ordered_indices = ordered_indices
172 .into_iter()
173 .map(|i| i + self.nr_leaves.next_power_of_two() - 1)
174 .collect();
175
176 let mut idx = ordered_indices[0];
177 let mut leaves: Vec<Vec<u8>> = batch_val
179 .iter()
180 .map(|val| D::digest(val.to_bytes()).to_vec())
181 .collect();
182
183 let mut values = proof.values.clone();
184
185 while idx > 0 {
186 let mut new_hashes = Vec::with_capacity(ordered_indices.len());
187 let mut new_indices = Vec::with_capacity(ordered_indices.len());
188 let mut i = 0;
189 idx = parent(idx);
190 while i < ordered_indices.len() {
191 new_indices.push(parent(ordered_indices[i]));
192 if ordered_indices[i] & 1 == 0 {
193 new_hashes.push(
194 D::new()
195 .chain(values.first().ok_or(MerkleTreeError::SerializationError)?)
196 .chain(&leaves[i])
197 .finalize()
198 .to_vec(),
199 );
200 values.remove(0);
201 } else {
202 let sibling = sibling(ordered_indices[i]);
203 if i < ordered_indices.len() - 1 && ordered_indices[i + 1] == sibling {
204 new_hashes.push(
205 D::new().chain(&leaves[i]).chain(&leaves[i + 1]).finalize().to_vec(),
206 );
207 i += 1;
208 } else if sibling < nr_nodes {
209 new_hashes.push(
210 D::new()
211 .chain(&leaves[i])
212 .chain(values.first().ok_or(MerkleTreeError::SerializationError)?)
213 .finalize()
214 .to_vec(),
215 );
216 values.remove(0);
217 } else {
218 new_hashes.push(
219 D::new().chain(&leaves[i]).chain(D::digest([0u8])).finalize().to_vec(),
220 );
221 }
222 }
223 i += 1;
224 }
225 leaves.clone_from(&new_hashes);
226 ordered_indices.clone_from(&new_indices);
227 }
228
229 if leaves.len() == 1 && leaves[0] == self.root {
230 return Ok(());
231 }
232
233 Err(MerkleTreeError::BatchPathInvalid(proof.clone()))
234 }
235
236 #[deprecated(
244 since = "0.5.0",
245 note = "Use `verify_leaves_membership_from_batch_path` instead"
246 )]
247 pub fn check(
248 &self,
249 batch_val: &[MerkleTreeLeaf],
250 proof: &MerkleBatchPath<D>,
251 ) -> Result<(), MerkleTreeError<D>>
252 where
253 D: FixedOutput + Clone,
254 {
255 Self::verify_leaves_membership_from_batch_path(self, batch_val, proof)
256 }
257}
258
259impl<D: Digest> PartialEq for MerkleTreeBatchCommitment<D> {
260 fn eq(&self, other: &Self) -> bool {
261 self.root == other.root && self.nr_leaves == other.nr_leaves
262 }
263}
264
265impl<D: Digest> Eq for MerkleTreeBatchCommitment<D> {}