miden_protocol/block/nullifier_tree/
mod.rs1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use crate::block::BlockNumber;
5use crate::crypto::merkle::MerkleError;
6use crate::crypto::merkle::smt::{MutationSet, SMT_DEPTH, Smt};
7use crate::errors::NullifierTreeError;
8use crate::note::Nullifier;
9use crate::utils::serde::{
10 ByteReader,
11 ByteWriter,
12 Deserializable,
13 DeserializationError,
14 Serializable,
15};
16use crate::{Felt, Word};
17
18mod backend;
19pub use backend::NullifierTreeBackend;
20
21mod witness;
22pub use witness::NullifierWitness;
23
24mod partial;
25pub use partial::PartialNullifierTree;
26
27#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct NullifierTree<Backend = Smt> {
40 smt: Backend,
41}
42
43impl<Backend> Default for NullifierTree<Backend>
44where
45 Backend: Default,
46{
47 fn default() -> Self {
48 Self { smt: Default::default() }
49 }
50}
51
52impl<Backend> NullifierTree<Backend>
53where
54 Backend: NullifierTreeBackend<Error = MerkleError>,
55{
56 pub const DEPTH: u8 = SMT_DEPTH;
61
62 pub fn new_unchecked(backend: Backend) -> Self {
71 NullifierTree { smt: backend }
72 }
73
74 pub fn root(&self) -> Word {
79 self.smt.root()
80 }
81
82 pub fn num_nullifiers(&self) -> usize {
84 self.smt.num_entries()
85 }
86
87 pub fn entries(&self) -> impl Iterator<Item = (Nullifier, BlockNumber)> {
89 self.smt.entries().map(|(nullifier, value)| {
90 (
91 Nullifier::from_raw(nullifier),
92 NullifierBlock::new(value)
93 .expect("SMT should only store valid NullifierBlocks")
94 .into(),
95 )
96 })
97 }
98
99 pub fn open(&self, nullifier: &Nullifier) -> NullifierWitness {
106 NullifierWitness::new(self.smt.open(&nullifier.as_word()))
107 }
108
109 pub fn get_block_num(&self, nullifier: &Nullifier) -> Option<BlockNumber> {
112 let nullifier_block = self.smt.get_value(&nullifier.as_word());
113 if nullifier_block.is_unspent() {
114 return None;
115 }
116
117 Some(nullifier_block.into())
118 }
119
120 pub fn compute_mutations<I>(
129 &self,
130 nullifiers: impl IntoIterator<Item = (Nullifier, BlockNumber), IntoIter = I>,
131 ) -> Result<NullifierMutationSet, NullifierTreeError>
132 where
133 I: Iterator<Item = (Nullifier, BlockNumber)> + Clone,
134 {
135 let nullifiers = nullifiers.into_iter();
136 for (nullifier, _) in nullifiers.clone() {
137 if self.get_block_num(&nullifier).is_some() {
138 return Err(NullifierTreeError::NullifierAlreadySpent(nullifier));
139 }
140 }
141
142 let mutation_set = self
143 .smt
144 .compute_mutations(
145 nullifiers
146 .into_iter()
147 .map(|(nullifier, block_num)| {
148 (nullifier.as_word(), NullifierBlock::from(block_num).into())
149 })
150 .collect::<Vec<_>>(),
151 )
152 .map_err(NullifierTreeError::ComputeMutations)?;
153
154 Ok(NullifierMutationSet::new(mutation_set))
155 }
156
157 pub fn mark_spent(
167 &mut self,
168 nullifier: Nullifier,
169 block_num: BlockNumber,
170 ) -> Result<(), NullifierTreeError> {
171 let prev_nullifier_value = self
172 .smt
173 .insert(nullifier.as_word(), NullifierBlock::from(block_num))
174 .map_err(NullifierTreeError::MaxLeafEntriesExceeded)?;
175
176 if prev_nullifier_value.is_spent() {
177 Err(NullifierTreeError::NullifierAlreadySpent(nullifier))
178 } else {
179 Ok(())
180 }
181 }
182
183 pub fn apply_mutations(
190 &mut self,
191 mutations: NullifierMutationSet,
192 ) -> Result<(), NullifierTreeError> {
193 self.smt
194 .apply_mutations(mutations.into_mutation_set())
195 .map_err(NullifierTreeError::TreeRootConflict)
196 }
197}
198
199impl Serializable for NullifierTree {
203 fn write_into<W: ByteWriter>(&self, target: &mut W) {
204 self.entries().collect::<Vec<_>>().write_into(target);
205 }
206}
207
208impl Deserializable for NullifierTree {
209 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
210 let entries = Vec::<(Nullifier, BlockNumber)>::read_from(source)?;
211 Self::with_entries(entries)
212 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
213 }
214}
215
216#[derive(Debug, Clone, PartialEq, Eq)]
227pub struct NullifierMutationSet {
228 mutation_set: MutationSet<SMT_DEPTH, Word, Word>,
229}
230
231impl NullifierMutationSet {
232 fn new(mutation_set: MutationSet<SMT_DEPTH, Word, Word>) -> Self {
237 Self { mutation_set }
238 }
239
240 pub fn as_mutation_set(&self) -> &MutationSet<SMT_DEPTH, Word, Word> {
245 &self.mutation_set
246 }
247
248 pub fn into_mutation_set(self) -> MutationSet<SMT_DEPTH, Word, Word> {
253 self.mutation_set
254 }
255}
256
257#[derive(Debug, PartialEq, Eq, Copy, Clone)]
271pub struct NullifierBlock(BlockNumber);
272
273impl NullifierBlock {
274 pub const UNSPENT: NullifierBlock = NullifierBlock(BlockNumber::GENESIS);
275
276 pub fn new(word: Word) -> Result<Self, NullifierTreeError> {
283 let block_num = u32::try_from(word[0].as_canonical_u64())
284 .map(BlockNumber::from)
285 .map_err(|_| NullifierTreeError::InvalidNullifierBlockNumber(word))?;
286
287 if word[1..4].iter().any(|felt| *felt != Felt::ZERO) {
288 return Err(NullifierTreeError::InvalidNullifierBlockNumber(word));
289 }
290
291 Ok(NullifierBlock(block_num))
292 }
293
294 pub fn is_spent(&self) -> bool {
296 !self.is_unspent()
297 }
298
299 pub fn is_unspent(&self) -> bool {
301 self == &Self::UNSPENT
302 }
303}
304
305impl From<BlockNumber> for NullifierBlock {
306 fn from(block_num: BlockNumber) -> Self {
307 Self(block_num)
308 }
309}
310
311impl From<NullifierBlock> for BlockNumber {
312 fn from(value: NullifierBlock) -> BlockNumber {
313 value.0
314 }
315}
316
317impl From<NullifierBlock> for Word {
318 fn from(value: NullifierBlock) -> Word {
319 Word::from([Felt::from(value.0), Felt::ZERO, Felt::ZERO, Felt::ZERO])
320 }
321}
322
323impl TryFrom<Word> for NullifierBlock {
324 type Error = NullifierTreeError;
325
326 fn try_from(value: Word) -> Result<Self, Self::Error> {
327 Self::new(value)
328 }
329}
330
331#[cfg(test)]
335mod tests {
336 use assert_matches::assert_matches;
337
338 use super::NullifierTree;
339 use crate::Word;
340 use crate::block::BlockNumber;
341 use crate::block::nullifier_tree::NullifierBlock;
342 use crate::errors::NullifierTreeError;
343 use crate::note::Nullifier;
344
345 #[test]
346 fn leaf_value_encode_decode() {
347 let block_num = BlockNumber::from(0xffff_ffff_u32);
348 let nullifier_block = NullifierBlock::from(block_num);
349 let block_num_recovered = nullifier_block.into();
350 assert_eq!(block_num, block_num_recovered);
351 }
352
353 #[test]
354 fn leaf_value_encoding() {
355 let block_num = BlockNumber::from(123);
356 let nullifier_value = NullifierBlock::from(block_num);
357 assert_eq!(
358 nullifier_value,
359 NullifierBlock::new(Word::from([block_num.as_u32(), 0, 0, 0u32])).unwrap()
360 );
361 }
362
363 #[test]
364 fn leaf_value_decoding() {
365 let block_num = 123;
366 let nullifier_value = NullifierBlock::new(Word::from([block_num, 0, 0, 0u32])).unwrap();
367 let decoded_block_num: BlockNumber = nullifier_value.into();
368
369 assert_eq!(decoded_block_num, block_num.into());
370 }
371
372 #[test]
373 fn apply_mutations() {
374 let nullifier1 = Nullifier::dummy(1);
375 let nullifier2 = Nullifier::dummy(2);
376 let nullifier3 = Nullifier::dummy(3);
377
378 let block1 = BlockNumber::from(1);
379 let block2 = BlockNumber::from(2);
380 let block3 = BlockNumber::from(3);
381
382 let mut tree = NullifierTree::with_entries([(nullifier1, block1)]).unwrap();
383
384 let mutations =
385 tree.compute_mutations([(nullifier2, block2), (nullifier3, block3)]).unwrap();
386
387 tree.apply_mutations(mutations).unwrap();
388
389 assert_eq!(tree.num_nullifiers(), 3);
390 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
391 assert_eq!(tree.get_block_num(&nullifier2).unwrap(), block2);
392 assert_eq!(tree.get_block_num(&nullifier3).unwrap(), block3);
393 }
394
395 #[test]
396 fn nullifier_already_spent() {
397 let nullifier1 = Nullifier::dummy(1);
398
399 let block1 = BlockNumber::from(1);
400 let block2 = BlockNumber::from(2);
401
402 let mut tree = NullifierTree::with_entries([(nullifier1, block1)]).unwrap();
403
404 let err = tree.clone().compute_mutations([(nullifier1, block1)]).unwrap_err();
406 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
407
408 let err = tree.clone().mark_spent(nullifier1, block1).unwrap_err();
409 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
410
411 let err = tree.clone().compute_mutations([(nullifier1, block2)]).unwrap_err();
413 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
414
415 let err = tree.mark_spent(nullifier1, block2).unwrap_err();
416 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
417 }
418
419 #[cfg(feature = "std")]
420 #[test]
421 fn large_smt_backend_basic_operations() {
422 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
423
424 let nullifier1 = Nullifier::dummy(1);
426 let nullifier2 = Nullifier::dummy(2);
427 let nullifier3 = Nullifier::dummy(3);
428
429 let block1 = BlockNumber::from(1);
430 let block2 = BlockNumber::from(2);
431 let block3 = BlockNumber::from(3);
432
433 let mut tree = NullifierTree::new_unchecked(
435 LargeSmt::with_entries(
436 MemoryStorage::default(),
437 [
438 (nullifier1.as_word(), NullifierBlock::from(block1).into()),
439 (nullifier2.as_word(), NullifierBlock::from(block2).into()),
440 ],
441 )
442 .unwrap(),
443 );
444
445 assert_eq!(tree.num_nullifiers(), 2);
447 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
448 assert_eq!(tree.get_block_num(&nullifier2).unwrap(), block2);
449
450 let _witness1 = tree.open(&nullifier1);
452
453 tree.mark_spent(nullifier3, block3).unwrap();
455 assert_eq!(tree.num_nullifiers(), 3);
456 assert_eq!(tree.get_block_num(&nullifier3).unwrap(), block3);
457 }
458
459 #[cfg(feature = "std")]
460 #[test]
461 fn large_smt_backend_nullifier_already_spent() {
462 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
463
464 let nullifier1 = Nullifier::dummy(1);
465
466 let block1 = BlockNumber::from(1);
467 let block2 = BlockNumber::from(2);
468
469 let mut tree = NullifierTree::new_unchecked(
470 LargeSmt::with_entries(
471 MemoryStorage::default(),
472 [(nullifier1.as_word(), NullifierBlock::from(block1).into())],
473 )
474 .unwrap(),
475 );
476
477 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
478
479 let err = tree.mark_spent(nullifier1, block2).unwrap_err();
480 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
481 }
482
483 #[cfg(feature = "std")]
484 #[test]
485 fn large_smt_backend_apply_mutations() {
486 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
487
488 let nullifier1 = Nullifier::dummy(1);
489 let nullifier2 = Nullifier::dummy(2);
490 let nullifier3 = Nullifier::dummy(3);
491
492 let block1 = BlockNumber::from(1);
493 let block2 = BlockNumber::from(2);
494 let block3 = BlockNumber::from(3);
495
496 let mut tree = LargeSmt::with_entries(
497 MemoryStorage::default(),
498 [(nullifier1.as_word(), NullifierBlock::from(block1).into())],
499 )
500 .map(NullifierTree::new_unchecked)
501 .unwrap();
502
503 let mutations =
504 tree.compute_mutations([(nullifier2, block2), (nullifier3, block3)]).unwrap();
505
506 tree.apply_mutations(mutations).unwrap();
507
508 assert_eq!(tree.num_nullifiers(), 3);
509 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
510 assert_eq!(tree.get_block_num(&nullifier2).unwrap(), block2);
511 assert_eq!(tree.get_block_num(&nullifier3).unwrap(), block3);
512 }
513
514 #[cfg(feature = "std")]
515 #[test]
516 fn large_smt_backend_same_root_as_regular_smt() {
517 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
518
519 let nullifier1 = Nullifier::dummy(1);
520 let nullifier2 = Nullifier::dummy(2);
521
522 let block1 = BlockNumber::from(1);
523 let block2 = BlockNumber::from(2);
524
525 let large_tree = LargeSmt::with_entries(
527 MemoryStorage::default(),
528 [
529 (nullifier1.as_word(), NullifierBlock::from(block1).into()),
530 (nullifier2.as_word(), NullifierBlock::from(block2).into()),
531 ],
532 )
533 .map(NullifierTree::new_unchecked)
534 .unwrap();
535
536 let regular_tree =
538 NullifierTree::with_entries([(nullifier1, block1), (nullifier2, block2)]).unwrap();
539
540 assert_eq!(large_tree.root(), regular_tree.root());
542
543 let large_entries: std::collections::BTreeMap<_, _> = large_tree.entries().collect();
545 let regular_entries: std::collections::BTreeMap<_, _> = regular_tree.entries().collect();
546
547 assert_eq!(large_entries, regular_entries);
548 }
549}