use crate::SyscallCode;
use super::{
hint::{hint_len, hint_read},
precompiles::{
edwards::{edwards_add, edwards_decompress_syscall},
fptower::{fp2_addsub_syscall, fp2_mul_syscall, fp_op_syscall},
keccak::keccak_permute,
poseidon2::poseidon2,
sha256::{sha256_compress, sha256_extend},
uint256::uint256_mul,
uint256_ops::uint256_ops,
uint256x2048::u256x2048_mul,
weierstrass::{
weierstrass_add_assign_syscall, weierstrass_decompress_syscall,
weierstrass_double_assign_syscall,
},
},
write::write,
};
use sp1_curves::{
edwards::ed25519::Ed25519,
weierstrass::{
bls12_381::{Bls12381, Bls12381BaseField},
bn254::{Bn254, Bn254BaseField},
secp256k1::Secp256k1,
secp256r1::Secp256r1,
},
};
use sp1_jit::{RiscRegister, SyscallContext};
#[cfg(all(
target_arch = "x86_64",
target_endian = "little",
any(not(feature = "profiling"), test)
))]
pub(super) extern "C" fn sp1_ecall_handler(ctx: *mut sp1_jit::JitContext) -> u64 {
let ctx = unsafe { &mut *ctx };
let code = SyscallCode::from_u32(ctx.rr(RiscRegister::X5) as u32);
let (pc, clk) = (ctx.pc, ctx.clk);
let result = ecall_handler(ctx, code);
match code {
SyscallCode::EXIT_UNCONSTRAINED => {
ctx.pc = ctx.pc.wrapping_add(4);
ctx.clk = ctx.clk.wrapping_add(256);
}
SyscallCode::HALT => {
ctx.pc = 1;
ctx.clk = clk.wrapping_add(256);
}
_ => {
ctx.pc = pc.wrapping_add(4);
ctx.clk = clk.wrapping_add(256);
}
}
result
}
pub fn ecall_handler(ctx: &mut impl SyscallContext, code: SyscallCode) -> u64 {
let arg1 = ctx.rr(RiscRegister::X10);
let arg2 = ctx.rr(RiscRegister::X11);
if ctx.is_unconstrained()
&& (code != SyscallCode::WRITE && code != SyscallCode::EXIT_UNCONSTRAINED)
{
panic!("Unconstrained mode is not allowed for this syscall: {code:?}");
}
match code {
SyscallCode::SHA_EXTEND => unsafe { sha256_extend(ctx, arg1, arg2) },
SyscallCode::SHA_COMPRESS => unsafe { sha256_compress(ctx, arg1, arg2) },
SyscallCode::KECCAK_PERMUTE => unsafe { keccak_permute(ctx, arg1, arg2) },
SyscallCode::SECP256K1_ADD => unsafe {
weierstrass_add_assign_syscall::<Secp256k1>(ctx, arg1, arg2)
},
SyscallCode::SECP256K1_DOUBLE => unsafe {
weierstrass_double_assign_syscall::<Secp256k1>(ctx, arg1, arg2)
},
SyscallCode::SECP256K1_DECOMPRESS => {
weierstrass_decompress_syscall::<Secp256k1>(ctx, arg1, arg2)
}
SyscallCode::SECP256R1_ADD => unsafe {
weierstrass_add_assign_syscall::<Secp256r1>(ctx, arg1, arg2)
},
SyscallCode::SECP256R1_DOUBLE => unsafe {
weierstrass_double_assign_syscall::<Secp256r1>(ctx, arg1, arg2)
},
SyscallCode::SECP256R1_DECOMPRESS => {
weierstrass_decompress_syscall::<Secp256r1>(ctx, arg1, arg2)
}
SyscallCode::BLS12381_ADD => unsafe {
weierstrass_add_assign_syscall::<Bls12381>(ctx, arg1, arg2)
},
SyscallCode::BLS12381_DOUBLE => unsafe {
weierstrass_double_assign_syscall::<Bls12381>(ctx, arg1, arg2)
},
SyscallCode::BLS12381_DECOMPRESS => {
weierstrass_decompress_syscall::<Bls12381>(ctx, arg1, arg2)
}
SyscallCode::BN254_ADD => unsafe {
weierstrass_add_assign_syscall::<Bn254>(ctx, arg1, arg2)
},
SyscallCode::BN254_DOUBLE => unsafe {
weierstrass_double_assign_syscall::<Bn254>(ctx, arg1, arg2)
},
SyscallCode::ED_ADD => unsafe { edwards_add::<Ed25519>(ctx, arg1, arg2) },
SyscallCode::ED_DECOMPRESS => unsafe { edwards_decompress_syscall(ctx, arg1, arg2) },
SyscallCode::BLS12381_FP_ADD
| SyscallCode::BLS12381_FP_SUB
| SyscallCode::BLS12381_FP_MUL => unsafe {
fp_op_syscall::<Bls12381BaseField>(ctx, arg1, arg2, code.fp_op_map())
},
SyscallCode::BLS12381_FP2_ADD | SyscallCode::BLS12381_FP2_SUB => unsafe {
fp2_addsub_syscall::<Bls12381BaseField>(ctx, arg1, arg2, code.fp_op_map())
},
SyscallCode::BLS12381_FP2_MUL => unsafe {
fp2_mul_syscall::<Bls12381BaseField>(ctx, arg1, arg2)
},
SyscallCode::BN254_FP_ADD | SyscallCode::BN254_FP_SUB | SyscallCode::BN254_FP_MUL => unsafe {
fp_op_syscall::<Bn254BaseField>(ctx, arg1, arg2, code.fp_op_map())
},
SyscallCode::BN254_FP2_ADD | SyscallCode::BN254_FP2_SUB => unsafe {
fp2_addsub_syscall::<Bn254BaseField>(ctx, arg1, arg2, code.fp_op_map())
},
SyscallCode::BN254_FP2_MUL => unsafe { fp2_mul_syscall::<Bn254BaseField>(ctx, arg1, arg2) },
SyscallCode::UINT256_MUL => unsafe { uint256_mul(ctx, arg1, arg2) },
SyscallCode::U256XU2048_MUL => unsafe { u256x2048_mul(ctx, arg1, arg2) },
SyscallCode::ENTER_UNCONSTRAINED => {
ctx.enter_unconstrained().expect("Failed to enter unconstrained mode");
Some(1)
}
SyscallCode::EXIT_UNCONSTRAINED => {
ctx.exit_unconstrained();
Some(0)
}
SyscallCode::HINT_LEN => unsafe { hint_len(ctx, arg1, arg2) },
SyscallCode::HINT_READ => unsafe { hint_read(ctx, arg1, arg2) },
SyscallCode::WRITE => unsafe { write(ctx, arg1, arg2) },
SyscallCode::UINT256_MUL_CARRY | SyscallCode::UINT256_ADD_CARRY => unsafe {
uint256_ops(ctx, arg1, arg2)
},
SyscallCode::POSEIDON2 => unsafe { poseidon2(ctx, arg1, arg2) },
SyscallCode::HALT => {
ctx.set_exit_code(arg1 as u32);
None
}
SyscallCode::MPROTECT
| SyscallCode::VERIFY_SP1_PROOF
| SyscallCode::COMMIT
| SyscallCode::COMMIT_DEFERRED_PROOFS => None,
}.unwrap_or(code as u64)
}