Skip to content

Commit

Permalink
feat: new precompile secp256r1 (#1612)
Browse files Browse the repository at this point in the history
Co-authored-by: John Guibas <[email protected]>
Co-authored-by: Tamir Hemo <[email protected]>
Co-authored-by: Bhargav Annem <[email protected]>
Co-authored-by: Eugene Rabinovich <[email protected]>
Co-authored-by: Shaked Regev <[email protected]>
Co-authored-by: Yuwen Zhang <[email protected]>
Co-authored-by: Matt Stam <[email protected]>
Co-authored-by: shakedregev <[email protected]>
Co-authored-by: Chris T. <[email protected]>
Co-authored-by: mattstam <[email protected]>
Co-authored-by: Kevin Jue <[email protected]>
Co-authored-by: Conner Swann <[email protected]>
Co-authored-by: Jonathan LEI <[email protected]>
Co-authored-by: Tamir Hemo <[email protected]>
Co-authored-by: rkm0959 <[email protected]>
Co-authored-by: Ratan Kaliani <[email protected]>
  • Loading branch information
17 people authored Nov 5, 2024
1 parent 432b4a4 commit e443fc9
Show file tree
Hide file tree
Showing 105 changed files with 9,733 additions and 7,400 deletions.
7,181 changes: 0 additions & 7,181 deletions Cargo.lock

This file was deleted.

6 changes: 5 additions & 1 deletion crates/core/executor/src/events/precompiles/ec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use serde::{Deserialize, Serialize};

use sp1_curves::{
params::{NumLimbs, NumWords},
weierstrass::{bls12_381::bls12381_decompress, secp256k1::secp256k1_decompress},
weierstrass::{
bls12_381::bls12381_decompress, secp256k1::secp256k1_decompress,
secp256r1::secp256r1_decompress,
},
AffinePoint, CurveType, EllipticCurve,
};
use sp1_primitives::consts::{bytes_to_words_le_vec, words_to_bytes_le_vec};
Expand Down Expand Up @@ -204,6 +207,7 @@ pub fn create_ec_decompress_event<E: EllipticCurve>(

let decompress_fn = match E::CURVE_TYPE {
CurveType::Secp256k1 => secp256k1_decompress::<E>,
CurveType::Secp256r1 => secp256r1_decompress::<E>,
CurveType::Bls12381 => bls12381_decompress::<E>,
_ => panic!("Unsupported curve"),
};
Expand Down
9 changes: 9 additions & 0 deletions crates/core/executor/src/events/precompiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ pub enum PrecompileEvent {
Secp256k1Double(EllipticCurveDoubleEvent),
/// Secp256k1 curve decompress precompile event.
Secp256k1Decompress(EllipticCurveDecompressEvent),
/// Secp256r1 curve add precompile event.
Secp256r1Add(EllipticCurveAddEvent),
/// Secp256r1 curve double precompile event.
Secp256r1Double(EllipticCurveDoubleEvent),
/// Secp256r1 curve decompress precompile event.
Secp256r1Decompress(EllipticCurveDecompressEvent),
/// K256 curve decompress precompile event.
K256Decompress(EllipticCurveDecompressEvent),
/// Bn254 curve add precompile event.
Expand Down Expand Up @@ -93,17 +99,20 @@ impl PrecompileLocalMemory for Vec<(SyscallEvent, PrecompileEvent)> {
iterators.push(e.local_mem_access.iter());
}
PrecompileEvent::Secp256k1Add(e)
| PrecompileEvent::Secp256r1Add(e)
| PrecompileEvent::EdAdd(e)
| PrecompileEvent::Bn254Add(e)
| PrecompileEvent::Bls12381Add(e) => {
iterators.push(e.local_mem_access.iter());
}
PrecompileEvent::Secp256k1Double(e)
| PrecompileEvent::Secp256r1Double(e)
| PrecompileEvent::Bn254Double(e)
| PrecompileEvent::Bls12381Double(e) => {
iterators.push(e.local_mem_access.iter());
}
PrecompileEvent::Secp256k1Decompress(e)
| PrecompileEvent::Secp256r1Decompress(e)
| PrecompileEvent::K256Decompress(e)
| PrecompileEvent::Bls12381Decompress(e) => {
iterators.push(e.local_mem_access.iter());
Expand Down
18 changes: 16 additions & 2 deletions crates/core/executor/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1669,8 +1669,8 @@ mod tests {
use sp1_stark::SP1CoreOpts;

use crate::programs::tests::{
fibonacci_program, panic_program, simple_memory_program, simple_program,
ssz_withdrawals_program,
fibonacci_program, panic_program, secp256r1_add_program, secp256r1_double_program,
simple_memory_program, simple_program, ssz_withdrawals_program,
};

use crate::Register;
Expand Down Expand Up @@ -1699,6 +1699,20 @@ mod tests {
runtime.run().unwrap();
}

#[test]
fn test_secp256r1_add_program_run() {
let program = secp256r1_add_program();
let mut runtime = Executor::new(program, SP1CoreOpts::default());
runtime.run().unwrap();
}

#[test]
fn test_secp256r1_double_program_run() {
let program = secp256r1_double_program();
let mut runtime = Executor::new(program, SP1CoreOpts::default());
runtime.run().unwrap();
}

#[test]
fn test_ssz_withdrawals_program_run() {
let program = ssz_withdrawals_program();
Expand Down
36 changes: 31 additions & 5 deletions crates/core/executor/src/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ use std::sync::{Arc, RwLock, RwLockWriteGuard};

use hashbrown::HashMap;
use sp1_curves::k256::{Invert, RecoveryId, Signature, VerifyingKey};
use sp1_curves::p256::Signature as p256Signature;

use crate::Executor;

/// A runtime hook, wrapped in a smart pointer.
pub type BoxedHook<'a> = Arc<RwLock<dyn Hook + Send + Sync + 'a>>;

/// The file descriptor through which to access `hook_ecrecover`.
pub const FD_ECRECOVER_HOOK: u32 = 5;
/// The file descriptor through which to access `hook_k1_ecrecover`.
pub const K1_ECRECOVER_HOOK: u32 = 5;
/// The file descriptor through which to access `hook_r1_ecrecover`.
pub const R1_ECRECOVER_HOOK: u32 = 6;

/// A runtime hook. May be called during execution by writing to a specified file descriptor,
/// accepting and returning arbitrary data.
Expand Down Expand Up @@ -75,7 +78,8 @@ impl<'a> Default for HookRegistry<'a> {
let table = HashMap::from([
// Note: To ensure any `fd` value is synced with `zkvm/precompiles/src/io.rs`,
// add an assertion to the test `hook_fds_match` below.
(FD_ECRECOVER_HOOK, hookify(hook_ecrecover)),
(K1_ECRECOVER_HOOK, hookify(hook_k1_ecrecover)),
(R1_ECRECOVER_HOOK, hookify(hook_r1_ecrecover)),
]);

Self { table }
Expand Down Expand Up @@ -117,7 +121,7 @@ pub struct HookEnv<'a, 'b: 'a> {
/// WARNING: This function is used to recover the public key outside of the zkVM context. These
/// values must be constrained by the zkVM for correctness.
#[must_use]
pub fn hook_ecrecover(_: HookEnv, buf: &[u8]) -> Vec<Vec<u8>> {
pub fn hook_k1_ecrecover(_: HookEnv, buf: &[u8]) -> Vec<Vec<u8>> {
assert_eq!(buf.len(), 65 + 32, "ecrecover input should have length 65 + 32");
let (sig, msg_hash) = buf.split_at(65);
let sig: &[u8; 65] = sig.try_into().unwrap();
Expand All @@ -141,14 +145,36 @@ pub fn hook_ecrecover(_: HookEnv, buf: &[u8]) -> Vec<Vec<u8>> {
vec![bytes.to_vec(), s_inverse.to_bytes().to_vec()]
}

/// Recovers s inverse from the signature using the secp256r1 crate.
///
/// # Arguments
///
/// * `env` - The environment in which the hook is invoked.
/// * `buf` - The buffer containing the signature.
/// - The signature is 64 bytes.
///
/// The result is a single 32 byte vector containing s inverse.
#[must_use]
pub fn hook_r1_ecrecover(_: HookEnv, buf: &[u8]) -> Vec<Vec<u8>> {
assert_eq!(buf.len(), 64, "ecrecover input should have length 64");
let sig: &[u8; 64] = buf.try_into().unwrap();
let sig = p256Signature::from_slice(sig).unwrap();

let (_, s) = sig.split_scalars();
let s_inverse = s.invert();

vec![s_inverse.to_bytes().to_vec()]
}

#[cfg(test)]
pub mod tests {
use super::*;

#[test]
pub fn hook_fds_match() {
use sp1_zkvm::lib::io;
assert_eq!(FD_ECRECOVER_HOOK, io::FD_ECRECOVER_HOOK);
assert_eq!(K1_ECRECOVER_HOOK, io::K1_ECRECOVER_HOOK);
assert_eq!(R1_ECRECOVER_HOOK, io::R1_ECRECOVER_HOOK);
}

#[test]
Expand Down
26 changes: 26 additions & 0 deletions crates/core/executor/src/programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ pub mod tests {
pub const SECP256K1_DOUBLE_ELF: &[u8] =
include_bytes!("../../../../tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf");

pub const SECP256R1_ADD_ELF: &[u8] =
include_bytes!("../../../../tests/secp256r1-add/elf/riscv32im-succinct-zkvm-elf");

pub const SECP256R1_DOUBLE_ELF: &[u8] =
include_bytes!("../../../../tests/secp256r1-double/elf/riscv32im-succinct-zkvm-elf");

pub const SHA_COMPRESS_ELF: &[u8] =
include_bytes!("../../../../tests/sha-compress/elf/riscv32im-succinct-zkvm-elf");

Expand Down Expand Up @@ -140,6 +146,26 @@ pub mod tests {
Program::from(FIBONACCI_ELF).unwrap()
}

/// Get the secp256r1 add program.
///
/// # Panics
///
/// This function will panic if the program fails to load.
#[must_use]
pub fn secp256r1_add_program() -> Program {
Program::from(SECP256R1_ADD_ELF).unwrap()
}

/// Get the secp256r1 double program.
///
/// # Panics
///
/// This function will panic if the program fails to load.
#[must_use]
pub fn secp256r1_double_program() -> Program {
Program::from(SECP256R1_DOUBLE_ELF).unwrap()
}

/// Get the SSZ withdrawals program.
///
/// # Panics
Expand Down
12 changes: 12 additions & 0 deletions crates/core/executor/src/syscalls/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ pub enum SyscallCode {

/// Executes the `BN254_FP2_MUL` precompile.
BN254_FP2_MUL = 0x00_01_01_2B,

/// Executes the `SECP256R1_ADD` precompile.
SECP256R1_ADD = 0x00_01_01_2C,

/// Executes the `SECP256R1_DOUBLE` precompile.
SECP256R1_DOUBLE = 0x00_00_01_2D,

/// Executes the `SECP256R1_DECOMPRESS` precompile.
SECP256R1_DECOMPRESS = 0x00_00_01_2E,
}

impl SyscallCode {
Expand Down Expand Up @@ -170,6 +179,9 @@ impl SyscallCode {
0x00_01_01_2A => SyscallCode::BN254_FP2_SUB,
0x00_01_01_2B => SyscallCode::BN254_FP2_MUL,
0x00_00_01_1C => SyscallCode::BLS12381_DECOMPRESS,
0x00_01_01_2C => SyscallCode::SECP256R1_ADD,
0x00_00_01_2D => SyscallCode::SECP256R1_DOUBLE,
0x00_00_01_2E => SyscallCode::SECP256R1_DECOMPRESS,
_ => panic!("invalid syscall number: {value}"),
}
}
Expand Down
16 changes: 16 additions & 0 deletions crates/core/executor/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use sp1_curves::{
bls12_381::{Bls12381, Bls12381BaseField},
bn254::{Bn254, Bn254BaseField},
secp256k1::Secp256k1,
secp256r1::Secp256r1,
},
};
use unconstrained::{EnterUnconstrainedSyscall, ExitUnconstrainedSyscall};
Expand Down Expand Up @@ -109,6 +110,21 @@ pub fn default_syscall_map() -> HashMap<SyscallCode, Arc<dyn Syscall>> {
Arc::new(WeierstrassDecompressSyscall::<Secp256k1>::new()),
);

syscall_map.insert(
SyscallCode::SECP256R1_ADD,
Arc::new(WeierstrassAddAssignSyscall::<Secp256r1>::new()),
);

syscall_map.insert(
SyscallCode::SECP256R1_DOUBLE,
Arc::new(WeierstrassDoubleAssignSyscall::<Secp256r1>::new()),
);

syscall_map.insert(
SyscallCode::SECP256R1_DECOMPRESS,
Arc::new(WeierstrassDecompressSyscall::<Secp256r1>::new()),
);

syscall_map
.insert(SyscallCode::BN254_ADD, Arc::new(WeierstrassAddAssignSyscall::<Bn254>::new()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ impl<E: EllipticCurve> Syscall for WeierstrassAddAssignSyscall<E> {
syscall_event,
PrecompileEvent::Bls12381Add(event),
),
CurveType::Secp256r1 => rt.record_mut().add_precompile_event(
syscall_code,
syscall_event,
PrecompileEvent::Secp256r1Add(event),
),
_ => panic!("Unsupported curve"),
}
None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ impl<E: EllipticCurve> Syscall for WeierstrassDecompressSyscall<E> {
syscall_event,
PrecompileEvent::Secp256k1Decompress(event),
),
CurveType::Bls12381 => rt.add_precompile_event(
CurveType::Secp256r1 => rt.record_mut().add_precompile_event(
syscall_code,
syscall_event,
PrecompileEvent::Secp256r1Decompress(event),
),
CurveType::Bls12381 => rt.record_mut().add_precompile_event(
syscall_code,
syscall_event,
PrecompileEvent::Bls12381Decompress(event),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ impl<E: EllipticCurve> Syscall for WeierstrassDoubleAssignSyscall<E> {
PrecompileEvent::Secp256k1Double(event),
);
}
CurveType::Secp256r1 => rt.record_mut().add_precompile_event(
syscall_code,
syscall_event,
PrecompileEvent::Secp256r1Double(event),
),
CurveType::Bn254 => {
rt.add_precompile_event(
syscall_code,
Expand Down
2 changes: 2 additions & 0 deletions crates/core/machine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ typenum = "1.17.0"
elliptic-curve = "0.13.8"
hex = "0.4.3"
k256 = { version = "0.13.3", features = ["expose-field"] }
p256 = { version = "0.13.2", features = ["expose-field"] }

num_cpus = "1.16.0"
size = "0.4.1"
tempfile = "3.10.1"
Expand Down
15 changes: 9 additions & 6 deletions crates/core/machine/src/operations/field/field_den.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::fmt::Debug;

use num::BigUint;
use p3_air::AirBuilder;
use p3_field::PrimeField32;
use sp1_core_executor::events::ByteRecord;
use sp1_curves::params::{FieldParameters, Limbs};
Expand Down Expand Up @@ -106,10 +107,10 @@ where
) where
V: Into<AB::Expr>,
{
let p_a = Polynomial::from(*a);
let p_b = (*b).into();
let p_result = self.result.into();
let p_carry = self.carry.into();
let p_a: Polynomial<<AB as AirBuilder>::Expr> = (*a).into();
let p_b: Polynomial<<AB as AirBuilder>::Expr> = (*b).into();
let p_result: Polynomial<<AB as AirBuilder>::Expr> = self.result.into();
let p_carry: Polynomial<<AB as AirBuilder>::Expr> = self.carry.into();

// Compute the vanishing polynomial:
// lhs(x) = sign * (b(x) * result(x) + result(x)) + (1 - sign) * (b(x) * result(x) +
Expand All @@ -120,9 +121,11 @@ where
let p_equation_rhs = if sign { p_a } else { p_result };

let p_lhs_minus_rhs = &p_equation_lhs - &p_equation_rhs;
let p_limbs = Polynomial::from_iter(P::modulus_field_iter::<AB::F>().map(AB::Expr::from));
let p_limbs: Polynomial<<AB as AirBuilder>::Expr> =
Polynomial::from_iter(P::modulus_field_iter::<AB::F>().map(AB::Expr::from));

let p_vanishing = p_lhs_minus_rhs - &p_carry * &p_limbs;
let p_vanishing: Polynomial<<AB as AirBuilder>::Expr> =
p_lhs_minus_rhs - &p_carry * &p_limbs;

let p_witness_low = self.witness_low.0.iter().into();
let p_witness_high = self.witness_high.0.iter().into();
Expand Down
13 changes: 7 additions & 6 deletions crates/core/machine/src/operations/field/field_inner_product.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::fmt::Debug;

use num::{BigUint, Zero};
use p3_air::AirBuilder;
use p3_field::{AbstractField, PrimeField32};
use sp1_core_executor::events::ByteRecord;
use sp1_curves::params::{FieldParameters, Limbs};
Expand Down Expand Up @@ -93,16 +94,16 @@ where
pub fn eval<AB: SP1AirBuilder<Var = V>>(
&self,
builder: &mut AB,
a: &[Limbs<AB::Var, P::Limbs>],
b: &[Limbs<AB::Var, P::Limbs>],
a: &[impl Into<Polynomial<AB::Expr>> + Clone],
b: &[impl Into<Polynomial<AB::Expr>> + Clone],
is_real: impl Into<AB::Expr> + Clone,
) where
V: Into<AB::Expr>,
{
let p_a_vec: Vec<Polynomial<AB::Expr>> = a.iter().map(|x| (*x).into()).collect();
let p_b_vec: Vec<Polynomial<AB::Expr>> = b.iter().map(|x| (*x).into()).collect();
let p_result = self.result.into();
let p_carry = self.carry.into();
let p_a_vec: Vec<Polynomial<AB::Expr>> = a.iter().cloned().map(|x| x.into()).collect();
let p_b_vec: Vec<Polynomial<AB::Expr>> = b.iter().cloned().map(|x| x.into()).collect();
let p_result: Polynomial<<AB as AirBuilder>::Expr> = self.result.into();
let p_carry: Polynomial<<AB as AirBuilder>::Expr> = self.carry.into();

let p_zero = Polynomial::<AB::Expr>::new(vec![AB::Expr::zero()]);

Expand Down
Loading

0 comments on commit e443fc9

Please sign in to comment.