Skip to content

Commit

Permalink
fix #600
Browse files Browse the repository at this point in the history
  • Loading branch information
hackaugusto committed May 31, 2024
1 parent 0e5ccd5 commit bc65dfe
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 184 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* Replaced `cargo-make` with just `make` for running tasks (#696).
* [BREAKING] Introduce `OutputNote::Partial` variant (#698).
* [BREAKING] Split `Account` struct constructor into `new()` and `from_parts()` (#699).
* [BREAKING] Changed the encoding of inputs notes in the advice map for consumed notes. Now the data
is prefixed by its length, and the input and output notes encoding match (#707).

## 0.3.0 (2024-05-14)

Expand Down
18 changes: 7 additions & 11 deletions miden-lib/asm/kernels/transaction/api.masm
Original file line number Diff line number Diff line change
Expand Up @@ -410,23 +410,19 @@ export.get_note_vault_info
# => [VAULT_HASH, num_assets]
end

#! Returns the number of inputs and inputs hash for the note currently being processed. Panics if
#! a note is not being processed.
#! Returns the current note's inputs hash.
#!
#! Inputs: [0, 0, 0, 0, 0]
#! Outputs: [NOTE_INPUTS_HASH, num_inputs]
#! Inputs: [ZERO]
#! Outputs: [NOTE_INPUTS_HASH]
#!
#! Where:
#! - num_inputs is the number of inputs associated with the note.
#! - NOTE_INPUTS_HASH is the note inputs hash of the note currently being processed.
#! - NOTE_INPUTS_HASH, is the current note's inputs hash.
export.get_note_inputs_hash
# get the number of inputs and the inputs hash
exec.note::get_note_inputs_hash
# => [NOTE_INPUTS_HASH, num_inputs, 0, 0, 0, 0, 0]
# => [NOTE_INPUTS_HASH, ZERO]

# organize the stack for return
movup.5 drop movup.5 drop movup.5 drop movup.5 drop movup.5 drop
# => [NOTE_INPUTS_HASH, num_inputs]
swapw dropw
# => [NOTE_INPUTS_HASH]
end

#! Returns the sender of the note currently being processed. Panics if a note is not being
Expand Down
29 changes: 2 additions & 27 deletions miden-lib/asm/miden/kernels/tx/memory.masm
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,8 @@ const.CONSUMED_NOTE_INPUTS_HASH_OFFSET=3
const.CONSUMED_NOTE_ASSETS_HASH_OFFSET=4
const.CONSUMED_NOTE_METADATA_OFFSET=5
const.CONSUMED_NOTE_ARGS_OFFSET=6
const.CONSUMED_NOTE_NUM_INPUTS_OFFSET=7
const.CONSUMED_NOTE_NUM_ASSETS_OFFSET=8
const.CONSUMED_NOTE_ASSETS_OFFSET=9
const.CONSUMED_NOTE_NUM_ASSETS_OFFSET=7
const.CONSUMED_NOTE_ASSETS_OFFSET=8

# CREATED NOTES
# -------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -898,30 +897,6 @@ export.set_consumed_note_args
mem_storew dropw
end

#! Returns the number of inputs for the consumed note located at the specified memory address.
#!
#! Stack: [consumed_note_ptr]
#! Output: [num_inputs]
#!
#! - consumed_note_ptr is the memory address at which the consumed note data begins.
#! - num_inputs is the number of inputs defined for the consumed note.
export.get_consumed_note_num_inputs
push.CONSUMED_NOTE_NUM_INPUTS_OFFSET add
mem_load
end

#! Sets the number of inputs for a consumed note located at the specified memory address.
#!
#! Stack: [consumed_note_ptr, num_inputs]
#! Output: []
#!
#! - consumed_note_ptr is the memory address at which the consumed note data begins.
#! - num_inputs is the number of inputs for the consumed note.
export.set_consumed_note_num_inputs
push.CONSUMED_NOTE_NUM_INPUTS_OFFSET add
mem_store
end

#! Returns the number of assets in the consumed note located at the specified memory address.
#!
#! Stack: [consumed_note_ptr]
Expand Down
24 changes: 10 additions & 14 deletions miden-lib/asm/miden/kernels/tx/note.masm
Original file line number Diff line number Diff line change
Expand Up @@ -77,31 +77,27 @@ export.get_vault_info
# => [VAULT_HASH, num_assets]
end

#! Returns the number of inputs and inputs hash for the note currently being processed. Panics if
#! a note is not being processed.
#! Returns the commitment to the note's inputs.
#!
#! Panics if a note is not being processed.
#!
#! Inputs: []
#! Outputs: [NOTE_INPUTS_HASH, num_inputs]
#! Outputs: [NOTE_INPUTS_HASH]
#!
#! - num_inputs is the number of inputs associated with the note.
#! Where:
#! - NOTE_INPUTS_HASH is the note inputs hash of the note currently being processed.
export.get_note_inputs_hash
# get the current consumed note pointer
exec.memory::get_current_consumed_note_ptr
# => [ptr]

# assert the pointer is not zero - this would suggest the procedure has been called from an
# incorrect context
# The kernel memory is initialized by prologue::process_input_notes_data, and reset by
# note_processing_teardown before running the tx_script. If the value is `0` it is likely this
# procedure is being called outside of the kernel context.
dup neq.0 assert.err=ERR_NOTE_INVALID_INPUTS
# => [ptr]

# get the number of inputs for the note
dup exec.memory::get_consumed_note_num_inputs
# => [num_inputs, ptr]

# get the note inputs hash from the note pointer
swap exec.memory::get_consumed_note_inputs_hash
# => [NOTE_INPUTS_HASH, num_inputs]
exec.memory::get_consumed_note_inputs_hash
# => [NOTE_INPUTS_HASH]
end

#! Increment current consumed note pointer to the next note and returns the pointer value.
Expand Down
35 changes: 6 additions & 29 deletions miden-lib/asm/miden/kernels/tx/prologue.masm
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ const.ERR_PROLOGUE_ACCT_ID_MISMATCH=0x00020019
# Reference block MMR and note's authentication MMR must match
const.ERR_PROLOGUE_NOTE_MMR_DIGEST_MISMATCH=0x0002001A

# Number of note inputs exceeded the maximum limit of 128
const.ERR_PROLOGUE_NOTE_TOO_MANY_INPUTS=0x0002001B

# Number of note assets exceeded the maximum limit of 256
const.ERR_PROLOGUE_NOTE_TOO_MANY_ASSETS=0x0002001C

Expand Down Expand Up @@ -162,7 +159,7 @@ end
#! This procedure loads the MMR peaks from the advice provider, verifies their hash matches the
#! reference block, and insert the reference block in the MMR. The reference block is added to the
#! MMR so that notes created at this block can be consumed, since the MMR can't contain it and is
#! always one block behind. The number MMR peaks in is variable, from 16 up to 63, depending on
#! always one block behind. The number MMR peaks is variable, from 16 up to 63, depending on
#! `num_blocks`.
#!
#! Stack: []
Expand Down Expand Up @@ -564,7 +561,6 @@ end
#! ASSETS_HASH,
#! METADATA,
#! ARGS,
#! inputs_count,
#! assets_count,
#! ASSET_0, ..., ASSET_N,
#! block_num,
Expand All @@ -581,14 +577,13 @@ end
#! - ASSETS_HASH, sequential hash of the padded note's assets.
#! - METADATA, note's metadata.
#! - ARGS, user arguments passed to the note.
#! - inputs_count, note's inputs count.
#! - assets_count, note's assets count.
#! - ASSET_0, ..., ASSET_N, padded note's assets.
#! - block_num, note's creation block number.
#! - SUB_HASH, the block's sub_hash for which the note was created.
#! - NOTE_ROOT, the merkle root of the note's tree.
proc.process_input_note
# nullifier
# note details
# ---------------------------------------------------------------------------------------------

dup exec.memory::get_consumed_note_ptr
Expand All @@ -597,7 +592,7 @@ proc.process_input_note
dup exec.memory::get_consumed_note_core_ptr
# => [note_data_ptr, note_ptr, idx]

# read nullifier (SERIAL_NUMBER, SCRIPT_ROOT, INPUTS_HASH, ASSETS_HASH)
# read note details (SERIAL_NUMBER, SCRIPT_ROOT, INPUTS_HASH, ASSETS_HASH)
padw padw padw
adv_pipe hperm
adv_pipe hperm
Expand All @@ -621,18 +616,6 @@ proc.process_input_note
padw adv_loadw dup.4 exec.memory::set_consumed_note_args
# => [note_ptr]

# number of inputs
# ---------------------------------------------------------------------------------------------

adv_push.1
# => [num_inputs, note_ptr]

dup exec.constants::get_max_inputs_per_note lte assert.err=ERR_PROLOGUE_NOTE_TOO_MANY_INPUTS
# => [num_inputs, note_ptr]

dup.1 exec.memory::set_consumed_note_num_inputs
# => [note_ptr]

# assets
# ---------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -761,19 +744,13 @@ end
#!
#! Stack: []
#! Advice stack: [num_notes],
#! Advice map: { NULLIFIER_COMMITMENT => [(SERIAL_NUMBER, SCRIPT_ROOT, INPUTS_HASH, ASSETS_HASH, METADATA, NA, A0, ..., An){num_notes}] }
#! Advice map: { NULLIFIER_COMMITMENT => NOTE_DATA }
#! Output: []
#!
#! Where:
#! - num_notes is the number of input notes.
#! - NULLIFIER_COMMITMENT, sequential hash of all input notes' nullifiers.
#! - SERIAL_NUMBER, note's serial.
#! - SCRIPT_ROOT, note's script root.
#! - INPUTS_HASH, sequential hash of the padded note's inputs.
#! - ASSETS_HASH, sequential hash of the padded note's assets.
#! - METADATA, note's metadata.
#! - NA are optional note args for the nth input note.
#! - A0..An are the assets of the nth input note.
#! - NOTE_DATA, input notes' details, for format see prologue::process_input_note.
proc.process_input_notes_data
# get the number of input notes from the advice stack
adv_push.1
Expand Down Expand Up @@ -952,7 +929,7 @@ end
#! - number_of_input_notes, number of input notes.
#! - TX_SCRIPT_ROOT, the transaction's script root.
#! - MMR_PEAKS, is the MMR peak data, see process_chain_data
#! - NOTE_DATA, is the data of all input notes, see process_input_notes_data
#! - NOTE_DATA, input notes' details, for format see prologue::process_input_note.
export.prepare_transaction
exec.process_global_inputs
# => []
Expand Down
31 changes: 22 additions & 9 deletions miden-lib/asm/miden/note.masm
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use.miden::kernels::tx::constants
use.std::crypto::hashes::native
use.std::mem

Expand All @@ -7,6 +8,9 @@ use.std::mem
# Provided note data does not match the commitment
const.ERR_NOTE_DATA_MISMATCH=0x00020040

# Number of note inputs exceeded the maximum limit of 128
const.ERR_NOTE_TOO_MANY_INPUTS=0x0002001B

#! Writes the data currently on the advice stack into the memory at the specified location and
#! verifies that the hash of the written data is equal to the provided hash.
#!
Expand Down Expand Up @@ -68,25 +72,34 @@ end

#! Loads the note's inputs to `dest_ptr`.
#!
#! Inputs: [dest_ptr]
#! Outputs: [num_inputs, dest_ptr]
#! Advice Map: { INPUTS_HASH: INPUTS }
#! Inputs:
#! Stack: [dest_ptr]
#! Advice Map: { INPUTS_HASH: [inputs_len, INPUTS] }
#! Outputs:
#! Stack: [num_inputs, dest_ptr]
#!
#! Where:
#! - dest_ptr is the memory address to write the inputs.
#! - INPUTS_HASH, sequential hash of the padded note's inputs.
#! - inputs_len, the note's input count.
#! - INPUTS, the data corresponding to the note's inputs.
export.get_inputs
# get the current consumed note inputs hash
padw push.0 syscall.get_note_inputs_hash
# => [INPUTS_HASH, num_inputs, dest_ptr]
padw syscall.get_note_inputs_hash
# => [INPUTS_HASH, dest_ptr]

# load the inputs from the advice map to the advice stack
adv.push_mapval
# => [INPUTS_HASH, num_inputs, dest_ptr]
# => [INPUTS_HASH, dest_ptr]

adv_push.1
# => [num_inputs, INPUTS_HASH, dest_ptr]

# validate the input length
dup exec.constants::get_max_inputs_per_note lte assert.err=ERR_NOTE_TOO_MANY_INPUTS
# => [num_inputs, INPUTS_HASH, dest_ptr]

# calculate the number of words required to store the inputs
dup.4 u32divmod.4 neq.0 add
dup movdn.5 u32divmod.4 neq.0 add
# => [num_words, INPUTS_HASH, num_inputs, dest_ptr]

# round up the number of words the next multiple of 2
Expand All @@ -97,7 +110,7 @@ export.get_inputs
dup.6 add dup.6
# => [start_ptr, end_ptr, INPUTS_HASH, num_inputs, dest_ptr]

# write the data from the advice stack into memory
# check the input data matches the commitment, and write it to memory.
exec.write_advice_data_to_memory
# => [num_inputs, dest_ptr]
end
Expand Down
16 changes: 5 additions & 11 deletions miden-lib/src/tests/test_prologue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ use crate::transaction::{
CHAIN_MMR_NUM_LEAVES_PTR, CHAIN_MMR_PEAKS_PTR, CHAIN_ROOT_PTR, CONSUMED_NOTE_ARGS_OFFSET,
CONSUMED_NOTE_ASSETS_HASH_OFFSET, CONSUMED_NOTE_ASSETS_OFFSET, CONSUMED_NOTE_ID_OFFSET,
CONSUMED_NOTE_INPUTS_HASH_OFFSET, CONSUMED_NOTE_METADATA_OFFSET,
CONSUMED_NOTE_NUM_ASSETS_OFFSET, CONSUMED_NOTE_NUM_INPUTS_OFFSET,
CONSUMED_NOTE_SCRIPT_ROOT_OFFSET, CONSUMED_NOTE_SECTION_OFFSET,
CONSUMED_NOTE_SERIAL_NUM_OFFSET, INIT_ACCT_HASH_PTR, INIT_NONCE_PTR, NOTE_ROOT_PTR,
NULLIFIER_COMMITMENT_PTR, NULLIFIER_DB_ROOT_PTR, PREV_BLOCK_HASH_PTR, PROOF_HASH_PTR,
PROTOCOL_VERSION_IDX, TIMESTAMP_IDX, TX_SCRIPT_ROOT_PTR,
CONSUMED_NOTE_NUM_ASSETS_OFFSET, CONSUMED_NOTE_SCRIPT_ROOT_OFFSET,
CONSUMED_NOTE_SECTION_OFFSET, CONSUMED_NOTE_SERIAL_NUM_OFFSET, INIT_ACCT_HASH_PTR,
INIT_NONCE_PTR, NOTE_ROOT_PTR, NULLIFIER_COMMITMENT_PTR, NULLIFIER_DB_ROOT_PTR,
PREV_BLOCK_HASH_PTR, PROOF_HASH_PTR, PROTOCOL_VERSION_IDX, TIMESTAMP_IDX,
TX_SCRIPT_ROOT_PTR,
},
TransactionKernel,
};
Expand Down Expand Up @@ -320,12 +320,6 @@ fn consumed_notes_memory_assertions(
"note args should be stored at the correct offset"
);

assert_eq!(
read_note_element(process, note_idx, CONSUMED_NOTE_NUM_INPUTS_OFFSET),
[Felt::from(note.inputs().num_values() as u32), ZERO, ZERO, ZERO],
"number of inputs should be stored at the correct offset"
);

assert_eq!(
read_note_element(process, note_idx, CONSUMED_NOTE_NUM_ASSETS_OFFSET),
[Felt::from(note.assets().num_assets() as u32), ZERO, ZERO, ZERO],
Expand Down
16 changes: 16 additions & 0 deletions miden-lib/src/transaction/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ use miden_objects::{
pub enum TransactionKernelError {
FailedToAddAssetToNote(NoteError),
InvalidStorageSlotIndex(u64),
InvalidNoteInputs {
expected: Digest,
got: Digest,
data: Option<Vec<Felt>>,
},
MalformedAccountId(AccountError),
MalformedAsset(AssetError),
MalformedAssetOnAccountVaultUpdate(AssetError),
Expand All @@ -24,6 +29,7 @@ pub enum TransactionKernelError {
MalformedRecipientData(Vec<Felt>),
MalformedTag(Felt),
MissingNoteDetails(NoteMetadata, Digest),
MissingNoteInputs,
MissingStorageSlotValue(u8, String),
UnknownAccountProcedure(Digest),
MissingNote(String),
Expand All @@ -39,6 +45,13 @@ impl fmt::Display for TransactionKernelError {
let num_slots = AccountStorage::NUM_STORAGE_SLOTS;
write!(f, "storage slot index {index} is invalid, must be smaller than {num_slots}")
},
TransactionKernelError::InvalidNoteInputs { expected, got, data } => {
write!(
f,
"The note input data does not match its hash, expected: {} got: {} data {:?}",
expected, got, data
)
},
TransactionKernelError::MalformedAccountId(err) => {
write!( f, "Account id data extracted from the stack by the event handler is not well formed {err}")
},
Expand Down Expand Up @@ -78,6 +91,9 @@ impl fmt::Display for TransactionKernelError {
TransactionKernelError::MissingNoteDetails(metadata, recipient) => {
write!( f, "Public note missing the details in the advice provider. metadata: {metadata:?}, recipient: {recipient:?}")
},
TransactionKernelError::MissingNoteInputs => {
write!(f, "Public note missing or incomplete inputs in the advice provider")
},
TransactionKernelError::MissingStorageSlotValue(index, err) => {
write!(f, "value for storage slot {index} could not be found: {err}")
},
Expand Down
Loading

0 comments on commit bc65dfe

Please sign in to comment.