miden_processor/fast/
crypto_ops.rs

1use vm_core::{
2    Felt, ZERO, chiplets::hasher::STATE_WIDTH, crypto::hash::Rpo256, mast::MastForest, utils::range,
3};
4
5use super::FastProcessor;
6use crate::{AdviceProvider, ErrorContext, ExecutionError, Host};
7
8impl FastProcessor {
9    /// Applies a permutation of the Rpo256 hash function to the top 12 elements of the stack.
10    ///
11    /// Analogous to `Process::op_hperm`.
12    pub fn op_hperm(&mut self) {
13        let state_range = range(self.stack_top_idx - STATE_WIDTH, STATE_WIDTH);
14        let hashed_state = {
15            let mut input_state: [Felt; STATE_WIDTH] =
16                self.stack[state_range.clone()].try_into().unwrap();
17
18            Rpo256::apply_permutation(&mut input_state);
19
20            input_state
21        };
22
23        self.stack[state_range].copy_from_slice(&hashed_state);
24    }
25
26    /// Analogous to `Process::op_mpverify`.
27    pub fn op_mpverify(
28        &mut self,
29        err_code: Felt,
30        host: &mut impl Host,
31        program: &MastForest,
32    ) -> Result<(), ExecutionError> {
33        // read node value, depth, index and root value from the stack
34        let node = self.stack_get_word(0);
35        let depth = self.stack_get(4);
36        let index = self.stack_get(5);
37        let root = self.stack_get_word(6);
38
39        // get a Merkle path from the advice provider for the specified root and node index
40        let path = host.advice_provider_mut().get_merkle_path(
41            root,
42            &depth,
43            &index,
44            &ErrorContext::default(),
45        )?;
46
47        // verify the path
48        match path.verify(index.as_int(), node.into(), &root.into()) {
49            Ok(_) => Ok(()),
50            Err(_) => {
51                let err_msg = program.resolve_error_message(err_code);
52                Err(ExecutionError::merkle_path_verification_failed(
53                    node,
54                    index,
55                    root.into(),
56                    err_code,
57                    err_msg,
58                    &ErrorContext::default(),
59                ))
60            },
61        }
62    }
63
64    /// Analogous to `Process::op_mrupdate`.
65    pub fn op_mrupdate(&mut self, host: &mut impl Host) -> Result<(), ExecutionError> {
66        // read old node value, depth, index, tree root and new node values from the stack
67        let old_node = self.stack_get_word(0);
68        let depth = self.stack_get(4);
69        let index = self.stack_get(5);
70        let old_root = self.stack_get_word(6);
71        let new_node = self.stack_get_word(10);
72
73        // update the node at the specified index in the Merkle tree specified by the old root, and
74        // get a Merkle path to it. The length of the returned path is expected to match the
75        // specified depth. If the new node is the root of a tree, this instruction will append the
76        // whole sub-tree to this node.
77        let (path, new_root) = host.advice_provider_mut().update_merkle_node(
78            old_root,
79            &depth,
80            &index,
81            new_node,
82            &ErrorContext::default(),
83        )?;
84
85        assert_eq!(path.len(), depth.as_int() as usize);
86
87        // verify that the old node is consistent with the Merkle path
88        if path.verify(index.as_int(), old_node.into(), &old_root.into()).is_err() {
89            return Err(ExecutionError::merkle_path_verification_failed(
90                old_node,
91                index,
92                old_root.into(),
93                ZERO,
94                None,
95                &ErrorContext::default(),
96            ));
97        }
98
99        // Replace the old node value with computed new root; everything else remains the same.
100        self.stack_write_word(0, &new_root);
101
102        Ok(())
103    }
104}