From 5d3d591a5f94956d1f304e773d62d206ee23dd91 Mon Sep 17 00:00:00 2001 From: kaylee Date: Wed, 15 May 2024 11:43:13 +0000 Subject: [PATCH 1/3] everything --- Cargo.lock | 45 + core/Cargo.toml | 1 + core/src/operations/field/field_den.rs | 14 +- .../operations/field/field_inner_product.rs | 10 +- core/src/operations/field/field_op.rs | 26 +- core/src/operations/field/util_air.rs | 7 +- core/src/runtime/record.rs | 16 + core/src/runtime/syscall.rs | 24 +- core/src/stark/air.rs | 10 + .../weierstrass/weierstrass_add.rs | 24 +- .../weierstrass/weierstrass_double.rs | 18 +- core/src/utils/ec/mod.rs | 2 + core/src/utils/ec/weierstrass/mod.rs | 1 + core/src/utils/ec/weierstrass/secp384r1.rs | 144 ++++ core/src/utils/programs.rs | 9 + tests/secp384r1-add/Cargo.lock | 812 +++++++++++++++++ tests/secp384r1-add/Cargo.toml | 10 + .../elf/riscv32im-succinct-zkvm-elf | Bin 0 -> 117908 bytes tests/secp384r1-add/src/main.rs | 49 ++ tests/secp384r1-double/Cargo.lock | 812 +++++++++++++++++ tests/secp384r1-double/Cargo.toml | 10 + .../elf/riscv32im-succinct-zkvm-elf | Bin 0 -> 117296 bytes tests/secp384r1-double/src/main.rs | 41 + tests/secp384r1-mul/Cargo.lock | 814 ++++++++++++++++++ tests/secp384r1-mul/Cargo.toml | 9 + .../elf/riscv32im-succinct-zkvm-elf | Bin 0 -> 121680 bytes tests/secp384r1-mul/src/main.rs | 44 + zkvm/entrypoint/Cargo.toml | 1 + zkvm/entrypoint/src/syscalls/mod.rs | 8 + zkvm/entrypoint/src/syscalls/secp384r1.rs | 42 + zkvm/precompiles/Cargo.toml | 1 + zkvm/precompiles/src/lib.rs | 3 + zkvm/precompiles/src/secp384r1.rs | 190 ++++ 33 files changed, 3177 insertions(+), 20 deletions(-) create mode 100644 core/src/utils/ec/weierstrass/secp384r1.rs create mode 100644 tests/secp384r1-add/Cargo.lock create mode 100644 tests/secp384r1-add/Cargo.toml create mode 100755 tests/secp384r1-add/elf/riscv32im-succinct-zkvm-elf create mode 100644 tests/secp384r1-add/src/main.rs create mode 100644 tests/secp384r1-double/Cargo.lock create mode 100644 tests/secp384r1-double/Cargo.toml create mode 100755 tests/secp384r1-double/elf/riscv32im-succinct-zkvm-elf create mode 100644 tests/secp384r1-double/src/main.rs create mode 100644 tests/secp384r1-mul/Cargo.lock create mode 100644 tests/secp384r1-mul/Cargo.toml create mode 100755 tests/secp384r1-mul/elf/riscv32im-succinct-zkvm-elf create mode 100644 tests/secp384r1-mul/src/main.rs create mode 100644 zkvm/entrypoint/src/syscalls/secp384r1.rs create mode 100644 zkvm/precompiles/src/secp384r1.rs diff --git a/Cargo.lock b/Cargo.lock index de99543221..29ec1b028b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1422,6 +1422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -1603,6 +1604,8 @@ dependencies = [ "ff 0.13.0", "generic-array 0.14.7", "group 0.13.0", + "hkdf", + "pem-rfc7468", "pkcs8", "rand_core", "sec1", @@ -2076,6 +2079,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -3115,6 +3127,18 @@ dependencies = [ "serde", ] +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "pairing" version = "0.22.0" @@ -3209,6 +3233,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -3326,6 +3359,15 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -4343,6 +4385,7 @@ dependencies = [ "p3-symmetric", "p3-uni-stark", "p3-util", + "p384", "rand", "rayon-scan", "rrs-lib", @@ -4404,6 +4447,7 @@ dependencies = [ "hex", "k256", "num", + "p384", "rand", "serde", "snowbridge-amcl", @@ -4652,6 +4696,7 @@ dependencies = [ "once_cell", "p3-baby-bear", "p3-field", + "p384", "rand", "serde", "sha2", diff --git a/core/Cargo.toml b/core/Cargo.toml index e477ec2639..1b44380fa4 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -46,6 +46,7 @@ curve25519-dalek = { version = "4.1.2" } elliptic-curve = "0.13.8" hex = "0.4.3" k256 = { version = "0.13.3", features = ["expose-field"] } +p384 = { version = "0.13.0", features = ["expose-field"] } num_cpus = "1.16.0" serde_with = "3.8.1" size = "0.4.1" diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index eab87631ca..26d1e1b1bc 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -113,9 +113,11 @@ where V: Into, { let p_a = Polynomial::from(*a); - let p_b = (*b).into(); + // let p_b = (*b).into(); + let p_b = Polynomial::from(*b); let p_result = self.result.into(); - let p_carry = self.carry.into(); + // let p_carry = self.carry.into(); + let p_carry = Polynomial::from(self.carry); // Compute the vanishing polynomial: // lhs(x) = sign * (b(x) * result(x) + result(x)) + (1 - sign) * (b(x) * result(x) + a(x)) @@ -136,7 +138,13 @@ where let p_witness_low = self.witness_low.0.iter().into(); let p_witness_high = self.witness_high.0.iter().into(); - eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); + eval_field_operation::( + builder, + &p_vanishing, + &p_witness_low, + &p_witness_high, + is_real.clone(), + ); // Range checks for the result, carry, and witness columns. builder.slice_range_check_u8(&self.result.0, shard.clone(), is_real.clone()); diff --git a/core/src/operations/field/field_inner_product.rs b/core/src/operations/field/field_inner_product.rs index 070b174bd1..efe3b3a416 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/core/src/operations/field/field_inner_product.rs @@ -116,7 +116,7 @@ where let p_a_vec: Vec> = a.iter().map(|x| (*x).into()).collect(); let p_b_vec: Vec> = b.iter().map(|x| (*x).into()).collect(); let p_result = self.result.into(); - let p_carry = self.carry.into(); + let p_carry: Polynomial = self.carry.into(); let p_zero = Polynomial::::new(vec![AB::Expr::zero()]); @@ -135,7 +135,13 @@ where let p_witness_low = self.witness_low.0.iter().into(); let p_witness_high = self.witness_high.0.iter().into(); - eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); + eval_field_operation::( + builder, + &p_vanishing, + &p_witness_low, + &p_witness_high, + is_real.clone(), + ); // Range checks for the result, carry, and witness columns. builder.slice_range_check_u8(&self.result.0, shard.clone(), is_real.clone()); diff --git a/core/src/operations/field/field_op.rs b/core/src/operations/field/field_op.rs index 9c8943d0ce..6087103926 100644 --- a/core/src/operations/field/field_op.rs +++ b/core/src/operations/field/field_op.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; -use num::{BigUint, Zero}; +use num::BigUint; use p3_air::AirBuilder; use p3_field::PrimeField32; use sp1_derive::AlignedBorrow; @@ -117,14 +117,14 @@ impl FieldOpCols { modulus: &BigUint, op: FieldOperation, ) -> BigUint { - if b == &BigUint::zero() && op == FieldOperation::Div { - // Division by 0 is allowed only when dividing 0 so that padded rows can be all 0. - assert_eq!( - *a, - BigUint::zero(), - "division by zero is allowed only when dividing zero" - ); - } + // if b == &BigUint::zero() && op == FieldOperation::Div { + // // Division by 0 is allowed only when dividing 0 so that padded rows can be all 0. + // assert_eq!( + // *a, + // BigUint::zero(), + // "division by zero is allowed only when dividing zero" + // ); + // } let result = match op { // If doing the subtraction operation, a - b = result, equivalent to a = result + b. @@ -212,7 +212,13 @@ impl FieldOpCols { let p_vanishing = p_op_minus_result - &(&p_carry * &p_modulus); let p_witness_low = self.witness_low.0.iter().into(); let p_witness_high = self.witness_high.0.iter().into(); - eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); + eval_field_operation::( + builder, + &p_vanishing, + &p_witness_low, + &p_witness_high, + is_real.clone(), + ); // Range checks for the result, carry, and witness columns. builder.slice_range_check_u8(&self.result.0, shard.clone(), is_real.clone()); diff --git a/core/src/operations/field/util_air.rs b/core/src/operations/field/util_air.rs index 54ae64216d..c8c552084c 100644 --- a/core/src/operations/field/util_air.rs +++ b/core/src/operations/field/util_air.rs @@ -2,13 +2,16 @@ use p3_field::AbstractField; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::operations::field::params::FieldParameters; +use p3_air::AirBuilder; + +use super::params::FieldParameters; pub fn eval_field_operation( builder: &mut AB, p_vanishing: &Polynomial, p_witness_low: &Polynomial, p_witness_high: &Polynomial, + is_real: impl Into + Clone, ) { // Reconstruct and shift back the witness polynomial let limb: AB::Expr = AB::F::from_canonical_u32(2u32.pow(P::NB_BITS_PER_LIMB as u32)).into(); @@ -26,6 +29,6 @@ pub fn eval_field_operation( let constraints = p_vanishing - &(p_witness * root_monomial); for constr in constraints.as_coefficients() { - builder.assert_zero(constr); + builder.when(is_real.clone()).assert_zero(constr); } } diff --git a/core/src/runtime/record.rs b/core/src/runtime/record.rs index 83210fcb22..caf7ee3e38 100644 --- a/core/src/runtime/record.rs +++ b/core/src/runtime/record.rs @@ -81,6 +81,10 @@ pub struct ExecutionRecord { pub secp256k1_double_events: Vec, + pub secp384r1_add_events: Vec, + + pub secp384r1_double_events: Vec, + pub bn254_add_events: Vec, pub bn254_double_events: Vec, @@ -119,6 +123,8 @@ pub struct ShardingConfig { pub keccak_len: usize, pub secp256k1_add_len: usize, pub secp256k1_double_len: usize, + pub secp384r1_add_len: usize, + pub secp384r1_double_len: usize, pub bn254_add_len: usize, pub bn254_double_len: usize, pub bls12381_add_len: usize, @@ -149,6 +155,8 @@ impl Default for ShardingConfig { keccak_len: shard_size, secp256k1_add_len: shard_size, secp256k1_double_len: shard_size, + secp384r1_add_len: shard_size, + secp384r1_double_len: shard_size, bn254_add_len: shard_size, bn254_double_len: shard_size, bls12381_add_len: shard_size, @@ -211,6 +219,14 @@ impl MachineRecord for ExecutionRecord { "secp256k1_double_events".to_string(), self.secp256k1_double_events.len(), ); + stats.insert( + "secp384r1_add_events".to_string(), + self.secp384r1_add_events.len(), + ); + stats.insert( + "secp384r1_double_events".to_string(), + self.secp384r1_double_events.len(), + ); stats.insert("bn254_add_events".to_string(), self.bn254_add_events.len()); stats.insert( "bn254_double_events".to_string(), diff --git a/core/src/runtime/syscall.rs b/core/src/runtime/syscall.rs index 4e6304b429..ad9226f525 100644 --- a/core/src/runtime/syscall.rs +++ b/core/src/runtime/syscall.rs @@ -19,7 +19,7 @@ use crate::syscall::{ }; use crate::utils::ec::edwards::ed25519::{Ed25519, Ed25519Parameters}; use crate::utils::ec::weierstrass::bls12_381::Bls12381; -use crate::utils::ec::weierstrass::{bn254::Bn254, secp256k1::Secp256k1}; +use crate::utils::ec::weierstrass::{bn254::Bn254, secp256k1::Secp256k1, secp384r1::Secp384r1}; use crate::{runtime::ExecutionRecord, runtime::MemoryReadRecord, runtime::MemoryWriteRecord}; /// A system call is invoked by the the `ecall` instruction with a specific value in register t0. @@ -102,6 +102,12 @@ pub enum SyscallCode { /// Executes the `BLS12381_DOUBLE` precompile. BLS12381_DOUBLE = 0x00_00_01_1F, + + /// Executes the `SECP256K1_ADD` precompile. + SECP384R1_ADD = 0x00_01_01_16, + + /// Executes the `SECP256K1_DOUBLE` precompile. + SECP384R1_DOUBLE = 0x00_00_01_17, } impl SyscallCode { @@ -132,6 +138,8 @@ impl SyscallCode { 0x00_00_00_F1 => SyscallCode::HINT_READ, 0x00_00_01_1D => SyscallCode::UINT256_MUL, 0x00_00_01_1C => SyscallCode::BLS12381_DECOMPRESS, + 0x00_01_01_16 => SyscallCode::SECP384R1_ADD, + 0x00_00_01_17 => SyscallCode::SECP384R1_DOUBLE, _ => panic!("invalid syscall number: {}", value), } } @@ -281,6 +289,14 @@ pub fn default_syscall_map() -> HashMap> { SyscallCode::SECP256K1_DOUBLE, Rc::new(WeierstrassDoubleAssignChip::::new()), ); + syscall_map.insert( + SyscallCode::SECP384R1_ADD, + Rc::new(WeierstrassAddAssignChip::::new()), + ); + syscall_map.insert( + SyscallCode::SECP384R1_DOUBLE, + Rc::new(WeierstrassDoubleAssignChip::::new()), + ); syscall_map.insert(SyscallCode::SHA_COMPRESS, Rc::new(ShaCompressChip::new())); syscall_map.insert( SyscallCode::SECP256K1_DECOMPRESS, @@ -402,6 +418,12 @@ mod tests { SyscallCode::SECP256K1_DOUBLE => { assert_eq!(code as u32, sp1_zkvm::syscalls::SECP256K1_DOUBLE) } + SyscallCode::SECP384R1_ADD => { + assert_eq!(code as u32, sp1_zkvm::syscalls::SECP384R1_ADD) + } + SyscallCode::SECP384R1_DOUBLE => { + assert_eq!(code as u32, sp1_zkvm::syscalls::SECP384R1_DOUBLE) + } SyscallCode::BLAKE3_COMPRESS_INNER => { assert_eq!(code as u32, sp1_zkvm::syscalls::BLAKE3_COMPRESS_INNER) } diff --git a/core/src/stark/air.rs b/core/src/stark/air.rs index dc181b18d2..2599aad526 100644 --- a/core/src/stark/air.rs +++ b/core/src/stark/air.rs @@ -36,6 +36,7 @@ pub(crate) mod riscv_chips { pub use crate::utils::ec::weierstrass::bls12_381::Bls12381Parameters; pub use crate::utils::ec::weierstrass::bn254::Bn254Parameters; pub use crate::utils::ec::weierstrass::secp256k1::Secp256k1Parameters; + pub use crate::utils::ec::weierstrass::secp384r1::Secp384r1Parameters; pub use crate::utils::ec::weierstrass::SwCurve; } @@ -86,6 +87,10 @@ pub enum RiscvAir { Secp256k1Add(WeierstrassAddAssignChip>), /// A precompile for doubling a point on the Elliptic curve secp256k1. Secp256k1Double(WeierstrassDoubleAssignChip>), + /// A precompile for addition on the Elliptic curve secp384r1. + Secp384r1Add(WeierstrassAddAssignChip>), + /// A precompile for doubling a point on the Elliptic curve secp384r1. + Secp384r1Double(WeierstrassDoubleAssignChip>), /// A precompile for the Keccak permutation. KeccakP(KeccakPermuteChip), /// A precompile for the Blake3 compression function. (Disabled by default.) @@ -138,6 +143,11 @@ impl RiscvAir { let secp256k1_double_assign = WeierstrassDoubleAssignChip::>::new(); chips.push(RiscvAir::Secp256k1Double(secp256k1_double_assign)); + let secp384r1_add_assign = WeierstrassAddAssignChip::>::new(); + chips.push(RiscvAir::Secp384r1Add(secp384r1_add_assign)); + let secp384r1_double_assign = + WeierstrassDoubleAssignChip::>::new(); + chips.push(RiscvAir::Secp384r1Double(secp384r1_double_assign)); let keccak_permute = KeccakPermuteChip::new(); chips.push(RiscvAir::KeccakP(keccak_permute)); let bn254_add_assign = WeierstrassAddAssignChip::>::new(); diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index f2282632b8..07d51cb57a 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -80,6 +80,7 @@ impl Syscall for WeierstrassAddAssignChip { CurveType::Secp256k1 => rt.record_mut().secp256k1_add_events.push(event), CurveType::Bn254 => rt.record_mut().bn254_add_events.push(event), CurveType::Bls12381 => rt.record_mut().bls12381_add_events.push(event), + CurveType::Secp384r1 => rt.record_mut().secp384r1_add_events.push(event), _ => panic!("Unsupported curve"), } None @@ -181,6 +182,7 @@ where CurveType::Secp256k1 => "Secp256k1AddAssign".to_string(), CurveType::Bn254 => "Bn254AddAssign".to_string(), CurveType::Bls12381 => "Bls12381AddAssign".to_string(), + CurveType::Secp384r1 => "Secp384r1AddAssign".to_string(), _ => panic!("Unsupported curve"), } } @@ -194,6 +196,7 @@ where CurveType::Secp256k1 => &input.secp256k1_add_events, CurveType::Bn254 => &input.bn254_add_events, CurveType::Bls12381 => &input.bls12381_add_events, + CurveType::Secp384r1 => &input.secp384r1_add_events, _ => panic!("Unsupported curve"), }; @@ -273,6 +276,7 @@ where CurveType::Secp256k1 => !shard.secp256k1_add_events.is_empty(), CurveType::Bn254 => !shard.bn254_add_events.is_empty(), CurveType::Bls12381 => !shard.bls12381_add_events.is_empty(), + CurveType::Secp384r1 => !shard.secp384r1_add_events.is_empty(), _ => panic!("Unsupported curve"), } } @@ -432,6 +436,9 @@ where CurveType::Bls12381 => { AB::F::from_canonical_u32(SyscallCode::BLS12381_ADD.syscall_id()) } + CurveType::Secp384r1 => { + AB::F::from_canonical_u32(SyscallCode::SECP384R1_ADD.syscall_id()) + } _ => panic!("Unsupported curve"), }; @@ -455,7 +462,8 @@ mod tests { run_test, setup_logger, tests::{ BLS12381_ADD_ELF, BLS12381_DOUBLE_ELF, BLS12381_MUL_ELF, BN254_ADD_ELF, - BN254_MUL_ELF, SECP256K1_ADD_ELF, SECP256K1_MUL_ELF, + BN254_MUL_ELF, SECP256K1_ADD_ELF, SECP256K1_MUL_ELF, SECP384R1_ADD_ELF, + SECP384R1_MUL_ELF, }, }, }; @@ -467,6 +475,13 @@ mod tests { run_test(program).unwrap(); } + #[test] + fn test_secp384r1_add_simple() { + setup_logger(); + let program = Program::from(SECP384R1_ADD_ELF); + run_test(program).unwrap(); + } + #[test] fn test_bn254_add_simple() { setup_logger(); @@ -488,6 +503,13 @@ mod tests { run_test(program).unwrap(); } + #[test] + fn test_secp384r1_mul_simple() { + setup_logger(); + let program = Program::from(SECP384R1_MUL_ELF); + run_test(program).unwrap(); + } + #[test] fn test_bls12381_add_simple() { setup_logger(); diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index 2730c4924e..d8dfeb5c35 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -81,6 +81,7 @@ impl Syscall for WeierstrassDoubleAssi CurveType::Secp256k1 => rt.record_mut().secp256k1_double_events.push(event), CurveType::Bn254 => rt.record_mut().bn254_double_events.push(event), CurveType::Bls12381 => rt.record_mut().bls12381_double_events.push(event), + CurveType::Secp384r1 => rt.record_mut().secp384r1_double_events.push(event), _ => panic!("Unsupported curve"), } None @@ -203,6 +204,7 @@ where CurveType::Secp256k1 => "Secp256k1DoubleAssign".to_string(), CurveType::Bn254 => "Bn254DoubleAssign".to_string(), CurveType::Bls12381 => "Bls12381DoubleAssign".to_string(), + CurveType::Secp384r1 => "Secp384r1DoubleAssign".to_string(), _ => panic!("Unsupported curve"), } } @@ -217,6 +219,7 @@ where CurveType::Secp256k1 => &input.secp256k1_double_events, CurveType::Bn254 => &input.bn254_double_events, CurveType::Bls12381 => &input.bls12381_double_events, + CurveType::Secp384r1 => &input.secp384r1_double_events, _ => panic!("Unsupported curve"), }; @@ -296,6 +299,7 @@ where CurveType::Secp256k1 => !shard.secp256k1_double_events.is_empty(), CurveType::Bn254 => !shard.bn254_double_events.is_empty(), CurveType::Bls12381 => !shard.bls12381_double_events.is_empty(), + CurveType::Secp384r1 => !shard.secp384r1_double_events.is_empty(), _ => panic!("Unsupported curve"), } } @@ -465,6 +469,9 @@ where CurveType::Bls12381 => { AB::F::from_canonical_u32(SyscallCode::BLS12381_DOUBLE.syscall_id()) } + CurveType::Secp384r1 => { + AB::F::from_canonical_u32(SyscallCode::SECP384R1_DOUBLE.syscall_id()) + } _ => panic!("Unsupported curve"), }; @@ -486,7 +493,9 @@ pub mod tests { runtime::Program, utils::{ run_test, setup_logger, - tests::{BLS12381_DOUBLE_ELF, BN254_DOUBLE_ELF, SECP256K1_DOUBLE_ELF}, + tests::{ + BLS12381_DOUBLE_ELF, BN254_DOUBLE_ELF, SECP256K1_DOUBLE_ELF, SECP384R1_DOUBLE_ELF, + }, }, }; @@ -510,4 +519,11 @@ pub mod tests { let program = Program::from(BLS12381_DOUBLE_ELF); run_test(program).unwrap(); } + + #[test] + fn test_secp384r1_double_simple() { + setup_logger(); + let program = Program::from(SECP384R1_DOUBLE_ELF); + run_test(program).unwrap(); + } } diff --git a/core/src/utils/ec/mod.rs b/core/src/utils/ec/mod.rs index 6ec4ad0327..511f0e592b 100644 --- a/core/src/utils/ec/mod.rs +++ b/core/src/utils/ec/mod.rs @@ -28,6 +28,7 @@ pub enum CurveType { Bn254, Ed25519, Bls12381, + Secp384r1, } impl Display for CurveType { @@ -37,6 +38,7 @@ impl Display for CurveType { CurveType::Bn254 => write!(f, "Bn254"), CurveType::Ed25519 => write!(f, "Ed25519"), CurveType::Bls12381 => write!(f, "Bls12381"), + CurveType::Secp384r1 => write!(f, "Secp384r1"), } } } diff --git a/core/src/utils/ec/weierstrass/mod.rs b/core/src/utils/ec/weierstrass/mod.rs index 5ab6f47ae5..c802509b65 100644 --- a/core/src/utils/ec/weierstrass/mod.rs +++ b/core/src/utils/ec/weierstrass/mod.rs @@ -11,6 +11,7 @@ use crate::utils::ec::{AffinePoint, EllipticCurve, EllipticCurveParameters}; pub mod bls12_381; pub mod bn254; pub mod secp256k1; +pub mod secp384r1; /// Parameters that specify a short Weierstrass curve : y^2 = x^3 + ax + b. pub trait WeierstrassParameters: EllipticCurveParameters { diff --git a/core/src/utils/ec/weierstrass/secp384r1.rs b/core/src/utils/ec/weierstrass/secp384r1.rs new file mode 100644 index 0000000000..9027a44935 --- /dev/null +++ b/core/src/utils/ec/weierstrass/secp384r1.rs @@ -0,0 +1,144 @@ +//! Modulo defining the Secp384r1 curve and its base field. The constants are all taken from +//! https://www.secg.org/sec2-v2.pdf. + +use std::str::FromStr; + +use generic_array::GenericArray; +use num::traits::FromBytes; +use num::traits::ToBytes; +use num::BigUint; +use p384::FieldElement; +use serde::{Deserialize, Serialize}; +use typenum::{U48, U94}; + +use super::{SwCurve, WeierstrassParameters}; +use crate::operations::field::params::FieldParameters; +use crate::operations::field::params::NumLimbs; +use crate::utils::ec::CurveType; +use crate::utils::ec::EllipticCurveParameters; + +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +/// Secp384r1 curve parameter +pub struct Secp384r1Parameters; + +pub type Secp384r1 = SwCurve; + +#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)] +/// Secp384r1 base field parameter +pub struct Secp384r1BaseField; + +impl FieldParameters for Secp384r1BaseField { + const MODULUS: &'static [u8] = &[ + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + ]; + + /// A rough witness-offset estimate given the size of the limbs and the size of the field. + const WITNESS_OFFSET: usize = 1usize << 15; + + fn modulus() -> BigUint { + BigUint::from_bytes_le(Self::MODULUS) + } +} + +impl NumLimbs for Secp384r1BaseField { + type Limbs = U48; + type Witness = U94; +} + +impl EllipticCurveParameters for Secp384r1Parameters { + type BaseField = Secp384r1BaseField; + const CURVE_TYPE: CurveType = CurveType::Secp384r1; +} + +impl WeierstrassParameters for Secp384r1Parameters { + const A: GenericArray = GenericArray::from_array([ + 252, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 254, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, + ]); + + const B: GenericArray = GenericArray::from_array([ + 239, 42, 236, 211, 237, 200, 133, 42, 157, 209, 46, 138, 141, 57, 86, 198, 90, 135, 19, 80, + 143, 8, 20, 3, 18, 65, 129, 254, 110, 156, 29, 24, 25, 45, 248, 227, 107, 5, 142, 152, 228, + 231, 62, 226, 167, 47, 49, 179, + ]); + fn generator() -> (BigUint, BigUint) { + let x = BigUint::from_str( + "26247035095799689268623156744566981891852923491109213387815615900925518854738050089022388053975719786650872476732087", + ) + .unwrap(); + let y = BigUint::from_str( + "8325710961489029985546751289520108179287853048861315594709205902480503199884419224438643760392947333078086511627871", + ) + .unwrap(); + (x, y) + } + + fn prime_group_order() -> num::BigUint { + BigUint::from_slice(&[ + 0xCCC52973, 0xECEC196A, 0x48B0A77A, 0x581A0DB2, 0xF4372DDF, 0xC7634D81, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + ]) + } + + fn a_int() -> BigUint { + BigUint::from_slice(&[ + 0xFFFFFFFC, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + ]) + } + + fn b_int() -> BigUint { + BigUint::from_slice(&[ + 0xD3EC2AEF, 0x2A85C8ED, 0x8A2ED19D, 0xC656398D, 0x5013875A, 0x0314088F, 0xFE814112, + 0x181D9C6E, 0xE3F82D19, 0x988E056B, 0xE23EE7E4, 0xB3312FA7, + ]) + } +} + +pub fn secp384r1_sqrt(n: &BigUint) -> BigUint { + let be_bytes = n.to_be_bytes(); + let mut bytes = [0_u8; 48]; + bytes[48 - be_bytes.len()..].copy_from_slice(&be_bytes); + let fe = FieldElement::from_bytes(&bytes.into()).unwrap(); + let result_bytes = fe.sqrt().unwrap().to_bytes(); + BigUint::from_be_bytes(&result_bytes as &[u8]) +} + +#[cfg(test)] +mod tests { + + use super::*; + use crate::utils::ec::utils::biguint_from_limbs; + use num::bigint::RandBigInt; + use rand::thread_rng; + + #[test] + fn test_weierstrass_biguint_scalar_mul_p384() { + assert_eq!( + biguint_from_limbs(Secp384r1BaseField::MODULUS), + Secp384r1BaseField::modulus() + ); + } + + #[test] + fn test_secp384r_sqrt() { + let mut rng = thread_rng(); + for _ in 0..10 { + // Check that sqrt(x^2)^2 == x^2 + // We use x^2 since not all field elements have a square root + let x = rng.gen_biguint(256) % Secp384r1BaseField::modulus(); + let x_2 = (&x * &x) % Secp384r1BaseField::modulus(); + let sqrt = secp384r1_sqrt(&x_2); + + println!("sqrt: {}", sqrt); + + let sqrt_2 = (&sqrt * &sqrt) % Secp384r1BaseField::modulus(); + + assert_eq!(sqrt_2, x_2); + } + } +} diff --git a/core/src/utils/programs.rs b/core/src/utils/programs.rs index 839a55b37a..2b68f8bf98 100644 --- a/core/src/utils/programs.rs +++ b/core/src/utils/programs.rs @@ -58,12 +58,18 @@ pub mod tests { pub const SECP256K1_ADD_ELF: &[u8] = include_bytes!("../../../tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf"); + pub const SECP384R1_ADD_ELF: &[u8] = + include_bytes!("../../../tests/secp384r1-add/elf/riscv32im-succinct-zkvm-elf"); + pub const SECP256K1_DECOMPRESS_ELF: &[u8] = include_bytes!("../../../tests/secp256k1-decompress/elf/riscv32im-succinct-zkvm-elf"); pub const SECP256K1_DOUBLE_ELF: &[u8] = include_bytes!("../../../tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf"); + pub const SECP384R1_DOUBLE_ELF: &[u8] = + include_bytes!("../../../tests/secp384r1-double/elf/riscv32im-succinct-zkvm-elf"); + pub const SHA_COMPRESS_ELF: &[u8] = include_bytes!("../../../tests/sha-compress/elf/riscv32im-succinct-zkvm-elf"); @@ -85,6 +91,9 @@ pub mod tests { pub const SECP256K1_MUL_ELF: &[u8] = include_bytes!("../../../tests/secp256k1-mul/elf/riscv32im-succinct-zkvm-elf"); + pub const SECP384R1_MUL_ELF: &[u8] = + include_bytes!("../../../tests/secp384r1-mul/elf/riscv32im-succinct-zkvm-elf"); + pub const BLS12381_ADD_ELF: &[u8] = include_bytes!("../../../tests/bls12381-add/elf/riscv32im-succinct-zkvm-elf"); diff --git a/tests/secp384r1-add/Cargo.lock b/tests/secp384r1-add/Cargo.lock new file mode 100644 index 0000000000..12c8b61081 --- /dev/null +++ b/tests/secp384r1-add/Cargo.lock @@ -0,0 +1,812 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "tap", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "scale-info" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp384r1-add-test" +version = "0.1.0" +dependencies = [ + "hex-literal", + "num", + "sp1-zkvm", +] + +[[package]] +name = "serde" +version = "1.0.202" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.202" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "sp1-precompiles" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "getrandom", + "hex", + "k256", + "num", + "p384", + "rand", + "serde", + "snowbridge-amcl", +] + +[[package]] +name = "sp1-zkvm" +version = "0.1.0" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "k256", + "libm", + "once_cell", + "p384", + "rand", + "serde", + "sha2", + "sp1-precompiles", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/tests/secp384r1-add/Cargo.toml b/tests/secp384r1-add/Cargo.toml new file mode 100644 index 0000000000..c0b4d7f139 --- /dev/null +++ b/tests/secp384r1-add/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] +[package] +version = "0.1.0" +name = "secp384r1-add-test" +edition = "2021" + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +hex-literal = "0.4.1" +num = { version = "0.4.1", default-features = false } \ No newline at end of file diff --git a/tests/secp384r1-add/elf/riscv32im-succinct-zkvm-elf b/tests/secp384r1-add/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000000000000000000000000000000000..18b96e7315089b55df915cd707c37a4c28bdc4af GIT binary patch literal 117908 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 XuiD;I-j9!aqkIs({`u{Jdffj2ymeG< literal 0 HcmV?d00001 diff --git a/tests/secp384r1-double/src/main.rs b/tests/secp384r1-double/src/main.rs new file mode 100644 index 0000000000..a3b8a28ad3 --- /dev/null +++ b/tests/secp384r1-double/src/main.rs @@ -0,0 +1,41 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +extern "C" { + fn syscall_secp384r1_double(p: *mut u32); +} + +pub fn main() { + for _ in 0..10i64.pow(3) { + // generator. + // 26247035095799689268623156744566981891852923491109213387815615900925518854738050089022388053975719786650872476732087 + // 8325710961489029985546751289520108179287853048861315594709205902480503199884419224438643760392947333078086511627871 + let a: [u8; 96] = [ + 183, 10, 118, 114, 56, 94, 84, 58, 108, 41, 85, 191, 93, 242, 2, 85, 56, 42, 84, 130, + 224, 65, 247, 89, 152, 155, 167, 139, 98, 59, 29, 110, 116, 173, 32, 243, 30, 199, 177, + 142, 55, 5, 139, 190, 34, 202, 135, 170, 95, 14, 234, 144, 124, 29, 67, 122, 157, 129, + 126, 29, 206, 177, 96, 10, 192, 184, 240, 181, 19, 49, 218, 233, 124, 20, 154, 40, 189, + 29, 244, 248, 41, 220, 146, 146, 191, 152, 158, 93, 111, 44, 38, 150, 74, 222, 23, 54, + ]; + + unsafe { + syscall_secp384r1_double(a.as_mut_ptr() as *mut u32); + } + + // 2 * generator. + // 1362138308511466522361153706999924933599454966107597910086607881313301390679204654798639248640660900363360053616481 + // 21933325650940841369538204578070064804451893403314136885642470114978241170633179043576249504748352841115137159204480 + let b: [u8; 96] = [ + 97, 223, 149, 82, 199, 169, 150, 91, 248, 100, 14, 190, 110, 232, 224, 79, 158, 110, + 185, 159, 209, 7, 210, 81, 214, 52, 244, 166, 89, 89, 2, 137, 240, 151, 91, 197, 69, 0, + 38, 105, 217, 210, 163, 123, 5, 153, 217, 8, 128, 14, 148, 10, 112, 30, 80, 97, 45, + 226, 57, 77, 233, 67, 253, 95, 37, 180, 106, 37, 95, 80, 78, 144, 62, 196, 108, 188, + 117, 216, 117, 178, 116, 186, 109, 253, 223, 232, 191, 183, 237, 60, 27, 91, 250, 241, + 128, 142, + ]; + + assert_eq!(a, b); + } + + println!("done"); +} diff --git a/tests/secp384r1-mul/Cargo.lock b/tests/secp384r1-mul/Cargo.lock new file mode 100644 index 0000000000..41b1a0b56c --- /dev/null +++ b/tests/secp384r1-mul/Cargo.lock @@ -0,0 +1,814 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "tap", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "scale-info" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp384r1-mul-test" +version = "0.1.0" +dependencies = [ + "sp1-derive", + "sp1-zkvm", +] + +[[package]] +name = "serde" +version = "1.0.202" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.202" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "sp1-derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-precompiles" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "getrandom", + "hex", + "k256", + "num", + "p384", + "rand", + "serde", + "snowbridge-amcl", +] + +[[package]] +name = "sp1-zkvm" +version = "0.1.0" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "k256", + "libm", + "once_cell", + "p384", + "rand", + "serde", + "sha2", + "sp1-precompiles", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/tests/secp384r1-mul/Cargo.toml b/tests/secp384r1-mul/Cargo.toml new file mode 100644 index 0000000000..6a4fa80a3f --- /dev/null +++ b/tests/secp384r1-mul/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] +[package] +name = "secp384r1-mul-test" +version = "0.1.0" +edition = "2021" + +[dependencies] +sp1-zkvm = { path = "../../zkvm/entrypoint" } +sp1-derive = { path = "../../derive" } \ No newline at end of file diff --git a/tests/secp384r1-mul/elf/riscv32im-succinct-zkvm-elf b/tests/secp384r1-mul/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000000000000000000000000000000000..634b860c6587f4bafe3fd95739c507cd2a64339a GIT binary patch literal 121680 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 OUvk`E|F%2OANN12%yVP_ literal 0 HcmV?d00001 diff --git a/tests/secp384r1-mul/src/main.rs b/tests/secp384r1-mul/src/main.rs new file mode 100644 index 0000000000..770ddefeae --- /dev/null +++ b/tests/secp384r1-mul/src/main.rs @@ -0,0 +1,44 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +use sp1_zkvm::precompiles::secp384r1::Secp384r1Operations; +use sp1_zkvm::precompiles::utils::AffinePoint; + +#[sp1_derive::cycle_tracker] +pub fn main() { + // generator. + // 26247035095799689268623156744566981891852923491109213387815615900925518854738050089022388053975719786650872476732087 + // 8325710961489029985546751289520108179287853048861315594709205902480503199884419224438643760392947333078086511627871 + let a: [u8; 96] = [ + 183, 10, 118, 114, 56, 94, 84, 58, 108, 41, 85, 191, 93, 242, 2, 85, 56, 42, 84, 130, 224, + 65, 247, 89, 152, 155, 167, 139, 98, 59, 29, 110, 116, 173, 32, 243, 30, 199, 177, 142, 55, + 5, 139, 190, 34, 202, 135, 170, 95, 14, 234, 144, 124, 29, 67, 122, 157, 129, 126, 29, 206, + 177, 96, 10, 192, 184, 240, 181, 19, 49, 218, 233, 124, 20, 154, 40, 189, 29, 244, 248, 41, + 220, 146, 146, 191, 152, 158, 93, 111, 44, 38, 150, 74, 222, 23, 54, + ]; + + let mut a_point = AffinePoint::::from_le_bytes(a); + + // scalar. + // 3 + let scalar: [u32; 12] = [3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + println!("cycle-tracker-start: secp384r1_mul"); + a_point.mul_assign(&scalar); + println!("cycle-tracker-end: secp384r1_mul"); + + // 3 * generator. + // 1150902892488483458936980703033240421996917307006362560128741616924334451190275252566486993672663650518120360101937 + // 31026896179475916024120184231935979451435829475766013456640577102369059008378103381483562093497986423351518602141169 + let c: [u8; 96] = [ + 49, 200, 0, 5, 199, 229, 215, 2, 13, 88, 38, 80, 174, 187, 8, 180, 166, 109, 86, 211, 64, + 242, 164, 190, 6, 205, 45, 32, 16, 57, 157, 203, 152, 125, 220, 95, 126, 60, 121, 100, 20, + 250, 111, 96, 212, 65, 122, 7, 241, 29, 47, 10, 96, 40, 95, 182, 152, 210, 181, 228, 107, + 189, 74, 194, 172, 30, 17, 220, 14, 76, 104, 247, 165, 90, 17, 133, 28, 180, 32, 133, 153, + 252, 169, 2, 150, 190, 11, 125, 131, 66, 12, 11, 202, 247, 149, 201, + ]; + + assert_eq!(a_point.to_le_bytes(), c); + + println!("done"); +} diff --git a/zkvm/entrypoint/Cargo.toml b/zkvm/entrypoint/Cargo.toml index e111a881ea..de013e3ef6 100644 --- a/zkvm/entrypoint/Cargo.toml +++ b/zkvm/entrypoint/Cargo.toml @@ -12,6 +12,7 @@ bincode = "1.3.3" cfg-if = "1.0.0" getrandom = { version = "0.2.15", features = ["custom"] } k256 = { version = "0.13.3", features = ["ecdsa", "std", "bits"] } +p384 = { version = "0.13.0", features = ["ecdsa", "std", "bits"] } once_cell = "1.19.0" rand = "0.8.5" serde = { version = "1.0.201", features = ["derive"] } diff --git a/zkvm/entrypoint/src/syscalls/mod.rs b/zkvm/entrypoint/src/syscalls/mod.rs index 760cabad2c..9678d390c8 100644 --- a/zkvm/entrypoint/src/syscalls/mod.rs +++ b/zkvm/entrypoint/src/syscalls/mod.rs @@ -7,6 +7,7 @@ mod io; mod keccak_permute; mod memory; mod secp256k1; +mod secp384r1; mod sha_compress; mod sha_extend; mod sys; @@ -23,6 +24,7 @@ pub use io::*; pub use keccak_permute::*; pub use memory::*; pub use secp256k1::*; +pub use secp384r1::*; pub use sha_compress::*; pub use sha_extend::*; pub use sys::*; @@ -105,3 +107,9 @@ pub const BLS12381_ADD: u32 = 0x00_01_01_1E; /// Executes the `BLS12381_DOUBLE` precompile. pub const BLS12381_DOUBLE: u32 = 0x00_00_01_1F; + +/// Executes `SECP384R1_ADD`. +pub const SECP384R1_ADD: u32 = 0x00_01_01_16; + +/// Executes `SECP384R1_DOUBLE`. +pub const SECP384R1_DOUBLE: u32 = 0x00_00_01_17; diff --git a/zkvm/entrypoint/src/syscalls/secp384r1.rs b/zkvm/entrypoint/src/syscalls/secp384r1.rs new file mode 100644 index 0000000000..859878e503 --- /dev/null +++ b/zkvm/entrypoint/src/syscalls/secp384r1.rs @@ -0,0 +1,42 @@ +#[cfg(target_os = "zkvm")] +use core::arch::asm; + +/// Adds two Secp384r1 points. +/// +/// The result is stored in the first point. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_secp384r1_add(p: *mut u32, q: *mut u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::SECP384R1_ADD, + in("a0") p, + in("a1") q + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// Double a Secp384r1 point. +/// +/// The result is stored in the first point. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_secp384r1_double(p: *mut u32) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::SECP384R1_DOUBLE, + in("a0") p, + in("a1") 0 + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} diff --git a/zkvm/precompiles/Cargo.toml b/zkvm/precompiles/Cargo.toml index e38ba017a3..6e7123459b 100644 --- a/zkvm/precompiles/Cargo.toml +++ b/zkvm/precompiles/Cargo.toml @@ -11,6 +11,7 @@ cfg-if = "1.0.0" getrandom = { version = "0.2.15", features = ["custom"] } hex = "0.4.3" k256 = { version = "0.13.3", features = ["ecdsa", "std", "bits"] } +p384 = { version = "0.13.0", features = ["ecdsa", "std", "bits"] } rand = "0.8.5" serde = { version = "1.0.201", features = ["derive"] } num = {version = "0.4.3"} diff --git a/zkvm/precompiles/src/lib.rs b/zkvm/precompiles/src/lib.rs index f5cf90bdcc..9aca481c1d 100644 --- a/zkvm/precompiles/src/lib.rs +++ b/zkvm/precompiles/src/lib.rs @@ -6,6 +6,7 @@ pub mod bls12381; pub mod bn254; pub mod io; pub mod secp256k1; +pub mod secp384r1; pub mod uint256_div; pub mod unconstrained; pub mod utils; @@ -22,6 +23,8 @@ extern "C" { pub fn syscall_ed_decompress(point: &mut [u8; 64]); pub fn syscall_secp256k1_add(p: *mut u32, q: *const u32); pub fn syscall_secp256k1_double(p: *mut u32); + pub fn syscall_secp384r1_add(p: *mut u32, q: *const u32); + pub fn syscall_secp384r1_double(p: *mut u32); pub fn syscall_secp256k1_decompress(point: &mut [u8; 64], is_odd: bool); pub fn syscall_bn254_add(p: *mut u32, q: *const u32); pub fn syscall_bn254_double(p: *mut u32); diff --git a/zkvm/precompiles/src/secp384r1.rs b/zkvm/precompiles/src/secp384r1.rs new file mode 100644 index 0000000000..a023a56850 --- /dev/null +++ b/zkvm/precompiles/src/secp384r1.rs @@ -0,0 +1,190 @@ +#![allow(unused)] + +use crate::utils::{AffinePoint, CurveOperations}; +use crate::{syscall_secp384r1_add, syscall_secp384r1_double}; +use anyhow::Context; +use anyhow::{anyhow, Result}; +use core::convert::TryInto; +use k256::ecdsa::hazmat::bits2field; +use k256::ecdsa::signature::hazmat::PrehashVerifier; +use k256::ecdsa::RecoveryId; +use p384::ecdsa::{Signature, VerifyingKey}; +use p384::elliptic_curve::ff::PrimeFieldBits; +use p384::elliptic_curve::ops::Invert; +use p384::elliptic_curve::sec1::ToEncodedPoint; +use p384::elliptic_curve::PrimeField; +use p384::{NistP384, PublicKey, Scalar}; + +use crate::io; +use crate::unconstrained; + +const NUM_WORDS: usize = 24; + +#[derive(Copy, Clone)] +pub struct Secp384r1Operations; + +impl CurveOperations for Secp384r1Operations { + const GENERATOR: [u32; NUM_WORDS] = [ + 1920338615, 978607672, 3210029420, 1426256477, 2186553912, 1509376480, 2343017368, + 1847409506, 4079005044, 2394015518, 3196781879, 2861025826, 2431258207, 2051218812, + 494829981, 174109134, 3052452032, 3923390739, 681186428, 4176747965, 2459098153, + 1570674879, 2519084143, 907533898, + ]; + + fn add_assign(limbs: &mut [u32; NUM_WORDS], other: &[u32; NUM_WORDS]) { + unsafe { + syscall_secp384r1_add(limbs.as_mut_ptr(), other.as_ptr()); + } + } + + fn double(limbs: &mut [u32; NUM_WORDS]) { + unsafe { + syscall_secp384r1_double(limbs.as_mut_ptr()); + } + } +} + +/// Verifies a secp384r1 signature using the public key and the message hash. If the s_inverse is +/// provided, it will be validated and used to verify the signature. Otherwise, the inverse of s +/// will be computed and used. +/// +/// Warning: this function does not check if the key is actually on the curve. +pub fn verify_signature( + pubkey: &[u8; 97], + msg_hash: &[u8; 48], + signature: &Signature, + s_inverse: Option<&Scalar>, +) -> bool { + cfg_if::cfg_if! { + if #[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] { + let pubkey_x = Scalar::from_repr(bits2field::(&pubkey[1..49]).unwrap()).unwrap(); + let pubkey_y = Scalar::from_repr(bits2field::(&pubkey[49..]).unwrap()).unwrap(); + + let mut pubkey_x_le_bytes = pubkey_x.to_bytes(); + pubkey_x_le_bytes.reverse(); + let mut pubkey_y_le_bytes = pubkey_y.to_bytes(); + pubkey_y_le_bytes.reverse(); + + // Convert the public key to an affine point + let affine = AffinePoint::::from(pubkey_x_le_bytes.into(), pubkey_y_le_bytes.into()); + + const GENERATOR: AffinePoint = AffinePoint::::generator_in_affine(); + + let field = bits2field::(msg_hash); + if field.is_err() { + return false; + } + let field = Scalar::from_repr(field.unwrap()).unwrap(); + let z = field; + let (r, s) = signature.split_scalars(); + let computed_s_inv; + let s_inv = match s_inverse { + Some(s_inv) => { + assert_eq!(s_inv * s.as_ref(), Scalar::ONE); + s_inv + } + None => { + computed_s_inv = s.invert(); + &computed_s_inv + } + }; + + let u1 = z * s_inv; + let u2 = *r * s_inv; + + let res = double_and_add_base(&u1, &GENERATOR, &u2, &affine).unwrap(); + let mut x_bytes_be = [0u8; 48]; + for i in 0..8 { + x_bytes_be[i * 4..(i * 4) + 4].copy_from_slice(&res.limbs[i].to_le_bytes()); + } + x_bytes_be.reverse(); + + let x_field = bits2field::(&x_bytes_be); + if x_field.is_err() { + return false; + } + *r == Scalar::from_repr(x_field.unwrap()).unwrap() + } else { + let public_key = PublicKey::from_sec1_bytes(pubkey); + if public_key.is_err() { + return false; + } + let public_key = public_key.unwrap(); + + let verify_key = VerifyingKey::from(&public_key); + let res = verify_key + .verify_prehash(msg_hash, signature) + .context("invalid signature"); + + res.is_ok() + } + } +} + +#[allow(non_snake_case)] +fn double_and_add_base( + a: &Scalar, + A: &AffinePoint, + b: &Scalar, + B: &AffinePoint, +) -> Option> { + let mut res: Option> = None; + let mut temp_A = *A; + let mut temp_B = *B; + + let a_bits = a.to_le_bits(); + let b_bits = b.to_le_bits(); + for (a_bit, b_bit) in a_bits.iter().zip(b_bits) { + if *a_bit { + match res.as_mut() { + Some(res) => res.add_assign(&temp_A), + None => res = Some(temp_A), + }; + } + + if b_bit { + match res.as_mut() { + Some(res) => res.add_assign(&temp_B), + None => res = Some(temp_B), + }; + } + + temp_A.double(); + temp_B.double(); + } + + res +} + +/// Outside of the VM, computes the pubkey and s_inverse value from a signature and a message hash. +/// +/// WARNING: The values are read from outside of the VM and are not constrained to be correct. +/// Either use `decompress_pubkey` and `verify_signature` to verify the results of this function, or +/// use `ecrecover`. +pub fn unconstrained_ecrecover(sig: &[u8; 97], msg_hash: &[u8; 48]) -> ([u8; 49], Scalar) { + unconstrained! { + let mut recovery_id = sig[96]; + let mut sig = Signature::from_slice(&sig[..96]).unwrap(); + + if let Some(sig_normalized) = sig.normalize_s() { + sig = sig_normalized; + recovery_id ^= 1 + }; + let recid = RecoveryId::from_byte(recovery_id).expect("Recovery ID is valid"); + + let recovered_key = VerifyingKey::recover_from_prehash(&msg_hash[..], &sig, recid).unwrap(); + let bytes = recovered_key.to_sec1_bytes(); + io::hint_slice(&bytes); + + let (_, s) = sig.split_scalars(); + let s_inverse = s.invert(); + io::hint_slice(&s_inverse.to_bytes()); + } + + let recovered_bytes: [u8; 49] = io::read_vec().try_into().unwrap(); + + let s_inv_bytes: [u8; 48] = io::read_vec().try_into().unwrap(); + let s_inverse = Scalar::from_repr(bits2field::(&s_inv_bytes).unwrap()).unwrap(); + + (recovered_bytes, s_inverse) +} From 028f83a6f8b527286cd8b4adf235ff98eb35b231 Mon Sep 17 00:00:00 2001 From: kaylee Date: Thu, 16 May 2024 04:34:00 +0000 Subject: [PATCH 2/3] small updates --- tests/secp384r1-double/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/secp384r1-double/src/main.rs b/tests/secp384r1-double/src/main.rs index a3b8a28ad3..b70b08773d 100644 --- a/tests/secp384r1-double/src/main.rs +++ b/tests/secp384r1-double/src/main.rs @@ -10,7 +10,7 @@ pub fn main() { // generator. // 26247035095799689268623156744566981891852923491109213387815615900925518854738050089022388053975719786650872476732087 // 8325710961489029985546751289520108179287853048861315594709205902480503199884419224438643760392947333078086511627871 - let a: [u8; 96] = [ + let mut a: [u8; 96] = [ 183, 10, 118, 114, 56, 94, 84, 58, 108, 41, 85, 191, 93, 242, 2, 85, 56, 42, 84, 130, 224, 65, 247, 89, 152, 155, 167, 139, 98, 59, 29, 110, 116, 173, 32, 243, 30, 199, 177, 142, 55, 5, 139, 190, 34, 202, 135, 170, 95, 14, 234, 144, 124, 29, 67, 122, 157, 129, From 5936f406413f1c1a3beb6561fe7d8e22f48a95ab Mon Sep 17 00:00:00 2001 From: kaylee Date: Thu, 16 May 2024 04:44:20 +0000 Subject: [PATCH 3/3] fixed --- core/src/runtime/record.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/core/src/runtime/record.rs b/core/src/runtime/record.rs index caf7ee3e38..ee5fec2823 100644 --- a/core/src/runtime/record.rs +++ b/core/src/runtime/record.rs @@ -283,6 +283,10 @@ impl MachineRecord for ExecutionRecord { .append(&mut other.secp256k1_add_events); self.secp256k1_double_events .append(&mut other.secp256k1_double_events); + self.secp384r1_add_events + .append(&mut other.secp384r1_add_events); + self.secp384r1_double_events + .append(&mut other.secp384r1_double_events); self.bn254_add_events.append(&mut other.bn254_add_events); self.bn254_double_events .append(&mut other.bn254_double_events); @@ -468,6 +472,26 @@ impl MachineRecord for ExecutionRecord { .extend_from_slice(secp256k1_double_chunk); } + // secp384r1 curve add events. + for (secp384r1_add_chunk, shard) in take(&mut self.secp384r1_add_events) + .chunks_mut(config.secp384r1_add_len) + .zip(shards.iter_mut()) + { + shard + .secp384r1_add_events + .extend_from_slice(secp384r1_add_chunk); + } + + // secp384r1 curve double events. + for (secp384r1_double_chunk, shard) in take(&mut self.secp384r1_double_events) + .chunks_mut(config.secp384r1_double_len) + .zip(shards.iter_mut()) + { + shard + .secp384r1_double_events + .extend_from_slice(secp384r1_double_chunk); + } + // bn254 curve add events. for (bn254_add_chunk, shard) in take(&mut self.bn254_add_events) .chunks_mut(config.bn254_add_len)