Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: change advice provider to trait
This commit introduces a change of the advice provider to be a trait. It also provides a standard implementation `BaseAdviceProvider`. related issue: #409
- Loading branch information
Showing
18 changed files
with
358 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
use super::{ | ||
AdviceProvider, AdviceSet, BTreeMap, ExecutionError, Felt, IntoBytes, ProgramInputs, | ||
StarkField, Word, | ||
}; | ||
|
||
// MEMORY ADVICE PROVIDER | ||
// ================================================================================================ | ||
|
||
/// An in-memory `[AdviceProvider]` implementation to support program execution. | ||
/// | ||
/// Uses `[BTreeMap]` as backend. | ||
#[derive(Debug, Clone, Default)] | ||
pub struct MemAdviceProvider { | ||
step: u32, | ||
tape: Vec<Felt>, | ||
values: BTreeMap<[u8; 32], Vec<Felt>>, | ||
sets: BTreeMap<[u8; 32], AdviceSet>, | ||
} | ||
|
||
#[cfg(test)] | ||
impl MemAdviceProvider { | ||
// ADVISE SETS | ||
// -------------------------------------------------------------------------------------------- | ||
|
||
/// Returns true if the advice set with the specified root is present in this advice provider. | ||
pub fn has_advice_set(&self, root: Word) -> bool { | ||
self.sets.contains_key(&root.into_bytes()) | ||
} | ||
} | ||
|
||
// TODO remove if `ProgramInputs` is deprecated, or convert to `TryFrom` | ||
impl From<ProgramInputs> for MemAdviceProvider { | ||
fn from(inputs: ProgramInputs) -> Self { | ||
let (_, mut tape, values, sets) = inputs.into_parts(); | ||
tape.reverse(); | ||
Self { | ||
step: 0, | ||
tape, | ||
values, | ||
sets, | ||
} | ||
} | ||
} | ||
|
||
impl AdviceProvider for MemAdviceProvider { | ||
// ADVICE TAPE | ||
// -------------------------------------------------------------------------------------------- | ||
|
||
fn read_tape(&mut self) -> Result<Felt, ExecutionError> { | ||
self.tape.pop().ok_or(ExecutionError::AdviceTapeReadFailed(self.step)) | ||
} | ||
|
||
fn read_tape_w(&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) | ||
} | ||
|
||
fn read_tape_dw(&mut self) -> Result<[Word; 2], ExecutionError> { | ||
let word0 = self.read_tape_w()?; | ||
let word1 = self.read_tape_w()?; | ||
|
||
Ok([word0, word1]) | ||
} | ||
|
||
fn write_tape(&mut self, value: Felt) { | ||
self.tape.push(value); | ||
} | ||
|
||
fn write_tape_from_map(&mut self, key: Word) -> Result<(), ExecutionError> { | ||
let values = self | ||
.values | ||
.get(&key.into_bytes()) | ||
.ok_or(ExecutionError::AdviceKeyNotFound(key))?; | ||
self.tape.extend(values.iter().rev()); | ||
|
||
Ok(()) | ||
} | ||
|
||
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)), | ||
} | ||
} | ||
|
||
// ADVISE SETS | ||
// -------------------------------------------------------------------------------------------- | ||
|
||
fn get_tree_node(&self, root: Word, depth: Felt, index: Felt) -> Result<Word, ExecutionError> { | ||
// look up the advice set and return an error if none is found | ||
let advice_set = self | ||
.sets | ||
.get(&root.into_bytes()) | ||
.ok_or_else(|| ExecutionError::AdviceSetNotFound(root.into_bytes()))?; | ||
|
||
// get the tree node from the advice set based on depth and index | ||
let node = advice_set | ||
.get_node(depth.as_int() as u32, index.as_int()) | ||
.map_err(ExecutionError::AdviceSetLookupFailed)?; | ||
|
||
Ok(node) | ||
} | ||
|
||
fn get_merkle_path( | ||
&self, | ||
root: Word, | ||
depth: Felt, | ||
index: Felt, | ||
) -> Result<Vec<Word>, ExecutionError> { | ||
// look up the advice set and return an error if none is found | ||
let advice_set = self | ||
.sets | ||
.get(&root.into_bytes()) | ||
.ok_or_else(|| ExecutionError::AdviceSetNotFound(root.into_bytes()))?; | ||
|
||
// get the Merkle path from the advice set based on depth and index | ||
let path = advice_set | ||
.get_path(depth.as_int() as u32, index.as_int()) | ||
.map_err(ExecutionError::AdviceSetLookupFailed)?; | ||
|
||
Ok(path) | ||
} | ||
|
||
fn update_merkle_leaf( | ||
&mut self, | ||
root: Word, | ||
index: Felt, | ||
leaf_value: Word, | ||
update_in_copy: bool, | ||
) -> Result<Vec<Word>, ExecutionError> { | ||
// look up the advice set and return error if none is found. if we are updating a copy, | ||
// clone the advice set; otherwise remove it from the map because the root will change, | ||
// and we'll re-insert the set later under a different root. | ||
let mut advice_set = if update_in_copy { | ||
// look up the advice set and return an error if none is found | ||
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()))? | ||
}; | ||
|
||
// get the Merkle path from the advice set for the leaf at the specified index | ||
let path = advice_set | ||
.get_path(advice_set.depth(), index.as_int()) | ||
.map_err(ExecutionError::AdviceSetLookupFailed)?; | ||
|
||
// update the advice set and re-insert it into the map | ||
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) | ||
} | ||
|
||
// CONTEXT MANAGEMENT | ||
// -------------------------------------------------------------------------------------------- | ||
|
||
fn advance_clock(&mut self) { | ||
self.step += 1; | ||
} | ||
} |
Oops, something went wrong.