halo2curves_axiom/secp256k1/
curve.rs

1use crate::ff::WithSmallOrderMulGroup;
2use crate::ff::{Field, PrimeField};
3use crate::group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding};
4use crate::hash_to_curve::svdw_hash_to_curve;
5use crate::secp256k1::Fp;
6use crate::secp256k1::Fq;
7use crate::{Coordinates, CurveAffine, CurveAffineExt, CurveExt};
8use core::cmp;
9use core::fmt::Debug;
10use core::iter::Sum;
11use core::ops::{Add, Mul, Neg, Sub};
12use rand::RngCore;
13use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
14
15#[cfg(feature = "derive_serde")]
16use serde::{Deserialize, Serialize};
17
18impl group::cofactor::CofactorGroup for Secp256k1 {
19    type Subgroup = Secp256k1;
20
21    fn clear_cofactor(&self) -> Self {
22        *self
23    }
24
25    fn into_subgroup(self) -> CtOption<Self::Subgroup> {
26        CtOption::new(self, 1.into())
27    }
28
29    fn is_torsion_free(&self) -> Choice {
30        1.into()
31    }
32}
33
34// Reference: https://neuromancer.sk/std/secg/secp256k1
35const SECP_GENERATOR_X: Fp = Fp::from_raw([
36    0x59F2815B16F81798,
37    0x029BFCDB2DCE28D9,
38    0x55A06295CE870B07,
39    0x79BE667EF9DCBBAC,
40]);
41const SECP_GENERATOR_Y: Fp = Fp::from_raw([
42    0x9C47D08FFB10D4B8,
43    0xFD17B448A6855419,
44    0x5DA4FBFC0E1108A8,
45    0x483ADA7726A3C465,
46]);
47
48const SECP_A: Fp = Fp::from_raw([0, 0, 0, 0]);
49const SECP_B: Fp = Fp::from_raw([7, 0, 0, 0]);
50
51use crate::{
52    impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
53    impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
54    new_curve_impl,
55};
56
57new_curve_impl!(
58    (pub),
59    Secp256k1,
60    Secp256k1Affine,
61    true,
62    Fp,
63    Fq,
64    (SECP_GENERATOR_X,SECP_GENERATOR_Y),
65    SECP_A,
66    SECP_B,
67    "secp256k1",
68    |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, Secp256k1::SVDW_Z),
69);
70
71impl Secp256k1 {
72    const SVDW_Z: Fp = Fp::ONE;
73}
74
75#[test]
76fn test_curve() {
77    crate::tests::curve::curve_tests::<Secp256k1>();
78}
79
80#[test]
81fn test_hash_to_curve() {
82    crate::tests::curve::hash_to_curve_test::<Secp256k1>();
83}
84
85#[test]
86fn test_serialization() {
87    crate::tests::curve::random_serialization_test::<Secp256k1>();
88    #[cfg(feature = "derive_serde")]
89    crate::tests::curve::random_serde_test::<Secp256k1>();
90}
91
92#[test]
93fn test_endo_consistency() {
94    let g = Secp256k1::generator();
95    assert_eq!(g * Fq::ZETA, g.endo());
96}
97
98#[test]
99fn ecdsa_example() {
100    use crate::group::Curve;
101    use crate::CurveAffine;
102    use ff::FromUniformBytes;
103    use rand_core::OsRng;
104
105    fn mod_n(x: Fp) -> Fq {
106        let mut x_repr = [0u8; 32];
107        x_repr.copy_from_slice(x.to_repr().as_ref());
108        let mut x_bytes = [0u8; 64];
109        x_bytes[..32].copy_from_slice(&x_repr[..]);
110        Fq::from_uniform_bytes(&x_bytes)
111    }
112
113    let g = Secp256k1::generator();
114
115    for _ in 0..1000 {
116        // Generate a key pair
117        let sk = Fq::random(OsRng);
118        let pk = (g * sk).to_affine();
119
120        // Generate a valid signature
121        // Suppose `m_hash` is the message hash
122        let msg_hash = Fq::random(OsRng);
123
124        let (r, s) = {
125            // Draw arandomness
126            let k = Fq::random(OsRng);
127            let k_inv = k.invert().unwrap();
128
129            // Calculate `r`
130            let r_point = (g * k).to_affine().coordinates().unwrap();
131            let x = r_point.x();
132            let r = mod_n(*x);
133
134            // Calculate `s`
135            let s = k_inv * (msg_hash + (r * sk));
136
137            (r, s)
138        };
139
140        {
141            // Verify
142            let s_inv = s.invert().unwrap();
143            let u_1 = msg_hash * s_inv;
144            let u_2 = r * s_inv;
145
146            let v_1 = g * u_1;
147            let v_2 = pk * u_2;
148
149            let r_point = (v_1 + v_2).to_affine().coordinates().unwrap();
150            let x_candidate = r_point.x();
151            let r_candidate = mod_n(*x_candidate);
152
153            assert_eq!(r, r_candidate);
154        }
155    }
156}