This crate wraps the syscall and precompile intrinsics for the SP1 zkVM.
To add a new syscall or precompile, follow these steps to implement it in sp1
:
-
Update
SyscallCode
Enum:- Add a new entry to the
SyscallCode
enum. - Update
SyscallCode::from_u32
andtest_syscall_consistency_zkvm
incore/src/runtime/syscall.rs
.
- Add a new entry to the
-
Add ffi interface:
- Add the new function name with
syscall_
prefix inzkvm/entrypoint/src/syscalls
. - Mark the function as
#[no_mangle]
- Add the new function name with
-
Implement the Syscall Chip:
- Add your syscall chip in
sp1/src/syscall/mod.rs
. - Implement the
Syscall
trait for your syscall chip.
- Add your syscall chip in
-
Add to Default Syscall Map:
- Include the new chip in the
default_syscall_map
incore/src/runtime/syscall.rs
.
- Include the new chip in the
-
Verify the Syscall:
- Add the corresponding
Cols
struct. - Implement
MachineAir<F>
,BaseAir<F>
, andAir<AB>
for the syscall chip.
- Add the corresponding
-
Update
RiscvAir
:- Add the chip type as a new variant of
RiscvAir
. - Update
RiscvAir::get_all
incore/src/stark/air.rs
.
- Add the chip type as a new variant of
After implementing the syscall in sp1
, you can add the wrapper in this crate.
Almost all syscalls involve raw pointer dereferencing and casting.
Therefore, the wrapper function SHOULD be marked as unsafe
unless the safety is guaranteed by the function signature
(e.g., no raw pointers in the signature, and the syscall does not violate safety).
- If marking the function as safe, explain and prove in the comments why it does not need to be marked as
unsafe
. - If the function is marked as
unsafe
, write a detailed safety section in the comments, listing all assumptions and invariants.
/// `BN254_SCALAR_MUL` syscall implements as `*a = *a * b`,
/// where `a` and `b` are `Fr` elements.
/// The signature ensures write access to `a` and read access to `b`.
/// Also the values of `a` and `b` are `Fr` valid.
fn bn256_scalar_mul(a: &mut Fr, b: &Fr) {
syscall!(SYSCALL_ID_BN254_SCALAR_MUL, a, b)
}