miden_objects/note/
inputs.rs

1use alloc::vec::Vec;
2
3use crate::{
4    Digest, Felt, Hasher, MAX_INPUTS_PER_NOTE, WORD_SIZE, ZERO,
5    errors::NoteError,
6    utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
7};
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    commitment: 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.commitment
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 `INPUTS || PADDING`, where:
70    ///
71    /// Where:
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        pad_inputs(&self.values)
76    }
77}
78
79impl Default for NoteInputs {
80    fn default() -> Self {
81        pad_and_build(vec![])
82    }
83}
84
85impl PartialEq for NoteInputs {
86    fn eq(&self, other: &Self) -> bool {
87        let NoteInputs { values: inputs, commitment: _ } = self;
88        inputs == &other.values
89    }
90}
91
92impl Eq for NoteInputs {}
93
94// CONVERSION
95// ================================================================================================
96
97impl From<NoteInputs> for Vec<Felt> {
98    fn from(value: NoteInputs) -> Self {
99        value.values
100    }
101}
102
103impl TryFrom<Vec<Felt>> for NoteInputs {
104    type Error = NoteError;
105
106    fn try_from(value: Vec<Felt>) -> Result<Self, Self::Error> {
107        NoteInputs::new(value)
108    }
109}
110
111// HELPER FUNCTIONS
112// ================================================================================================
113
114/// Returns a vector with built from the provided inputs and padded to the next multiple of 8.
115fn pad_inputs(inputs: &[Felt]) -> Vec<Felt> {
116    const BLOCK_SIZE: usize = WORD_SIZE * 2;
117
118    let padded_len = inputs.len().next_multiple_of(BLOCK_SIZE);
119    let mut padded_inputs = Vec::with_capacity(padded_len);
120    padded_inputs.extend(inputs.iter());
121    padded_inputs.resize(padded_len, ZERO);
122
123    padded_inputs
124}
125
126/// Pad `values` and returns a new `NoteInputs`.
127fn pad_and_build(values: Vec<Felt>) -> NoteInputs {
128    let commitment = {
129        let padded_values = pad_inputs(&values);
130        Hasher::hash_elements(&padded_values)
131    };
132
133    NoteInputs { values, commitment }
134}
135
136// SERIALIZATION
137// ================================================================================================
138
139impl Serializable for NoteInputs {
140    fn write_into<W: ByteWriter>(&self, target: &mut W) {
141        let NoteInputs { values, commitment: _commitment } = self;
142        target.write_u8(values.len().try_into().expect("inputs len is not a u8 value"));
143        target.write_many(values);
144    }
145}
146
147impl Deserializable for NoteInputs {
148    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
149        let num_values = source.read_u8()? as usize;
150        let values = source.read_many::<Felt>(num_values)?;
151        Self::new(values).map_err(|v| DeserializationError::InvalidValue(format!("{v}")))
152    }
153}
154
155// TESTS
156// ================================================================================================
157
158#[cfg(test)]
159mod tests {
160    use miden_crypto::utils::Deserializable;
161
162    use super::{Felt, NoteInputs, Serializable};
163
164    #[test]
165    fn test_input_ordering() {
166        // inputs are provided in reverse stack order
167        let inputs = vec![Felt::new(1), Felt::new(2), Felt::new(3)];
168        // we expect the inputs to be padded to length 16 and to remain in reverse stack order.
169        let expected_ordering = vec![Felt::new(1), Felt::new(2), Felt::new(3)];
170
171        let note_inputs = NoteInputs::new(inputs).expect("note created should succeed");
172        assert_eq!(&expected_ordering, &note_inputs.values);
173    }
174
175    #[test]
176    fn test_input_serialization() {
177        let inputs = vec![Felt::new(1), Felt::new(2), Felt::new(3)];
178        let note_inputs = NoteInputs::new(inputs).unwrap();
179
180        let bytes = note_inputs.to_bytes();
181        let parsed_note_inputs = NoteInputs::read_from_bytes(&bytes).unwrap();
182        assert_eq!(note_inputs, parsed_note_inputs);
183    }
184}