miden_processor/fast/
crypto_ops.rs

1use miden_core::{
2    Felt, ZERO, chiplets::hasher::STATE_WIDTH, crypto::hash::Rpo256, mast::MastForest, utils::range,
3};
4
5use super::FastProcessor;
6use crate::{ErrorContext, ExecutionError};
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        program: &MastForest,
31        err_ctx: &impl ErrorContext,
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 = self
41            .advice
42            .get_merkle_path(root, &depth, &index)
43            .map_err(|err| ExecutionError::advice_error(err, self.clk, err_ctx))?;
44
45        // verify the path
46        match path.verify(index.as_int(), node, &root) {
47            Ok(_) => Ok(()),
48            Err(_) => {
49                let err_msg = program.resolve_error_message(err_code);
50                Err(ExecutionError::merkle_path_verification_failed(
51                    node, index, root, err_code, err_msg, err_ctx,
52                ))
53            },
54        }
55    }
56
57    /// Analogous to `Process::op_mrupdate`.
58    pub fn op_mrupdate(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
59        // read old node value, depth, index, tree root and new node values from the stack
60        let old_node = self.stack_get_word(0);
61        let depth = self.stack_get(4);
62        let index = self.stack_get(5);
63        let old_root = self.stack_get_word(6);
64        let new_node = self.stack_get_word(10);
65
66        // update the node at the specified index in the Merkle tree specified by the old root, and
67        // get a Merkle path to it. The length of the returned path is expected to match the
68        // specified depth. If the new node is the root of a tree, this instruction will append the
69        // whole sub-tree to this node.
70        let (path, new_root) =
71            self.advice
72                .update_merkle_node(old_root, &depth, &index, new_node)
73                .map_err(|err| ExecutionError::advice_error(err, self.clk, err_ctx))?;
74
75        assert_eq!(path.len(), depth.as_int() as usize);
76
77        // verify that the old node is consistent with the Merkle path
78        if path.verify(index.as_int(), old_node, &old_root).is_err() {
79            return Err(ExecutionError::merkle_path_verification_failed(
80                old_node, index, old_root, ZERO, None, err_ctx,
81            ));
82        }
83
84        // Replace the old node value with computed new root; everything else remains the same.
85        self.stack_write_word(0, &new_root);
86
87        Ok(())
88    }
89}