Skip to main content

miden_protocol/note/
location.rs

1use miden_crypto::merkle::SparseMerklePath;
2
3use super::{
4    ByteReader,
5    ByteWriter,
6    Deserializable,
7    DeserializationError,
8    NoteError,
9    Serializable,
10};
11use crate::block::BlockNumber;
12use crate::crypto::merkle::InnerNodeInfo;
13use crate::{MAX_BATCHES_PER_BLOCK, MAX_OUTPUT_NOTES_PER_BATCH, Word};
14
15/// Contains information about the location of a note.
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct NoteLocation {
18    /// The block number the note was created in.
19    block_num: BlockNumber,
20
21    /// The index of the note in the [`BlockNoteTree`](crate::block::BlockNoteTree) of the block
22    /// the note was created in.
23    block_note_tree_index: u16,
24}
25
26impl NoteLocation {
27    /// Returns the block number the note was created in.
28    pub fn block_num(&self) -> BlockNumber {
29        self.block_num
30    }
31
32    /// Returns the index of the note in the [`BlockNoteTree`](crate::block::BlockNoteTree) of the
33    /// block the note was created in.
34    ///
35    /// # Note
36    ///
37    /// The height of the Merkle tree is [crate::constants::BLOCK_NOTE_TREE_DEPTH].
38    /// Thus, the maximum index is `2 ^ BLOCK_NOTE_TREE_DEPTH - 1`.
39    pub fn block_note_tree_index(&self) -> u16 {
40        self.block_note_tree_index
41    }
42}
43
44/// Contains the data required to prove inclusion of a note in the canonical chain.
45#[derive(Clone, Debug, PartialEq, Eq)]
46pub struct NoteInclusionProof {
47    /// Details about the note's location.
48    location: NoteLocation,
49
50    /// The note's authentication Merkle path its block's the note root.
51    note_path: SparseMerklePath,
52}
53
54impl NoteInclusionProof {
55    /// Returns a new [NoteInclusionProof].
56    pub fn new(
57        block_num: BlockNumber,
58        block_note_tree_index: u16,
59        note_path: SparseMerklePath,
60    ) -> Result<Self, NoteError> {
61        const HIGHEST_INDEX: usize = MAX_BATCHES_PER_BLOCK * MAX_OUTPUT_NOTES_PER_BATCH - 1;
62        if block_note_tree_index as usize > HIGHEST_INDEX {
63            return Err(NoteError::BlockNoteTreeIndexOutOfBounds {
64                block_note_tree_index,
65                highest_index: HIGHEST_INDEX,
66            });
67        }
68
69        let location = NoteLocation { block_num, block_note_tree_index };
70
71        Ok(Self { location, note_path })
72    }
73
74    // ACCESSORS
75    // --------------------------------------------------------------------------------------------
76
77    /// Returns the location of the note.
78    pub fn location(&self) -> &NoteLocation {
79        &self.location
80    }
81
82    /// Returns the Sparse Merkle path to the note in the note Merkle tree of the block the note was
83    /// created in.
84    pub fn note_path(&self) -> &SparseMerklePath {
85        &self.note_path
86    }
87
88    /// Returns an iterator over inner nodes of this proof assuming that `note_commitment` is the
89    /// value of the node to which this proof opens.
90    pub fn authenticated_nodes(
91        &self,
92        note_commitment: Word,
93    ) -> impl Iterator<Item = InnerNodeInfo> {
94        // SAFETY: expect() is fine here because we check index consistency in the constructor
95        self.note_path
96            .authenticated_nodes(self.location.block_note_tree_index().into(), note_commitment)
97            .expect("note index is not out of bounds")
98    }
99}
100
101// SERIALIZATION
102// ================================================================================================
103
104impl Serializable for NoteLocation {
105    fn write_into<W: ByteWriter>(&self, target: &mut W) {
106        target.write(self.block_num);
107        target.write_u16(self.block_note_tree_index);
108    }
109}
110
111impl Deserializable for NoteLocation {
112    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
113        let block_num = source.read()?;
114        let block_note_tree_index = source.read_u16()?;
115
116        Ok(Self { block_num, block_note_tree_index })
117    }
118}
119
120impl Serializable for NoteInclusionProof {
121    fn write_into<W: ByteWriter>(&self, target: &mut W) {
122        self.location.write_into(target);
123        self.note_path.write_into(target);
124    }
125}
126
127impl Deserializable for NoteInclusionProof {
128    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
129        let location = NoteLocation::read_from(source)?;
130        let note_path = SparseMerklePath::read_from(source)?;
131
132        Ok(Self { location, note_path })
133    }
134}