1use super::{
11 internal::{
12 build_light_weight_tree_internal, MerkleNode, MerkleTreeIntoIter, MerkleTreeIter,
13 MerkleTreeProof,
14 },
15 AppendableMerkleTreeScheme, DigestAlgorithm, Element, ForgetableMerkleTreeScheme, Index,
16 LookupResult, MerkleProof, MerkleTreeScheme, NodeValue, ToTraversalPath,
17};
18use crate::{
19 errors::MerkleTreeError, impl_forgetable_merkle_tree_scheme, impl_merkle_tree_scheme,
20 VerificationResult,
21};
22use alloc::sync::Arc;
23use ark_std::{borrow::Borrow, fmt::Debug, marker::PhantomData, string::ToString, vec, vec::Vec};
24use num_bigint::BigUint;
25use num_traits::pow::pow;
26use serde::{Deserialize, Serialize};
27
28impl_merkle_tree_scheme!(LightWeightMerkleTree);
29impl_forgetable_merkle_tree_scheme!(LightWeightMerkleTree);
30
31impl<E, H, I, const ARITY: usize, T> LightWeightMerkleTree<E, H, I, ARITY, T>
32where
33 E: Element,
34 H: DigestAlgorithm<E, I, T>,
35 I: Index,
36 T: NodeValue,
37{
38 pub fn new(height: usize) -> Self {
40 Self {
41 root: Arc::new(MerkleNode::<E, I, T>::Empty),
42 height,
43 num_leaves: 0,
44 _phantom: PhantomData,
45 }
46 }
47}
48
49impl<E, H, const ARITY: usize, T> LightWeightMerkleTree<E, H, u64, ARITY, T>
50where
51 E: Element,
52 H: DigestAlgorithm<E, u64, T>,
53 T: NodeValue,
54{
55 pub fn from_elems(
61 height: Option<usize>,
62 elems: impl IntoIterator<Item = impl Borrow<E>>,
63 ) -> Result<Self, MerkleTreeError> {
64 let (root, height, num_leaves) =
65 build_light_weight_tree_internal::<E, H, ARITY, T>(height, elems)?;
66 Ok(Self {
67 root,
68 height,
69 num_leaves,
70 _phantom: PhantomData,
71 })
72 }
73}
74
75impl<E, H, const ARITY: usize, T> AppendableMerkleTreeScheme
76 for LightWeightMerkleTree<E, H, u64, ARITY, T>
77where
78 E: Element,
79 H: DigestAlgorithm<E, u64, T>,
80 T: NodeValue,
81{
82 fn push(&mut self, elem: impl Borrow<Self::Element>) -> Result<(), MerkleTreeError> {
83 <Self as AppendableMerkleTreeScheme>::extend(self, [elem])
84 }
85
86 fn extend(
87 &mut self,
88 elems: impl IntoIterator<Item = impl Borrow<Self::Element>>,
89 ) -> Result<(), MerkleTreeError> {
90 let mut iter = elems.into_iter().peekable();
91
92 let traversal_path =
93 ToTraversalPath::<ARITY>::to_traversal_path(&self.num_leaves, self.height);
94 let (root, num_inserted) = self.root.extend_and_forget_internal::<H, ARITY>(
95 self.height,
96 &self.num_leaves,
97 &traversal_path,
98 true,
99 &mut iter,
100 )?;
101 self.root = root;
102 self.num_leaves += num_inserted;
103 if iter.peek().is_some() {
104 return Err(MerkleTreeError::ExceedCapacity);
105 }
106 Ok(())
107 }
108}
109
110#[cfg(test)]
111mod mt_tests {
112 use crate::{
113 internal::MerkleNode,
114 prelude::{RescueLightWeightMerkleTree, RescueMerkleTree},
115 *,
116 };
117 use ark_bls12_377::Fr as Fr377;
118 use ark_bls12_381::Fr as Fr381;
119 use ark_bn254::Fr as Fr254;
120 use jf_rescue::RescueParameter;
121
122 #[test]
123 fn test_light_mt_builder() {
124 test_light_mt_builder_helper::<Fr254>();
125 test_light_mt_builder_helper::<Fr377>();
126 test_light_mt_builder_helper::<Fr381>();
127 }
128
129 fn test_light_mt_builder_helper<F: RescueParameter>() {
130 let arity: usize = RescueLightWeightMerkleTree::<F>::ARITY;
131 let mut data = vec![F::from(0u64); arity];
132 assert!(RescueLightWeightMerkleTree::<F>::from_elems(Some(1), &data).is_ok());
133 data.push(F::from(0u64));
134 assert!(RescueLightWeightMerkleTree::<F>::from_elems(Some(1), &data).is_err());
135 }
136
137 #[test]
138 fn test_light_mt_insertion() {
139 test_light_mt_insertion_helper::<Fr254>();
140 test_light_mt_insertion_helper::<Fr377>();
141 test_light_mt_insertion_helper::<Fr381>();
142 }
143
144 fn test_light_mt_insertion_helper<F: RescueParameter>() {
145 let mut mt = RescueLightWeightMerkleTree::<F>::new(2);
146 assert_eq!(mt.capacity(), BigUint::from(9u64));
147 assert!(mt.push(F::from(2u64)).is_ok());
148 assert!(mt.push(F::from(3u64)).is_ok());
149 assert!(mt.extend(&[F::from(0u64); 9]).is_err()); assert_eq!(mt.num_leaves(), 9); assert!(mt.push(F::from(0u64)).is_err());
154 assert!(mt.extend(&[]).is_ok());
155 assert!(mt.extend(&[F::from(1u64)]).is_err());
156
157 (0..8).for_each(|i| assert!(mt.lookup(i).expect_not_in_memory().is_ok()));
159 assert!(mt.lookup(8).expect_ok().is_ok());
160 }
161
162 #[test]
163 fn test_light_mt_lookup() {
164 test_light_mt_lookup_helper::<Fr254>();
165 test_light_mt_lookup_helper::<Fr377>();
166 test_light_mt_lookup_helper::<Fr381>();
167 }
168
169 fn test_light_mt_lookup_helper<F: RescueParameter>() {
170 let mt = RescueLightWeightMerkleTree::<F>::from_elems(None, [F::from(0u64)]).unwrap();
172 let (elem, _) = mt.lookup(0).expect_ok().unwrap();
173 assert_eq!(elem, &F::from(0u64));
174
175 let mut mt =
176 RescueLightWeightMerkleTree::<F>::from_elems(Some(2), [F::from(3u64), F::from(1u64)])
177 .unwrap();
178 let mut full_mt =
179 RescueMerkleTree::<F>::from_elems(Some(2), [F::from(3u64), F::from(1u64)]).unwrap();
180 assert!(mt.lookup(0).expect_not_in_memory().is_ok());
181 assert!(mt.lookup(1).expect_ok().is_ok());
182 assert!(mt.extend(&[F::from(33u64), F::from(41u64)]).is_ok());
183 assert!(full_mt.extend(&[F::from(33u64), F::from(41u64)]).is_ok());
184 assert!(mt.lookup(0).expect_not_in_memory().is_ok());
185 assert!(mt.lookup(1).expect_not_in_memory().is_ok());
186 assert!(mt.lookup(2).expect_not_in_memory().is_ok());
187 assert!(mt.lookup(3).expect_ok().is_ok());
188
189 assert_eq!(mt.commitment(), full_mt.commitment());
191
192 let commitment = mt.commitment();
193 let (elem, proof) = full_mt.lookup(0).expect_ok().unwrap();
194 assert_eq!(elem, &F::from(3u64));
195 assert!(
196 RescueLightWeightMerkleTree::<F>::verify(&commitment, 0, elem, &proof)
197 .unwrap()
198 .is_ok()
199 );
200
201 assert!(
203 RescueLightWeightMerkleTree::<F>::verify(&commitment, 0, F::from(14u64), &proof)
204 .unwrap()
205 .is_err()
206 );
207
208 assert!(
210 RescueLightWeightMerkleTree::<F>::verify(&commitment, 2, elem, &proof)
211 .unwrap()
212 .is_err()
213 );
214
215 let mut bad_proof = proof.clone();
216 bad_proof.0[0][0] = F::one();
217
218 assert!(
219 RescueLightWeightMerkleTree::<F>::verify(&commitment, 0, elem, &bad_proof)
220 .unwrap()
221 .is_err()
222 );
223 }
224
225 #[test]
226 fn test_light_mt_serde() {
227 test_light_mt_serde_helper::<Fr254>();
228 test_light_mt_serde_helper::<Fr377>();
229 test_light_mt_serde_helper::<Fr381>();
230 }
231
232 fn test_light_mt_serde_helper<F: RescueParameter>() {
233 let mt =
234 RescueLightWeightMerkleTree::<F>::from_elems(Some(2), [F::from(3u64), F::from(1u64)])
235 .unwrap();
236 let (_, proof) = mt.lookup(1).expect_ok().unwrap();
237
238 assert_eq!(
239 mt,
240 bincode::deserialize(&bincode::serialize(&mt).unwrap()).unwrap()
241 );
242 assert_eq!(
243 proof,
244 bincode::deserialize(&bincode::serialize(&proof).unwrap()).unwrap()
245 );
246 }
247}