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>(
128 &self,
129 nullifiers: impl IntoIterator<Item = (Nullifier, BlockNumber), IntoIter = I>,
130 ) -> Result<NullifierMutationSet, NullifierTreeError>
131 where
132 I: Iterator<Item = (Nullifier, BlockNumber)> + Clone,
133 {
134 let nullifiers = nullifiers.into_iter();
135 for (nullifier, _) in nullifiers.clone() {
136 if self.get_block_num(&nullifier).is_some() {
137 return Err(NullifierTreeError::NullifierAlreadySpent(nullifier));
138 }
139 }
140
141 let mutation_set = self
142 .smt
143 .compute_mutations(
144 nullifiers
145 .into_iter()
146 .map(|(nullifier, block_num)| {
147 (nullifier.as_word(), NullifierBlock::from(block_num).into())
148 })
149 .collect::<Vec<_>>(),
150 )
151 .map_err(NullifierTreeError::ComputeMutations)?;
152
153 Ok(NullifierMutationSet::new(mutation_set))
154 }
155
156 pub fn mark_spent(
166 &mut self,
167 nullifier: Nullifier,
168 block_num: BlockNumber,
169 ) -> Result<(), NullifierTreeError> {
170 let prev_nullifier_value = self
171 .smt
172 .insert(nullifier.as_word(), NullifierBlock::from(block_num))
173 .map_err(NullifierTreeError::MaxLeafEntriesExceeded)?;
174
175 if prev_nullifier_value.is_spent() {
176 Err(NullifierTreeError::NullifierAlreadySpent(nullifier))
177 } else {
178 Ok(())
179 }
180 }
181
182 pub fn apply_mutations(
189 &mut self,
190 mutations: NullifierMutationSet,
191 ) -> Result<(), NullifierTreeError> {
192 self.smt
193 .apply_mutations(mutations.into_mutation_set())
194 .map_err(NullifierTreeError::TreeRootConflict)
195 }
196}
197
198impl Serializable for NullifierTree {
202 fn write_into<W: ByteWriter>(&self, target: &mut W) {
203 self.entries().collect::<Vec<_>>().write_into(target);
204 }
205}
206
207impl Deserializable for NullifierTree {
208 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
209 let entries = Vec::<(Nullifier, BlockNumber)>::read_from(source)?;
210 Self::with_entries(entries)
211 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq)]
226pub struct NullifierMutationSet {
227 mutation_set: MutationSet<SMT_DEPTH, Word, Word>,
228}
229
230impl NullifierMutationSet {
231 fn new(mutation_set: MutationSet<SMT_DEPTH, Word, Word>) -> Self {
236 Self { mutation_set }
237 }
238
239 pub fn as_mutation_set(&self) -> &MutationSet<SMT_DEPTH, Word, Word> {
244 &self.mutation_set
245 }
246
247 pub fn into_mutation_set(self) -> MutationSet<SMT_DEPTH, Word, Word> {
252 self.mutation_set
253 }
254}
255
256#[derive(Debug, PartialEq, Eq, Copy, Clone)]
270pub struct NullifierBlock(BlockNumber);
271
272impl NullifierBlock {
273 pub const UNSPENT: NullifierBlock = NullifierBlock(BlockNumber::GENESIS);
274
275 pub fn new(word: Word) -> Result<Self, NullifierTreeError> {
282 let block_num = u32::try_from(word[0].as_canonical_u64())
283 .map(BlockNumber::from)
284 .map_err(|_| NullifierTreeError::InvalidNullifierBlockNumber(word))?;
285
286 if word[1..4].iter().any(|felt| *felt != Felt::ZERO) {
287 return Err(NullifierTreeError::InvalidNullifierBlockNumber(word));
288 }
289
290 Ok(NullifierBlock(block_num))
291 }
292
293 pub fn is_spent(&self) -> bool {
295 !self.is_unspent()
296 }
297
298 pub fn is_unspent(&self) -> bool {
300 self == &Self::UNSPENT
301 }
302}
303
304impl From<BlockNumber> for NullifierBlock {
305 fn from(block_num: BlockNumber) -> Self {
306 Self(block_num)
307 }
308}
309
310impl From<NullifierBlock> for BlockNumber {
311 fn from(value: NullifierBlock) -> BlockNumber {
312 value.0
313 }
314}
315
316impl From<NullifierBlock> for Word {
317 fn from(value: NullifierBlock) -> Word {
318 Word::from([Felt::from(value.0), Felt::ZERO, Felt::ZERO, Felt::ZERO])
319 }
320}
321
322impl TryFrom<Word> for NullifierBlock {
323 type Error = NullifierTreeError;
324
325 fn try_from(value: Word) -> Result<Self, Self::Error> {
326 Self::new(value)
327 }
328}
329
330#[cfg(test)]
334mod tests {
335 use assert_matches::assert_matches;
336
337 use super::NullifierTree;
338 use crate::Word;
339 use crate::block::BlockNumber;
340 use crate::block::nullifier_tree::NullifierBlock;
341 use crate::errors::NullifierTreeError;
342 use crate::note::Nullifier;
343
344 #[test]
345 fn leaf_value_encode_decode() {
346 let block_num = BlockNumber::from(0xffff_ffff_u32);
347 let nullifier_block = NullifierBlock::from(block_num);
348 let block_num_recovered = nullifier_block.into();
349 assert_eq!(block_num, block_num_recovered);
350 }
351
352 #[test]
353 fn leaf_value_encoding() {
354 let block_num = BlockNumber::from(123);
355 let nullifier_value = NullifierBlock::from(block_num);
356 assert_eq!(
357 nullifier_value,
358 NullifierBlock::new(Word::from([block_num.as_u32(), 0, 0, 0u32])).unwrap()
359 );
360 }
361
362 #[test]
363 fn leaf_value_decoding() {
364 let block_num = 123;
365 let nullifier_value = NullifierBlock::new(Word::from([block_num, 0, 0, 0u32])).unwrap();
366 let decoded_block_num: BlockNumber = nullifier_value.into();
367
368 assert_eq!(decoded_block_num, block_num.into());
369 }
370
371 #[test]
372 fn apply_mutations() {
373 let nullifier1 = Nullifier::dummy(1);
374 let nullifier2 = Nullifier::dummy(2);
375 let nullifier3 = Nullifier::dummy(3);
376
377 let block1 = BlockNumber::from(1);
378 let block2 = BlockNumber::from(2);
379 let block3 = BlockNumber::from(3);
380
381 let mut tree = NullifierTree::with_entries([(nullifier1, block1)]).unwrap();
382
383 let mutations = tree
385 .compute_mutations([(nullifier2, block1), (nullifier3, block3), (nullifier2, block2)])
386 .unwrap();
387
388 tree.apply_mutations(mutations).unwrap();
389
390 assert_eq!(tree.num_nullifiers(), 3);
391 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
392 assert_eq!(tree.get_block_num(&nullifier2).unwrap(), block2);
393 assert_eq!(tree.get_block_num(&nullifier3).unwrap(), block3);
394 }
395
396 #[test]
397 fn nullifier_already_spent() {
398 let nullifier1 = Nullifier::dummy(1);
399
400 let block1 = BlockNumber::from(1);
401 let block2 = BlockNumber::from(2);
402
403 let mut tree = NullifierTree::with_entries([(nullifier1, block1)]).unwrap();
404
405 let err = tree.clone().compute_mutations([(nullifier1, block1)]).unwrap_err();
407 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
408
409 let err = tree.clone().mark_spent(nullifier1, block1).unwrap_err();
410 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
411
412 let err = tree.clone().compute_mutations([(nullifier1, block2)]).unwrap_err();
414 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
415
416 let err = tree.mark_spent(nullifier1, block2).unwrap_err();
417 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
418 }
419
420 #[cfg(feature = "std")]
421 #[test]
422 fn large_smt_backend_basic_operations() {
423 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
424
425 let nullifier1 = Nullifier::dummy(1);
427 let nullifier2 = Nullifier::dummy(2);
428 let nullifier3 = Nullifier::dummy(3);
429
430 let block1 = BlockNumber::from(1);
431 let block2 = BlockNumber::from(2);
432 let block3 = BlockNumber::from(3);
433
434 let mut tree = NullifierTree::new_unchecked(
436 LargeSmt::with_entries(
437 MemoryStorage::default(),
438 [
439 (nullifier1.as_word(), NullifierBlock::from(block1).into()),
440 (nullifier2.as_word(), NullifierBlock::from(block2).into()),
441 ],
442 )
443 .unwrap(),
444 );
445
446 assert_eq!(tree.num_nullifiers(), 2);
448 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
449 assert_eq!(tree.get_block_num(&nullifier2).unwrap(), block2);
450
451 let _witness1 = tree.open(&nullifier1);
453
454 tree.mark_spent(nullifier3, block3).unwrap();
456 assert_eq!(tree.num_nullifiers(), 3);
457 assert_eq!(tree.get_block_num(&nullifier3).unwrap(), block3);
458 }
459
460 #[cfg(feature = "std")]
461 #[test]
462 fn large_smt_backend_nullifier_already_spent() {
463 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
464
465 let nullifier1 = Nullifier::dummy(1);
466
467 let block1 = BlockNumber::from(1);
468 let block2 = BlockNumber::from(2);
469
470 let mut tree = NullifierTree::new_unchecked(
471 LargeSmt::with_entries(
472 MemoryStorage::default(),
473 [(nullifier1.as_word(), NullifierBlock::from(block1).into())],
474 )
475 .unwrap(),
476 );
477
478 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
479
480 let err = tree.mark_spent(nullifier1, block2).unwrap_err();
481 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
482 }
483
484 #[cfg(feature = "std")]
485 #[test]
486 fn large_smt_backend_apply_mutations() {
487 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
488
489 let nullifier1 = Nullifier::dummy(1);
490 let nullifier2 = Nullifier::dummy(2);
491 let nullifier3 = Nullifier::dummy(3);
492
493 let block1 = BlockNumber::from(1);
494 let block2 = BlockNumber::from(2);
495 let block3 = BlockNumber::from(3);
496
497 let mut tree = LargeSmt::with_entries(
498 MemoryStorage::default(),
499 [(nullifier1.as_word(), NullifierBlock::from(block1).into())],
500 )
501 .map(NullifierTree::new_unchecked)
502 .unwrap();
503
504 let mutations =
505 tree.compute_mutations([(nullifier2, block2), (nullifier3, block3)]).unwrap();
506
507 tree.apply_mutations(mutations).unwrap();
508
509 assert_eq!(tree.num_nullifiers(), 3);
510 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
511 assert_eq!(tree.get_block_num(&nullifier2).unwrap(), block2);
512 assert_eq!(tree.get_block_num(&nullifier3).unwrap(), block3);
513 }
514
515 #[cfg(feature = "std")]
516 #[test]
517 fn large_smt_backend_same_root_as_regular_smt() {
518 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
519
520 let nullifier1 = Nullifier::dummy(1);
521 let nullifier2 = Nullifier::dummy(2);
522
523 let block1 = BlockNumber::from(1);
524 let block2 = BlockNumber::from(2);
525
526 let large_tree = LargeSmt::with_entries(
528 MemoryStorage::default(),
529 [
530 (nullifier1.as_word(), NullifierBlock::from(block1).into()),
531 (nullifier2.as_word(), NullifierBlock::from(block2).into()),
532 ],
533 )
534 .map(NullifierTree::new_unchecked)
535 .unwrap();
536
537 let regular_tree =
539 NullifierTree::with_entries([(nullifier1, block1), (nullifier2, block2)]).unwrap();
540
541 assert_eq!(large_tree.root(), regular_tree.root());
543
544 let large_entries: std::collections::BTreeMap<_, _> = large_tree.entries().collect();
546 let regular_entries: std::collections::BTreeMap<_, _> = regular_tree.entries().collect();
547
548 assert_eq!(large_entries, regular_entries);
549 }
550}