Skip to content

Commit

Permalink
feat: enable variable number of note inputs (#455)
Browse files Browse the repository at this point in the history
  • Loading branch information
bobbinth authored Feb 12, 2024
1 parent b3dfd19 commit 3c5d56f
Show file tree
Hide file tree
Showing 20 changed files with 322 additions and 189 deletions.
21 changes: 11 additions & 10 deletions miden-lib/asm/kernels/transaction/api.masm
Original file line number Diff line number Diff line change
Expand Up @@ -308,21 +308,22 @@ export.get_note_vault_info
# => [VAULT_HASH, num_assets]
end

#! Returns the note inputs hash of the note currently being processed. Panics if a note is not
#! being processed.
#! Returns the number of inputs and inputs hash for the note currently being processed. Panics if
#! a note is not being processed.
#!
#! Inputs: [0, 0, 0, 0]
#! Outputs: [NOTE_INPUTS_HASH]
#! Inputs: [0, 0, 0, 0, 0]
#! Outputs: [NOTE_INPUTS_HASH, num_inputs]
#!
#! - 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.
export.get_note_inputs_hash
# get the note inputs hash
exec.note::get_inputs_hash
# => [NOTE_INPUTS_HASH, 0, 0, 0, 0]
export.get_note_inputs_info
# get the number of inputs and the inputs hash
exec.note::get_inputs_info
# => [NOTE_INPUTS_HASH, num_inputs, 0, 0, 0, 0, 0]

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

#! Returns the sender of the note currently being processed. Panics if a note is not being
Expand Down
13 changes: 13 additions & 0 deletions miden-lib/asm/miden/kernels/tx/constants.masm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# The number of elements in a Word
const.WORD_SIZE=4

# The maximum number of input values associated with a single note.
const.MAX_INPUTS_PER_NOTE=128

# The maximum number of assets that can be stored in a single note.
const.MAX_ASSETS_PER_NOTE=256

Expand Down Expand Up @@ -40,6 +43,16 @@ export.get_word_size
push.WORD_SIZE
end

#! Returns the max allowed number of input values per note.
#!
#! Stack: []
#! Output: [max_inputs_per_note]
#!
#! - max_inputs_per_note is the max inputs per note.
export.get_max_inputs_per_note
push.MAX_INPUTS_PER_NOTE
end

#! Returns the max allowed number of assets per note.
#!
#! Stack: []
Expand Down
34 changes: 31 additions & 3 deletions miden-lib/asm/miden/kernels/tx/memory.masm
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ const.ACCT_STORAGE_SLOT_TYPE_DATA_OFFSET=405
# The memory address at which the consumed note section begins.
const.CONSUMED_NOTE_SECTION_OFFSET=1048576

# The memory address at which the consumed note data section begins.
const.CONSUMED_NOTE_DATA_SECTION_OFFSET=1064960

# The memory address at which the number of consumed notes is stored.
const.CONSUMED_NOTE_NUM_PTR=1048576

Expand All @@ -133,8 +136,9 @@ const.CONSUMED_NOTE_SCRIPT_ROOT_OFFSET=2
const.CONSUMED_NOTE_INPUTS_HASH_OFFSET=3
const.CONSUMED_NOTE_ASSETS_HASH_OFFSET=4
const.CONSUMED_NOTE_METADATA_OFFSET=5
const.CONSUMED_NOTE_NUM_ASSETS_OFFSET=6
const.CONSUMED_NOTE_ASSETS_OFFSET=7
const.CONSUMED_NOTE_NUM_INPUTS_OFFSET=6
const.CONSUMED_NOTE_NUM_ASSETS_OFFSET=7
const.CONSUMED_NOTE_ASSETS_OFFSET=8

# CREATED NOTES
# -------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -755,7 +759,7 @@ end
#! - i is the index of the consumed note.
#! - ptr is the memory address of the data segment for consumed note i.
export.get_consumed_note_ptr
add.1 exec.constants::get_note_mem_size mul push.CONSUMED_NOTE_SECTION_OFFSET add
exec.constants::get_note_mem_size mul push.CONSUMED_NOTE_DATA_SECTION_OFFSET add
end

#! Set the hash of the consumed note at the specified memory address.
Expand Down Expand Up @@ -855,6 +859,30 @@ export.set_consumed_note_metadata
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
17 changes: 11 additions & 6 deletions miden-lib/asm/miden/kernels/tx/note.masm
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,15 @@ export.get_vault_info
# => [VAULT_HASH, num_assets]
end

#! Returns the note inputs hash of the note currently being processed. Panics if a note is not
#! being processed.
#! Returns the number of inputs and inputs hash for the note currently being processed. Panics if
#! a note is not being processed.
#!
#! Inputs: []
#! Outputs: [NOTE_INPUTS_HASH]
#! Outputs: [NOTE_INPUTS_HASH, num_inputs]
#!
#! - 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.
export.get_inputs_hash
export.get_inputs_info
# get the current consumed note pointer
exec.memory::get_current_consumed_note_ptr
# => [ptr]
Expand All @@ -77,9 +78,13 @@ export.get_inputs_hash
dup neq.0 assert
# => [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
exec.memory::get_consumed_note_inputs_hash
# => [NOTE_INPUTS_HASH]
swap exec.memory::get_consumed_note_inputs_hash
# => [NOTE_INPUTS_HASH, num_inputs]
end

#! Increment current consumed note pointer to the next note and returns the pointer value.
Expand Down
20 changes: 16 additions & 4 deletions miden-lib/asm/miden/kernels/tx/prologue.masm
Original file line number Diff line number Diff line change
Expand Up @@ -487,8 +487,7 @@ end
#!
#! Stack: [i]
#! Advice stack: [CN1_SN, CN1_SR, CN1_IR, CN1_VR,
#! CN1_NA,
#! CN1_A1, CN1_A2, ...]
#! C1_NI, CN1_NA, CN1_A1, CN1_A2, ...]
#!
#! Output: []
#!
Expand All @@ -498,6 +497,7 @@ end
#! - CN1_SR is the script root of input note 1.
#! - CN1_IR is the inputs root of input note 1.
#! - CN1_VR is the vault root of input note 1.
#! - CN1_NI is the number of inputs in input note 1.
#! - CN1_NA is the number of assets in input note 1.
#! - CN1_A1 is the first asset of input note 1.
#! - CN1_A2 is the second asset of input note 1.
Expand Down Expand Up @@ -534,16 +534,25 @@ proc.process_input_note
mem_storew dropw
# => [note_ptr]

# ingest note assets
# ingest note metadata
# ---------------------------------------------------------------------------------------------

# read the metadata from the advice provider and store in memory
# get the metadata from the advice provider and store in memory
padw adv_loadw dup.4
# => [note_ptr, NOTE_META, note_ptr]

exec.memory::set_consumed_note_metadata
# => [note_ptr]

# get the number of inputs from the advice provider and store it in memory
adv_push.1 dup dup.2
exec.memory::set_consumed_note_num_inputs
# => [num_inputs, note_ptr]

# make sure the number of inputs is in the valid range
exec.constants::get_max_inputs_per_note lte assert
# => [note_ptr]

# get the number of assets from the advice provider and store it in memory
adv_push.1 dup dup.2
exec.memory::set_consumed_note_num_assets
Expand All @@ -553,6 +562,9 @@ proc.process_input_note
dup exec.constants::get_max_assets_per_note lte assert
# => [num_assets, note_ptr]

# ingest note assets
# ---------------------------------------------------------------------------------------------

# round up the number of assets to the next multiple of 2 (simplifies reading of assets)
dup push.1 u32and add
# => [rounded_num_assets, note_ptr]
Expand Down
84 changes: 47 additions & 37 deletions miden-lib/asm/miden/note.masm
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
use.std::crypto::hashes::native
use.std::mem

#! 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.
#!
#! Inputs: [start_ptr, end_ptr, HASH]
#! Outputs: []
proc.write_advice_data_to_memory
# prepare the stack for reading from the advice stack
padw padw padw
# => [PAD, PAD, PAD, start_ptr, end_ptr, HASH]

# read the data from advice stack to memory
exec.mem::pipe_double_words_to_memory
# => [PERM, PERM, PERM, end_ptr, HASH]

# extract the digest
exec.native::state_to_digest
# => [DIGEST, end_ptr, HASH]

# drop pointer for reading from memory
movup.4 drop
# => [DIGEST, HASH]

# assert the computed hash is equal to the expected hash
assert_eqw
# => []
end

#! Writes the assets of the currently executing note into memory starting at the specified address.
#!
#! Inputs: [dest_ptr]
Expand Down Expand Up @@ -28,61 +55,44 @@ export.get_assets
dup.6 add dup.6
# => [start_ptr, end_ptr, VAULT_HASH, num_assets, dest_ptr]

# prepare the stack for reading from the advice stack
padw padw padw
# => [PAD, PAD, PAD, start_ptr, end_ptr, VAULT_HASH, num_assets, dest_ptr]

# read the assets from advice stack to memory
exec.mem::pipe_double_words_to_memory
# => [PERM, PERM, PERM, end_ptr, VAULT_HASH, num_assets, dest_ptr]

# extract the digest
exec.native::state_to_digest
# => [DIGEST, end_ptr, VAULT_HASH, num_assets, dest_ptr]

# drop pointer for reading from memory
movup.4 drop
# => [DIGEST, VAULT_HASH, num_assets, dest_ptr]

# assert the vault hash is what we expect
assert_eqw
# write the data from the advice stack into memory
exec.write_advice_data_to_memory
# => [num_assets, dest_ptr]
end

#! Writes the inputs of the currently execute note into memory starting at the specified address.
#!
#! Inputs: [dest_ptr]
#! Outputs: [dest_ptr]
#! Outputs: [num_inputs, dest_ptr]
#!
#! - dest_ptr is the memory address to write the inputs.
export.get_inputs
# duplicate the dest_ptr
dup
# => [dest_ptr, dest_ptr]
padw push.0
# => [0, 0, 0, 0, 0, dest_ptr]

# get the current consumed note inputs hash
padw syscall.get_note_inputs_hash
# => [INPUTS_HASH, dest_ptr, dest_ptr]
syscall.get_note_inputs_info
# => [INPUTS_HASH, num_inputs, dest_ptr]

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

# prepare stack for inputs ingestion
movup.4 padw padw padw
# => [WORD, WORD, ZERO, addr, INPUTS_HASH, dest_ptr]
# calculate the number of words required to store the inputs
dup.4 u32divmod.4 neq.0 add
# => [num_words, INPUTS_HASH, num_inputs, dest_ptr]

# load the note inputs from the advice provider
adv_pipe hperm adv_pipe hperm
# => [PERM, PERM, PERM, addr', INPUTS_HASH, dest_ptr]
# round up the number of words the next multiple of 2
dup is_odd add
# => [even_num_words, INPUTS_HASH, num_inputs, dest_ptr]

# extract inputs hash and assert it matches commitment stored in memory
dropw swapw dropw movup.4 drop
# => [DIG, INPUTS_HASH, dest_ptr]
# calculate the start and end pointer for reading to memory
dup.6 add dup.6
# => [start_ptr, end_ptr, INPUTS_HASH, num_inputs, dest_ptr]

# assert the inputs hash matches the commitment stored in memory
assert_eqw
# => [dest_ptr]
# write the data from the advice stack into memory
exec.write_advice_data_to_memory
# => [num_inputs, dest_ptr]
end

#! Returns the sender of the note currently being processed. Panics if a note is not being
Expand Down
4 changes: 4 additions & 0 deletions miden-lib/asm/note_scripts/P2ID.masm
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ begin

# store the note inputs to memory starting at address 0
push.0 exec.note::get_inputs
# => [num_inputs, inputs_ptr]

# make sure the number of inputs is 1
eq.1 assert
# => [inputs_ptr]

# read the target account id from the note inputs
Expand Down
4 changes: 4 additions & 0 deletions miden-lib/asm/note_scripts/P2IDR.masm
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ begin

# store the note inputs to memory starting at address 0
push.0 exec.note::get_inputs
# => [num_inputs, inputs_ptr]

# make sure the number of inputs is 2
eq.2 assert
# => [inputs_ptr]

# read the reclaim block height and target account id from the note inputs
Expand Down
4 changes: 4 additions & 0 deletions miden-lib/asm/note_scripts/SWAP.masm
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ begin

# store note inputs into memory starting at address 0
push.0 exec.note::get_inputs
# => [num_inputs, inputs_ptr]

# make sure the number of inputs is 9
eq.9 assert
# => [inputs_ptr]

# load recipient
Expand Down
9 changes: 3 additions & 6 deletions miden-lib/src/notes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use miden_objects::{
accounts::AccountId, assets::Asset, crypto::rand::FeltRng, notes::Note,
utils::collections::Vec, Felt, NoteError, Word, ZERO,
utils::collections::Vec, Felt, NoteError, Word,
};

use self::utils::build_note_script;
Expand Down Expand Up @@ -29,7 +29,7 @@ pub fn create_p2id_note<R: FeltRng>(
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/P2ID.masb"));
let note_script = build_note_script(bytes)?;

let inputs = [target.into(), ZERO, ZERO, ZERO];
let inputs = [target.into()];
let tag: Felt = target.into();
let serial_num = rng.draw_word();

Expand Down Expand Up @@ -58,7 +58,7 @@ pub fn create_p2idr_note<R: FeltRng>(
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/P2IDR.masb"));
let note_script = build_note_script(bytes)?;

let inputs = [target.into(), recall_height.into(), ZERO, ZERO];
let inputs = [target.into(), recall_height.into()];
let tag: Felt = target.into();
let serial_num = rng.draw_word();

Expand Down Expand Up @@ -96,9 +96,6 @@ pub fn create_swap_note<R: FeltRng>(
asset_word[2],
asset_word[3],
sender.into(),
ZERO,
ZERO,
ZERO,
];

let tag: Felt = Felt::new(0);
Expand Down
Loading

0 comments on commit 3c5d56f

Please sign in to comment.