1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
use super::{utils, ExecutionError, Felt, InputError, Word};
use vm_core::{
    crypto::merkle::{MerkleError, MerklePath, MerklePathSet, MerkleTree, NodeIndex, SimpleSmt},
    utils::{
        collections::{BTreeMap, Vec},
        IntoBytes,
    },
    StarkField,
};

mod inputs;
pub use inputs::AdviceInputs;

mod mem_provider;
pub use mem_provider::MemAdviceProvider;

mod merkle_set;
pub use merkle_set::MerkleSet;

mod source;
pub use source::AdviceSource;

// ADVICE PROVIDER
// ================================================================================================

// TODO elaborate on why this is non-deterministic (seems it is a simple state machine).

// TODO the `advance_clock` seems to be an internal of the VM and shouldn't necessarily be here.

// TODO this will likely suffer a breaking change as we introduce a generic storage for big Merkle
// sets.
// The purpose of this clock is to keep the feedback of the provided in sync with the execution
// trace of the VM, but on the other hand the VM can control the calls/traces itself, without the
// need for the advice provider (or any other external component) to keep track of it. If we
// delegate this control to the advice provider - especially if it is a trait, the user might
// implement it incorrectly, creating undefined behavior on the VM side (that expects the counter
// to incrementally increase).

/// Common behavior of advice providers for program execution.
///
/// An advice provider supplies non-deterministic inputs to the processor.
///
/// 1. Provide a tape functionality that yields elements as a stack (last in, first out). These can
///    be yielded as elements, words or double words.
/// 2. Provide a map functionality that will store temporary tapes that can be appended to the main
///    tape. This operation should not allow key overwrite; that is: if a given key exists, the
///    implementation should error if the user attempts to insert this key again, instead of the
///    common behavior of the maps to simply override the previous contents. This is a design
///    decision to increase the runtime robustness of the execution.
/// 3. Provide merkle sets, that are mappings from a Merkle root its tree. The tree should yield
///    nodes & leaves, and will provide a Merkle path if a leaf is updated.
pub trait AdviceProvider {
    // ACCESSORS
    // --------------------------------------------------------------------------------------------

    /// Creates a "by reference" advice provider for this instance.
    ///
    /// The returned adapter also implements `AdviceProvider` and will simply mutably borrow this
    /// instance.
    fn by_ref(&mut self) -> &mut Self {
        // this trait follows the same model as
        // [io::Read](https://doc.rust-lang.org/std/io/trait.Read.html#method.by_ref).
        //
        // this approach allows the flexibility to take an advice provider either as owned or by
        // mutable reference - both equally compatible with the trait requirements as we implement
        // `AdviceProvider` for mutable references of any type that also implements advice
        // provider.
        self
    }

    // ADVICE TAPE
    // --------------------------------------------------------------------------------------------

    /// Pops an element from the advice tape and returns it.
    ///
    /// # Errors
    /// Returns an error if the advice tape is empty.
    fn read_tape(&mut self) -> Result<Felt, ExecutionError>;

    /// Pops a word (4 elements) from the advice tape and returns it.
    ///
    /// Note: a word is always stored as little-endian. A `[...,a,b,c,d]` tape will yield
    /// `[d,c,b,a]`.
    ///
    /// # Errors
    /// Returns an error if the advice tape does not contain a full word.
    fn read_tape_w(&mut self) -> Result<Word, ExecutionError>;

    /// Pops a double word (8 elements) from the advice tape and returns them.
    ///
    /// Note: a double word is always stored as little-endian. A `[...,a,b,c,d,e,f,g,h]` tape will
    /// yield `[h,g,f,e],[,d,c,b,a]`.
    ///
    /// # Errors
    /// Returns an error if the advice tape does not contain two words.
    fn read_tape_dw(&mut self) -> Result<[Word; 2], ExecutionError>;

    /// Writes values specified by the source to the head of the advice tape.
    fn write_tape(&mut self, source: AdviceSource) -> Result<(), ExecutionError>;

    /// Maps a key to a value list to be yielded by `write_tape_from_map`.
    ///
    /// # Errors
    /// Returns an error if the key is already present in the advice map.
    fn insert_into_map(&mut self, key: Word, values: Vec<Felt>) -> Result<(), ExecutionError>;

    // ADVISE SETS
    // --------------------------------------------------------------------------------------------

    /// Returns a node/leaf for the given depth and index in a Merkle tree with the given root.
    ///
    /// # Errors
    /// Returns an error if:
    /// - A Merkle tree for the specified root cannot be found in this advice provider.
    /// - The specified depth is either zero or greater than the depth of the Merkle tree
    ///   identified by the specified root.
    /// - Value of the node at the specified depth and index is not known to this advice provider.
    fn get_tree_node(&self, root: Word, depth: Felt, index: Felt) -> Result<Word, ExecutionError>;

    /// Returns a path to a node at the specified index in a Merkle tree with the specified root.
    ///
    /// # Errors
    /// Returns an error if:
    /// - A Merkle tree for the specified root cannot be found in this advice provider.
    /// - The specified depth is either zero or greater than the depth of the Merkle tree
    ///   identified by the specified root.
    /// - Path to the node at the specified depth and index is not known to this advice provider.
    fn get_merkle_path(
        &self,
        root: Word,
        depth: Felt,
        index: Felt,
    ) -> Result<MerklePath, ExecutionError>;

    /// Updates a leaf at the specified index on an existing Merkle tree with the specified root;
    /// returns the Merkle path from the updated leaf to the new root.
    ///
    /// If `update_in_copy` is set to true, retains both the tree prior to the update (i.e. with
    /// the original root), and the new updated tree. Otherwise, the old merkle set is removed from
    /// this provider.
    ///
    /// # Errors
    /// Returns an error if:
    /// - A Merkle tree for the specified root cannot be found in this advice provider.
    /// - The specified depth is either zero or greater than the depth of the Merkle tree
    ///   identified by the specified root.
    /// - Path to the leaf at the specified index in the specified Merkle tree is not known to this
    ///   advice provider.
    fn update_merkle_leaf(
        &mut self,
        root: Word,
        index: Felt,
        leaf_value: Word,
        update_in_copy: bool,
    ) -> Result<MerklePath, ExecutionError>;

    // CONTEXT MANAGEMENT
    // --------------------------------------------------------------------------------------------

    /// Increments the clock cycle.
    ///
    /// This is used to keep the state of the VM in sync with the state of the advice provider, and
    /// should be incrementally updated when called.
    fn advance_clock(&mut self);
}

impl<'a, T> AdviceProvider for &'a mut T
where
    T: AdviceProvider,
{
    fn read_tape(&mut self) -> Result<Felt, ExecutionError> {
        T::read_tape(self)
    }

    fn read_tape_w(&mut self) -> Result<Word, ExecutionError> {
        T::read_tape_w(self)
    }

    fn read_tape_dw(&mut self) -> Result<[Word; 2], ExecutionError> {
        T::read_tape_dw(self)
    }

    fn write_tape(&mut self, source: AdviceSource) -> Result<(), ExecutionError> {
        T::write_tape(self, source)
    }

    fn insert_into_map(&mut self, key: Word, values: Vec<Felt>) -> Result<(), ExecutionError> {
        T::insert_into_map(self, key, values)
    }

    fn get_tree_node(&self, root: Word, depth: Felt, index: Felt) -> Result<Word, ExecutionError> {
        T::get_tree_node(self, root, depth, index)
    }

    fn get_merkle_path(
        &self,
        root: Word,
        depth: Felt,
        index: Felt,
    ) -> Result<MerklePath, ExecutionError> {
        T::get_merkle_path(self, root, depth, index)
    }

    fn update_merkle_leaf(
        &mut self,
        root: Word,
        index: Felt,
        leaf_value: Word,
        update_in_copy: bool,
    ) -> Result<MerklePath, ExecutionError> {
        T::update_merkle_leaf(self, root, index, leaf_value, update_in_copy)
    }

    fn advance_clock(&mut self) {
        T::advance_clock(self)
    }
}