pessimistic_proof_core/
nullifier_tree.rs

1use agglayer_primitives::{Digest, FromBool};
2use agglayer_tries::proof::{SmtNonInclusionProof, ToBits};
3use serde::{Deserialize, Serialize};
4use serde_with::serde_as;
5use unified_bridge::{GlobalIndex, NetworkId};
6
7use crate::ProofError;
8
9// 32 bits for the network id and 32 bits for the LET index
10pub const NULLIFIER_TREE_DEPTH: usize = 64;
11
12/// A commitment to the set of per-network nullifier trees maintained by the
13/// local network
14#[serde_as]
15#[derive(Clone, Debug, Serialize, Deserialize)]
16pub struct NullifierTree {
17    /// The Merkle Root of the nullifier tree
18    #[serde_as(as = "_")]
19    pub root: Digest,
20}
21
22pub type NullifierPath = SmtNonInclusionProof<NULLIFIER_TREE_DEPTH>;
23
24#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
25pub struct NullifierKey {
26    pub network_id: NetworkId,
27    pub let_index: u32,
28}
29
30impl From<GlobalIndex> for NullifierKey {
31    fn from(value: GlobalIndex) -> Self {
32        Self {
33            network_id: value.network_id(),
34            let_index: value.leaf_index(),
35        }
36    }
37}
38
39impl ToBits<64> for NullifierKey {
40    fn to_bits(&self) -> [bool; 64] {
41        std::array::from_fn(|i| {
42            if i < 32 {
43                (self.network_id.to_u32() >> i) & 1 == 1
44            } else {
45                (self.let_index >> (i - 32)) & 1 == 1
46            }
47        })
48    }
49}
50
51impl NullifierTree {
52    pub fn verify_and_update(
53        &mut self,
54        key: NullifierKey,
55        path_to_update: &NullifierPath,
56    ) -> Result<(), ProofError> {
57        self.root = path_to_update
58            .verify_and_update(key, Digest::from_bool(true), self.root)
59            .ok_or(ProofError::InvalidNullifierPath)?;
60
61        Ok(())
62    }
63}