Skip to content

Commit

Permalink
Rebased from next
Browse files Browse the repository at this point in the history
  • Loading branch information
phklive committed Jul 18, 2024
1 parent 19df86c commit cd0ef51
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 140 deletions.
58 changes: 32 additions & 26 deletions miden-lib/asm/miden/kernels/tx/account.masm
Original file line number Diff line number Diff line change
Expand Up @@ -469,33 +469,39 @@ export.set_map_item.3
# => [OLD_MAP_ROOT, OLD_VALUE, ...]
end

#! Verifies that the procedure root is part of the account code Merkle tree. Panics if the
#! procedure root is not part of the account code Merkle tree.
#!
#! Stack: [PROC_ROOT]
#! Output: [PROC_ROOT]
#!
#! - PROC_ROOT is the hash of the procedure to authenticate.
export.authenticate_procedure.1
# load the account code root onto the stack
exec.memory::get_acct_code_root swapw
# => [PROC_ROOT, CODE_ROOT]

# load the index of the procedure root onto the advice stack, and move it to the operand stack
emit.ACCOUNT_PUSH_PROCEDURE_INDEX_EVENT adv_push.1 movdn.4
# => [PROC_ROOT, index, CODE_ROOT]

# push the depth of the code Merkle tree onto the stack
push.ACCOUNT_CODE_TREE_DEPTH movdn.4
# => [PROC_ROOT, depth, index, CODE_ROOT]

# verify the procedure exists in the account code Merkle tree
mtree_verify
# => [PROC_ROOT, depth, index, CODE_ROOT]
#! Returns the procedure information
#! procedure root is not part of the account code.
#!
#! Stack: [index, ...]
#! Output: [PROC_ELEMENTS, storage_offset, ...]
#!
#! - PROC_ELEMENTS are field elements representing the procedure
#! - storage_offset is the procedure storage offset
export.get_procedure_info
# get procedure section ptr
push.2 mul exec.memory::get_account_procedures_section_offset add dup push.1 add swap
# => [proc_ptr, offset_ptr]

# load procedure information from memory
padw movup.4 mem_loadw movup.4 mem_load movdn.4
# => [PROC_ELEMENTS, storage_offset]
end

# drop accessory variables
movup.4 drop movup.4 drop swapw dropw
# => [PROC_ROOT]
#! Stack: [PROC_ROOT]
#! Output: [storage_offset]
export.authenticate_procedure
# load the index of the procedure onto the advice stack and move it to the operand stack
emit.ACCOUNT_PUSH_PROCEDURE_INDEX_EVENT adv_push.1
# => [index, PROC_ROOT]

# get the procedure info (ROOT, storage_offset) of the account procedure stored at the
# index we got above
exec.get_procedure_info
# => [PROC_ELEMENTS, storage_offset, PROC_ROOT]

# make sure stored proc root is the same as we got with the parameter
movup.4 movdn.8 assert_eqw.err=112
# => [storage_offset]
end

#! Validates that the account seed, provided via the advice map, satisfies the seed requirements.
Expand Down
13 changes: 13 additions & 0 deletions miden-lib/asm/miden/kernels/tx/memory.masm
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ const.ACCT_CORE_DATA_SECTION_END_OFFSET=404
# The memory address at which the account storage slot type data beings
const.ACCT_STORAGE_SLOT_TYPE_DATA_OFFSET=405

# The memory address at which the account procedures section begins.
const.ACCT_PROCEDURES_SECTION_OFFSET=700

# INPUT NOTES DATA
# -------------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -644,6 +647,16 @@ export.set_acct_nonce
drop movup.3 push.ACCT_ID_AND_NONCE_PTR mem_storew dropw
end

#! Returns the account procedures section offset.
#!
#! Stack: []
#! Output: [section_offset]
#!
#! - section_offset is the new account procedures section offset start.
export.get_account_procedures_section_offset
push.ACCT_PROCEDURES_SECTION_OFFSET
end

#! Sets the code root of the account.
#!
#! Stack: [CODE_ROOT]
Expand Down
41 changes: 41 additions & 0 deletions miden-lib/asm/miden/kernels/tx/prologue.masm
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,46 @@ proc.validate_new_account
# => []
end

proc.validate_account_procedures
# get code_root to query elements from AdviceMap
exec.memory::get_acct_code_root
# => [ACCT_CODE_ROOT]

# query elements from AdviceMap and get len
adv.push_mapval adv_push.1
# => [len, ACCT_CODE_ROOT]

# Should be done using a memory constant, loc at which piped elements will live
push.0 exec.memory::get_account_procedures_section_offset
# => [location, counter, len, ACCT_CODE_ROOT]

# start looping
padw padw padw push.1
# => [PAD, PAD, PAD, 1, location, counter, len, ACCT_CODE_ROOT]

while.true
# pipe elements from advice map and hash them
adv_pipe hperm
# => [HASH, HASH, HASH, location, counter, len, ACCT_CODE_ROOT]

# check if we piped all procedure elements
movup.13 add.1 dup movdn.14 dup.15 neq
# => [should_loop, HASH, HASH, HASH, location, counter, len, ACCT_CODE_ROOT]
end

# keep relevant hash
exec.native::state_to_digest
# => [HASH, location, counter, len, ACCT_CODE_ROOT]

# drop location, counter and len
movup.4 movup.5 movup.6 drop drop drop
# => [HASH, ACCT_CODE_ROOT]

# verify hashed values match root
assert_eqw
# => []
end

#! Saves the account data to memory and validates it.
#!
#! This procedure will:
Expand Down Expand Up @@ -476,6 +516,7 @@ proc.process_account_data
# code root updates
exec.memory::get_acct_code_root
exec.memory::set_new_acct_code_root dropw
exec.validate_account_procedures
# => []

# copy the initial account vault hash to the input vault hash to support transaction asset
Expand Down
7 changes: 5 additions & 2 deletions miden-lib/src/transaction/inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,11 @@ fn add_account_to_advice_inputs(
// --- account code -------------------------------------------------------
let code = account.code();

// extend the merkle store with account code tree
inputs.extend_merkle_store(code.procedure_tree().inner_nodes());
// extend the advice_map with the account code data and procedure length
let num_procs = code.as_elements().len() / 8;
let mut procs = code.as_elements();
procs.insert(0, Felt::from(num_procs as u32));
inputs.extend_map([(*code.procedure_commitment(), procs)]);

// --- account seed -------------------------------------------------------
if let Some(account_seed) = account_seed {
Expand Down
7 changes: 6 additions & 1 deletion miden-tx/src/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ impl TransactionCompiler {
) -> Result<AccountCode, TransactionCompilerError> {
let account_code = AccountCode::new(account_code, &self.assembler)
.map_err(TransactionCompilerError::LoadAccountFailed)?;
self.account_procedures.insert(account_id, account_code.procedures().to_vec());

self.account_procedures.insert(
account_id,
account_code.procedures().iter().map(|(p, _)| *p).collect::<Vec<Digest>>(),
);

Ok(account_code)
}

Expand Down
2 changes: 1 addition & 1 deletion miden-tx/src/compiler/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fn test_load_account() {

let acct_procs = [hex_to_bytes(ACCT_PROC_1), hex_to_bytes(ACCT_PROC_2)];
for proc in account_code.procedures() {
assert!(acct_procs.contains(&proc.as_bytes().to_vec()));
assert!(acct_procs.contains(&proc.0.as_bytes().to_vec()));
}
}

Expand Down
27 changes: 8 additions & 19 deletions miden-tx/src/host/account_procs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use miden_lib::transaction::TransactionKernelError;
use miden_objects::accounts::AccountCode;

use super::{AdviceProvider, BTreeMap, Digest, NodeIndex, ProcessState};
use super::{AdviceProvider, BTreeMap, Digest, Felt, ProcessState};

// ACCOUNT PROCEDURE INDEX MAP
// ================================================================================================
Expand All @@ -13,27 +12,17 @@ impl AccountProcedureIndexMap {
/// Returns a new [AccountProcedureIndexMap] instantiated with account procedures present in
/// the provided advice provider.
///
/// This function assumes that the account procedure tree (or a part thereof) is loaded into the
/// Merkle store of the provided advice provider.
pub fn new<A: AdviceProvider>(account_code_root: Digest, adv_provider: &A) -> Self {
// get the Merkle store with the procedure tree from the advice provider
let proc_store = adv_provider.get_store_subset([account_code_root].iter());
// get the account procedures from the advice_map
let procs = adv_provider.get_mapped_values(&account_code_root).unwrap();

// iterate over all possible procedure indexes
let mut result = BTreeMap::new();
for i in 0..AccountCode::MAX_NUM_PROCEDURES {
let index = NodeIndex::new(AccountCode::PROCEDURE_TREE_DEPTH, i as u64)
.expect("procedure tree index is valid");
// if the node at the current index does not exist, skip it and try the next node;this
// situation is valid if not all account procedures are loaded into the advice provider
if let Ok(proc_root) = proc_store.get_node(account_code_root, index) {
// if we got an empty digest, this means we got to the end of the procedure list
if proc_root == Digest::default() {
break;
}
result.insert(proc_root, i as u8);
}

for (proc_idx, proc_info) in procs[1..].chunks_exact(8).enumerate() {
let root: [Felt; 4] = proc_info[0..4].try_into().expect("Slice with incorrect len.");
result.insert(Digest::from(root), proc_idx.try_into().unwrap());
}

Self(result)
}

Expand Down
4 changes: 2 additions & 2 deletions miden-tx/src/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use miden_objects::{
Digest, Hasher,
};
use vm_processor::{
crypto::NodeIndex, AdviceExtractor, AdviceInjector, AdviceProvider, AdviceSource, ContextId,
ExecutionError, Felt, Host, HostResponse, ProcessState,
AdviceExtractor, AdviceInjector, AdviceProvider, AdviceSource, ContextId, ExecutionError, Felt,
Host, HostResponse, ProcessState,
};

mod account_delta_tracker;
Expand Down
27 changes: 8 additions & 19 deletions miden-tx/src/testing/account_procs.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use alloc::collections::BTreeMap;

use miden_lib::transaction::TransactionKernelError;
use miden_objects::accounts::AccountCode;
use vm_processor::{crypto::NodeIndex, AdviceProvider, Digest, ProcessState};
use vm_processor::{AdviceProvider, Digest, Felt, ProcessState};

// ACCOUNT PROCEDURE INDEX MAP
// ================================================================================================
Expand All @@ -14,27 +13,17 @@ impl AccountProcedureIndexMap {
/// Returns a new [AccountProcedureIndexMap] instantiated with account procedures present in
/// the provided advice provider.
///
/// This function assumes that the account procedure tree (or a part thereof) is loaded into the
/// Merkle store of the provided advice provider.
pub fn new<A: AdviceProvider>(account_code_root: Digest, adv_provider: &A) -> Self {
// get the Merkle store with the procedure tree from the advice provider
let proc_store = adv_provider.get_store_subset([account_code_root].iter());
// get the account procedures from the advice_map
let procs = adv_provider.get_mapped_values(&account_code_root).unwrap();

// iterate over all possible procedure indexes
let mut result = BTreeMap::new();
for i in 0..AccountCode::MAX_NUM_PROCEDURES {
let index = NodeIndex::new(AccountCode::PROCEDURE_TREE_DEPTH, i as u64)
.expect("procedure tree index is valid");
// if the node at the current index does not exist, skip it and try the next node;this
// situation is valid if not all account procedures are loaded into the advice provider
if let Ok(proc_root) = proc_store.get_node(account_code_root, index) {
// if we got an empty digest, this means we got to the end of the procedure list
if proc_root == Digest::default() {
break;
}
result.insert(proc_root, i as u8);
}

for (proc_idx, proc_info) in procs[1..].chunks_exact(8).enumerate() {
let root: [Felt; 4] = proc_info[0..4].try_into().expect("Slice with incorrect len.");
result.insert(Digest::from(root), proc_idx.try_into().unwrap());
}

Self(result)
}

Expand Down
12 changes: 5 additions & 7 deletions miden-tx/src/tests/kernel_tests/test_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,14 +511,12 @@ fn test_authenticate_procedure() {
.build();
let account = tx_context.tx_inputs().account();

let proc0_index = LeafIndex::new(0).unwrap();
let proc1_index = LeafIndex::new(1).unwrap();
let tc_0: [Felt; 4] = account.code().procedures()[0].0.as_elements().try_into().unwrap();
let tc_1: [Felt; 4] = account.code().procedures()[1].0.as_elements().try_into().unwrap();
let tc_2: [Felt; 4] = account.code().procedures()[2].0.as_elements().try_into().unwrap();

let test_cases = vec![
(account.code().procedure_tree().get_leaf(&proc0_index), true),
(account.code().procedure_tree().get_leaf(&proc1_index), true),
([ONE, ZERO, ONE, ZERO], false),
];
let test_cases =
vec![(tc_0, true), (tc_1, true), (tc_2, true), ([ONE, ZERO, ONE, ZERO], false)];

for (root, valid) in test_cases.into_iter() {
let tx_context = TransactionContextBuilder::with_standard_account(
Expand Down
Loading

0 comments on commit cd0ef51

Please sign in to comment.