Skip to main content

miden_protocol/note/
mod.rs

1use miden_crypto::Word;
2use miden_crypto::utils::{ByteReader, ByteWriter, Deserializable, Serializable};
3use miden_processor::DeserializationError;
4
5use crate::account::AccountId;
6use crate::errors::NoteError;
7use crate::{Felt, Hasher, WORD_SIZE, ZERO};
8
9mod assets;
10pub use assets::NoteAssets;
11
12mod details;
13pub use details::NoteDetails;
14
15mod header;
16pub use header::{NoteHeader, compute_note_commitment};
17
18mod storage;
19pub use storage::NoteStorage;
20
21mod metadata;
22pub use metadata::NoteMetadata;
23
24mod attachment;
25pub use attachment::{
26    NoteAttachment,
27    NoteAttachmentArray,
28    NoteAttachmentContent,
29    NoteAttachmentKind,
30    NoteAttachmentScheme,
31};
32
33mod note_id;
34pub use note_id::NoteId;
35
36mod note_tag;
37pub use note_tag::NoteTag;
38
39mod note_type;
40pub use note_type::NoteType;
41
42mod nullifier;
43pub use nullifier::Nullifier;
44
45mod location;
46pub use location::{NoteInclusionProof, NoteLocation};
47
48mod partial;
49pub use partial::PartialNote;
50
51mod recipient;
52pub use recipient::NoteRecipient;
53
54mod script;
55pub use script::NoteScript;
56
57mod file;
58pub use file::NoteFile;
59
60// NOTE
61// ================================================================================================
62
63/// A note with all the data required for it to be consumed by executing it against the transaction
64/// kernel.
65///
66/// Notes consist of note metadata and details. Note metadata is always public, but details may be
67/// either public, encrypted, or private, depending on the note type. Note details consist of note
68/// assets, script, storage, and a serial number, the three latter grouped into a recipient object.
69///
70/// Note details can be reduced to two unique identifiers: [NoteId] and [Nullifier]. The former is
71/// publicly associated with a note, while the latter is known only to entities which have access
72/// to full note details.
73///
74/// Fungible and non-fungible asset transfers are done by moving assets to the note's assets. The
75/// note's script determines the conditions required for the note consumption, i.e. the target
76/// account of a P2ID or conditions of a SWAP, and the effects of the note. The serial number has
77/// a double duty of preventing double spend, and providing unlikability to the consumer of a note.
78/// The note's storage allows for customization of its script.
79///
80/// To create a note, the kernel does not require all the information above, a user can create a
81/// note only with the commitment to the script, storage, the serial number (i.e., the recipient),
82/// and the kernel only verifies the source account has the assets necessary for the note creation.
83/// See [NoteRecipient] for more details.
84#[derive(Clone, Debug, PartialEq, Eq)]
85pub struct Note {
86    header: NoteHeader,
87    details: NoteDetails,
88
89    nullifier: Nullifier,
90}
91
92impl Note {
93    // CONSTRUCTOR
94    // --------------------------------------------------------------------------------------------
95
96    /// Returns a new [Note] created with the specified parameters.
97    pub fn new(assets: NoteAssets, metadata: NoteMetadata, recipient: NoteRecipient) -> Self {
98        let details = NoteDetails::new(assets, recipient);
99        let header = NoteHeader::new(details.id(), metadata);
100        let nullifier = details.nullifier();
101
102        Self { header, details, nullifier }
103    }
104
105    // PUBLIC ACCESSORS
106    // --------------------------------------------------------------------------------------------
107
108    /// Returns the note's header.
109    pub fn header(&self) -> &NoteHeader {
110        &self.header
111    }
112
113    /// Returns the note's unique identifier.
114    ///
115    /// This value is both an unique identifier and a commitment to the note.
116    pub fn id(&self) -> NoteId {
117        self.header.id()
118    }
119
120    /// Returns the note's metadata.
121    pub fn metadata(&self) -> &NoteMetadata {
122        self.header.metadata()
123    }
124
125    /// Returns the note's assets.
126    pub fn assets(&self) -> &NoteAssets {
127        self.details.assets()
128    }
129
130    /// Returns the note's recipient serial_num, the secret required to consume the note.
131    pub fn serial_num(&self) -> Word {
132        self.details.serial_num()
133    }
134
135    /// Returns the note's recipient script which locks the assets of this note.
136    pub fn script(&self) -> &NoteScript {
137        self.details.script()
138    }
139
140    /// Returns the note's recipient storage which customizes the script's behavior.
141    pub fn storage(&self) -> &NoteStorage {
142        self.details.storage()
143    }
144
145    /// Returns the note's recipient.
146    pub fn recipient(&self) -> &NoteRecipient {
147        self.details.recipient()
148    }
149
150    /// Returns the note's nullifier.
151    ///
152    /// This is public data, used to prevent double spend.
153    pub fn nullifier(&self) -> Nullifier {
154        self.nullifier
155    }
156
157    /// Returns a commitment to the note and its metadata.
158    ///
159    /// > hash(NOTE_ID || NOTE_METADATA_COMMITMENT)
160    ///
161    /// This value is used primarily for authenticating notes consumed when the are consumed
162    /// in a transaction.
163    pub fn commitment(&self) -> Word {
164        self.header.commitment()
165    }
166}
167
168// AS REF
169// ================================================================================================
170
171impl AsRef<NoteRecipient> for Note {
172    fn as_ref(&self) -> &NoteRecipient {
173        self.recipient()
174    }
175}
176
177// CONVERSIONS FROM NOTE
178// ================================================================================================
179
180impl From<Note> for NoteHeader {
181    fn from(note: Note) -> Self {
182        note.header
183    }
184}
185
186impl From<&Note> for NoteDetails {
187    fn from(note: &Note) -> Self {
188        note.details.clone()
189    }
190}
191
192impl From<Note> for NoteDetails {
193    fn from(note: Note) -> Self {
194        note.details
195    }
196}
197
198impl From<Note> for PartialNote {
199    fn from(note: Note) -> Self {
200        let (assets, recipient, ..) = note.details.into_parts();
201        PartialNote::new(note.header.into_metadata(), recipient.digest(), assets)
202    }
203}
204
205// SERIALIZATION
206// ================================================================================================
207
208impl Serializable for Note {
209    fn write_into<W: ByteWriter>(&self, target: &mut W) {
210        let Self {
211            header,
212            details,
213
214            // nullifier is not serialized as it can be computed from the rest of the data
215            nullifier: _,
216        } = self;
217
218        // only metadata is serialized as note ID can be computed from note details
219        header.metadata().write_into(target);
220        details.write_into(target);
221    }
222}
223
224impl Deserializable for Note {
225    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
226        let metadata = NoteMetadata::read_from(source)?;
227        let details = NoteDetails::read_from(source)?;
228        let (assets, recipient) = details.into_parts();
229
230        Ok(Self::new(assets, metadata, recipient))
231    }
232}