Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion sdk/patch-libs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod bn254;
pub mod ed25519;
pub mod io;
pub mod secp256k1;
pub mod secp256r1;
pub mod unconstrained;
pub mod utils;
pub mod verify;
Expand Down Expand Up @@ -37,7 +38,7 @@ extern "C" {
/// Executes an Ed25519 curve decompression on the given point.
pub fn syscall_ed_decompress(point: &mut [u8; 64]);

/// Executes an Sepc256k1 curve addition on the given points.
/// Executes an Secp256k1 curve addition on the given points.
pub fn syscall_secp256k1_add(p: *mut [u32; 16], q: *const [u32; 16]);

/// Executes an Secp256k1 curve doubling on the given point.
Expand All @@ -46,6 +47,15 @@ extern "C" {
/// Executes an Secp256k1 curve decompression on the given point.
pub fn syscall_secp256k1_decompress(point: &mut [u8; 64], is_odd: bool);

/// Executes an Secp256r1 curve addition on the given points.
pub fn syscall_secp256r1_add(p: *mut [u32; 16], q: *const [u32; 16]);

/// Executes an Secp256r1 curve doubling on the given point.
pub fn syscall_secp256r1_double(p: *mut [u32; 16]);

/// Executes an Secp256r1 curve decompression on the given point.
pub fn syscall_secp256r1_decompress(point: &mut [u8; 64], is_odd: bool);

/// Executes a Bn254 curve addition on the given points.
pub fn syscall_bn254_add(p: *mut [u32; 16], q: *const [u32; 16]);

Expand Down
69 changes: 69 additions & 0 deletions sdk/patch-libs/src/secp256r1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::{
syscall_secp256r1_add, syscall_secp256r1_double,
utils::{AffinePoint, WeierstrassAffinePoint, WeierstrassPoint},
};

/// The number of limbs in [Secp256r1Point].
pub const N: usize = 16;

/// An affine point on the Secp256r1 curve.
#[derive(Copy, Clone)]
#[repr(align(4))]
pub struct Secp256r1Point(pub WeierstrassPoint<N>);

impl WeierstrassAffinePoint<N> for Secp256r1Point {
fn infinity() -> Self {
Self(WeierstrassPoint::Infinity)
}

fn is_infinity(&self) -> bool {
matches!(self.0, WeierstrassPoint::Infinity)
}
}

impl AffinePoint<N> for Secp256r1Point {
const GENERATOR: [u32; N] = [
3633889942, 4104206661, 770388896, 1996717441, 1671708914, 4173129445, 3777774151,
1796723186, 935285237, 3417718888, 1798397646, 734933847, 2081398294, 2397563722,
4263149467, 1340293858,
];

fn new(limbs: [u32; N]) -> Self {
Self(WeierstrassPoint::Affine(limbs))
}

fn limbs_ref(&self) -> &[u32; N] {
match &self.0 {
WeierstrassPoint::Infinity => panic!("Infinity point has no limbs"),
WeierstrassPoint::Affine(limbs) => limbs,
}
}

fn limbs_mut(&mut self) -> &mut [u32; N] {
match &mut self.0 {
WeierstrassPoint::Infinity => panic!("Infinity point has no limbs"),
WeierstrassPoint::Affine(limbs) => limbs,
}
}

fn complete_add_assign(&mut self, other: &Self) {
self.weierstrass_add_assign(other);
}

fn add_assign(&mut self, other: &Self) {
let a = self.limbs_mut();
let b = other.limbs_ref();
unsafe {
syscall_secp256r1_add(a, b);
}
}

fn double(&mut self) {
match &mut self.0 {
WeierstrassPoint::Infinity => (),
WeierstrassPoint::Affine(limbs) => unsafe {
syscall_secp256r1_double(limbs);
},
}
}
}
11 changes: 11 additions & 0 deletions sdk/sdk/src/riscv_ecalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod keccak_permute;
mod memory;
mod poseidon2;
mod secp256k1;
mod secp256r1;
mod sha_compress;
mod sha_extend;
mod sys;
Expand Down Expand Up @@ -60,6 +61,16 @@ pub const SECP256K1_DOUBLE: u32 = 0x00_00_01_0B;
/// Executes `K256_DECOMPRESS`.
pub const SECP256K1_DECOMPRESS: u32 = 0x00_00_01_0C;

/// Executes `SECP256R1_ADD`.
pub const SECP256R1_ADD: u32 = 0x00_01_01_30;

/// Executes `SECP256R1_DOUBLE`.
pub const SECP256R1_DOUBLE: u32 = 0x00_00_01_31;

/// Executes `R256_DECOMPRESS`.
#[allow(clippy::mistyped_literal_suffixes)]
pub const SECP256R1_DECOMPRESS: u32 = 0x00_00_01_32;

/// Executes `BN254_ADD`.
pub const BN254_ADD: u32 = 0x00_01_01_0E;

Expand Down
86 changes: 86 additions & 0 deletions sdk/sdk/src/riscv_ecalls/secp256r1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#[cfg(target_os = "zkvm")]
use core::arch::asm;

/// Adds two Secp256r1 points.
///
/// The result is stored in the first point.
///
/// ### Safety
///
/// The caller must ensure that `p` and `q` are valid pointers to data that is aligned along a four
/// byte boundary. Additionally, the caller must ensure that `p` and `q` are valid points on the
/// secp256r1 curve, and that `p` and `q` are not equal to each other.
#[allow(unused_variables)]
#[no_mangle]
pub extern "C" fn syscall_secp256r1_add(p: *mut [u32; 16], q: *mut [u32; 16]) {
#[cfg(target_os = "zkvm")]
unsafe {
asm!(
"ecall",
in("t0") crate::riscv_ecalls::SECP256R1_ADD,
in("a0") p,
in("a1") q
);
}

#[cfg(not(target_os = "zkvm"))]
unreachable!()
}

/// Double a Secp256r1 point.
///
/// The result is stored in-place in the supplied buffer.
///
/// ### Safety
///
/// The caller must ensure that `p` is valid pointer to data that is aligned along a four byte
/// boundary.
#[allow(unused_variables)]
#[no_mangle]
pub extern "C" fn syscall_secp256r1_double(p: *mut [u32; 16]) {
#[cfg(target_os = "zkvm")]
unsafe {
asm!(
"ecall",
in("t0") crate::riscv_ecalls::SECP256R1_DOUBLE,
in("a0") p,
in("a1") 0
);
}

#[cfg(not(target_os = "zkvm"))]
unreachable!()
}

/// Decompresses a compressed Secp256r1 point.
///
/// The input array should be 64 bytes long, with the first 32 bytes containing the X coordinate in
/// big-endian format. The second half of the input will be overwritten with the Y coordinate of the
/// decompressed point in big-endian format using the point's parity (is_odd).
///
/// ### Safety
///
/// The caller must ensure that `point` is valid pointer to data that is aligned along a four byte
/// boundary.
#[allow(unused_variables)]
#[no_mangle]
pub extern "C" fn syscall_secp256r1_decompress(point: &mut [u8; 64], is_odd: bool) {
#[cfg(target_os = "zkvm")]
{
// Memory system/FpOps are little endian so we'll just flip the whole array before/after
point.reverse();
let p = point.as_mut_ptr();
unsafe {
asm!(
"ecall",
in("t0") crate::riscv_ecalls::SECP256R1_DECOMPRESS,
in("a0") p,
in("a1") is_odd as u8
);
}
point.reverse();
}

#[cfg(not(target_os = "zkvm"))]
unreachable!()
}
2 changes: 1 addition & 1 deletion vm/src/chips/gadgets/curves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl Display for CurveType {
pub struct AffinePoint<E> {
pub x: BigUint,
pub y: BigUint,
_marker: std::marker::PhantomData<E>,
_marker: std::marker::PhantomData<fn(E) -> E>,
}

impl<E: EllipticCurveParameters> AffinePoint<E> {
Expand Down
7 changes: 7 additions & 0 deletions vm/src/chips/gadgets/curves/weierstrass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ use crate::chips::gadgets::utils::conversions::{biguint_to_rug, rug_to_biguint};
pub mod bls381;
pub mod bn254;
pub mod secp256k1;
pub mod secp256r1;

// re-export names
pub use bls381::Bls12381;
pub use bn254::Bn254;
pub use secp256k1::Secp256k1;
pub use secp256r1::Secp256r1;

/// Parameters that specify a short Weierstrass curve : y^2 = x^3 + ax + b.
pub trait WeierstrassParameters: EllipticCurveParameters {
Expand Down
6 changes: 3 additions & 3 deletions vm/src/chips/gadgets/curves/weierstrass/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ pub fn secp256k1_sqrt(n: &BigUint) -> BigUint {
let mut bytes = [0_u8; 32];
bytes[32 - be_bytes.len()..].copy_from_slice(&be_bytes);
let fe = FieldElement::from_bytes(&bytes.into()).unwrap();
let result_bytes = fe.sqrt().unwrap().normalize().to_bytes();
BigUint::from_be_bytes(&result_bytes as &[u8])
let result_bytes = fe.sqrt().expect("bad sqrt").normalize().to_bytes();
BigUint::from_be_bytes(&result_bytes)
}

#[cfg(test)]
Expand All @@ -118,7 +118,7 @@ mod tests {
use rand::thread_rng;

#[test]
fn test_secp256k_sqrt() {
fn test_secp256k1_sqrt() {
let mut rng = thread_rng();
for _ in 0..10 {
// Check that sqrt(x^2)^2 == x^2
Expand Down
Loading
Loading