|
1 |
| -use vm_core::{ZERO, chiplets::hasher::apply_permutation}; |
| 1 | +use miden_air::trace::decoder::NUM_USER_OP_HELPERS; |
| 2 | +use vm_core::{Felt, ZERO}; |
2 | 3 |
|
3 | 4 | use super::CoreTraceFragmentGenerator;
|
| 5 | +use crate::processor::Processor; |
4 | 6 |
|
5 | 7 | impl CoreTraceFragmentGenerator {
|
6 | 8 | /// Performs a hash permutation operation.
|
7 | 9 | /// Applies Rescue Prime Optimized permutation to the top 12 elements of the stack.
|
8 |
| - pub(crate) fn hperm(&mut self) { |
9 |
| - // Get the top 12 elements from the stack (in reverse order for hasher state) |
10 |
| - let mut hasher_state = [ |
11 |
| - self.stack_get(11), |
12 |
| - self.stack_get(10), |
13 |
| - self.stack_get(9), |
14 |
| - self.stack_get(8), |
15 |
| - self.stack_get(7), |
16 |
| - self.stack_get(6), |
17 |
| - self.stack_get(5), |
18 |
| - self.stack_get(4), |
19 |
| - self.stack_get(3), |
20 |
| - self.stack_get(2), |
21 |
| - self.stack_get(1), |
22 |
| - self.stack_get(0), |
23 |
| - ]; |
24 |
| - |
25 |
| - // TODO(plafer): use hasher state replay (and in other crypto ops) |
26 |
| - // Apply the RPO permutation |
27 |
| - apply_permutation(&mut hasher_state); |
| 10 | + pub(crate) fn op_hperm(&mut self) -> [Felt; NUM_USER_OP_HELPERS] { |
| 11 | + let (addr, computed_hash) = self.state.hasher.replay_permutation(); |
28 | 12 |
|
29 | 13 | // Put the result back on the stack (in reverse order)
|
30 |
| - for (i, &value) in hasher_state.iter().rev().enumerate() { |
31 |
| - self.stack_set(i, value); |
| 14 | + for (i, &value) in computed_hash.iter().rev().enumerate() { |
| 15 | + self.stack_write(i, value); |
32 | 16 | }
|
| 17 | + |
| 18 | + [addr, ZERO, ZERO, ZERO, ZERO, ZERO] |
33 | 19 | }
|
34 | 20 |
|
35 | 21 | /// Verifies a Merkle path.
|
36 |
| - pub(crate) fn mpverify(&mut self) { |
37 |
| - // For parallel trace generation, we assume the Merkle path verification is already done |
38 |
| - // This would involve complex cryptographic verification in the actual implementation |
39 |
| - |
40 |
| - // The operation pops the node value (4 elements), depth, index, and root (4 elements) |
41 |
| - // and verifies the path. In parallel mode, we assume verification succeeds. |
| 22 | + /// |
| 23 | + /// In this implementation, we don't actually verify the path. |
| 24 | + pub(crate) fn op_mpverify(&mut self) -> [Felt; NUM_USER_OP_HELPERS] { |
| 25 | + let depth = self.stack_get(4); |
| 26 | + let index = self.stack_get(5); |
| 27 | + let root = self.stack_get_word(6); |
42 | 28 |
|
43 |
| - // Stack layout: [node_value(4), depth, index, root(4), ...] |
44 |
| - // After verification: [root(4), ...] |
| 29 | + // Replay the Merkle path retrieval from the advice provider |
| 30 | + let _path = self.state.advice.replay_merkle_path(root, depth, index); |
| 31 | + let (addr, computed_root) = self.state.hasher.replay_build_merkle_root(); |
45 | 32 |
|
46 |
| - // Move root to top and remove other elements |
47 |
| - let root = [ |
48 |
| - self.stack_get(9), // root[0] |
49 |
| - self.stack_get(8), // root[1] |
50 |
| - self.stack_get(7), // root[2] |
51 |
| - self.stack_get(6), // root[3] |
52 |
| - ]; |
53 |
| - |
54 |
| - // Set root at top of stack |
55 |
| - for (i, &value) in root.iter().enumerate() { |
56 |
| - self.stack_set(i, value); |
57 |
| - } |
| 33 | + debug_assert_eq!(root, computed_root, "Merkle root mismatch"); |
58 | 34 |
|
59 |
| - // Remove the consumed elements (node_value + depth + index = 6 elements) |
60 |
| - self.stack_shift_left(6); |
| 35 | + [addr, ZERO, ZERO, ZERO, ZERO, ZERO] |
61 | 36 | }
|
62 | 37 |
|
63 | 38 | /// Updates the Merkle root.
|
64 |
| - pub(crate) fn mrupdate(&mut self) { |
65 |
| - // For parallel trace generation, we assume the Merkle root update is already computed |
66 |
| - // This would involve complex cryptographic computations in the actual implementation |
67 |
| - |
68 |
| - // In a real implementation, this would: |
69 |
| - // 1. Pop the old leaf value, new leaf value, and Merkle path |
70 |
| - // 2. Compute the new root by updating the path with the new leaf |
71 |
| - // 3. Push the new root onto the stack |
72 |
| - |
73 |
| - // For now, we'll assume the operation succeeds and produces a placeholder root |
74 |
| - let new_root = [ZERO; 4]; // Placeholder for computed new root |
75 |
| - |
76 |
| - // Remove consumed elements and place new root |
77 |
| - // This is a simplified implementation - actual stack manipulation would depend |
78 |
| - // on the specific input format |
79 |
| - for (i, &value) in new_root.iter().enumerate() { |
80 |
| - self.stack_set(i, value); |
81 |
| - } |
| 39 | + pub(crate) fn op_mrupdate(&mut self) { |
| 40 | + todo!() |
82 | 41 | }
|
83 | 42 |
|
84 | 43 | /// Performs FRI extension fold operation.
|
85 |
| - pub(crate) fn fri_ext2fold4(&mut self) { |
86 |
| - // For parallel trace generation, we assume the FRI fold operation is already computed |
87 |
| - // This is a complex cryptographic operation used in polynomial commitments |
88 |
| - |
89 |
| - // In actual implementation, this would perform FRI (Fast Reed-Solomon Interactive Oracle |
90 |
| - // Proofs) extension field folding operations |
91 |
| - |
92 |
| - // For now, we'll assume the operation succeeds with a placeholder result |
| 44 | + pub(crate) fn op_fri_ext2fold4(&mut self) { |
| 45 | + todo!() |
93 | 46 | }
|
94 | 47 |
|
95 | 48 | /// Evaluates a polynomial using Horner's method (base field).
|
96 |
| - pub(crate) fn horner_eval_base(&mut self) { |
97 |
| - // For parallel trace generation, we assume the polynomial evaluation is already computed |
98 |
| - // This would evaluate a polynomial at a given point using Horner's method in the base field |
99 |
| - |
100 |
| - // In actual implementation, this would: |
101 |
| - // 1. Pop polynomial coefficients and evaluation point from stack |
102 |
| - // 2. Compute polynomial value using Horner's method: p(x) = a_n + x(a_{n-1} + x(a_{n-2} + |
103 |
| - // ...)) |
104 |
| - // 3. Push result onto stack |
105 |
| - |
106 |
| - let result = ZERO; // Placeholder for computed result |
107 |
| - self.stack_set(0, result); |
| 49 | + pub(crate) fn op_horner_eval_base(&mut self) { |
| 50 | + todo!() |
108 | 51 | }
|
109 | 52 |
|
110 | 53 | /// Evaluates a polynomial using Horner's method (extension field).
|
111 |
| - pub(crate) fn horner_eval_ext(&mut self) { |
112 |
| - // For parallel trace generation, we assume the polynomial evaluation is already computed |
113 |
| - // This would evaluate a polynomial at a given point using Horner's method in the extension |
114 |
| - // field |
115 |
| - |
116 |
| - // Similar to base field version but operates in quadratic extension field |
117 |
| - let result = [ZERO, ZERO]; // Placeholder for extension field result |
118 |
| - |
119 |
| - self.stack_set(0, result[0]); |
120 |
| - self.stack_set(1, result[1]); |
| 54 | + pub(crate) fn op_horner_eval_ext(&mut self) { |
| 55 | + todo!() |
121 | 56 | }
|
122 | 57 |
|
123 | 58 | /// Evaluates an arithmetic circuit.
|
124 |
| - pub(crate) fn arithmetic_circuit_eval(&mut self) { |
125 |
| - // For parallel trace generation, we assume the circuit evaluation is already computed |
126 |
| - // This would evaluate an arithmetic circuit with given inputs |
127 |
| - |
128 |
| - // In actual implementation, this would: |
129 |
| - // 1. Pop circuit description and inputs from stack |
130 |
| - // 2. Evaluate the arithmetic circuit |
131 |
| - // 3. Push results onto stack |
132 |
| - |
133 |
| - let result = ZERO; // Placeholder for computed result |
134 |
| - self.stack_set(0, result); |
| 59 | + pub(crate) fn op_arithmetic_circuit_eval(&mut self) { |
| 60 | + todo!() |
135 | 61 | }
|
136 | 62 | }
|
0 commit comments