use super::{AdviceInjector, Decorator, ExecutionError, Felt, Process, StarkField};
use vm_core::{utils::collections::Vec, WORD_LEN, ZERO};
impl Process {
pub(super) fn execute_decorator(
&mut self,
decorator: &Decorator,
) -> Result<(), ExecutionError> {
match decorator {
Decorator::Advice(injector) => self.dec_advice(injector)?,
Decorator::AsmOp(assembly_op) => {
if self.decoder.in_debug_mode() {
self.decoder
.append_asmop(self.system.clk(), assembly_op.clone());
}
}
}
Ok(())
}
pub fn dec_advice(&mut self, injector: &AdviceInjector) -> Result<(), ExecutionError> {
match injector {
AdviceInjector::MerkleNode => self.inject_merkle_node(),
AdviceInjector::DivResultU64 => self.inject_div_result_u64(),
AdviceInjector::MapValue => self.inject_map_value(),
AdviceInjector::Memory(start_addr, num_words) => {
self.inject_mem_values(*start_addr, *num_words)
}
}
}
fn inject_merkle_node(&mut self) -> Result<(), ExecutionError> {
let depth = self.stack.get(0);
let index = self.stack.get(1);
let root = [
self.stack.get(5),
self.stack.get(4),
self.stack.get(3),
self.stack.get(2),
];
let node = self.advice.get_tree_node(root, depth, index)?;
self.advice.write_tape(node[3]);
self.advice.write_tape(node[2]);
self.advice.write_tape(node[1]);
self.advice.write_tape(node[0]);
Ok(())
}
fn inject_div_result_u64(&mut self) -> Result<(), ExecutionError> {
let divisor_hi = self.stack.get(0).as_int();
let divisor_lo = self.stack.get(1).as_int();
let divisor = (divisor_hi << 32) + divisor_lo;
if divisor == 0 {
return Err(ExecutionError::DivideByZero(self.system.clk()));
}
let dividend_hi = self.stack.get(2).as_int();
let dividend_lo = self.stack.get(3).as_int();
let dividend = (dividend_hi << 32) + dividend_lo;
let quotient = dividend / divisor;
let remainder = dividend - quotient * divisor;
let (q_hi, q_lo) = u64_to_u32_elements(quotient);
let (r_hi, r_lo) = u64_to_u32_elements(remainder);
self.advice.write_tape(r_hi);
self.advice.write_tape(r_lo);
self.advice.write_tape(q_hi);
self.advice.write_tape(q_lo);
Ok(())
}
fn inject_map_value(&mut self) -> Result<(), ExecutionError> {
let top_word = self.stack.get_top_word();
self.advice.write_tape_from_map(top_word)?;
Ok(())
}
fn inject_mem_values(&mut self, start_addr: u32, num_words: u32) -> Result<(), ExecutionError> {
let ctx = self.system.ctx();
let mut values = Vec::with_capacity(num_words as usize * WORD_LEN);
for i in 0..num_words {
let mem_value = self
.chiplets
.get_mem_value(ctx, (start_addr + i) as u64)
.unwrap_or([ZERO; WORD_LEN]);
values.extend_from_slice(&mem_value);
}
let top_word = self.stack.get_top_word();
self.advice.insert_into_map(top_word, values)?;
Ok(())
}
}
fn u64_to_u32_elements(value: u64) -> (Felt, Felt) {
let hi = Felt::new(value >> 32);
let lo = Felt::new((value as u32) as u64);
(hi, lo)
}
#[cfg(test)]
mod tests {
use super::{
super::{Felt, FieldElement, Kernel, Operation, StarkField},
Process,
};
use crate::Word;
use vm_core::{AdviceInjector, AdviceSet, Decorator, ProgramInputs};
#[test]
fn inject_merkle_node() {
let leaves = [init_leaf(1), init_leaf(2), init_leaf(3), init_leaf(4)];
let tree = AdviceSet::new_merkle_tree(leaves.to_vec()).unwrap();
let stack_inputs = [
tree.root()[0].as_int(),
tree.root()[1].as_int(),
tree.root()[2].as_int(),
tree.root()[3].as_int(),
1,
tree.depth() as u64,
];
let inputs = ProgramInputs::new(&stack_inputs, &[], vec![tree.clone()]).unwrap();
let mut process = Process::new(&Kernel::default(), inputs);
process.execute_op(Operation::Noop).unwrap();
process
.execute_decorator(&Decorator::Advice(AdviceInjector::MerkleNode))
.unwrap();
process.execute_op(Operation::Read).unwrap();
process.execute_op(Operation::Read).unwrap();
process.execute_op(Operation::Read).unwrap();
process.execute_op(Operation::Read).unwrap();
let expected_stack = build_expected(&[
leaves[1][3],
leaves[1][2],
leaves[1][1],
leaves[1][0],
Felt::new(2),
Felt::new(1),
tree.root()[3],
tree.root()[2],
tree.root()[1],
tree.root()[0],
]);
assert_eq!(expected_stack, process.stack.trace_state());
}
fn init_leaf(value: u64) -> Word {
[Felt::new(value), Felt::ZERO, Felt::ZERO, Felt::ZERO]
}
fn build_expected(values: &[Felt]) -> [Felt; 16] {
let mut expected = [Felt::ZERO; 16];
for (&value, result) in values.iter().zip(expected.iter_mut()) {
*result = value
}
expected
}
}