miden_objects/note/
inputs.rs

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