miden_objects/note/
recipient.rs

1use alloc::vec::Vec;
2use core::fmt::Debug;
3
4use miden_crypto::Felt;
5
6use super::{
7    ByteReader,
8    ByteWriter,
9    Deserializable,
10    DeserializationError,
11    Hasher,
12    NoteInputs,
13    NoteScript,
14    Serializable,
15    Word,
16};
17
18/// Value that describes under which condition a note can be consumed.
19///
20/// The recipient is not an account address, instead it is a value that describes when a note
21/// can be consumed. Because not all notes have predetermined consumer addresses, e.g. swap
22/// notes can be consumed by anyone, the recipient is defined as the code and its inputs, that
23/// when successfully executed results in the note's consumption.
24///
25/// Recipient is computed as:
26///
27/// > hash(hash(hash(serial_num, [0; 4]), script_root), input_commitment)
28#[derive(Clone, Debug, PartialEq, Eq)]
29pub struct NoteRecipient {
30    serial_num: Word,
31    script: NoteScript,
32    inputs: NoteInputs,
33    digest: Word,
34}
35
36impl NoteRecipient {
37    pub fn new(serial_num: Word, script: NoteScript, inputs: NoteInputs) -> Self {
38        let digest = compute_recipient_digest(serial_num, &script, &inputs);
39        Self { serial_num, script, inputs, digest }
40    }
41
42    // PUBLIC ACCESSORS
43    // --------------------------------------------------------------------------------------------
44
45    /// The recipient's serial_num, the secret required to consume the note.
46    pub fn serial_num(&self) -> Word {
47        self.serial_num
48    }
49
50    /// The recipients's script which locks the assets of this note.
51    pub fn script(&self) -> &NoteScript {
52        &self.script
53    }
54
55    /// The recipient's inputs which customizes the script's behavior.
56    pub fn inputs(&self) -> &NoteInputs {
57        &self.inputs
58    }
59
60    /// The recipient's digest, which commits to its details.
61    ///
62    /// This is the public data required to create a note.
63    pub fn digest(&self) -> Word {
64        self.digest
65    }
66
67    /// Returns the recipient formatted to be used with the advice map.
68    ///
69    /// The format is `inputs_length || INPUTS_COMMITMENT || SCRIPT_ROOT || SERIAL_NUMBER`
70    ///
71    /// Where:
72    /// - inputs_length is the length of the note inputs
73    /// - INPUTS_COMMITMENT is the commitment of the note inputs
74    /// - SCRIPT_ROOT is the commitment of the note script (i.e., the script's MAST root)
75    /// - SERIAL_NUMBER is the recipient's serial number
76    pub fn format_for_advice(&self) -> Vec<Felt> {
77        let mut result = Vec::with_capacity(13);
78        result.push(self.inputs.num_values().into());
79        result.extend(self.inputs.commitment());
80        result.extend(self.script.root());
81        result.extend(self.serial_num);
82        result
83    }
84}
85
86fn compute_recipient_digest(serial_num: Word, script: &NoteScript, inputs: &NoteInputs) -> Word {
87    let serial_num_hash = Hasher::merge(&[serial_num, Word::empty()]);
88    let merge_script = Hasher::merge(&[serial_num_hash, script.root()]);
89    Hasher::merge(&[merge_script, inputs.commitment()])
90}
91
92// SERIALIZATION
93// ================================================================================================
94
95impl Serializable for NoteRecipient {
96    fn write_into<W: ByteWriter>(&self, target: &mut W) {
97        let Self {
98            script,
99            inputs,
100            serial_num,
101
102            // These attributes don't have to be serialized, they can be re-computed from the rest
103            // of the data
104            digest: _,
105        } = self;
106
107        script.write_into(target);
108        inputs.write_into(target);
109        serial_num.write_into(target);
110    }
111}
112
113impl Deserializable for NoteRecipient {
114    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
115        let script = NoteScript::read_from(source)?;
116        let inputs = NoteInputs::read_from(source)?;
117        let serial_num = Word::read_from(source)?;
118
119        Ok(Self::new(serial_num, script, inputs))
120    }
121}