Skip to main content

sp1_core_executor/
syscall_code.rs

1//! Syscall definitions for the SP1 RISC-V zkVM.
2
3use deepsize2::DeepSizeOf;
4use enum_map::Enum;
5use serde::{Deserialize, Serialize};
6use strum::EnumIter;
7
8use crate::{events::FieldOperation, RiscvAirId};
9
10/// System Calls.
11///
12/// A system call is invoked by the the `ecall` instruction with a specific value in register t0.
13/// The syscall number is a 32-bit integer with the following little-endian layout:
14///
15/// | Byte 0 | Byte 1 | Byte 2 | Byte 3 |
16/// | ------ | ------ | ------ | ------ |
17/// |   ID   | Table  | Unused | Unused |
18///
19/// where:
20/// - Byte 0: The system call identifier.
21/// - Byte 1: Whether the handler of the system call has its own table. This is used in the CPU
22///   table to determine whether to lookup the syscall using the syscall interaction.
23/// - Byte 2: Previously, this was the number of additional cycles the syscall uses. Now, this byte
24///   is unused, as each syscall instruction increments the clock by 256 additionally.
25/// - Byte 3: Currently unused.
26#[derive(
27    Debug,
28    Copy,
29    Clone,
30    PartialEq,
31    Eq,
32    Hash,
33    EnumIter,
34    Ord,
35    PartialOrd,
36    Serialize,
37    Deserialize,
38    Enum,
39    Default,
40    DeepSizeOf,
41)]
42#[allow(non_camel_case_types)]
43#[allow(clippy::upper_case_acronyms)]
44#[repr(u32)]
45pub enum SyscallCode {
46    /// Halts the program.
47    #[default]
48    HALT = 0x00_00_00_00,
49
50    /// Write to the output buffer.
51    WRITE = 0x00_00_00_02,
52
53    /// Enter unconstrained block.
54    ENTER_UNCONSTRAINED = 0x00_00_00_03,
55
56    /// Exit unconstrained block.
57    EXIT_UNCONSTRAINED = 0x00_00_00_04,
58
59    /// Executes the `SHA_EXTEND` precompile.
60    SHA_EXTEND = 0x00_30_01_05,
61
62    /// Executes the `SHA_COMPRESS` precompile.
63    SHA_COMPRESS = 0x00_01_01_06,
64
65    /// Executes the `ED_ADD` precompile.
66    ED_ADD = 0x00_01_01_07,
67
68    /// Executes the `ED_DECOMPRESS` precompile.
69    ED_DECOMPRESS = 0x00_00_01_08,
70
71    /// Executes the `KECCAK_PERMUTE` precompile.
72    KECCAK_PERMUTE = 0x00_01_01_09,
73
74    /// Executes the `SECP256K1_ADD` precompile.
75    SECP256K1_ADD = 0x00_01_01_0A,
76
77    /// Executes the `SECP256K1_DOUBLE` precompile.
78    SECP256K1_DOUBLE = 0x00_00_01_0B,
79
80    /// Executes the `SECP256K1_DECOMPRESS` precompile.
81    SECP256K1_DECOMPRESS = 0x00_00_01_0C,
82
83    /// Executes the `BN254_ADD` precompile.
84    BN254_ADD = 0x00_01_01_0E,
85
86    /// Executes the `BN254_DOUBLE` precompile.
87    BN254_DOUBLE = 0x00_00_01_0F,
88
89    /// Executes the `COMMIT` precompile.
90    COMMIT = 0x00_00_00_10,
91
92    /// Executes the `COMMIT_DEFERRED_PROOFS` precompile.
93    COMMIT_DEFERRED_PROOFS = 0x00_00_00_1A,
94
95    /// Executes the `VERIFY_SP1_PROOF` precompile.
96    VERIFY_SP1_PROOF = 0x00_00_00_1B,
97
98    /// Executes the `BLS12381_DECOMPRESS` precompile.
99    BLS12381_DECOMPRESS = 0x00_00_01_1C,
100
101    /// Executes the `HINT_LEN` precompile.
102    HINT_LEN = 0x00_00_00_F0,
103
104    /// Executes the `HINT_READ` precompile.
105    HINT_READ = 0x00_00_00_F1,
106
107    /// Executes the `UINT256_MUL` precompile.
108    UINT256_MUL = 0x00_01_01_1D,
109
110    /// Executes the `U256XU2048_MUL` precompile.
111    U256XU2048_MUL = 0x00_01_01_2F,
112
113    /// Executes the `BLS12381_ADD` precompile.
114    BLS12381_ADD = 0x00_01_01_1E,
115
116    /// Executes the `BLS12381_DOUBLE` precompile.
117    BLS12381_DOUBLE = 0x00_00_01_1F,
118
119    /// Executes the `BLS12381_FP_ADD` precompile.
120    BLS12381_FP_ADD = 0x00_01_01_20,
121
122    /// Executes the `BLS12381_FP_SUB` precompile.
123    BLS12381_FP_SUB = 0x00_01_01_21,
124
125    /// Executes the `BLS12381_FP_MUL` precompile.
126    BLS12381_FP_MUL = 0x00_01_01_22,
127
128    /// Executes the `BLS12381_FP2_ADD` precompile.
129    BLS12381_FP2_ADD = 0x00_01_01_23,
130
131    /// Executes the `BLS12381_FP2_SUB` precompile.
132    BLS12381_FP2_SUB = 0x00_01_01_24,
133
134    /// Executes the `BLS12381_FP2_MUL` precompile.
135    BLS12381_FP2_MUL = 0x00_01_01_25,
136
137    /// Executes the `BN254_FP_ADD` precompile.
138    BN254_FP_ADD = 0x00_01_01_26,
139
140    /// Executes the `BN254_FP_SUB` precompile.
141    BN254_FP_SUB = 0x00_01_01_27,
142
143    /// Executes the `BN254_FP_MUL` precompile.
144    BN254_FP_MUL = 0x00_01_01_28,
145
146    /// Executes the `BN254_FP2_ADD` precompile.
147    BN254_FP2_ADD = 0x00_01_01_29,
148
149    /// Executes the `BN254_FP2_SUB` precompile.
150    BN254_FP2_SUB = 0x00_01_01_2A,
151
152    /// Executes the `BN254_FP2_MUL` precompile.
153    BN254_FP2_MUL = 0x00_01_01_2B,
154
155    /// Executes the `SECP256R1_ADD` precompile.
156    SECP256R1_ADD = 0x00_01_01_2C,
157
158    /// Executes the `SECP256R1_DOUBLE` precompile.
159    SECP256R1_DOUBLE = 0x00_00_01_2D,
160
161    /// Executes the `SECP256R1_DECOMPRESS` precompile.
162    SECP256R1_DECOMPRESS = 0x00_00_01_2E,
163
164    /// Executes the `UINT256_ADD_CARRY` precompile.
165    UINT256_ADD_CARRY = 0x00_01_01_30,
166
167    /// Executes the `UINT256_MUL_CARRY` precompile.
168    UINT256_MUL_CARRY = 0x00_01_01_31,
169
170    /// Executes the `MPROTECT` syscall.
171    #[allow(clippy::mistyped_literal_suffixes)]
172    MPROTECT = 0x00_00_01_32,
173
174    /// Executes the `POSEIDON2` syscall.
175    POSEIDON2 = 0x00_00_01_33,
176}
177
178impl SyscallCode {
179    /// Create a [`SyscallCode`] from a u32.
180    #[must_use]
181    pub fn from_u32(value: u32) -> Self {
182        match value {
183            0x00_00_00_00 => SyscallCode::HALT,
184            0x00_00_00_02 => SyscallCode::WRITE,
185            0x00_00_00_03 => SyscallCode::ENTER_UNCONSTRAINED,
186            0x00_00_00_04 => SyscallCode::EXIT_UNCONSTRAINED,
187            0x00_30_01_05 => SyscallCode::SHA_EXTEND,
188            0x00_01_01_06 => SyscallCode::SHA_COMPRESS,
189            0x00_01_01_07 => SyscallCode::ED_ADD,
190            0x00_00_01_08 => SyscallCode::ED_DECOMPRESS,
191            0x00_01_01_09 => SyscallCode::KECCAK_PERMUTE,
192            0x00_01_01_0A => SyscallCode::SECP256K1_ADD,
193            0x00_00_01_0B => SyscallCode::SECP256K1_DOUBLE,
194            0x00_00_01_0C => SyscallCode::SECP256K1_DECOMPRESS,
195            0x00_01_01_0E => SyscallCode::BN254_ADD,
196            0x00_00_01_0F => SyscallCode::BN254_DOUBLE,
197            0x00_01_01_1E => SyscallCode::BLS12381_ADD,
198            0x00_00_01_1F => SyscallCode::BLS12381_DOUBLE,
199            0x00_00_00_10 => SyscallCode::COMMIT,
200            0x00_00_00_1A => SyscallCode::COMMIT_DEFERRED_PROOFS,
201            0x00_00_00_1B => SyscallCode::VERIFY_SP1_PROOF,
202            0x00_00_00_F0 => SyscallCode::HINT_LEN,
203            0x00_00_00_F1 => SyscallCode::HINT_READ,
204            0x00_01_01_1D => SyscallCode::UINT256_MUL,
205            0x00_01_01_2F => SyscallCode::U256XU2048_MUL,
206            0x00_01_01_20 => SyscallCode::BLS12381_FP_ADD,
207            0x00_01_01_21 => SyscallCode::BLS12381_FP_SUB,
208            0x00_01_01_22 => SyscallCode::BLS12381_FP_MUL,
209            0x00_01_01_23 => SyscallCode::BLS12381_FP2_ADD,
210            0x00_01_01_24 => SyscallCode::BLS12381_FP2_SUB,
211            0x00_01_01_25 => SyscallCode::BLS12381_FP2_MUL,
212            0x00_01_01_26 => SyscallCode::BN254_FP_ADD,
213            0x00_01_01_27 => SyscallCode::BN254_FP_SUB,
214            0x00_01_01_28 => SyscallCode::BN254_FP_MUL,
215            0x00_01_01_29 => SyscallCode::BN254_FP2_ADD,
216            0x00_01_01_2A => SyscallCode::BN254_FP2_SUB,
217            0x00_01_01_2B => SyscallCode::BN254_FP2_MUL,
218            0x00_00_01_1C => SyscallCode::BLS12381_DECOMPRESS,
219            0x00_01_01_2C => SyscallCode::SECP256R1_ADD,
220            0x00_00_01_2D => SyscallCode::SECP256R1_DOUBLE,
221            0x00_00_01_2E => SyscallCode::SECP256R1_DECOMPRESS,
222            0x00_01_01_30 => SyscallCode::UINT256_ADD_CARRY,
223            0x00_01_01_31 => SyscallCode::UINT256_MUL_CARRY,
224            #[allow(clippy::mistyped_literal_suffixes)]
225            0x00_00_01_32 => SyscallCode::MPROTECT,
226            0x00_00_01_33 => SyscallCode::POSEIDON2,
227            _ => panic!("invalid syscall number: {value}"),
228        }
229    }
230
231    /// Get the system call identifier.
232    #[must_use]
233    pub fn syscall_id(self) -> u32 {
234        (self as u32).to_le_bytes()[0].into()
235    }
236
237    /// Get whether the handler of the system call has its own table.
238    #[must_use]
239    pub fn should_send(self) -> u32 {
240        (self as u32).to_le_bytes()[1].into()
241    }
242
243    /// Map a syscall to another one in order to coalesce their counts.
244    #[must_use]
245    #[allow(clippy::match_same_arms)]
246    pub fn count_map(&self) -> Self {
247        match self {
248            SyscallCode::BN254_FP_SUB => SyscallCode::BN254_FP_ADD,
249            SyscallCode::BN254_FP_MUL => SyscallCode::BN254_FP_ADD,
250            SyscallCode::BN254_FP2_SUB => SyscallCode::BN254_FP2_ADD,
251            SyscallCode::BLS12381_FP_SUB => SyscallCode::BLS12381_FP_ADD,
252            SyscallCode::BLS12381_FP_MUL => SyscallCode::BLS12381_FP_ADD,
253            SyscallCode::BLS12381_FP2_SUB => SyscallCode::BLS12381_FP2_ADD,
254            _ => *self,
255        }
256    }
257
258    /// Map a syscall to a field operation.
259    #[must_use]
260    pub fn fp_op_map(&self) -> FieldOperation {
261        match self {
262            SyscallCode::BLS12381_FP_ADD
263            | SyscallCode::BLS12381_FP2_ADD
264            | SyscallCode::BN254_FP_ADD
265            | SyscallCode::BN254_FP2_ADD => FieldOperation::Add,
266            SyscallCode::BLS12381_FP_SUB
267            | SyscallCode::BLS12381_FP2_SUB
268            | SyscallCode::BN254_FP_SUB
269            | SyscallCode::BN254_FP2_SUB => FieldOperation::Sub,
270            SyscallCode::BLS12381_FP_MUL
271            | SyscallCode::BLS12381_FP2_MUL
272            | SyscallCode::BN254_FP_MUL
273            | SyscallCode::BN254_FP2_MUL => FieldOperation::Mul,
274            _ => unreachable!(),
275        }
276    }
277
278    /// Map a syscall to a uint256 operation.
279    #[must_use]
280    pub fn uint256_op_map(&self) -> crate::events::Uint256Operation {
281        match self {
282            SyscallCode::UINT256_ADD_CARRY => crate::events::Uint256Operation::Add,
283            SyscallCode::UINT256_MUL_CARRY => crate::events::Uint256Operation::Mul,
284            _ => unreachable!(),
285        }
286    }
287
288    /// Get the ID of the AIR used in the syscall implementation.
289    #[must_use]
290    pub fn as_air_id(self) -> Option<RiscvAirId> {
291        Some(match self {
292            SyscallCode::SHA_EXTEND => RiscvAirId::ShaExtend,
293            SyscallCode::SHA_COMPRESS => RiscvAirId::ShaCompress,
294            SyscallCode::ED_ADD => RiscvAirId::EdAddAssign,
295            SyscallCode::ED_DECOMPRESS => RiscvAirId::EdDecompress,
296            SyscallCode::KECCAK_PERMUTE => RiscvAirId::KeccakPermute,
297            SyscallCode::SECP256K1_ADD => RiscvAirId::Secp256k1AddAssign,
298            SyscallCode::SECP256K1_DOUBLE => RiscvAirId::Secp256k1DoubleAssign,
299            SyscallCode::SECP256K1_DECOMPRESS => RiscvAirId::Secp256k1Decompress,
300            SyscallCode::BN254_ADD => RiscvAirId::Bn254AddAssign,
301            SyscallCode::BN254_DOUBLE => RiscvAirId::Bn254DoubleAssign,
302            SyscallCode::BLS12381_DECOMPRESS => RiscvAirId::Bls12381Decompress,
303            SyscallCode::UINT256_MUL => RiscvAirId::Uint256MulMod,
304            SyscallCode::U256XU2048_MUL => RiscvAirId::U256XU2048Mul,
305            SyscallCode::BLS12381_ADD => RiscvAirId::Bls12381AddAssign,
306            SyscallCode::BLS12381_DOUBLE => RiscvAirId::Bls12381DoubleAssign,
307            SyscallCode::BLS12381_FP_ADD
308            | SyscallCode::BLS12381_FP_SUB
309            | SyscallCode::BLS12381_FP_MUL => RiscvAirId::Bls12381FpOpAssign,
310            SyscallCode::BLS12381_FP2_ADD | SyscallCode::BLS12381_FP2_SUB => {
311                RiscvAirId::Bls12381Fp2AddSubAssign
312            }
313            SyscallCode::BLS12381_FP2_MUL => RiscvAirId::Bls12381Fp2MulAssign,
314            SyscallCode::BN254_FP_ADD | SyscallCode::BN254_FP_SUB | SyscallCode::BN254_FP_MUL => {
315                RiscvAirId::Bn254FpOpAssign
316            }
317            SyscallCode::BN254_FP2_ADD | SyscallCode::BN254_FP2_SUB => {
318                RiscvAirId::Bn254Fp2AddSubAssign
319            }
320            SyscallCode::BN254_FP2_MUL => RiscvAirId::Bn254Fp2MulAssign,
321            SyscallCode::SECP256R1_ADD => RiscvAirId::Secp256r1AddAssign,
322            SyscallCode::SECP256R1_DOUBLE => RiscvAirId::Secp256r1DoubleAssign,
323            SyscallCode::SECP256R1_DECOMPRESS => RiscvAirId::Secp256r1Decompress,
324            SyscallCode::UINT256_ADD_CARRY | SyscallCode::UINT256_MUL_CARRY => {
325                RiscvAirId::Uint256Ops
326            }
327            SyscallCode::MPROTECT => RiscvAirId::Mprotect,
328            SyscallCode::POSEIDON2 => RiscvAirId::Poseidon2,
329            SyscallCode::HALT
330            | SyscallCode::WRITE
331            | SyscallCode::ENTER_UNCONSTRAINED
332            | SyscallCode::EXIT_UNCONSTRAINED
333            | SyscallCode::COMMIT
334            | SyscallCode::COMMIT_DEFERRED_PROOFS
335            | SyscallCode::VERIFY_SP1_PROOF
336            | SyscallCode::HINT_LEN
337            | SyscallCode::HINT_READ => return None,
338        })
339    }
340
341    /// The maximum number of touched words for each syscall code.
342    #[must_use]
343    #[allow(clippy::match_same_arms)]
344    pub fn touched_addresses(&self) -> usize {
345        // To get this number, either analyze the number of touched memory in the executor of the
346        // syscall, or run a program with the syscall and analyze the ratio of heights of the
347        // `MemoryLocal` table and the corresponding syscall table in the precompile shard.
348        match self {
349            SyscallCode::SHA_EXTEND => 64,
350            SyscallCode::SHA_COMPRESS => 72,
351            SyscallCode::KECCAK_PERMUTE => 25,
352            SyscallCode::BLS12381_ADD
353            | SyscallCode::BLS12381_FP2_ADD
354            | SyscallCode::BLS12381_FP2_SUB
355            | SyscallCode::BLS12381_FP2_MUL => 24,
356            SyscallCode::BLS12381_DECOMPRESS
357            | SyscallCode::BLS12381_DOUBLE
358            | SyscallCode::BLS12381_FP_ADD
359            | SyscallCode::BLS12381_FP_SUB
360            | SyscallCode::BLS12381_FP_MUL => 12,
361            SyscallCode::ED_ADD
362            | SyscallCode::SECP256K1_ADD
363            | SyscallCode::SECP256R1_ADD
364            | SyscallCode::BN254_ADD
365            | SyscallCode::BN254_FP2_ADD
366            | SyscallCode::BN254_FP2_SUB
367            | SyscallCode::BN254_FP2_MUL => 16,
368            SyscallCode::ED_DECOMPRESS
369            | SyscallCode::SECP256K1_DECOMPRESS
370            | SyscallCode::SECP256R1_DECOMPRESS
371            | SyscallCode::SECP256K1_DOUBLE
372            | SyscallCode::SECP256R1_DOUBLE
373            | SyscallCode::BN254_DOUBLE
374            | SyscallCode::BN254_FP_ADD
375            | SyscallCode::BN254_FP_SUB
376            | SyscallCode::BN254_FP_MUL => 8,
377            SyscallCode::UINT256_MUL => 12,
378            SyscallCode::UINT256_ADD_CARRY | SyscallCode::UINT256_MUL_CARRY => 20,
379            SyscallCode::U256XU2048_MUL => 72,
380            SyscallCode::MPROTECT => 0,
381            SyscallCode::POSEIDON2 => 8,
382            _ => 0,
383        }
384    }
385
386    /// The maximum number of touched pages for each syscall code.
387    #[must_use]
388    #[allow(clippy::match_same_arms)]
389    pub fn touched_pages(&self) -> usize {
390        // To get this number, either analyze the number of touched pages in the executor of the
391        // syscall, or check the number of `AddressSlicePageProtOperation` in the corresponding AIR.
392        // This function assumes that each slice touches two pages, which is the maximum.
393        match self {
394            SyscallCode::SHA_EXTEND => 2 * 2,
395            SyscallCode::SHA_COMPRESS => 3 * 2,
396            SyscallCode::KECCAK_PERMUTE => 2 * 2,
397            SyscallCode::BLS12381_ADD
398            | SyscallCode::SECP256K1_ADD
399            | SyscallCode::SECP256R1_ADD
400            | SyscallCode::BN254_ADD
401            | SyscallCode::ED_ADD
402            | SyscallCode::BLS12381_DECOMPRESS
403            | SyscallCode::SECP256K1_DECOMPRESS
404            | SyscallCode::SECP256R1_DECOMPRESS
405            | SyscallCode::ED_DECOMPRESS => 2 * 2,
406
407            SyscallCode::BLS12381_DOUBLE
408            | SyscallCode::SECP256K1_DOUBLE
409            | SyscallCode::SECP256R1_DOUBLE
410            | SyscallCode::BN254_DOUBLE => 2,
411
412            SyscallCode::BLS12381_FP2_ADD
413            | SyscallCode::BLS12381_FP2_SUB
414            | SyscallCode::BLS12381_FP2_MUL
415            | SyscallCode::BLS12381_FP_ADD
416            | SyscallCode::BLS12381_FP_SUB
417            | SyscallCode::BLS12381_FP_MUL
418            | SyscallCode::BN254_FP2_ADD
419            | SyscallCode::BN254_FP2_SUB
420            | SyscallCode::BN254_FP2_MUL
421            | SyscallCode::BN254_FP_ADD
422            | SyscallCode::BN254_FP_SUB
423            | SyscallCode::BN254_FP_MUL => 2 * 2,
424
425            SyscallCode::UINT256_MUL => 2 * 2,
426            SyscallCode::UINT256_ADD_CARRY | SyscallCode::UINT256_MUL_CARRY => 5 * 2,
427            SyscallCode::U256XU2048_MUL => 4 * 2,
428            SyscallCode::MPROTECT => 1,
429            SyscallCode::POSEIDON2 => 2,
430            _ => 0,
431        }
432    }
433}
434
435impl std::fmt::Display for SyscallCode {
436    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437        write!(f, "{self:?}")
438    }
439}