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::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
10use crate::{Felt, FieldElement, Word};
11
12mod backend;
13pub use backend::NullifierTreeBackend;
14
15mod witness;
16pub use witness::NullifierWitness;
17
18mod partial;
19pub use partial::PartialNullifierTree;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct NullifierTree<Backend = Smt> {
34 smt: Backend,
35}
36
37impl<Backend> Default for NullifierTree<Backend>
38where
39 Backend: Default,
40{
41 fn default() -> Self {
42 Self { smt: Default::default() }
43 }
44}
45
46impl<Backend> NullifierTree<Backend>
47where
48 Backend: NullifierTreeBackend<Error = MerkleError>,
49{
50 pub const DEPTH: u8 = SMT_DEPTH;
55
56 pub fn new_unchecked(backend: Backend) -> Self {
65 NullifierTree { smt: backend }
66 }
67
68 pub fn root(&self) -> Word {
73 self.smt.root()
74 }
75
76 pub fn num_nullifiers(&self) -> usize {
78 self.smt.num_entries()
79 }
80
81 pub fn entries(&self) -> impl Iterator<Item = (Nullifier, BlockNumber)> {
83 self.smt.entries().map(|(nullifier, value)| {
84 (
85 Nullifier::from_raw(nullifier),
86 NullifierBlock::new(value)
87 .expect("SMT should only store valid NullifierBlocks")
88 .into(),
89 )
90 })
91 }
92
93 pub fn open(&self, nullifier: &Nullifier) -> NullifierWitness {
100 NullifierWitness::new(self.smt.open(&nullifier.as_word()))
101 }
102
103 pub fn get_block_num(&self, nullifier: &Nullifier) -> Option<BlockNumber> {
106 let nullifier_block = self.smt.get_value(&nullifier.as_word());
107 if nullifier_block.is_unspent() {
108 return None;
109 }
110
111 Some(nullifier_block.into())
112 }
113
114 pub fn compute_mutations<I>(
122 &self,
123 nullifiers: impl IntoIterator<Item = (Nullifier, BlockNumber), IntoIter = I>,
124 ) -> Result<NullifierMutationSet, NullifierTreeError>
125 where
126 I: Iterator<Item = (Nullifier, BlockNumber)> + Clone,
127 {
128 let nullifiers = nullifiers.into_iter();
129 for (nullifier, _) in nullifiers.clone() {
130 if self.get_block_num(&nullifier).is_some() {
131 return Err(NullifierTreeError::NullifierAlreadySpent(nullifier));
132 }
133 }
134
135 let mutation_set = self
136 .smt
137 .compute_mutations(
138 nullifiers
139 .into_iter()
140 .map(|(nullifier, block_num)| {
141 (nullifier.as_word(), NullifierBlock::from(block_num).into())
142 })
143 .collect::<Vec<_>>(),
144 )
145 .map_err(NullifierTreeError::ComputeMutations)?;
146
147 Ok(NullifierMutationSet::new(mutation_set))
148 }
149
150 pub fn mark_spent(
160 &mut self,
161 nullifier: Nullifier,
162 block_num: BlockNumber,
163 ) -> Result<(), NullifierTreeError> {
164 let prev_nullifier_value = self
165 .smt
166 .insert(nullifier.as_word(), NullifierBlock::from(block_num))
167 .map_err(NullifierTreeError::MaxLeafEntriesExceeded)?;
168
169 if prev_nullifier_value.is_spent() {
170 Err(NullifierTreeError::NullifierAlreadySpent(nullifier))
171 } else {
172 Ok(())
173 }
174 }
175
176 pub fn apply_mutations(
183 &mut self,
184 mutations: NullifierMutationSet,
185 ) -> Result<(), NullifierTreeError> {
186 self.smt
187 .apply_mutations(mutations.into_mutation_set())
188 .map_err(NullifierTreeError::TreeRootConflict)
189 }
190}
191
192impl Serializable for NullifierTree {
196 fn write_into<W: ByteWriter>(&self, target: &mut W) {
197 self.entries().collect::<Vec<_>>().write_into(target);
198 }
199}
200
201impl Deserializable for NullifierTree {
202 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
203 let entries = Vec::<(Nullifier, BlockNumber)>::read_from(source)?;
204 Self::with_entries(entries)
205 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
206 }
207}
208
209#[derive(Debug, Clone, PartialEq, Eq)]
220pub struct NullifierMutationSet {
221 mutation_set: MutationSet<SMT_DEPTH, Word, Word>,
222}
223
224impl NullifierMutationSet {
225 fn new(mutation_set: MutationSet<SMT_DEPTH, Word, Word>) -> Self {
230 Self { mutation_set }
231 }
232
233 pub fn as_mutation_set(&self) -> &MutationSet<SMT_DEPTH, Word, Word> {
238 &self.mutation_set
239 }
240
241 pub fn into_mutation_set(self) -> MutationSet<SMT_DEPTH, Word, Word> {
246 self.mutation_set
247 }
248}
249
250#[derive(Debug, PartialEq, Eq, Copy, Clone)]
264pub struct NullifierBlock(BlockNumber);
265
266impl NullifierBlock {
267 pub const UNSPENT: NullifierBlock = NullifierBlock(BlockNumber::GENESIS);
268
269 pub fn new(word: Word) -> Result<Self, NullifierTreeError> {
276 let block_num = u32::try_from(word[0].as_int())
277 .map(BlockNumber::from)
278 .map_err(|_| NullifierTreeError::InvalidNullifierBlockNumber(word))?;
279
280 if word[1..4].iter().any(|felt| *felt != Felt::ZERO) {
281 return Err(NullifierTreeError::InvalidNullifierBlockNumber(word));
282 }
283
284 Ok(NullifierBlock(block_num))
285 }
286
287 pub fn is_spent(&self) -> bool {
289 !self.is_unspent()
290 }
291
292 pub fn is_unspent(&self) -> bool {
294 self == &Self::UNSPENT
295 }
296}
297
298impl From<BlockNumber> for NullifierBlock {
299 fn from(block_num: BlockNumber) -> Self {
300 Self(block_num)
301 }
302}
303
304impl From<NullifierBlock> for BlockNumber {
305 fn from(value: NullifierBlock) -> BlockNumber {
306 value.0
307 }
308}
309
310impl From<NullifierBlock> for Word {
311 fn from(value: NullifierBlock) -> Word {
312 Word::from([Felt::from(value.0), Felt::ZERO, Felt::ZERO, Felt::ZERO])
313 }
314}
315
316impl TryFrom<Word> for NullifierBlock {
317 type Error = NullifierTreeError;
318
319 fn try_from(value: Word) -> Result<Self, Self::Error> {
320 Self::new(value)
321 }
322}
323
324#[cfg(test)]
328mod tests {
329 use assert_matches::assert_matches;
330
331 use super::NullifierTree;
332 use crate::Word;
333 use crate::block::BlockNumber;
334 use crate::block::nullifier_tree::NullifierBlock;
335 use crate::errors::NullifierTreeError;
336 use crate::note::Nullifier;
337
338 #[test]
339 fn leaf_value_encode_decode() {
340 let block_num = BlockNumber::from(0xffff_ffff_u32);
341 let nullifier_block = NullifierBlock::from(block_num);
342 let block_num_recovered = nullifier_block.into();
343 assert_eq!(block_num, block_num_recovered);
344 }
345
346 #[test]
347 fn leaf_value_encoding() {
348 let block_num = BlockNumber::from(123);
349 let nullifier_value = NullifierBlock::from(block_num);
350 assert_eq!(
351 nullifier_value,
352 NullifierBlock::new(Word::from([block_num.as_u32(), 0, 0, 0u32])).unwrap()
353 );
354 }
355
356 #[test]
357 fn leaf_value_decoding() {
358 let block_num = 123;
359 let nullifier_value = NullifierBlock::new(Word::from([block_num, 0, 0, 0u32])).unwrap();
360 let decoded_block_num: BlockNumber = nullifier_value.into();
361
362 assert_eq!(decoded_block_num, block_num.into());
363 }
364
365 #[test]
366 fn apply_mutations() {
367 let nullifier1 = Nullifier::dummy(1);
368 let nullifier2 = Nullifier::dummy(2);
369 let nullifier3 = Nullifier::dummy(3);
370
371 let block1 = BlockNumber::from(1);
372 let block2 = BlockNumber::from(2);
373 let block3 = BlockNumber::from(3);
374
375 let mut tree = NullifierTree::with_entries([(nullifier1, block1)]).unwrap();
376
377 let mutations = tree
379 .compute_mutations([(nullifier2, block1), (nullifier3, block3), (nullifier2, block2)])
380 .unwrap();
381
382 tree.apply_mutations(mutations).unwrap();
383
384 assert_eq!(tree.num_nullifiers(), 3);
385 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
386 assert_eq!(tree.get_block_num(&nullifier2).unwrap(), block2);
387 assert_eq!(tree.get_block_num(&nullifier3).unwrap(), block3);
388 }
389
390 #[test]
391 fn nullifier_already_spent() {
392 let nullifier1 = Nullifier::dummy(1);
393
394 let block1 = BlockNumber::from(1);
395 let block2 = BlockNumber::from(2);
396
397 let mut tree = NullifierTree::with_entries([(nullifier1, block1)]).unwrap();
398
399 let err = tree.clone().compute_mutations([(nullifier1, block1)]).unwrap_err();
401 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
402
403 let err = tree.clone().mark_spent(nullifier1, block1).unwrap_err();
404 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
405
406 let err = tree.clone().compute_mutations([(nullifier1, block2)]).unwrap_err();
408 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
409
410 let err = tree.mark_spent(nullifier1, block2).unwrap_err();
411 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
412 }
413
414 #[cfg(feature = "std")]
415 #[test]
416 fn large_smt_backend_basic_operations() {
417 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
418
419 let nullifier1 = Nullifier::dummy(1);
421 let nullifier2 = Nullifier::dummy(2);
422 let nullifier3 = Nullifier::dummy(3);
423
424 let block1 = BlockNumber::from(1);
425 let block2 = BlockNumber::from(2);
426 let block3 = BlockNumber::from(3);
427
428 let mut tree = NullifierTree::new_unchecked(
430 LargeSmt::with_entries(
431 MemoryStorage::default(),
432 [
433 (nullifier1.as_word(), NullifierBlock::from(block1).into()),
434 (nullifier2.as_word(), NullifierBlock::from(block2).into()),
435 ],
436 )
437 .unwrap(),
438 );
439
440 assert_eq!(tree.num_nullifiers(), 2);
442 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
443 assert_eq!(tree.get_block_num(&nullifier2).unwrap(), block2);
444
445 let _witness1 = tree.open(&nullifier1);
447
448 tree.mark_spent(nullifier3, block3).unwrap();
450 assert_eq!(tree.num_nullifiers(), 3);
451 assert_eq!(tree.get_block_num(&nullifier3).unwrap(), block3);
452 }
453
454 #[cfg(feature = "std")]
455 #[test]
456 fn large_smt_backend_nullifier_already_spent() {
457 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
458
459 let nullifier1 = Nullifier::dummy(1);
460
461 let block1 = BlockNumber::from(1);
462 let block2 = BlockNumber::from(2);
463
464 let mut tree = NullifierTree::new_unchecked(
465 LargeSmt::with_entries(
466 MemoryStorage::default(),
467 [(nullifier1.as_word(), NullifierBlock::from(block1).into())],
468 )
469 .unwrap(),
470 );
471
472 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
473
474 let err = tree.mark_spent(nullifier1, block2).unwrap_err();
475 assert_matches!(err, NullifierTreeError::NullifierAlreadySpent(nullifier) if nullifier == nullifier1);
476 }
477
478 #[cfg(feature = "std")]
479 #[test]
480 fn large_smt_backend_apply_mutations() {
481 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
482
483 let nullifier1 = Nullifier::dummy(1);
484 let nullifier2 = Nullifier::dummy(2);
485 let nullifier3 = Nullifier::dummy(3);
486
487 let block1 = BlockNumber::from(1);
488 let block2 = BlockNumber::from(2);
489 let block3 = BlockNumber::from(3);
490
491 let mut tree = LargeSmt::with_entries(
492 MemoryStorage::default(),
493 [(nullifier1.as_word(), NullifierBlock::from(block1).into())],
494 )
495 .map(NullifierTree::new_unchecked)
496 .unwrap();
497
498 let mutations =
499 tree.compute_mutations([(nullifier2, block2), (nullifier3, block3)]).unwrap();
500
501 tree.apply_mutations(mutations).unwrap();
502
503 assert_eq!(tree.num_nullifiers(), 3);
504 assert_eq!(tree.get_block_num(&nullifier1).unwrap(), block1);
505 assert_eq!(tree.get_block_num(&nullifier2).unwrap(), block2);
506 assert_eq!(tree.get_block_num(&nullifier3).unwrap(), block3);
507 }
508
509 #[cfg(feature = "std")]
510 #[test]
511 fn large_smt_backend_same_root_as_regular_smt() {
512 use miden_crypto::merkle::smt::{LargeSmt, MemoryStorage};
513
514 let nullifier1 = Nullifier::dummy(1);
515 let nullifier2 = Nullifier::dummy(2);
516
517 let block1 = BlockNumber::from(1);
518 let block2 = BlockNumber::from(2);
519
520 let large_tree = LargeSmt::with_entries(
522 MemoryStorage::default(),
523 [
524 (nullifier1.as_word(), NullifierBlock::from(block1).into()),
525 (nullifier2.as_word(), NullifierBlock::from(block2).into()),
526 ],
527 )
528 .map(NullifierTree::new_unchecked)
529 .unwrap();
530
531 let regular_tree =
533 NullifierTree::with_entries([(nullifier1, block1), (nullifier2, block2)]).unwrap();
534
535 assert_eq!(large_tree.root(), regular_tree.root());
537
538 let large_entries: std::collections::BTreeMap<_, _> = large_tree.entries().collect();
540 let regular_entries: std::collections::BTreeMap<_, _> = regular_tree.entries().collect();
541
542 assert_eq!(large_entries, regular_entries);
543 }
544}