use super::super::{AdviceProvider, ExecutionError, Felt, HostResponse};
use crate::ProcessState;
use alloc::vec::Vec;
use vm_core::{
crypto::hash::{Rpo256, RpoDigest},
EMPTY_WORD, WORD_SIZE,
};
pub(crate) fn insert_mem_values_into_adv_map<S: ProcessState, A: AdviceProvider>(
advice_provider: &mut A,
process: &S,
) -> Result<HostResponse, ExecutionError> {
let (start_addr, end_addr) = get_mem_addr_range(process, 4, 5)?;
let ctx = process.ctx();
let mut values = Vec::with_capacity(((end_addr - start_addr) as usize) * WORD_SIZE);
for addr in start_addr..end_addr {
let mem_value = process.get_mem_value(ctx, addr).unwrap_or(EMPTY_WORD);
values.extend_from_slice(&mem_value);
}
let key = process.get_stack_word(0);
advice_provider.insert_into_map(key, values)?;
Ok(HostResponse::None)
}
pub(crate) fn insert_hdword_into_adv_map<S: ProcessState, A: AdviceProvider>(
advice_provider: &mut A,
process: &S,
domain: Felt,
) -> Result<HostResponse, ExecutionError> {
let word0 = process.get_stack_word(0);
let word1 = process.get_stack_word(1);
let key = Rpo256::merge_in_domain(&[word1.into(), word0.into()], domain);
let mut values = Vec::with_capacity(2 * WORD_SIZE);
values.extend_from_slice(&word1);
values.extend_from_slice(&word0);
advice_provider.insert_into_map(key.into(), values)?;
Ok(HostResponse::None)
}
pub(crate) fn insert_hperm_into_adv_map<S: ProcessState, A: AdviceProvider>(
advice_provider: &mut A,
process: &S,
) -> Result<HostResponse, ExecutionError> {
let mut state = [
process.get_stack_item(11),
process.get_stack_item(10),
process.get_stack_item(9),
process.get_stack_item(8),
process.get_stack_item(7),
process.get_stack_item(6),
process.get_stack_item(5),
process.get_stack_item(4),
process.get_stack_item(3),
process.get_stack_item(2),
process.get_stack_item(1),
process.get_stack_item(0),
];
let values = state[Rpo256::RATE_RANGE].to_vec();
Rpo256::apply_permutation(&mut state);
let key = RpoDigest::new(
state[Rpo256::DIGEST_RANGE]
.try_into()
.expect("failed to extract digest from state"),
);
advice_provider.insert_into_map(key.into(), values)?;
Ok(HostResponse::None)
}
pub(crate) fn merge_merkle_nodes<S: ProcessState, A: AdviceProvider>(
advice_provider: &mut A,
process: &S,
) -> Result<HostResponse, ExecutionError> {
let lhs = process.get_stack_word(1);
let rhs = process.get_stack_word(0);
advice_provider.merge_roots(lhs, rhs)?;
Ok(HostResponse::None)
}
fn get_mem_addr_range<S: ProcessState>(
process: &S,
start_idx: usize,
end_idx: usize,
) -> Result<(u32, u32), ExecutionError> {
let start_addr = process.get_stack_item(start_idx).as_int();
let end_addr = process.get_stack_item(end_idx).as_int();
if start_addr > u32::MAX as u64 {
return Err(ExecutionError::MemoryAddressOutOfBounds(start_addr));
}
if end_addr > u32::MAX as u64 {
return Err(ExecutionError::MemoryAddressOutOfBounds(end_addr));
}
if start_addr > end_addr {
return Err(ExecutionError::InvalidMemoryRange {
start_addr,
end_addr,
});
}
Ok((start_addr as u32, end_addr as u32))
}