use alloc::vec::Vec;
use crate::errors::NoteError;
use crate::utils::serde::{
ByteReader,
ByteWriter,
Deserializable,
DeserializationError,
Serializable,
};
use crate::{Felt, Hasher, MAX_INPUTS_PER_NOTE, WORD_SIZE, Word, ZERO};
#[derive(Clone, Debug)]
pub struct NoteInputs {
values: Vec<Felt>,
commitment: Word,
}
impl NoteInputs {
pub fn new(values: Vec<Felt>) -> Result<Self, NoteError> {
if values.len() > MAX_INPUTS_PER_NOTE {
return Err(NoteError::TooManyInputs(values.len()));
}
Ok(pad_and_build(values))
}
pub fn commitment(&self) -> Word {
self.commitment
}
pub fn num_values(&self) -> u8 {
const _: () = assert!(MAX_INPUTS_PER_NOTE <= u8::MAX as usize);
debug_assert!(
self.values.len() < MAX_INPUTS_PER_NOTE,
"The constructor should have checked the number of inputs"
);
self.values.len() as u8
}
pub fn values(&self) -> &[Felt] {
&self.values
}
pub fn to_elements(&self) -> Vec<Felt> {
pad_inputs(&self.values)
}
}
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, commitment: _ } = self;
inputs == &other.values
}
}
impl Eq for NoteInputs {}
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)
}
}
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
}
fn pad_and_build(values: Vec<Felt>) -> NoteInputs {
let commitment = {
let padded_values = pad_inputs(&values);
Hasher::hash_elements(&padded_values)
};
NoteInputs { values, commitment }
}
impl Serializable for NoteInputs {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
let NoteInputs { values, commitment: _commitment } = 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}")))
}
}
#[cfg(test)]
mod tests {
use miden_crypto::utils::Deserializable;
use super::{Felt, NoteInputs, Serializable};
#[test]
fn test_input_ordering() {
let inputs = vec![Felt::new(1), Felt::new(2), Felt::new(3)];
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, ¬e_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);
}
}