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