openvm_ecc_guest/
k256.rs

1extern crate alloc;
2
3use core::ops::{Add, Neg};
4
5use hex_literal::hex;
6#[cfg(not(target_os = "zkvm"))]
7use lazy_static::lazy_static;
8#[cfg(not(target_os = "zkvm"))]
9use num_bigint::BigUint;
10use openvm_algebra_guest::{Field, IntMod};
11use openvm_algebra_moduli_macros::moduli_declare;
12use openvm_ecc_sw_macros::sw_declare;
13
14use super::group::{CyclicGroup, Group};
15use crate::weierstrass::{CachedMulTable, IntrinsicCurve};
16
17#[cfg(not(target_os = "zkvm"))]
18lazy_static! {
19    // The constants are taken from: https://en.bitcoin.it/wiki/Secp256k1
20    pub static ref SECP256K1_MODULUS: BigUint = BigUint::from_bytes_be(&hex!(
21        "FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F"
22    ));
23    pub static ref SECP256K1_ORDER: BigUint = BigUint::from_bytes_be(&hex!(
24        "FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141"
25    ));
26}
27
28pub const SECP256K1_NUM_LIMBS: usize = 32;
29pub const SECP256K1_LIMB_BITS: usize = 8;
30pub const SECP256K1_BLOCK_SIZE: usize = 32;
31const CURVE_B: Secp256k1Coord = Secp256k1Coord::from_const_bytes(seven_le());
32const fn seven_le() -> [u8; 32] {
33    let mut buf = [0u8; 32];
34    buf[0] = 7;
35    buf
36}
37
38moduli_declare! {
39    Secp256k1Coord { modulus = "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F" },
40    Secp256k1Scalar { modulus = "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141" },
41}
42
43sw_declare! {
44    Secp256k1Point { mod_type = Secp256k1Coord, b = CURVE_B },
45}
46
47impl Field for Secp256k1Coord {
48    const ZERO: Self = <Self as IntMod>::ZERO;
49    const ONE: Self = <Self as IntMod>::ONE;
50
51    type SelfRef<'a> = &'a Self;
52
53    fn double_assign(&mut self) {
54        IntMod::double_assign(self);
55    }
56
57    fn square_assign(&mut self) {
58        IntMod::square_assign(self);
59    }
60}
61
62impl CyclicGroup for Secp256k1Point {
63    // The constants are taken from: https://en.bitcoin.it/wiki/Secp256k1
64    const GENERATOR: Self = Secp256k1Point {
65        // from_const_bytes takes a little endian byte string
66        x: Secp256k1Coord::from_const_bytes(hex!(
67            "9817F8165B81F259D928CE2DDBFC9B02070B87CE9562A055ACBBDCF97E66BE79"
68        )),
69        y: Secp256k1Coord::from_const_bytes(hex!(
70            "B8D410FB8FD0479C195485A648B417FDA808110EFCFBA45D65C4A32677DA3A48"
71        )),
72    };
73    const NEG_GENERATOR: Self = Secp256k1Point {
74        x: Secp256k1Coord::from_const_bytes(hex!(
75            "9817F8165B81F259D928CE2DDBFC9B02070B87CE9562A055ACBBDCF97E66BE79"
76        )),
77        y: Secp256k1Coord::from_const_bytes(hex!(
78            "7727EF046F2FB863E6AB7A59B74BE80257F7EEF103045BA29A3B5CD98825C5B7"
79        )),
80    };
81}
82
83impl IntrinsicCurve for k256::Secp256k1 {
84    type Scalar = Secp256k1Scalar;
85    type Point = Secp256k1Point;
86
87    fn msm(coeffs: &[Self::Scalar], bases: &[Self::Point]) -> Self::Point
88    where
89        for<'a> &'a Self::Point: Add<&'a Self::Point, Output = Self::Point>,
90    {
91        // heuristic
92        if coeffs.len() < 25 {
93            let table = CachedMulTable::<Self>::new_with_prime_order(bases, 4);
94            table.windowed_mul(coeffs)
95        } else {
96            crate::msm(coeffs, bases)
97        }
98    }
99}