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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
use alloc::vec::Vec;

use super::{
    ByteReader, ByteWriter, Deserializable, DeserializationError, Digest, Felt, Hasher, NoteError,
    Serializable, WORD_SIZE, ZERO,
};
use crate::MAX_INPUTS_PER_NOTE;

// NOTE INPUTS
// ================================================================================================

/// A container for note inputs.
///
/// A note can be associated with up to 128 input values. Each value is represented by a single
/// field element. Thus, note input values can contain up to ~1 KB of data.
///
/// All inputs associated with a note can be reduced to a single commitment which is computed by
/// first padding the inputs with ZEROs to the next multiple of 8, and then by computing a
/// sequential hash of the resulting elements.
#[derive(Clone, Debug)]
pub struct NoteInputs {
    values: Vec<Felt>,
    hash: Digest,
}

impl NoteInputs {
    /// Maximum number of input values associated with a single note.
    const MAX_INPUTS_PER_NOTE: usize = MAX_INPUTS_PER_NOTE;

    // CONSTRUCTOR
    // --------------------------------------------------------------------------------------------
    /// Returns [NoteInputs] instantiated from the provided values.
    ///
    /// # Errors
    /// Returns an error if the number of provided inputs is greater than 128.
    pub fn new(values: Vec<Felt>) -> Result<Self, NoteError> {
        if values.len() > Self::MAX_INPUTS_PER_NOTE {
            return Err(NoteError::too_many_inputs(values.len()));
        }

        Ok(pad_and_build(values))
    }

    // PUBLIC ACCESSORS
    // --------------------------------------------------------------------------------------------

    /// Returns a commitment to these inputs.
    pub fn commitment(&self) -> Digest {
        self.hash
    }

    /// Returns the number of input values.
    ///
    /// The returned value is guaranteed to be smaller than or equal to 128.
    pub fn num_values(&self) -> u8 {
        debug_assert!(
            self.values.len() < 128,
            "The constructor should have checked the number of inputs"
        );
        self.values.len() as u8
    }

    /// Returns a reference to the input values.
    pub fn values(&self) -> &[Felt] {
        &self.values
    }

    /// Returns the note's input formatted to be used with the advice map.
    ///
    /// The format is `input_len || INPUTS || PADDING`, where:
    ///
    /// - input_len is the number of inputs
    /// - INPUTS is the variable inputs for the note
    /// - PADDING is the optional padding to align the data with a 2WORD boundary
    pub fn format_for_advice(&self) -> Vec<Felt> {
        // NOTE: keep map in sync with the `note::get_inputs` API procedure
        let mut padded = pad_inputs(&self.values);
        padded.insert(0, self.num_values().into());
        padded
    }
}

impl Default for NoteInputs {
    fn default() -> Self {
        pad_and_build(vec![])
    }
}

impl PartialEq for NoteInputs {
    fn eq(&self, other: &Self) -> bool {
        let NoteInputs { values: inputs, hash: _ } = self;
        inputs == &other.values
    }
}

impl Eq for NoteInputs {}

// CONVERSION
// ================================================================================================

impl From<NoteInputs> for Vec<Felt> {
    fn from(value: NoteInputs) -> Self {
        value.values
    }
}

impl TryFrom<Vec<Felt>> for NoteInputs {
    type Error = NoteError;

    fn try_from(value: Vec<Felt>) -> Result<Self, Self::Error> {
        NoteInputs::new(value)
    }
}

// HELPER FUNCTIONS
// ================================================================================================

/// Returns a vector with built from the provided inputs and padded to the next multiple of 8.
fn pad_inputs(inputs: &[Felt]) -> Vec<Felt> {
    const BLOCK_SIZE: usize = WORD_SIZE * 2;

    let padded_len = inputs.len().next_multiple_of(BLOCK_SIZE);
    let mut padded_inputs = Vec::with_capacity(padded_len);
    padded_inputs.extend(inputs.iter());
    padded_inputs.resize(padded_len, ZERO);

    padded_inputs
}

/// Pad `values` and returns a new `NoteInputs`.
fn pad_and_build(values: Vec<Felt>) -> NoteInputs {
    let hash = {
        let padded_values = pad_inputs(&values);
        Hasher::hash_elements(&padded_values)
    };

    NoteInputs { values, hash }
}

// SERIALIZATION
// ================================================================================================

impl Serializable for NoteInputs {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        let NoteInputs { values, hash: _hash } = self;
        target.write_u8(values.len().try_into().expect("inputs len is not a u8 value"));
        target.write_many(values);
    }
}

impl Deserializable for NoteInputs {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let num_values = source.read_u8()? as usize;
        let values = source.read_many::<Felt>(num_values)?;
        Self::new(values).map_err(|v| DeserializationError::InvalidValue(format!("{v}")))
    }
}

// TESTS
// ================================================================================================

#[cfg(test)]
mod tests {
    use miden_crypto::utils::Deserializable;

    use super::{Felt, NoteInputs, Serializable};

    #[test]
    fn test_input_ordering() {
        // inputs are provided in reverse stack order
        let inputs = vec![Felt::new(1), Felt::new(2), Felt::new(3)];
        // we expect the inputs to be padded to length 16 and to remain in reverse stack order.
        let expected_ordering = vec![Felt::new(1), Felt::new(2), Felt::new(3)];

        let note_inputs = NoteInputs::new(inputs).expect("note created should succeed");
        assert_eq!(&expected_ordering, &note_inputs.values);
    }

    #[test]
    fn test_input_serialization() {
        let inputs = vec![Felt::new(1), Felt::new(2), Felt::new(3)];
        let note_inputs = NoteInputs::new(inputs).unwrap();

        let bytes = note_inputs.to_bytes();
        let parsed_note_inputs = NoteInputs::read_from_bytes(&bytes).unwrap();
        assert_eq!(note_inputs, parsed_note_inputs);
    }
}