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}