Skip to main content

sp1_core_machine/
lib.rs

1#![allow(
2    clippy::new_without_default,
3    clippy::field_reassign_with_default,
4    clippy::unnecessary_cast,
5    clippy::cast_abs_to_unsigned,
6    clippy::needless_range_loop,
7    clippy::type_complexity,
8    clippy::unnecessary_unwrap,
9    clippy::default_constructed_unit_structs,
10    clippy::box_default,
11    clippy::assign_op_pattern,
12    deprecated,
13    incomplete_features
14)]
15#![warn(unused_extern_crates)]
16#[macro_use]
17extern crate static_assertions;
18
19pub mod adapter;
20pub mod air;
21pub mod alu;
22pub mod bytes;
23pub mod control_flow;
24pub mod executor;
25pub mod global;
26pub mod io;
27pub mod memory;
28pub mod operations;
29pub mod program;
30pub mod range;
31pub mod riscv;
32pub mod syscall;
33pub mod utils;
34pub mod utype;
35
36use air::SP1CoreAirBuilder;
37use memory::MemoryAccessCols;
38use operations::{AddressSlicePageProtOperation, IsZeroOperation, TrapOperation};
39use program::instruction::InstructionCols;
40use slop_air::AirBuilder;
41use slop_algebra::AbstractField;
42pub use sp1_core_executor::{SupervisorMode, UserMode};
43use sp1_derive::AlignedBorrow;
44use std::{fmt::Debug, marker::PhantomData};
45use struct_reflection::{StructReflection, StructReflectionHelper};
46
47pub trait TrustMode: Send + Sync + 'static {
48    const IS_TRUSTED: bool;
49    type AdapterCols<T>: StructReflectionHelper;
50    type SyscallInstrCols<T>: StructReflectionHelper;
51    type SliceProtCols<T>: StructReflectionHelper;
52    type AluX0SelectorCols<T>: StructReflectionHelper;
53    type TrapCodeCols<T>: StructReflectionHelper;
54}
55
56#[derive(AlignedBorrow, Default, Clone, Copy)]
57#[repr(C)]
58/// Strcut that represents an empty set of columns for a given type `T`.
59///
60/// The struct existis to facilitate the implementation traits needed for columns.
61pub struct EmptyCols<T>(PhantomData<T>);
62
63impl<T> StructReflection for EmptyCols<T> {
64    fn struct_reflection() -> Option<Vec<String>> {
65        None
66    }
67}
68
69impl TrustMode for SupervisorMode {
70    const IS_TRUSTED: bool = true;
71    type AdapterCols<T> = EmptyCols<T>;
72    type SyscallInstrCols<T> = EmptyCols<T>;
73    type SliceProtCols<T> = EmptyCols<T>;
74    type AluX0SelectorCols<T> = EmptyCols<T>;
75    type TrapCodeCols<T> = EmptyCols<T>;
76}
77
78#[derive(AlignedBorrow, Default, Debug, Clone, Copy, StructReflection)]
79#[repr(C)]
80pub struct UserModeReaderCols<T> {
81    pub is_trusted: T,
82}
83
84#[derive(AlignedBorrow, Default, Debug, Clone, Copy, StructReflection)]
85#[repr(C)]
86pub struct UserModeSyscallInstrCols<T> {
87    pub is_sig_return: IsZeroOperation<T>,
88    pub next_pc_record: MemoryAccessCols<T>,
89    pub trap_operation: TrapOperation<T>,
90    pub is_not_trap: IsZeroOperation<T>,
91    pub is_page_protect: IsZeroOperation<T>,
92    pub trap_code: T,
93    pub addresses: [[T; 3]; 3],
94}
95
96/// Selector columns for the AluX0 chip in User mode.
97///
98/// Each field is a boolean selector for one ALU opcode. Exactly one must be set per real row.
99#[derive(AlignedBorrow, Default, Debug, Clone, Copy, StructReflection)]
100#[repr(C)]
101pub struct AluX0OpcodeSelectors<T> {
102    pub instr_type: T,
103    pub base_opcode: T,
104    pub funct3: T,
105    pub funct7: T,
106    pub is_add: T,
107    pub is_sub: T,
108    pub is_mul: T,
109    pub is_mulh: T,
110    pub is_mulhsu: T,
111    pub is_mulhu: T,
112    pub is_div: T,
113    pub is_divu: T,
114    pub is_rem: T,
115    pub is_remu: T,
116    pub is_sll: T,
117    pub is_srl: T,
118    pub is_sra: T,
119    pub is_xor: T,
120    pub is_or: T,
121    pub is_and: T,
122    pub is_slt: T,
123    pub is_sltu: T,
124    pub is_addi: T,
125    pub is_addw: T,
126    pub is_subw: T,
127    pub is_sllw: T,
128    pub is_srlw: T,
129    pub is_sraw: T,
130    pub is_mulw: T,
131    pub is_divw: T,
132    pub is_divuw: T,
133    pub is_remw: T,
134    pub is_remuw: T,
135}
136
137#[derive(AlignedBorrow, Default, Debug, Clone, Copy, StructReflection)]
138#[repr(C)]
139pub struct UserModeTrapCodeCols<T> {
140    pub trap_code: T,
141}
142
143impl TrustMode for UserMode {
144    const IS_TRUSTED: bool = false;
145    type AdapterCols<T> = UserModeReaderCols<T>;
146    type SyscallInstrCols<T> = UserModeSyscallInstrCols<T>;
147    type SliceProtCols<T> = AddressSlicePageProtOperation<T>;
148    type AluX0SelectorCols<T> = AluX0OpcodeSelectors<T>;
149    type TrapCodeCols<T> = UserModeTrapCodeCols<T>;
150}
151
152fn eval_untrusted_program<AB: SP1CoreAirBuilder>(
153    builder: &mut AB,
154    pc: [impl Into<AB::Expr>; 3],
155    instruction: InstructionCols<AB::Expr>,
156    instruction_field_consts: [AB::Expr; 4],
157    clk: [AB::Expr; 2],
158    is_real: AB::Expr,
159    adapter_cols: UserModeReaderCols<AB::Var>,
160) {
161    builder.send_instruction_fetch(
162        pc,
163        instruction,
164        instruction_field_consts,
165        clk,
166        is_real.clone() - adapter_cols.is_trusted,
167    );
168
169    let is_untrusted = is_real.clone() - adapter_cols.is_trusted;
170    builder.assert_bool(adapter_cols.is_trusted);
171    builder.assert_bool(is_untrusted.clone());
172
173    // If the row is running an untrusted program, the page protection checks must be on.
174    let public_values = builder.extract_public_values();
175    builder.when(is_untrusted.clone()).assert_one(public_values.is_untrusted_programs_enabled);
176}
177
178/// Evaluate AluX0 opcode selectors for User mode.
179///
180/// Asserts all selectors are boolean, returns `[instr_type, base_opcode, funct3, funct7]`
181/// computed as linear combinations of selectors and constants.
182///
183/// The `imm_c` flag (from ALUTypeReader) determines whether the register or immediate
184/// form of the instruction encoding is used.
185fn eval_alu_x0_selectors<AB: SP1CoreAirBuilder>(
186    builder: &mut AB,
187    selectors: AluX0OpcodeSelectors<AB::Var>,
188    imm_c: AB::Expr,
189    is_real: AB::Expr,
190) {
191    use rrs_lib::instruction_formats::{OPCODE_OP, OPCODE_OP_32, OPCODE_OP_IMM, OPCODE_OP_IMM_32};
192    use sp1_core_executor::InstructionType;
193
194    // Assert all selectors are boolean.
195    builder.assert_bool(selectors.is_add);
196    builder.assert_bool(selectors.is_sub);
197    builder.assert_bool(selectors.is_mul);
198    builder.assert_bool(selectors.is_mulh);
199    builder.assert_bool(selectors.is_mulhsu);
200    builder.assert_bool(selectors.is_mulhu);
201    builder.assert_bool(selectors.is_div);
202    builder.assert_bool(selectors.is_divu);
203    builder.assert_bool(selectors.is_rem);
204    builder.assert_bool(selectors.is_remu);
205    builder.assert_bool(selectors.is_sll);
206    builder.assert_bool(selectors.is_srl);
207    builder.assert_bool(selectors.is_sra);
208    builder.assert_bool(selectors.is_xor);
209    builder.assert_bool(selectors.is_or);
210    builder.assert_bool(selectors.is_and);
211    builder.assert_bool(selectors.is_slt);
212    builder.assert_bool(selectors.is_sltu);
213    builder.assert_bool(selectors.is_addi);
214    builder.assert_bool(selectors.is_addw);
215    builder.assert_bool(selectors.is_subw);
216    builder.assert_bool(selectors.is_sllw);
217    builder.assert_bool(selectors.is_srlw);
218    builder.assert_bool(selectors.is_sraw);
219    builder.assert_bool(selectors.is_mulw);
220    builder.assert_bool(selectors.is_divw);
221    builder.assert_bool(selectors.is_divuw);
222    builder.assert_bool(selectors.is_remw);
223    builder.assert_bool(selectors.is_remuw);
224
225    // Assert exactly one selector is set when is_real.
226    let selector_sum: AB::Expr = selectors.is_add
227        + selectors.is_sub
228        + selectors.is_mul
229        + selectors.is_mulh
230        + selectors.is_mulhsu
231        + selectors.is_mulhu
232        + selectors.is_div
233        + selectors.is_divu
234        + selectors.is_rem
235        + selectors.is_remu
236        + selectors.is_sll
237        + selectors.is_srl
238        + selectors.is_sra
239        + selectors.is_xor
240        + selectors.is_or
241        + selectors.is_and
242        + selectors.is_slt
243        + selectors.is_sltu
244        + selectors.is_addi
245        + selectors.is_addw
246        + selectors.is_subw
247        + selectors.is_sllw
248        + selectors.is_srlw
249        + selectors.is_sraw
250        + selectors.is_mulw
251        + selectors.is_divw
252        + selectors.is_divuw
253        + selectors.is_remw
254        + selectors.is_remuw;
255    builder.assert_bool(selector_sum.clone());
256    builder.when(is_real.clone()).assert_one(selector_sum.clone());
257    builder.when_not(is_real.clone()).assert_zero(selector_sum.clone());
258
259    // Helper: group selectors by their register-form base_opcode.
260    // OPCODE_OP (0x33): ADD, SUB, MUL..REMU, SLL, SRL, SRA, XOR, OR, AND, SLT, SLTU
261    let is_op: AB::Expr = selectors.is_add
262        + selectors.is_sub
263        + selectors.is_mul
264        + selectors.is_mulh
265        + selectors.is_mulhsu
266        + selectors.is_mulhu
267        + selectors.is_div
268        + selectors.is_divu
269        + selectors.is_rem
270        + selectors.is_remu
271        + selectors.is_sll
272        + selectors.is_srl
273        + selectors.is_sra
274        + selectors.is_xor
275        + selectors.is_or
276        + selectors.is_and
277        + selectors.is_slt
278        + selectors.is_sltu;
279
280    // OPCODE_OP_32 (0x3b): ADDW, SUBW, SLLW, SRLW, SRAW, MULW..REMUW
281    let is_op_32: AB::Expr = selectors.is_addw
282        + selectors.is_subw
283        + selectors.is_sllw
284        + selectors.is_srlw
285        + selectors.is_sraw
286        + selectors.is_mulw
287        + selectors.is_divw
288        + selectors.is_divuw
289        + selectors.is_remw
290        + selectors.is_remuw;
291
292    // OPCODE_OP_IMM (0x13): ADDI, and imm variants of SLL..SLTU
293    // OPCODE_OP_IMM_32 (0x1b): imm variants of ADDW, SLLW, SRLW, SRAW
294
295    // Opcodes that have an immediate variant with OPCODE_OP_IMM:
296    let has_imm_op_imm: AB::Expr = selectors.is_sll
297        + selectors.is_srl
298        + selectors.is_sra
299        + selectors.is_xor
300        + selectors.is_or
301        + selectors.is_and
302        + selectors.is_slt
303        + selectors.is_sltu
304        + selectors.is_addi;
305
306    // Opcodes that have an immediate variant with OPCODE_OP_IMM_32:
307    let has_imm_op_imm_32: AB::Expr =
308        selectors.is_addw + selectors.is_sllw + selectors.is_srlw + selectors.is_sraw;
309
310    // --- base_opcode ---
311    // reg form: is_op * OPCODE_OP + is_op_32 * OPCODE_OP_32 + is_addi * OPCODE_OP_IMM
312    // imm form: has_imm_op_imm * OPCODE_OP_IMM + has_imm_op_imm_32 * OPCODE_OP_IMM_32
313    let is_addi: AB::Expr = selectors.is_addi.into();
314    let reg_base_opcode: AB::Expr = is_op.clone() * AB::F::from_canonical_u32(OPCODE_OP)
315        + is_op_32.clone() * AB::F::from_canonical_u32(OPCODE_OP_32)
316        + is_addi.clone() * AB::F::from_canonical_u32(OPCODE_OP_IMM);
317
318    let imm_base_opcode: AB::Expr = has_imm_op_imm * AB::F::from_canonical_u32(OPCODE_OP_IMM)
319        + has_imm_op_imm_32 * AB::F::from_canonical_u32(OPCODE_OP_IMM_32);
320
321    let base_opcode: AB::Expr =
322        (is_real.clone() - imm_c.clone()) * reg_base_opcode + imm_c.clone() * imm_base_opcode;
323
324    // --- instr_type ---
325    // reg form: RType for everything except ADDI (IType)
326    // imm form: depends on opcode group
327    let reg_instr_type: AB::Expr = (is_op + is_op_32)
328        * AB::F::from_canonical_u32(InstructionType::RType as u32)
329        + is_addi * AB::F::from_canonical_u32(InstructionType::IType as u32);
330
331    // ITypeShamt imm: SLL, SRL, SRA
332    let is_shamt: AB::Expr = selectors.is_sll + selectors.is_srl + selectors.is_sra;
333    // ITypeShamt32 imm: SLLW, SRLW, SRAW
334    let is_shamt32: AB::Expr = selectors.is_sllw + selectors.is_srlw + selectors.is_sraw;
335    // IType imm: XOR, OR, AND, SLT, SLTU, ADDI, ADDW
336    let is_itype_imm: AB::Expr = selectors.is_xor
337        + selectors.is_or
338        + selectors.is_and
339        + selectors.is_slt
340        + selectors.is_sltu
341        + selectors.is_addi
342        + selectors.is_addw;
343
344    let imm_instr_type: AB::Expr = is_shamt
345        * AB::F::from_canonical_u32(InstructionType::ITypeShamt as u32)
346        + is_shamt32 * AB::F::from_canonical_u32(InstructionType::ITypeShamt32 as u32)
347        + is_itype_imm * AB::F::from_canonical_u32(InstructionType::IType as u32);
348
349    let instr_type: AB::Expr =
350        (is_real.clone() - imm_c.clone()) * reg_instr_type + imm_c.clone() * imm_instr_type;
351
352    // --- funct3 ---
353    // Same for both reg and imm forms.
354    // funct3 = 0b000: ADD, SUB, ADDI, MUL, ADDW, SUBW, MULW (contribute 0, omitted)
355    let funct3: AB::Expr =
356        // funct3 = 0b001: MULH, SLL, SLLW
357        (selectors.is_mulh
358            + selectors.is_sll
359            + selectors.is_sllw)
360            * AB::F::from_canonical_u32(0b001)
361        // funct3 = 0b010: MULHSU, SLT
362        + (selectors.is_mulhsu + selectors.is_slt)
363            * AB::F::from_canonical_u32(0b010)
364        // funct3 = 0b011: MULHU, SLTU
365        + (selectors.is_mulhu + selectors.is_sltu)
366            * AB::F::from_canonical_u32(0b011)
367        // funct3 = 0b100: DIV, XOR, DIVW
368        + (selectors.is_div
369            + selectors.is_xor
370            + selectors.is_divw)
371            * AB::F::from_canonical_u32(0b100)
372        // funct3 = 0b101: DIVU, SRL, SRA, DIVUW, SRLW, SRAW
373        + (selectors.is_divu
374            + selectors.is_srl
375            + selectors.is_sra
376            + selectors.is_divuw
377            + selectors.is_srlw
378            + selectors.is_sraw)
379            * AB::F::from_canonical_u32(0b101)
380        // funct3 = 0b110: REM, OR, REMW
381        + (selectors.is_rem
382            + selectors.is_or
383            + selectors.is_remw)
384            * AB::F::from_canonical_u32(0b110)
385        // funct3 = 0b111: REMU, AND, REMUW
386        + (selectors.is_remu
387            + selectors.is_and
388            + selectors.is_remuw)
389            * AB::F::from_canonical_u32(0b111);
390
391    // --- funct7 ---
392    // Only present in register form.
393    // funct7 = 0b0000000 (0): ADD, SLL, SRL, XOR, OR, AND, SLT, SLTU, ADDW, SLLW, SRLW
394    //   (these contribute 0, so omitted)
395    // funct7 = 0b0100000 (32): SUB, SRA, SUBW, SRAW
396    // funct7 = 0b0000001 (1): MUL, MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU,
397    //                          MULW, DIVW, DIVUW, REMW, REMUW
398    let funct7: AB::Expr =
399        // funct7 = 32
400        (selectors.is_sub
401            + selectors.is_sra
402            + selectors.is_subw
403            + selectors.is_sraw)
404            * AB::F::from_canonical_u32(0b0100000)
405        // funct7 = 1
406        + (selectors.is_mul
407            + selectors.is_mulh
408            + selectors.is_mulhsu
409            + selectors.is_mulhu
410            + selectors.is_div
411            + selectors.is_divu
412            + selectors.is_rem
413            + selectors.is_remu
414            + selectors.is_mulw
415            + selectors.is_divw
416            + selectors.is_divuw
417            + selectors.is_remw
418            + selectors.is_remuw)
419            * AB::F::from_canonical_u32(0b0000001);
420
421    builder.assert_eq(selectors.instr_type, instr_type);
422    builder.assert_eq(selectors.base_opcode, base_opcode);
423    builder.assert_eq(selectors.funct3, funct3);
424    builder.assert_eq(selectors.funct7, funct7);
425}
426
427// Re-export the `SP1RecursionProof` struct from sp1_core_machine.
428//
429// This is done to avoid a circular dependency between sp1_core_machine and sp1_core_executor, and
430// enable crates that depend on sp1_core_machine to import the `SP1RecursionProof` type directly.
431pub mod recursion {
432    pub use sp1_core_executor::SP1RecursionProof;
433}
434
435#[cfg(test)]
436pub mod programs {
437    #[allow(dead_code)]
438    #[allow(missing_docs)]
439    pub mod tests {
440        use sp1_core_executor::{add_halt, Instruction, Opcode, Program};
441
442        pub use test_artifacts::{
443            FIBONACCI_ELF, KECCAK_PERMUTE_ELF, PANIC_ELF, SECP256R1_ADD_ELF, SECP256R1_DOUBLE_ELF,
444            SSZ_WITHDRAWALS_ELF, U256XU2048_MUL_ELF,
445        };
446
447        #[must_use]
448        pub fn simple_program() -> Program {
449            let mut instructions = vec![
450                Instruction::new(Opcode::ADDI, 29, 0, 5, false, true),
451                Instruction::new(Opcode::ADDI, 30, 0, 37, false, true),
452                Instruction::new(Opcode::ADD, 31, 30, 29, false, false),
453            ];
454            add_halt(&mut instructions);
455            Program::new(instructions, 0, 0)
456        }
457
458        /// Get the fibonacci program.
459        ///
460        /// # Panics
461        ///
462        /// This function will panic if the program fails to load.
463        #[must_use]
464        pub fn fibonacci_program() -> Program {
465            Program::from(&FIBONACCI_ELF).unwrap()
466        }
467
468        /// Get the secp256r1 add program.
469        ///
470        /// # Panics
471        ///
472        /// This function will panic if the program fails to load.
473        #[must_use]
474        pub fn secp256r1_add_program() -> Program {
475            Program::from(&SECP256R1_ADD_ELF).unwrap()
476        }
477
478        /// Get the secp256r1 double program.
479        ///
480        /// # Panics
481        ///
482        /// This function will panic if the program fails to load.
483        #[must_use]
484        pub fn secp256r1_double_program() -> Program {
485            Program::from(&SECP256R1_DOUBLE_ELF).unwrap()
486        }
487
488        /// Get the SSZ withdrawals program.
489        ///
490        /// # Panics
491        ///
492        /// This function will panic if the program fails to load.
493        #[must_use]
494        pub fn ssz_withdrawals_program() -> Program {
495            Program::from(&SSZ_WITHDRAWALS_ELF).unwrap()
496        }
497
498        /// Get the keccak permute program.
499        ///
500        /// # Panics
501        ///
502        /// This function will panic if the program fails to load.
503        #[must_use]
504        pub fn keccak_permute_program() -> Program {
505            Program::from(&KECCAK_PERMUTE_ELF).unwrap()
506        }
507
508        /// Get the panic program.
509        ///
510        /// # Panics
511        ///
512        /// This function will panic if the program fails to load.
513        #[must_use]
514        pub fn panic_program() -> Program {
515            Program::from(&PANIC_ELF).unwrap()
516        }
517
518        #[must_use]
519        #[allow(clippy::unreadable_literal)]
520        pub fn simple_memory_program() -> Program {
521            let instructions = vec![
522                Instruction::new(Opcode::ADDI, 29, 0, 0x12348765, false, true),
523                // SW and LW
524                Instruction::new(Opcode::SW, 29, 0, 0x27654320, false, true),
525                Instruction::new(Opcode::LW, 28, 0, 0x27654320, false, true),
526                // LBU
527                Instruction::new(Opcode::LBU, 27, 0, 0x27654320, false, true),
528                Instruction::new(Opcode::LBU, 26, 0, 0x27654321, false, true),
529                Instruction::new(Opcode::LBU, 25, 0, 0x27654322, false, true),
530                Instruction::new(Opcode::LBU, 24, 0, 0x27654323, false, true),
531                // LB
532                Instruction::new(Opcode::LB, 23, 0, 0x27654320, false, true),
533                Instruction::new(Opcode::LB, 22, 0, 0x27654321, false, true),
534                // LHU
535                Instruction::new(Opcode::LHU, 21, 0, 0x27654320, false, true),
536                Instruction::new(Opcode::LHU, 20, 0, 0x27654322, false, true),
537                // LU
538                Instruction::new(Opcode::LH, 19, 0, 0x27654320, false, true),
539                Instruction::new(Opcode::LH, 18, 0, 0x27654322, false, true),
540                // SB
541                Instruction::new(Opcode::ADDI, 17, 0, 0x38276525, false, true),
542                // Save the value 0x12348765 into address 0x43627530
543                Instruction::new(Opcode::SW, 29, 0, 0x43627530, false, true),
544                Instruction::new(Opcode::SB, 17, 0, 0x43627530, false, true),
545                Instruction::new(Opcode::LW, 16, 0, 0x43627530, false, true),
546                Instruction::new(Opcode::SB, 17, 0, 0x43627531, false, true),
547                Instruction::new(Opcode::LW, 15, 0, 0x43627530, false, true),
548                Instruction::new(Opcode::SB, 17, 0, 0x43627532, false, true),
549                Instruction::new(Opcode::LW, 14, 0, 0x43627530, false, true),
550                Instruction::new(Opcode::SB, 17, 0, 0x43627533, false, true),
551                Instruction::new(Opcode::LW, 13, 0, 0x43627530, false, true),
552                // SH
553                // Save the value 0x12348765 into address 0x43627530
554                Instruction::new(Opcode::SW, 29, 0, 0x43627530, false, true),
555                Instruction::new(Opcode::SH, 17, 0, 0x43627530, false, true),
556                Instruction::new(Opcode::LW, 12, 0, 0x43627530, false, true),
557                Instruction::new(Opcode::SH, 17, 0, 0x43627532, false, true),
558                Instruction::new(Opcode::LW, 11, 0, 0x43627530, false, true),
559            ];
560            Program::new(instructions, 0, 0)
561        }
562    }
563}