Skip to main content

miden_protocol/note/
mod.rs

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