1use columns::NUM_SYSCALL_INSTR_COLS;
2use p3_air::BaseAir;
3
4pub mod air;
5pub mod columns;
6pub mod trace;
7
8#[derive(Default)]
9pub struct SyscallInstrsChip;
10
11impl<F> BaseAir<F> for SyscallInstrsChip {
12 fn width(&self) -> usize {
13 NUM_SYSCALL_INSTR_COLS
14 }
15}
16
17#[cfg(test)]
18mod tests {
19 use std::borrow::BorrowMut;
20
21 use p3_baby_bear::BabyBear;
22 use p3_field::AbstractField;
23 use p3_matrix::dense::RowMajorMatrix;
24 use sp1_core_executor::{ExecutionRecord, Instruction, Opcode, Program};
25 use sp1_stark::{
26 air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, chip_name, CpuProver,
27 MachineProver, Val,
28 };
29 use sp1_zkvm::syscalls::{COMMIT, COMMIT_DEFERRED_PROOFS, HALT, SHA_EXTEND};
30
31 use crate::{
32 cpu::{columns::CpuCols, CpuChip},
33 io::SP1Stdin,
34 riscv::RiscvAir,
35 syscall::instructions::{columns::SyscallInstrColumns, SyscallInstrsChip},
36 utils::run_malicious_test,
37 };
38
39 #[test]
40 fn test_malicious_next_pc() {
41 struct TestCase {
42 program: Vec<Instruction>,
43 incorrect_next_pc: u32,
44 }
45
46 let test_cases = vec![
47 TestCase {
48 program: vec![
49 Instruction::new(Opcode::ADD, 5, 0, HALT, false, true), Instruction::new(Opcode::ECALL, 5, 10, 11, false, false), Instruction::new(Opcode::ADD, 30, 0, 100, false, true),
54 ],
55 incorrect_next_pc: 8, },
57 TestCase {
58 program: vec![
59 Instruction::new(Opcode::ADD, 5, 0, SHA_EXTEND, false, true), Instruction::new(Opcode::ADD, 10, 0, 40, false, true), Instruction::new(Opcode::ECALL, 5, 10, 11, false, false), Instruction::new(Opcode::ADD, 30, 0, 100, false, true),
64 ],
65 incorrect_next_pc: 0, },
67 ];
68
69 for test_case in test_cases {
70 let program = Program::new(test_case.program, 0, 0);
71 let stdin = SP1Stdin::new();
72
73 type P = CpuProver<BabyBearPoseidon2, RiscvAir<BabyBear>>;
74
75 let malicious_trace_pv_generator =
76 move |prover: &P,
77 record: &mut ExecutionRecord|
78 -> Vec<(String, RowMajorMatrix<Val<BabyBearPoseidon2>>)> {
79 let mut malicious_record = record.clone();
81
82 if !malicious_record.cpu_events.is_empty() {
85 malicious_record.syscall_events[0].next_pc = test_case.incorrect_next_pc;
86 }
87
88 prover.generate_traces(&malicious_record)
89 };
90
91 let result =
92 run_malicious_test::<P>(program, stdin, Box::new(malicious_trace_pv_generator));
93 let syscall_chip_name = chip_name!(SyscallInstrsChip, BabyBear);
94 assert!(
95 result.is_err() && result.unwrap_err().is_constraints_failing(&syscall_chip_name)
96 );
97 }
98 }
99
100 #[test]
101 fn test_malicious_extra_cycles() {
102 let instructions = vec![
103 Instruction::new(Opcode::ADD, 5, 0, SHA_EXTEND, false, true), Instruction::new(Opcode::ADD, 10, 0, 40, false, true), Instruction::new(Opcode::ECALL, 5, 10, 11, false, false), Instruction::new(Opcode::ADD, 30, 20, 100, true, true),
109 ];
110 let program = Program::new(instructions, 0, 0);
111 let stdin = SP1Stdin::new();
112
113 type P = CpuProver<BabyBearPoseidon2, RiscvAir<BabyBear>>;
114
115 let malicious_trace_pv_generator =
116 |prover: &P,
117 record: &mut ExecutionRecord|
118 -> Vec<(String, RowMajorMatrix<Val<BabyBearPoseidon2>>)> {
119 let mut traces = prover.generate_traces(record);
120
121 let cpu_chip_name = chip_name!(CpuChip, BabyBear);
122 let syscall_chip_name = chip_name!(SyscallInstrsChip, BabyBear);
123
124 for (chip_name, trace) in traces.iter_mut() {
125 if *chip_name == cpu_chip_name {
126 let third_row = trace.row_mut(2);
127 let third_row: &mut CpuCols<BabyBear> = third_row.borrow_mut();
128 assert!(third_row.is_syscall == BabyBear::one());
129 third_row.num_extra_cycles = BabyBear::from_canonical_usize(8);
130 let fourth_row = trace.row_mut(3);
133 let fourth_row: &mut CpuCols<BabyBear> = fourth_row.borrow_mut();
134 fourth_row.clk_16bit_limb = BabyBear::from_canonical_usize(20);
135 }
137
138 if *chip_name == syscall_chip_name {
139 let first_row = trace.row_mut(0);
140 let first_row: &mut SyscallInstrColumns<BabyBear> = first_row.borrow_mut();
141 first_row.num_extra_cycles = BabyBear::from_canonical_usize(4);
142 }
144 }
145
146 traces
147 };
148
149 let result =
150 run_malicious_test::<P>(program, stdin, Box::new(malicious_trace_pv_generator));
151 let syscall_chip_name = chip_name!(SyscallInstrsChip, BabyBear);
152 assert!(result.is_err() && result.unwrap_err().is_constraints_failing(&syscall_chip_name));
153 }
154
155 #[test]
156 fn test_malicious_commit() {
157 let instructions = vec![
158 Instruction::new(Opcode::ADD, 5, 0, COMMIT, false, true), Instruction::new(Opcode::ADD, 10, 0, 0, false, false), Instruction::new(Opcode::ADD, 11, 0, 40, false, true), Instruction::new(Opcode::ECALL, 5, 10, 11, false, false), ];
165 let program = Program::new(instructions, 0, 0);
166 let stdin = SP1Stdin::new();
167
168 type P = CpuProver<BabyBearPoseidon2, RiscvAir<BabyBear>>;
169
170 let malicious_trace_pv_generator =
171 |prover: &P,
172 record: &mut ExecutionRecord|
173 -> Vec<(String, RowMajorMatrix<Val<BabyBearPoseidon2>>)> {
174 record.public_values.committed_value_digest[0] = 10; prover.generate_traces(record)
176 };
177
178 let result =
179 run_malicious_test::<P>(program, stdin, Box::new(malicious_trace_pv_generator));
180 let syscall_chip_name = chip_name!(SyscallInstrsChip, BabyBear);
181 assert!(result.is_err() && result.unwrap_err().is_constraints_failing(&syscall_chip_name));
182 }
183
184 #[test]
185 fn test_malicious_commit_deferred() {
186 let instructions = vec![
187 Instruction::new(Opcode::ADD, 5, 0, COMMIT_DEFERRED_PROOFS, false, true), Instruction::new(Opcode::ADD, 10, 0, 0, false, false), Instruction::new(Opcode::ADD, 11, 0, 40, false, true), Instruction::new(Opcode::ECALL, 5, 10, 11, false, false), ];
197 let program = Program::new(instructions, 0, 0);
198 let stdin = SP1Stdin::new();
199
200 type P = CpuProver<BabyBearPoseidon2, RiscvAir<BabyBear>>;
201
202 let malicious_trace_pv_generator =
203 |prover: &P,
204 record: &mut ExecutionRecord|
205 -> Vec<(String, RowMajorMatrix<Val<BabyBearPoseidon2>>)> {
206 record.public_values.deferred_proofs_digest[0] = 10; prover.generate_traces(record)
208 };
209
210 let result =
211 run_malicious_test::<P>(program, stdin, Box::new(malicious_trace_pv_generator));
212 let syscall_chip_name = chip_name!(SyscallInstrsChip, BabyBear);
213 assert!(result.is_err() && result.unwrap_err().is_constraints_failing(&syscall_chip_name));
214 }
215}