miden_objects/note/
recipient.rs

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