use miden::core::crypto::hashes::poseidon2
use miden::core::mem
use miden::protocol::kernel_proc_offsets::INPUT_NOTE_GET_ASSETS_INFO_OFFSET
use miden::protocol::kernel_proc_offsets::INPUT_NOTE_GET_RECIPIENT_OFFSET
use miden::protocol::kernel_proc_offsets::INPUT_NOTE_GET_STORAGE_INFO_OFFSET
use miden::protocol::kernel_proc_offsets::INPUT_NOTE_GET_METADATA_OFFSET
use miden::protocol::kernel_proc_offsets::INPUT_NOTE_GET_SERIAL_NUMBER_OFFSET
use miden::protocol::kernel_proc_offsets::INPUT_NOTE_GET_SCRIPT_ROOT_OFFSET
use miden::protocol::note
# ERRORS
# =================================================================================================
const ERR_NOTE_DATA_DOES_NOT_MATCH_COMMITMENT="note data does not match the commitment"
const ERR_NOTE_INVALID_NUMBER_OF_STORAGE_ITEMS="the specified number of note storage items does not match the actual number"
# ACTIVE NOTE PROCEDURES
# =================================================================================================
#
# By the "active note" notion here we assume the note which is currently being processed by the
# transaction kernel.
#! Writes the assets of the active note into memory starting at the specified address.
#!
#! Inputs: [dest_ptr]
#! Outputs: [num_assets, dest_ptr]
#!
#! Where:
#! - dest_ptr is the memory address to write the assets.
#! - num_assets is the number of assets in the active note.
#!
#! Panics if:
#! - no note is currently active.
#!
#! Invocation: exec
pub proc get_assets
# pad the stack
padw padw padw push.0.0
# => [pad(14), dest_ptr]
# push the flag indicating that we want to request assets info from the active note
push.1
# => [is_active_note = 1, pad(14), dest_ptr]
push.INPUT_NOTE_GET_ASSETS_INFO_OFFSET
# => [offset, is_active_note = 1, pad(14), dest_ptr]
syscall.exec_kernel_proc
# => [ASSETS_COMMITMENT, num_assets, pad(11), dest_ptr]
# clean the stack
swapdw dropw dropw movup.7 movup.7 movup.7 drop drop drop
# => [ASSETS_COMMITMENT, num_assets, dest_ptr]
# write the assets from the advice map into memory
exec.note::write_assets_to_memory
# => [num_assets, dest_ptr]
end
#! Returns the recipient of the active note.
#!
#! Inputs: []
#! Outputs: [RECIPIENT]
#!
#! Where:
#! - RECIPIENT is the commitment to the active note's script, storage, the serial number.
#!
#! Panics if:
#! - no note is currently active.
#!
#! Invocation: exec
pub proc get_recipient
# pad the stack
padw padw padw push.0.0
# => [pad(14)]
# push the flag indicating that we want to request recipient from the active note
push.1
# => [is_active_note = 1, pad(14)]
push.INPUT_NOTE_GET_RECIPIENT_OFFSET
# => [offset, is_active_note = 1, pad(14)]
syscall.exec_kernel_proc
# => [RECIPIENT, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [RECIPIENT]
end
#! Writes the active note's storage to memory starting at the specified address.
#!
#! Inputs:
#! Stack: [dest_ptr]
#! Advice Map: { NOTE_STORAGE_COMMITMENT: [STORAGE] }
#! Outputs:
#! Stack: [num_storage_items, dest_ptr]
#!
#! Where:
#! - dest_ptr is the memory address to write the note storage.
#! - NOTE_STORAGE_COMMITMENT is the commitment to the note's storage.
#! - STORAGE is the data corresponding to the note's storage.
#!
#! Panics if:
#! - no note is currently active.
#!
#! Invocation: exec
pub proc get_storage
# pad the stack
padw padw padw push.0.0
# => [pad(14), dest_ptr]
# push the flag indicating that we want to request inputs info from the active note
push.1
# => [is_active_note = 1, pad(14), dest_ptr]
push.INPUT_NOTE_GET_STORAGE_INFO_OFFSET
# => [offset, is_active_note = 1, pad(14), dest_ptr]
syscall.exec_kernel_proc
# => [NOTE_STORAGE_COMMITMENT, num_storage_items, pad(11), dest_ptr]
# clean the stack
swapdw dropw dropw
movup.5 drop movup.5 drop movup.5 drop
# => [NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# write the inputs to the memory using the provided destination pointer
exec.write_storage_to_memory
# => [num_storage_items, dest_ptr]
end
#! Returns the metadata of the active note.
#!
#! Inputs: []
#! Outputs: [NOTE_ATTACHMENT, METADATA_HEADER]
#!
#! Where:
#! - METADATA_HEADER is the metadata header of the specified input note.
#! - NOTE_ATTACHMENT is the attachment of the specified input note.
#!
#! Panics if:
#! - no note is currently active.
#!
#! Invocation: exec
pub proc get_metadata
# pad the stack
padw padw padw push.0.0
# => [pad(14)]
# push the flag indicating that we want to request metadata from the active note
push.1
# => [is_active_note = 1, pad(14)]
push.INPUT_NOTE_GET_METADATA_OFFSET
# => [offset, is_active_note = 1, pad(14)]
syscall.exec_kernel_proc
# => [NOTE_ATTACHMENT, METADATA_HEADER, pad(8)]
# clean the stack
swapdw dropw dropw
# => [NOTE_ATTACHMENT, METADATA_HEADER]
end
#! Returns the sender of the active note.
#!
#! Inputs: []
#! Outputs: [sender_id_suffix, sender_id_prefix]
#!
#! Where:
#! - sender_{suffix,prefix} are the suffix and prefix felts of the sender of the active note.
#!
#! Panics if:
#! - no note is currently active.
#!
#! Invocation: exec
pub proc get_sender
# get metadata and drop attachment
exec.get_metadata dropw
# => [METADATA_HEADER]
# extract the sender ID from the metadata header
exec.note::extract_sender_from_metadata
# => [sender_id_suffix, sender_id_prefix]
end
#! Returns the serial number of the active note.
#!
#! Inputs: []
#! Outputs: [SERIAL_NUMBER]
#!
#! Where:
#! - SERIAL_NUMBER is the serial number of the active note.
#!
#! Panics if:
#! - no note is currently active.
#!
#! Invocation: exec
pub proc get_serial_number
# pad the stack
padw padw padw push.0.0
# => [pad(14)]
# push the flag indicating that we want to request serial number from the active note
push.1
# => [is_active_note = 1, pad(14)]
push.INPUT_NOTE_GET_SERIAL_NUMBER_OFFSET
# => [offset, is_active_note = 1, pad(14)]
syscall.exec_kernel_proc
# => [SERIAL_NUMBER, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [SERIAL_NUMBER]
end
#! Returns the script root of the active note.
#!
#! Inputs: []
#! Outputs: [SCRIPT_ROOT]
#!
#! Where:
#! - SCRIPT_ROOT is the script root of the active note.
#!
#! Panics if:
#! - no note is currently active.
#!
#! Invocation: exec
pub proc get_script_root
# pad the stack
padw padw padw push.0.0
# => [pad(14)]
# push the flag indicating that we want to request script root from the active note
push.1
# => [is_active_note = 1, pad(14)]
push.INPUT_NOTE_GET_SCRIPT_ROOT_OFFSET
# => [offset, is_active_note = 1, pad(14)]
syscall.exec_kernel_proc
# => [SCRIPT_ROOT, pad(12)]
# clean the stack
swapdw dropw dropw swapw dropw
# => [SCRIPT_ROOT]
end
# HELPER PROCEDURES
# =================================================================================================
#! Writes the note storage stored in the advice map to the memory specified by the provided
#! destination pointer.
#!
#! Inputs:
#! Operand stack: [NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
#! Advice map: {
#! NOTE_STORAGE_COMMITMENT: [[INPUT_VALUES]]
#! }
#! Outputs:
#! Operand stack: [num_storage_items, dest_ptr]
proc write_storage_to_memory
# load the inputs from the advice map to the advice stack
# we pad the number of inputs to the next multiple of 8 so that we can use the
# `pipe_double_words_to_memory` instruction. The padded zeros don't affect the commitment
# computation.
adv.push_mapvaln.8
# OS => [NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [advice_num_storage_items, [INPUT_VALUES]]
# move the number of inputs obtained from advice map to the operand stack
adv_push.1 dup.5
# OS => [num_storage_items, advice_num_storage_items, NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [[INPUT_VALUES]]
assert_eq.err=ERR_NOTE_INVALID_NUMBER_OF_STORAGE_ITEMS
# OS => [NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [[INPUT_VALUES]]
# calculate the number of words required to store the inputs
dup.4 u32divmod.4 neq.0 add
# OS => [num_words, NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [[INPUT_VALUES]]
# round up the number of words to the next multiple of 2
dup is_odd add
# OS => [even_num_words, NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [[INPUT_VALUES]]
# compute the end pointer for writing the padded inputs (even_num_words * 4 elements)
dup.6 swap mul.4 add
# OS => [end_ptr, NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [[INPUT_VALUES]]
# prepare the stack for the `pipe_double_words_to_memory` procedure.
#
# To match `poseidon2::hash_elements` (used for NOTE_STORAGE_COMMITMENT), we set the first capacity
# element to `num_storage_items % 8`.
dup.6 dup.6
# OS => [num_storage_items, write_ptr, end_ptr, NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [[INPUT_VALUES]]
u32divmod.8 swap drop
# OS => [num_storage_items_mod_8, write_ptr, end_ptr, NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [[INPUT_VALUES]]
push.0.0.0 movup.3
# OS => [CAPACITY = [num_storage_items_mod_8, 0, 0, 0], write_ptr, end_ptr, NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [[INPUT_VALUES]]
padw padw
# OS => [RATE0, RATE1, CAPACITY, write_ptr, end_ptr, NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => [[INPUT_VALUES]]
# write the inputs from the advice stack into memory
exec.mem::pipe_double_words_to_memory
# OS => [RATE0, RATE1, CAPACITY, end_ptr', NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# AS => []
# extract the computed commitment from the hasher state
exec.poseidon2::squeeze_digest
# OS => [COMPUTED_COMMITMENT, end_ptr', NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# drop end_ptr'
movup.4 drop
# OS => [COMPUTED_COMMITMENT, NOTE_STORAGE_COMMITMENT, num_storage_items, dest_ptr]
# validate that the inputs written to memory match the inputs commitment
assert_eqw.err=ERR_NOTE_DATA_DOES_NOT_MATCH_COMMITMENT
# => [num_storage_items, dest_ptr]
end