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
use super::{
    ByteReader, ByteWriter, Deserializable, DeserializationError, Digest, Felt, Hasher, NoteError,
    Serializable, WORD_SIZE, ZERO,
};
use crate::{
    utils::{collections::*, format},
    MAX_INPUTS_PER_NOTE,
};

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

/// An 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()));
        }

        let hash = {
            let padded_values = pad_inputs(&values);
            Hasher::hash_elements(&padded_values)
        };

        Ok(Self { values, hash })
    }

    // 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 {
        self.values.len() as u8
    }

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

    /// Returns a vector of input values padded with ZEROs to the next multiple of 8.
    pub fn to_padded_values(&self) -> Vec<Felt> {
        pad_inputs(&self.values)
    }

    /// Returns a vector of input values.
    pub fn to_vec(&self) -> Vec<Felt> {
        self.values.to_vec()
    }
}

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

impl Eq for NoteInputs {}

// 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
}

// 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);
    }
}