Skip to content

Commit

Permalink
refactor: add native id check, move helper procs to account.masm
Browse files Browse the repository at this point in the history
  • Loading branch information
Fumuran committed Oct 3, 2024
1 parent 3c1582d commit 5a31101
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 241 deletions.
1 change: 1 addition & 0 deletions bin/tx-prover/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use tokio::{net::TcpListener, sync::Mutex};
use tonic::{Request, Response, Status};
use tracing::info;

#[rustfmt::skip]
pub mod generated;

pub struct Rpc {
Expand Down
6 changes: 3 additions & 3 deletions miden-lib/asm/kernels/transaction/api.masm
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,7 @@ export.start_foreign_context
# OS => [foreign_account_id]

# get the memory address and a flag whether this account was already loaded.
exec.memory::get_foreign_account_ptr
exec.account::get_foreign_account_ptr
# OS => [was_loaded, ptr, foreign_account_id]

if.true
Expand Down Expand Up @@ -1033,7 +1033,7 @@ export.start_foreign_context
# AS => []

# save the account procedure data into the memory
exec.memory::save_account_procedure_data
exec.account::save_account_procedure_data
# OS => [STORAGE_ROOT]
# AS => []

Expand All @@ -1043,7 +1043,7 @@ export.start_foreign_context
# AS => []

# save the storage slots data into the memory
exec.memory::save_account_storage_data
exec.account::save_account_storage_data
# OS => []
# AS => []
end
Expand Down
237 changes: 237 additions & 0 deletions miden-lib/asm/kernels/transaction/lib/account.masm
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use.std::collections::smt
use.std::crypto::hashes::native
use.std::mem

use.kernel::constants
use.kernel::memory
Expand Down Expand Up @@ -40,6 +41,27 @@ const.ERR_STORAGE_SLOT_INDEX_OUT_OF_BOUNDS=0x0002004E
# Storage offset is invalid for a faucet account (0 is prohibited being the faucet reserved data slot)
const.ERR_INVALID_FAUCET_STORAGE_OFFSET=0x0002004F

# Computed account code commitment does not match recorded account code commitment
const.ERR_ACCT_CODE_COMMITMENT_MISMATCH=0x0002004C

# Number of account procedures exceeded the maximum limit of 256
const.ERR_ACCT_TOO_MANY_PROCEDURES=0x0002004D

# Computed account storage commitment does not match recorded account storage commitment
const.ERR_ACCT_STORAGE_COMMITMENT_MISMATCH=0x00020050

# Number of account storage slots exceeded the maximum limit of 255
const.ERR_ACCT_TOO_MANY_STORAGE_SLOTS=0x00020058

# ID of the provided foreign account equals zero.
const.ERR_FOREIGN_ACCOUNT_ID_IS_ZERO=0x00020056

# Maximum allowed number of foreign account to be loaded (64) was exceeded.
const.ERR_MAX_NUM_FOREIGN_ACCOUNTS_EXCEEDED=0x00020057

# Provided foreign account ID is equal to the native account ID.
const.ERR_FOREIGN_ACCT_ID_EQUALS_NATIVE_ACCT_ID=0x00020059

# CONSTANTS
# =================================================================================================

Expand Down Expand Up @@ -662,6 +684,147 @@ export.validate_seed
# => []
end

# DATA LOADERS
# =================================================================================================

#! Saves storage slots data into memory and validates that the storage commitment matches the
#! sequential storage hash.
#!
#! Inputs:
#! Operand stack: [STORAGE_COMMITMENT]
#! Advice map: {
#! STORAGE_COMMITMENT: [[STORAGE_SLOT_DATA]],
#! }
#! Outputs:
#! Operand stack: []
#!
#! Where:
#! - STORAGE_COMMITMENT is the commitment of the foreign account's storage.
#! - STORAGE_SLOT_DATA is the data contained in the storage slot which is constructed as follows:
#! [SLOT_VALUE, slot_type, 0, 0, 0]
#!
#! Panics if:
#! - the number of account storage slots exceeded the maximum limit of 255.
#! - the computed account storage commitment does not match the provided account storage commitment
export.save_account_storage_data
# move storage slot data from the advice map to the advice stack
adv.push_mapvaln push.15160 drop # TODO: remove line, see miden-vm/#1122
# OS => [STORAGE_COMMITMENT]
# AS => [storage_slot_data_len, [STORAGE_SLOT_DATA]]

# push the length of the storage slot data onto the operand stack and compute the number of
# storage slots from it
adv_push.1 div.8
# OS => [num_storage_slots, STORAGE_COMMITMENT]
# AS => [[STORAGE_SLOT_DATA]]

# assert that account does not exceed allowed maximum number of storage slots
dup exec.get_max_num_storage_slots lte assert.err=ERR_ACCT_TOO_MANY_STORAGE_SLOTS
# OS => [num_storage_slots, STORAGE_COMMITMENT]
# AS => [[STORAGE_SLOT_DATA]]

# store number of storage slots in memory
dup exec.memory::set_num_storage_slots
# OS => [num_storage_slots, STORAGE_COMMITMENT]
# AS => [[STORAGE_SLOT_DATA]]

# setup acct_storage_slots_offset and end_ptr for reading from advice stack
mul.2 exec.memory::get_acct_storage_slots_section_ptr dup movdn.2 add swap
# OS => [acct_storage_slots_offset, end_ptr, STORAGE_COMMITMENT]
# AS => [[STORAGE_SLOT_DATA]]

# pad stack before reading from advice stack
padw padw padw
# OS => [PAD, PAD, PAD, acct_proc_offset, end_ptr, STORAGE_COMMITMENT]
# AS => [[STORAGE_SLOT_DATA]]

# read the data from advice stack to memory and hash
exec.mem::pipe_double_words_to_memory
# OS => [PERM, PERM, PERM, end_ptr', STORAGE_COMMITMENT]
# AS => []

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

# drop end_ptr
movup.4 drop
# OS => [DIGEST, STORAGE_COMMITMENT]

# verify hashed account storage slots match account storage commitment
assert_eqw.err=ERR_ACCT_STORAGE_COMMITMENT_MISMATCH
# OS => []
end

#! Saves account procedure data into memory and validates that the code commitment matches the
#! sequential procedure hash.
#!
#! Inputs:
#! Operand stack: [CODE_COMMITMENT]
#! Advice map: {
#! CODE_COMMITMENT: [num_procs, [ACCOUNT_PROCEDURE_DATA]],
#! }
#! Outputs:
#! Operand stack: []
#!
#! Where:
#! - CODE_COMMITMENT is the commitment of the foreign account's code.
#! - num_procs is the number of foreign account's procedures.
#! - ACCOUNT_PROCEDURE_DATA is the information about account procedure which is constructed as
#! follows: [PROCEDURE_MAST_ROOT, storage_offset, 0, 0, 0]
#!
#! Panics if:
#! - the number of account procedures exceeded the maximum limit of 256
#! - the computed account code commitment does not match the provided account code commitment
export.save_account_procedure_data
# move procedure data from the advice map to the advice stack
adv.push_mapval push.15161 drop # TODO: remove line, see miden-vm/#1122
# OS => [CODE_COMMITMENT]
# AS => [num_procs, [ACCOUNT_PROCEDURE_DATA]]

# push the number of procedures onto the operand stack before storing it in memory
adv_push.1
# OS => [num_procs, CODE_COMMITMENT]
# AS => [[ACCOUNT_PROCEDURE_DATA]]

# assert that account does not exceed allowed maximum number of procedures
dup exec.get_max_num_procedures lte assert.err=ERR_ACCT_TOO_MANY_PROCEDURES
# OS => [num_procs, CODE_COMMITMENT]
# AS => [[ACCOUNT_PROCEDURE_DATA]]

# store number of procedures in memory
dup exec.memory::set_num_account_procedures
# OS => [num_procs, CODE_COMMITMENT]
# AS => [[ACCOUNT_PROCEDURE_DATA]]

# setup acct_proc_offset and end_ptr for reading from advice stack
mul.2 exec.memory::get_acct_procedures_section_ptr dup movdn.2 add swap
# OS => [acct_proc_offset, end_ptr, CODE_COMMITMENT]
# AS => [[ACCOUNT_PROCEDURE_DATA]]

# pad stack before reading from advice stack
padw padw padw
# OS => [PAD, PAD, PAD, acct_proc_offset, end_ptr, CODE_COMMITMENT]
# AS => [[ACCOUNT_PROCEDURE_DATA]]

# read the data from advice stack to memory and hash
exec.mem::pipe_double_words_to_memory
# OS => [PERM, PERM, PERM, end_ptr', CODE_COMMITMENT]
# AS => []

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

# drop end_ptr
movup.4 drop
# OS => [DIGEST, CODE_COMMITMENT]

# verify hashed account procedures match account code commitment
assert_eqw.err=ERR_ACCT_CODE_COMMITMENT_MISMATCH
# OS => []
end

# HELPER PROCEDURES
# =================================================================================================

Expand Down Expand Up @@ -732,3 +895,77 @@ proc.get_procedure_storage_offset
mem_load
# => [storage_offset]
end

#! Returns the pointer to the next vacant memory slot if the account was not loaded before, and the
#! pointer to the account data otherwise.
#!
#! Stack: [foreign_account_id]
#! Output: [was_loaded, ptr, foreign_account_id]
#!
#! Where:
#! - foreign_account_id is the ID of the foreign account whose procedure is going to be executed.
#! - was_loaded is the binary flag indicating whether the foreign account was already loaded to the
#! memory.
#! - ptr is the memory pointer to the next empty memory slot or the memory pointer to the account
#! data, depending on the value of the was_loaded flag.
#!
#! Panics if:
#! - the ID of the provided foreign account equals zero.
#! - the maximum allowed number of foreign account to be loaded (64) was exceeded.
export.get_foreign_account_ptr
# check that foreign account id is not equal zero
dup neq.0 assert.err=ERR_FOREIGN_ACCOUNT_ID_IS_ZERO
# => [foreign_account_id]

# check that foreign account id is not equal to the native account id
dup exec.memory::get_native_account_id neq assert.err=ERR_FOREIGN_ACCT_ID_EQUALS_NATIVE_ACCT_ID

# get the initial account data pointer
exec.memory::get_native_account_data_ptr
# => [curr_account_ptr, foreign_account_id]

# push the flag to enter the loop
push.1

while.true
# drop the flag left from the previous loop
movup.2 drop
# => [curr_account_ptr, foreign_account_id]

# move the current account pointer to the next account data block
exec.memory::get_account_data_length add
# => [curr_account_ptr', foreign_account_id]

# load the first data word at the current account pointer
padw dup.4 mem_loadw
# => [FIRST_DATA_WORD, curr_account_ptr', foreign_account_id]

# check whether the first data words is an empty word, preserve the last value in this word
# (account id)
dup.3 movdn.4 padw eqw movdn.8 dropw dropw
# => [is_empty_word, last_data_value, curr_account_ptr', foreign_account_id]

# check whether the current id matches the foreign id
swap dup.3 eq
# => [is_equal_id, is_empty_word, curr_account_ptr', foreign_account_id]

# get the sum of the flags to obtain the loop flag
dup movdn.4 add
# => [flags_sum, curr_account_ptr', foreign_account_id, is_equal_id]

# get the loop flag
# it equals 0 if both `is_equal_id` and `is_empty_word` flags equal 0, so we should continue
# iterating
eq.0
# => [loop_flag, curr_account_ptr', foreign_account_id, is_equal_id]
end

# check that the loading of one more account won't exceed the maximum number of the foreign
# accounts which can be loaded.
dup exec.memory::get_max_foreign_account_ptr lte assert.err=ERR_MAX_NUM_FOREIGN_ACCOUNTS_EXCEEDED
# => [curr_account_ptr, foreign_account_id, is_equal_id]

# the resulting `was_loaded` flag is essentially equal to the `is_equal_id` flag
movup.2
# => [was_loaded, curr_account_ptr, foreign_account_id]
end
Loading

0 comments on commit 5a31101

Please sign in to comment.