Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

### Changes

- No longer pad the note inputs on insertion into advice map ([#2232](https://github.com/0xMiden/miden-base/pull/2232)).
- Added proc-macro `WordWrapper` to ease implementation of `Word`-wrapping types ([#2071](https://github.com/0xMiden/miden-base/pull/2108)).
- [BREAKING] Added `BlockBody` and `BlockProof` structs in preparation for validator signatures and deferred block proving ([#2012](https://github.com/0xMiden/miden-base/pull/2012)).
- [BREAKING] Renamed `TransactionEvent` into `TransactionEventId` and split event handling into data extraction and handling logic ([#2071](https://github.com/0xMiden/miden-base/pull/2071)).
Expand Down
8 changes: 1 addition & 7 deletions crates/miden-protocol/asm/protocol/active_note.masm
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ end
#! Operand stack: [num_inputs, dest_ptr]
proc write_inputs_to_memory
# load the inputs from the advice map to the advice stack
adv.push_mapvaln
adv.push_mapvaln.8
# OS => [NOTE_INPUTS_COMMITMENT, num_inputs, dest_ptr]
# AS => [advice_num_inputs, [INPUT_VALUES]]

Expand All @@ -283,12 +283,6 @@ proc write_inputs_to_memory
# OS => [num_inputs, advice_num_inputs, NOTE_INPUTS_COMMITMENT, num_inputs, dest_ptr]
# AS => [[INPUT_VALUES]]

# Validate the note inputs length. Round up the number of inputs to the next multiple of 8: that
# value should be equal to the length obtained from the `adv.push_mapvaln` procedure.
u32divmod.8 neq.0 add mul.8
# OS => [rounded_up_num_inputs, advice_num_inputs, NOTE_INPUTS_COMMITMENT, num_inputs, dest_ptr]
# AS => [[INPUT_VALUES]]

assert_eq.err=ERR_NOTE_INVALID_NUMBER_OF_INPUTS
# OS => [NOTE_INPUTS_COMMITMENT, num_inputs, dest_ptr]
# AS => [[INPUT_VALUES]]
Expand Down
7 changes: 1 addition & 6 deletions crates/miden-protocol/src/note/inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,8 @@ impl NoteInputs {
}

/// Returns the note's input as a vector of field elements.
///
/// The format is `INPUTS || PADDING`, where:
///
/// - INPUTS is the variable inputs for the note
/// - PADDING is the optional padding to align the data with a 2WORD boundary
pub fn to_elements(&self) -> Vec<Felt> {
pad_inputs(&self.values)
self.values.to_vec()
}
}

Expand Down
67 changes: 40 additions & 27 deletions crates/miden-testing/src/kernel_tests/tx/test_note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use miden_protocol::testing::account_id::{
};
use miden_protocol::transaction::memory::ACTIVE_INPUT_NOTE_PTR;
use miden_protocol::transaction::{OutputNote, TransactionArgs};
use miden_protocol::{Felt, Word, ZERO};
use miden_protocol::{Felt, Hasher, Word, ZERO};
use miden_standards::account::wallets::BasicWallet;
use miden_standards::code_builder::CodeBuilder;
use miden_standards::testing::note::NoteBuilder;
Expand Down Expand Up @@ -198,82 +198,95 @@ async fn test_build_recipient() -> anyhow::Result<()> {
// Define test values as Words
let word_1 = Word::from([1, 2, 3, 4u32]);
let word_2 = Word::from([5, 6, 7, 8u32]);
let word_3 = Word::from([9, 10, 11, 12u32]);
let word_4 = Word::from([13, 14, 15, 16u32]);
const BASE_ADDR: u32 = 4000;

let code = format!(
"
use miden::core::sys

use miden::protocol::note

begin
# put the values that will be hashed into the memory
push.{word_1} push.{base_addr} mem_storew_be dropw
push.{word_2} push.{addr_1} mem_storew_be dropw
push.{word_3} push.{addr_2} mem_storew_be dropw
push.{word_4} push.{addr_3} mem_storew_be dropw

# Test with 4 values
# Test with 4 values (needs padding to 8)
push.{script_root} # SCRIPT_ROOT
push.{serial_num} # SERIAL_NUM
push.4.4000 # num_inputs, inputs_ptr
exec.note::build_recipient
# => [RECIPIENT_4]

# Test with 5 values
# Test with 5 values (needs padding to 8)
push.{script_root} # SCRIPT_ROOT
push.{serial_num} # SERIAL_NUM
push.5.4000 # num_inputs, inputs_ptr
exec.note::build_recipient
# => [RECIPIENT_5, RECIPIENT_4]

# Test with 13 values
# Test with 8 values (no padding needed - exactly one rate block)
push.{script_root} # SCRIPT_ROOT
push.{serial_num} # SERIAL_NUM
push.13.4000 # num_inputs, inputs_ptr
push.8.4000 # num_inputs, inputs_ptr
exec.note::build_recipient
# => [RECIPIENT_13, RECIPIENT_5, RECIPIENT_4]
# => [RECIPIENT_8, RECIPIENT_5, RECIPIENT_4]

# truncate the stack
exec.sys::truncate_stack
end
",
word_1 = word_1,
word_2 = word_2,
word_3 = word_3,
word_4 = word_4,
base_addr = BASE_ADDR,
addr_1 = BASE_ADDR + 4,
addr_2 = BASE_ADDR + 8,
addr_3 = BASE_ADDR + 12,
script_root = note_script.root(),
serial_num = serial_num,
);

let exec_output = &tx_context.execute_code(&code).await?;

// Create expected recipients and get their digests
let note_inputs_4 = NoteInputs::new(word_1.to_vec())?;
let recipient_4 = NoteRecipient::new(serial_num, note_script.clone(), note_inputs_4);
// Create expected NoteInputs for each test case
let inputs_4 = word_1.to_vec();
let note_inputs_4 = NoteInputs::new(inputs_4.clone())?;

let mut inputs_5 = word_1.to_vec();
inputs_5.push(word_2[0]);
let note_inputs_5 = NoteInputs::new(inputs_5)?;
let recipient_5 = NoteRecipient::new(serial_num, note_script.clone(), note_inputs_5);
let note_inputs_5 = NoteInputs::new(inputs_5.clone())?;

let mut inputs_13 = word_1.to_vec();
inputs_13.extend_from_slice(&word_2.to_vec());
inputs_13.extend_from_slice(&word_3.to_vec());
inputs_13.push(word_4[0]);
let note_inputs_13 = NoteInputs::new(inputs_13)?;
let recipient_13 = NoteRecipient::new(serial_num, note_script, note_inputs_13);
let mut inputs_8 = word_1.to_vec();
inputs_8.extend_from_slice(&word_2.to_vec());
let note_inputs_8 = NoteInputs::new(inputs_8.clone())?;

// Create expected recipients and get their digests
let recipient_4 = NoteRecipient::new(serial_num, note_script.clone(), note_inputs_4.clone());
let recipient_5 = NoteRecipient::new(serial_num, note_script.clone(), note_inputs_5.clone());
let recipient_8 = NoteRecipient::new(serial_num, note_script.clone(), note_inputs_8.clone());

for note_inputs in [
(note_inputs_4, inputs_4.clone()),
(note_inputs_5, inputs_5.clone()),
(note_inputs_8, inputs_8.clone()),
] {
let inputs_advice_map_key = note_inputs.0.commitment();
assert_eq!(
exec_output.advice.get_mapped_values(&inputs_advice_map_key).unwrap(),
note_inputs.1,
"advice entry with note inputs should contain the unpadded values"
);

let num_inputs_advice_map_key =
Hasher::hash_elements(note_inputs.0.commitment().as_elements());
assert_eq!(
exec_output.advice.get_mapped_values(&num_inputs_advice_map_key).unwrap(),
&[Felt::from(note_inputs.0.num_values())],
"advice entry with num note inputs should contain the original number of values"
);
}

let mut expected_stack = alloc::vec::Vec::new();
expected_stack.extend_from_slice(recipient_4.digest().as_elements());
expected_stack.extend_from_slice(recipient_5.digest().as_elements());
expected_stack.extend_from_slice(recipient_13.digest().as_elements());
expected_stack.extend_from_slice(recipient_8.digest().as_elements());
expected_stack.reverse();

assert_eq!(exec_output.stack[0..12], expected_stack);
Expand Down
Loading