|
| 1 | +use super::{ |
| 2 | + operand::{MemOrConstant, MemOrFp, MemOrFpOrConstant}, |
| 3 | + operation::Operation, |
| 4 | +}; |
| 5 | + |
| 6 | +/// Defines the instruction set for this zkVM, specialized for the `AggregateMerge` logic. |
| 7 | +/// |
| 8 | +/// The ISA is minimal and includes basic arithmetic, memory operations, control flow, |
| 9 | +/// and powerful precompiles for hashing and extension field arithmetic. |
| 10 | +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| 11 | +pub enum Instruction<F> { |
| 12 | + /// Performs a basic arithmetic computation: `res = arg_a op arg_b`. |
| 13 | + /// |
| 14 | + /// This corresponds to the `ADD` and `MUL` opcodes in the design document. |
| 15 | + Computation { |
| 16 | + /// The arithmetic operation to perform (`Add` or `Mul`). |
| 17 | + operation: Operation, |
| 18 | + /// The first operand of the computation. |
| 19 | + arg_a: MemOrConstant<F>, |
| 20 | + /// The second operand of the computation. |
| 21 | + arg_b: MemOrFp, |
| 22 | + /// The memory location or constant that the result must be equal to. |
| 23 | + res: MemOrConstant<F>, |
| 24 | + }, |
| 25 | + /// Performs a memory dereference: `res = m[m[fp + shift_0] + shift_1]`. |
| 26 | + /// |
| 27 | + /// This corresponds to the `DEREF` opcode. |
| 28 | + Deref { |
| 29 | + /// The offset from `fp` for the first memory access, which yields a pointer. |
| 30 | + shift_0: usize, |
| 31 | + /// The offset added to the pointer from the first access to get the final address. |
| 32 | + shift_1: usize, |
| 33 | + /// The value that the result of the double dereference must be equal to. |
| 34 | + res: MemOrFpOrConstant<F>, |
| 35 | + }, |
| 36 | + /// A conditional jump, called `JUZ` (Jump Unless Zero). |
| 37 | + /// |
| 38 | + /// Changes the `pc` if `condition` is non-zero. |
| 39 | + JumpIfNotZero { |
| 40 | + /// The value to check. The jump is taken if this value is not zero. |
| 41 | + condition: MemOrConstant<F>, |
| 42 | + /// The destination `pc` for the jump. |
| 43 | + dest: MemOrConstant<F>, |
| 44 | + /// The new value for the frame pointer (`fp`) after the instruction. |
| 45 | + updated_fp: MemOrFp, |
| 46 | + }, |
| 47 | + /// **Precompile** for a Poseidon2 permutation over 16 base field elements. |
| 48 | + /// |
| 49 | + /// This is used for hashing operations within the `AggregateMerge` algorithm. |
| 50 | + /// The precompile performs: `Poseidon2(m'[m[fp+s]], m'[m[fp+s+1]]) = (m'[m[fp+s+2]], m'[m[fp+s+3]])`, |
| 51 | + /// where: |
| 52 | + /// - `s` is the shift, |
| 53 | + /// - `m` is scalar memory, |
| 54 | + /// - `m'` is vectorized memory access (a chunk of 8 base field elements, representing a degree-8 extension field element). |
| 55 | + Poseidon2_16 { |
| 56 | + /// The starting offset `s` from `fp`. The instruction reads 4 pointers from `m[fp+s]` to `m[fp+s+3]`. |
| 57 | + shift: usize, |
| 58 | + }, |
| 59 | + /// **Precompile** for a Poseidon2 permutation over 24 base field elements. |
| 60 | + /// |
| 61 | + /// This operates similarly to `Poseidon2_16` but on 3 concatenated input vectors and 3 output vectors. |
| 62 | + /// |
| 63 | + /// It reads 6 pointers from memory, starting at `m[fp+shift]`. |
| 64 | + Poseidon2_24 { |
| 65 | + /// The starting offset from `fp`. The instruction reads 6 pointers from `m[fp+shift]` to `m[fp+shift+5]`. |
| 66 | + shift: usize, |
| 67 | + }, |
| 68 | + /// **Precompile** for multiplication in the degree-8 extension field. |
| 69 | + /// |
| 70 | + /// This is important for speeding up recursive proof verification (`snark_verify`). |
| 71 | + ExtensionMul { |
| 72 | + /// An array of three offsets from `fp`. These point to the start of the 8-cell memory blocks |
| 73 | + /// for the two input extension field elements and the resulting output element. |
| 74 | + args: [usize; 3], |
| 75 | + }, |
| 76 | +} |
0 commit comments