halo2curves_axiom/secp256r1/
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::simple_svdw_hash_to_curve;
5use crate::secp256r1::Fp;
6use crate::secp256r1::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 Secp256r1 {
19 type Subgroup = Secp256r1;
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
34const SECP_GENERATOR_X: Fp = Fp::from_raw([
36 0xF4A13945D898C296,
37 0x77037D812DEB33A0,
38 0xF8BCE6E563A440F2,
39 0x6B17D1F2E12C4247,
40]);
41
42const SECP_GENERATOR_Y: Fp = Fp::from_raw([
43 0xCBB6406837BF51F5,
44 0x2BCE33576B315ECE,
45 0x8EE7EB4A7C0F9E16,
46 0x4FE342E2FE1A7F9B,
47]);
48
49const SECP_A: Fp = Fp::from_raw([
50 0xFFFFFFFFFFFFFFFC,
51 0x00000000FFFFFFFF,
52 0x0000000000000000,
53 0xFFFFFFFF00000001,
54]);
55const SECP_B: Fp = Fp::from_raw([
56 0x3BCE3C3E27D2604B,
57 0x651D06B0CC53B0F6,
58 0xB3EBBD55769886BC,
59 0x5AC635D8AA3A93E7,
60]);
61
62use crate::{
63 impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
64 impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
65 new_curve_impl,
66};
67
68new_curve_impl!(
69 (pub),
70 Secp256r1,
71 Secp256r1Affine,
72 true,
73 Fp,
74 Fq,
75 (SECP_GENERATOR_X,SECP_GENERATOR_Y),
76 SECP_A,
77 SECP_B,
78 "secp256r1",
79 |curve_id, domain_prefix| simple_svdw_hash_to_curve(curve_id, domain_prefix, Secp256r1::SSVDW_Z),
80);
81
82impl Secp256r1 {
83 const SSVDW_Z: Fp = Fp::from_raw([
87 0xfffffffffffffff5,
88 0x00000000ffffffff,
89 0x0000000000000000,
90 0xffffffff00000001,
91 ]);
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 use crate::group::Curve;
98 use crate::secp256r1::{Fp, Fq, Secp256r1};
99 use ff::FromUniformBytes;
100 use rand_core::OsRng;
101
102 #[test]
103 fn test_hash_to_curve() {
104 crate::tests::curve::hash_to_curve_test::<Secp256r1>();
105 }
106
107 #[test]
108 fn test_curve() {
109 crate::tests::curve::curve_tests::<Secp256r1>();
110 }
111
112 #[test]
113 fn test_serialization() {
114 crate::tests::curve::random_serialization_test::<Secp256r1>();
115 #[cfg(feature = "derive_serde")]
116 crate::tests::curve::random_serde_test::<Secp256r1>();
117 }
118
119 #[test]
120 fn ecdsa_example() {
121 fn mod_n(x: Fp) -> Fq {
122 let mut x_repr = [0u8; 32];
123 x_repr.copy_from_slice(x.to_repr().as_ref());
124 let mut x_bytes = [0u8; 64];
125 x_bytes[..32].copy_from_slice(&x_repr[..]);
126 Fq::from_uniform_bytes(&x_bytes)
127 }
128
129 let g = Secp256r1::generator();
130
131 for _ in 0..1000 {
132 let sk = Fq::random(OsRng);
134 let pk = (g * sk).to_affine();
135
136 let msg_hash = Fq::random(OsRng);
139
140 let (r, s) = {
141 let k = Fq::random(OsRng);
143 let k_inv = k.invert().unwrap();
144
145 let r_point = (g * k).to_affine().coordinates().unwrap();
147 let x = r_point.x();
148 let r = mod_n(*x);
149
150 let s = k_inv * (msg_hash + (r * sk));
152
153 (r, s)
154 };
155
156 {
157 let s_inv = s.invert().unwrap();
159 let u_1 = msg_hash * s_inv;
160 let u_2 = r * s_inv;
161
162 let v_1 = g * u_1;
163 let v_2 = pk * u_2;
164
165 let r_point = (v_1 + v_2).to_affine().coordinates().unwrap();
166 let x_candidate = r_point.x();
167 let r_candidate = mod_n(*x_candidate);
168
169 assert_eq!(r, r_candidate);
170 }
171 }
172 }
173}