halo2curves/secp256r1/
curve.rs

1use core::{
2    cmp,
3    fmt::Debug,
4    iter::Sum,
5    ops::{Add, Mul, Neg, Sub},
6};
7
8use rand::RngCore;
9use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
10
11use crate::{
12    ff::{Field, PrimeField, WithSmallOrderMulGroup},
13    group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding},
14    secp256r1::{Fp, Fq},
15    Coordinates, CurveAffine, CurveExt,
16};
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
34// Reference: https://neuromancer.sk/std/secg/secp256r1
35const 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_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
64    impl_binops_multiplicative_mixed, new_curve_impl,
65};
66
67new_curve_impl!(
68    (pub),
69    Secp256r1,
70    Secp256r1Affine,
71    Fp,
72    Fq,
73    (SECP_GENERATOR_X,SECP_GENERATOR_Y),
74    SECP_A,
75    SECP_B,
76    "secp256r1",
77    |domain_prefix| hash_to_curve(domain_prefix, hash_to_curve_suite(b"P256_XMD:SHA-256_SSWU_RO_")),
78    crate::serde::CompressedFlagConfig::Extra,
79    standard_sign
80);
81
82fn hash_to_curve_suite(domain: &[u8]) -> crate::hash_to_curve::Suite<Secp256r1, sha2::Sha256, 48> {
83    // Optimal Z with: <https://datatracker.ietf.org/doc/html/rfc9380#sswu-z-code>
84    // 0xffffffff00000001000000000000000000000000fffffffffffffffffffffff5
85    // Z = -10 (reference: <https://www.rfc-editor.org/rfc/rfc9380.html#section-8.2>)
86    const SSWU_Z: Fp = Fp::from_raw([
87        0xfffffffffffffff5,
88        0x00000000ffffffff,
89        0x0000000000000000,
90        0xffffffff00000001,
91    ]);
92
93    let iso_map = crate::hash_to_curve::Iso {
94        a: Secp256r1::a(),
95        b: Secp256r1::b(),
96        map: Box::new(move |x, y, z| Secp256r1 { x, y, z }),
97    };
98
99    crate::hash_to_curve::Suite::new(domain, SSWU_Z, crate::hash_to_curve::Method::SSWU(iso_map))
100}
101
102#[allow(clippy::type_complexity)]
103pub(crate) fn hash_to_curve<'a>(
104    domain_prefix: &'a str,
105    suite: crate::hash_to_curve::Suite<Secp256r1, sha2::Sha256, 48>,
106) -> Box<dyn Fn(&[u8]) -> Secp256r1 + 'a> {
107    Box::new(move |message| suite.hash_to_curve(domain_prefix, message))
108}
109
110#[cfg(test)]
111mod test {
112    use group::UncompressedEncoding;
113    use rand_core::OsRng;
114
115    use super::*;
116    use crate::{serde::SerdeObject, tests::curve::TestH2C};
117    crate::curve_testing_suite!(Secp256r1);
118    crate::curve_testing_suite!(Secp256r1, "ecdsa_example");
119    crate::curve_testing_suite!(
120        Secp256r1,
121        "constants",
122        Fp::MODULUS,
123        SECP_A,
124        SECP_B,
125        SECP_GENERATOR_X,
126        SECP_GENERATOR_Y,
127        Fq::MODULUS
128    );
129
130    #[test]
131    fn test_hash_to_curve() {
132        // Test vectors are taken from
133        // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-p256_xmdsha-256_sswu_ro_
134        [
135            TestH2C::<Secp256r1Affine>::new(
136                b"",
137                crate::tests::point_from_hex(
138                    "2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91c44247d3e4",
139                    "8a7a74985cc5c776cdfe4b1f19884970453912e9d31528c060be9ab5c43e8415",
140                ),
141            ),
142            TestH2C::<Secp256r1Affine>::new(
143                b"abc",
144                crate::tests::point_from_hex(
145                    "0bb8b87485551aa43ed54f009230450b492fead5f1cc91658775dac4a3388a0f",
146                    "5c41b3d0731a27a7b14bc0bf0ccded2d8751f83493404c84a88e71ffd424212e",
147                ),
148            ),
149            TestH2C::<Secp256r1Affine>::new(
150                b"abcdef0123456789",
151                crate::tests::point_from_hex(
152                    "65038ac8f2b1def042a5df0b33b1f4eca6bff7cb0f9c6c1526811864e544ed80",
153                    "cad44d40a656e7aff4002a8de287abc8ae0482b5ae825822bb870d6df9b56ca3",
154                ),
155            ),
156            TestH2C::<Secp256r1Affine>::new(
157                b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
158                crate::tests::point_from_hex(
159                    "4be61ee205094282ba8a2042bcb48d88dfbb609301c49aa8b078533dc65a0b5d",
160                    "98f8df449a072c4721d241a3b1236d3caccba603f916ca680f4539d2bfb3c29e",
161                ),
162            ), //
163            TestH2C::<Secp256r1Affine>::new(
164                b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
165                crate::tests::point_from_hex(
166                    "457ae2981f70ca85d8e24c308b14db22f3e3862c5ea0f652ca38b5e49cd64bc5",
167                    "ecb9f0eadc9aeed232dabc53235368c1394c78de05dd96893eefa62b0f4757dc",
168                ),
169            ),
170        ].iter().for_each(|test| {
171            test.run("QUUX-V01-CS02-with-");
172        });
173    }
174}