miden_processor/host/
mod.rs

1use alloc::sync::Arc;
2
3use vm_core::{
4    crypto::hash::RpoDigest, mast::MastForest, sys_events::SystemEvent, DebugOptions, SignatureKind,
5};
6
7use super::{ExecutionError, ProcessState};
8use crate::{KvMap, MemAdviceProvider};
9
10pub(super) mod advice;
11use advice::AdviceProvider;
12
13#[cfg(feature = "std")]
14mod debug;
15
16mod mast_forest_store;
17pub use mast_forest_store::{MastForestStore, MemMastForestStore};
18
19mod dsa;
20
21// HOST TRAIT
22// ================================================================================================
23
24/// Defines an interface by which the VM can interact with the host.
25///
26/// There are four main categories of interactions between the VM and the host:
27/// 1. accessing the advice provider,
28/// 2. getting a library's MAST forest,
29/// 3. handling advice events (which internally mutates the advice provider), and
30/// 4. handling debug and trace events.
31pub trait Host {
32    type AdviceProvider: AdviceProvider;
33
34    // REQUIRED METHODS
35    // --------------------------------------------------------------------------------------------
36
37    /// Returns a reference to the advice provider.
38    fn advice_provider(&self) -> &Self::AdviceProvider;
39
40    /// Returns a mutable reference to the advice provider.
41    fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider;
42
43    /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for
44    /// this digest could not be found in this [Host].
45    fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>>;
46
47    // PROVIDED METHODS
48    // --------------------------------------------------------------------------------------------
49
50    /// Handles the event emitted from the VM.
51    fn on_event(&mut self, _process: ProcessState, _event_id: u32) -> Result<(), ExecutionError> {
52        #[cfg(feature = "std")]
53        std::println!(
54            "Event with id {} emitted at step {} in context {}",
55            _event_id,
56            _process.clk(),
57            _process.ctx()
58        );
59        Ok(())
60    }
61
62    /// Handles the debug request from the VM.
63    fn on_debug(
64        &mut self,
65        _process: ProcessState,
66        _options: &DebugOptions,
67    ) -> Result<(), ExecutionError> {
68        #[cfg(feature = "std")]
69        debug::print_debug_info(_process, _options);
70        Ok(())
71    }
72
73    /// Handles the trace emitted from the VM.
74    fn on_trace(&mut self, _process: ProcessState, _trace_id: u32) -> Result<(), ExecutionError> {
75        #[cfg(feature = "std")]
76        std::println!(
77            "Trace with id {} emitted at step {} in context {}",
78            _trace_id,
79            _process.clk(),
80            _process.ctx()
81        );
82        Ok(())
83    }
84
85    /// Handles the failure of the assertion instruction.
86    fn on_assert_failed(&mut self, process: ProcessState, err_code: u32) -> ExecutionError {
87        ExecutionError::FailedAssertion {
88            clk: process.clk(),
89            err_code,
90            err_msg: None,
91        }
92    }
93}
94
95impl<H> Host for &mut H
96where
97    H: Host,
98{
99    type AdviceProvider = H::AdviceProvider;
100
101    fn advice_provider(&self) -> &Self::AdviceProvider {
102        H::advice_provider(self)
103    }
104
105    fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider {
106        H::advice_provider_mut(self)
107    }
108
109    fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>> {
110        H::get_mast_forest(self, node_digest)
111    }
112
113    fn on_debug(
114        &mut self,
115        process: ProcessState,
116        options: &DebugOptions,
117    ) -> Result<(), ExecutionError> {
118        H::on_debug(self, process, options)
119    }
120
121    fn on_event(&mut self, process: ProcessState, event_id: u32) -> Result<(), ExecutionError> {
122        H::on_event(self, process, event_id)
123    }
124
125    fn on_trace(&mut self, process: ProcessState, trace_id: u32) -> Result<(), ExecutionError> {
126        H::on_trace(self, process, trace_id)
127    }
128
129    fn on_assert_failed(&mut self, process: ProcessState, err_code: u32) -> ExecutionError {
130        H::on_assert_failed(self, process, err_code)
131    }
132}
133
134// DEFAULT HOST IMPLEMENTATION
135// ================================================================================================
136
137/// A default [Host] implementation that provides the essential functionality required by the VM.
138pub struct DefaultHost<A> {
139    adv_provider: A,
140    store: MemMastForestStore,
141}
142
143impl<A: Clone> Clone for DefaultHost<A> {
144    fn clone(&self) -> Self {
145        Self {
146            adv_provider: self.adv_provider.clone(),
147            store: self.store.clone(),
148        }
149    }
150}
151
152impl Default for DefaultHost<MemAdviceProvider> {
153    fn default() -> Self {
154        Self {
155            adv_provider: MemAdviceProvider::default(),
156            store: MemMastForestStore::default(),
157        }
158    }
159}
160
161impl<A: AdviceProvider> DefaultHost<A> {
162    pub fn new(adv_provider: A) -> Self {
163        Self {
164            adv_provider,
165            store: MemMastForestStore::default(),
166        }
167    }
168
169    pub fn load_mast_forest(&mut self, mast_forest: Arc<MastForest>) -> Result<(), ExecutionError> {
170        // Load the MAST's advice data into the advice provider.
171
172        for (digest, values) in mast_forest.advice_map().iter() {
173            if let Some(stored_values) = self.advice_provider().get_mapped_values(digest) {
174                if stored_values != values {
175                    return Err(ExecutionError::AdviceMapKeyAlreadyPresent(digest.into()));
176                }
177            } else {
178                self.advice_provider_mut().insert_into_map(digest.into(), values.clone());
179            }
180        }
181
182        self.store.insert(mast_forest);
183        Ok(())
184    }
185
186    #[cfg(any(test, feature = "testing"))]
187    pub fn advice_provider(&self) -> &A {
188        &self.adv_provider
189    }
190
191    #[cfg(any(test, feature = "testing"))]
192    pub fn advice_provider_mut(&mut self) -> &mut A {
193        &mut self.adv_provider
194    }
195
196    pub fn into_inner(self) -> A {
197        self.adv_provider
198    }
199}
200
201impl<A: AdviceProvider> Host for DefaultHost<A> {
202    type AdviceProvider = A;
203
204    fn advice_provider(&self) -> &Self::AdviceProvider {
205        &self.adv_provider
206    }
207
208    fn advice_provider_mut(&mut self) -> &mut Self::AdviceProvider {
209        &mut self.adv_provider
210    }
211
212    fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>> {
213        self.store.get(node_digest)
214    }
215
216    fn on_event(&mut self, process: ProcessState, event_id: u32) -> Result<(), ExecutionError> {
217        if event_id == SystemEvent::FalconSigToStack.into_event_id() {
218            // provide a default implementation for handling FalconSigToStack event since it is not
219            // handled any more by the system event handlers. the handler assumes that the private
220            // key is in the advice provider and uses it to in signature generation
221            let advice_provider = self.advice_provider_mut();
222            push_signature(advice_provider, process, SignatureKind::RpoFalcon512)
223        } else {
224            #[cfg(feature = "std")]
225            std::println!(
226                "Event with id {} emitted at step {} in context {}",
227                event_id,
228                process.clk(),
229                process.ctx()
230            );
231            Ok(())
232        }
233    }
234}
235
236// SIGNATURE EVENT HANDLER
237// ================================================================================================
238
239/// Pushes values onto the advice stack which are required for verification of a DSA in Miden
240/// VM.
241///
242/// Inputs:
243///   Operand stack: [PK, MSG, ...]
244///   Advice stack: [...]
245///
246/// Outputs:
247///   Operand stack: [PK, MSG, ...]
248///   Advice stack: \[DATA\]
249///
250/// Where:
251/// - PK is the digest of an expanded public.
252/// - MSG is the digest of the message to be signed.
253/// - DATA is the needed data for signature verification in the VM.
254///
255/// The advice provider is expected to contain the private key associated to the public key PK.
256pub fn push_signature(
257    advice_provider: &mut impl AdviceProvider,
258    process: ProcessState,
259    kind: SignatureKind,
260) -> Result<(), ExecutionError> {
261    let pub_key = process.get_stack_word(0);
262    let msg = process.get_stack_word(1);
263
264    let pk_sk = advice_provider
265        .get_mapped_values(&pub_key.into())
266        .ok_or(ExecutionError::AdviceMapKeyNotFound(pub_key))?;
267
268    let result = match kind {
269        SignatureKind::RpoFalcon512 => dsa::falcon_sign(pk_sk, msg)?,
270    };
271
272    for r in result {
273        advice_provider.push_stack(crate::AdviceSource::Value(r))?;
274    }
275    Ok(())
276}