use super::{ExecutionError, Felt, ProgramInputs, Word};
use vm_core::{
utils::{
collections::{BTreeMap, Vec},
IntoBytes,
},
AdviceSet, StarkField,
};
pub struct AdviceProvider {
step: u32,
tape: Vec<Felt>,
values: BTreeMap<[u8; 32], Vec<Felt>>,
sets: BTreeMap<[u8; 32], AdviceSet>,
}
impl AdviceProvider {
pub fn new(inputs: ProgramInputs) -> Self {
let (_, mut advice_tape, advice_map, advice_sets) = inputs.into_parts();
advice_tape.reverse();
Self {
step: 0,
tape: advice_tape,
values: advice_map,
sets: advice_sets,
}
}
pub fn read_tape(&mut self) -> Result<Felt, ExecutionError> {
self.tape
.pop()
.ok_or(ExecutionError::AdviceTapeReadFailed(self.step))
}
pub fn read_tapew(&mut self) -> Result<Word, ExecutionError> {
if self.tape.len() < 4 {
return Err(ExecutionError::AdviceTapeReadFailed(self.step));
}
let idx = self.tape.len() - 4;
let result = [
self.tape[idx + 3],
self.tape[idx + 2],
self.tape[idx + 1],
self.tape[idx],
];
self.tape.truncate(idx);
Ok(result)
}
pub fn read_tape_double(&mut self) -> Result<[Word; 2], ExecutionError> {
let word0 = self.read_tapew()?;
let word1 = self.read_tapew()?;
Ok([word0, word1])
}
pub fn write_tape(&mut self, value: Felt) {
self.tape.push(value);
}
pub fn write_tape_from_map(&mut self, key: Word) -> Result<(), ExecutionError> {
let values = self
.values
.get(&key.into_bytes())
.ok_or(ExecutionError::AdviceKeyNotFound(key))?;
for &elem in values.iter().rev() {
self.tape.push(elem);
}
Ok(())
}
pub fn insert_into_map(&mut self, key: Word, values: Vec<Felt>) -> Result<(), ExecutionError> {
match self.values.insert(key.into_bytes(), values) {
None => Ok(()),
Some(_) => Err(ExecutionError::DuplicateAdviceKey(key)),
}
}
#[cfg(test)]
pub fn has_advice_set(&self, root: Word) -> bool {
self.sets.contains_key(&root.into_bytes())
}
pub fn get_tree_node(
&mut self,
root: Word,
depth: Felt,
index: Felt,
) -> Result<Word, ExecutionError> {
let advice_set = self
.sets
.get(&root.into_bytes())
.ok_or_else(|| ExecutionError::AdviceSetNotFound(root.into_bytes()))?;
let node = advice_set
.get_node(depth.as_int() as u32, index.as_int())
.map_err(ExecutionError::AdviceSetLookupFailed)?;
Ok(node)
}
pub fn get_merkle_path(
&mut self,
root: Word,
depth: Felt,
index: Felt,
) -> Result<Vec<Word>, ExecutionError> {
let advice_set = self
.sets
.get(&root.into_bytes())
.ok_or_else(|| ExecutionError::AdviceSetNotFound(root.into_bytes()))?;
let path = advice_set
.get_path(depth.as_int() as u32, index.as_int())
.map_err(ExecutionError::AdviceSetLookupFailed)?;
Ok(path)
}
pub fn update_merkle_leaf(
&mut self,
root: Word,
index: Felt,
leaf_value: Word,
update_in_copy: bool,
) -> Result<Vec<Word>, ExecutionError> {
let mut advice_set = if update_in_copy {
self.sets
.get(&root.into_bytes())
.ok_or_else(|| ExecutionError::AdviceSetNotFound(root.into_bytes()))?
.clone()
} else {
self.sets
.remove(&root.into_bytes())
.ok_or_else(|| ExecutionError::AdviceSetNotFound(root.into_bytes()))?
};
let path = advice_set
.get_path(advice_set.depth(), index.as_int())
.map_err(ExecutionError::AdviceSetLookupFailed)?;
advice_set
.update_leaf(index.as_int(), leaf_value)
.map_err(ExecutionError::AdviceSetLookupFailed)?;
self.sets.insert(advice_set.root().into_bytes(), advice_set);
Ok(path)
}
pub fn advance_clock(&mut self) {
self.step += 1;
}
}