miden_objects/note/
inputs.rs

1use alloc::vec::Vec;
2
3use super::{
4    ByteReader, ByteWriter, Deserializable, DeserializationError, Digest, Felt, Hasher, NoteError,
5    Serializable, WORD_SIZE, ZERO,
6};
7use crate::MAX_INPUTS_PER_NOTE;
8
9// NOTE INPUTS
10// ================================================================================================
11
12/// A container for note inputs.
13///
14/// A note can be associated with up to 128 input values. Each value is represented by a single
15/// field element. Thus, note input values can contain up to ~1 KB of data.
16///
17/// All inputs associated with a note can be reduced to a single commitment which is computed by
18/// first padding the inputs with ZEROs to the next multiple of 8, and then by computing a
19/// sequential hash of the resulting elements.
20#[derive(Clone, Debug)]
21pub struct NoteInputs {
22    values: Vec<Felt>,
23    hash: Digest,
24}
25
26impl NoteInputs {
27    // CONSTRUCTOR
28    // --------------------------------------------------------------------------------------------
29
30    /// Returns [NoteInputs] instantiated from the provided values.
31    ///
32    /// # Errors
33    /// Returns an error if the number of provided inputs is greater than 128.
34    pub fn new(values: Vec<Felt>) -> Result<Self, NoteError> {
35        if values.len() > MAX_INPUTS_PER_NOTE {
36            return Err(NoteError::TooManyInputs(values.len()));
37        }
38
39        Ok(pad_and_build(values))
40    }
41
42    // PUBLIC ACCESSORS
43    // --------------------------------------------------------------------------------------------
44
45    /// Returns a commitment to these inputs.
46    pub fn commitment(&self) -> Digest {
47        self.hash
48    }
49
50    /// Returns the number of input values.
51    ///
52    /// The returned value is guaranteed to be smaller than or equal to 128.
53    pub fn num_values(&self) -> u8 {
54        const _: () = assert!(MAX_INPUTS_PER_NOTE <= u8::MAX as usize);
55        debug_assert!(
56            self.values.len() < MAX_INPUTS_PER_NOTE,
57            "The constructor should have checked the number of inputs"
58        );
59        self.values.len() as u8
60    }
61
62    /// Returns a reference to the input values.
63    pub fn values(&self) -> &[Felt] {
64        &self.values
65    }
66
67    /// Returns the note's input formatted to be used with the advice map.
68    ///
69    /// The format is `input_len || INPUTS || PADDING`, where:
70    ///
71    /// - input_len is the number of inputs
72    /// - INPUTS is the variable inputs for the note
73    /// - PADDING is the optional padding to align the data with a 2WORD boundary
74    pub fn format_for_advice(&self) -> Vec<Felt> {
75        // NOTE: keep map in sync with the `note::get_inputs` API procedure
76        let mut padded = pad_inputs(&self.values);
77        padded.insert(0, self.num_values().into());
78        padded
79    }
80}
81
82impl Default for NoteInputs {
83    fn default() -> Self {
84        pad_and_build(vec![])
85    }
86}
87
88impl PartialEq for NoteInputs {
89    fn eq(&self, other: &Self) -> bool {
90        let NoteInputs { values: inputs, hash: _ } = self;
91        inputs == &other.values
92    }
93}
94
95impl Eq for NoteInputs {}
96
97// CONVERSION
98// ================================================================================================
99
100impl From<NoteInputs> for Vec<Felt> {
101    fn from(value: NoteInputs) -> Self {
102        value.values
103    }
104}
105
106impl TryFrom<Vec<Felt>> for NoteInputs {
107    type Error = NoteError;
108
109    fn try_from(value: Vec<Felt>) -> Result<Self, Self::Error> {
110        NoteInputs::new(value)
111    }
112}
113
114// HELPER FUNCTIONS
115// ================================================================================================
116
117/// Returns a vector with built from the provided inputs and padded to the next multiple of 8.
118fn pad_inputs(inputs: &[Felt]) -> Vec<Felt> {
119    const BLOCK_SIZE: usize = WORD_SIZE * 2;
120
121    let padded_len = inputs.len().next_multiple_of(BLOCK_SIZE);
122    let mut padded_inputs = Vec::with_capacity(padded_len);
123    padded_inputs.extend(inputs.iter());
124    padded_inputs.resize(padded_len, ZERO);
125
126    padded_inputs
127}
128
129/// Pad `values` and returns a new `NoteInputs`.
130fn pad_and_build(values: Vec<Felt>) -> NoteInputs {
131    let hash = {
132        let padded_values = pad_inputs(&values);
133        Hasher::hash_elements(&padded_values)
134    };
135
136    NoteInputs { values, hash }
137}
138
139// SERIALIZATION
140// ================================================================================================
141
142impl Serializable for NoteInputs {
143    fn write_into<W: ByteWriter>(&self, target: &mut W) {
144        let NoteInputs { values, hash: _hash } = self;
145        target.write_u8(values.len().try_into().expect("inputs len is not a u8 value"));
146        target.write_many(values);
147    }
148}
149
150impl Deserializable for NoteInputs {
151    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
152        let num_values = source.read_u8()? as usize;
153        let values = source.read_many::<Felt>(num_values)?;
154        Self::new(values).map_err(|v| DeserializationError::InvalidValue(format!("{v}")))
155    }
156}
157
158// TESTS
159// ================================================================================================
160
161#[cfg(test)]
162mod tests {
163    use miden_crypto::utils::Deserializable;
164
165    use super::{Felt, NoteInputs, Serializable};
166
167    #[test]
168    fn test_input_ordering() {
169        // inputs are provided in reverse stack order
170        let inputs = vec![Felt::new(1), Felt::new(2), Felt::new(3)];
171        // we expect the inputs to be padded to length 16 and to remain in reverse stack order.
172        let expected_ordering = vec![Felt::new(1), Felt::new(2), Felt::new(3)];
173
174        let note_inputs = NoteInputs::new(inputs).expect("note created should succeed");
175        assert_eq!(&expected_ordering, &note_inputs.values);
176    }
177
178    #[test]
179    fn test_input_serialization() {
180        let inputs = vec![Felt::new(1), Felt::new(2), Felt::new(3)];
181        let note_inputs = NoteInputs::new(inputs).unwrap();
182
183        let bytes = note_inputs.to_bytes();
184        let parsed_note_inputs = NoteInputs::read_from_bytes(&bytes).unwrap();
185        assert_eq!(note_inputs, parsed_note_inputs);
186    }
187}