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 impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
15 impl_binops_multiplicative_mixed, new_curve_impl,
16 secp256k1::{Fp, Fq},
17 Coordinates, CurveAffine, CurveExt,
18};
19
20impl group::cofactor::CofactorGroup for Secp256k1 {
21 type Subgroup = Secp256k1;
22
23 fn clear_cofactor(&self) -> Self {
24 *self
25 }
26
27 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
28 CtOption::new(self, 1.into())
29 }
30
31 fn is_torsion_free(&self) -> Choice {
32 1.into()
33 }
34}
35
36const SECP_GENERATOR_X: Fp = Fp::from_raw([
38 0x59F2815B16F81798,
39 0x029BFCDB2DCE28D9,
40 0x55A06295CE870B07,
41 0x79BE667EF9DCBBAC,
42]);
43const SECP_GENERATOR_Y: Fp = Fp::from_raw([
44 0x9C47D08FFB10D4B8,
45 0xFD17B448A6855419,
46 0x5DA4FBFC0E1108A8,
47 0x483ADA7726A3C465,
48]);
49
50const SECP_A: Fp = Fp::from_raw([0, 0, 0, 0]);
51const SECP_B: Fp = Fp::from_raw([7, 0, 0, 0]);
52
53new_curve_impl!(
54 (pub),
55 Secp256k1,
56 Secp256k1Affine,
57 Fp,
58 Fq,
59 (SECP_GENERATOR_X,SECP_GENERATOR_Y),
60 SECP_A,
61 SECP_B,
62 "secp256k1",
63 |domain_prefix| hash_to_curve(domain_prefix, hash_to_curve_suite(b"secp256k1_XMD:SHA-256_SSWU_RO_")),
64 crate::serde::CompressedFlagConfig::Extra,
65 standard_sign
66);
67
68fn hash_to_curve_suite(domain: &[u8]) -> crate::hash_to_curve::Suite<Secp256k1, sha2::Sha256, 48> {
69 const SSWU_Z: Fp = Fp::from_raw([
72 0xfffffffefffffc24,
73 0xffffffffffffffff,
74 0xffffffffffffffff,
75 0xffffffffffffffff,
76 ]);
77
78 pub const ISO_SECP_A: Fp = Fp::from_raw([
83 0x405447c01a444533,
84 0xe953d363cb6f0e5d,
85 0xa08a5558f0f5d272,
86 0x3f8731abdd661adc,
87 ]);
88
89 pub const ISO_SECP_B: Fp = Fp::from_raw([1771, 0, 0, 0]);
90
91 let iso_map = crate::hash_to_curve::Iso {
92 a: ISO_SECP_A,
93 b: ISO_SECP_B,
94 map: Box::new(iso_map),
95 };
96
97 crate::hash_to_curve::Suite::new(domain, SSWU_Z, crate::hash_to_curve::Method::SSWU(iso_map))
98}
99
100#[allow(clippy::type_complexity)]
101pub(crate) fn hash_to_curve<'a>(
102 domain_prefix: &'a str,
103 suite: crate::hash_to_curve::Suite<Secp256k1, sha2::Sha256, 48>,
104) -> Box<dyn Fn(&[u8]) -> Secp256k1 + 'a> {
105 Box::new(move |message| suite.hash_to_curve(domain_prefix, message))
106}
107
108pub(crate) fn iso_map(x: Fp, y: Fp, z: Fp) -> Secp256k1 {
111 const K: [[Fp; 4]; 5] = [
113 [Fp::ZERO; 4],
114 [
115 Fp::from_raw([
116 0x8e38e38daaaaa8c7,
117 0x38e38e38e38e38e3,
118 0xe38e38e38e38e38e,
119 0x8e38e38e38e38e38,
120 ]),
121 Fp::from_raw([
122 0xdfff1044f17c6581,
123 0xd595d2fc0bf63b92,
124 0xb9f315cea7fd44c5,
125 0x7d3d4c80bc321d5,
126 ]),
127 Fp::from_raw([
128 0x4ecbd0b53d9dd262,
129 0xe4506144037c4031,
130 0xe2a413deca25caec,
131 0x534c328d23f234e6,
132 ]),
133 Fp::from_raw([
134 0x8e38e38daaaaa88c,
135 0x38e38e38e38e38e3,
136 0xe38e38e38e38e38e,
137 0x8e38e38e38e38e38,
138 ]),
139 ],
140 [
141 Fp::from_raw([
142 0x9fe6b745781eb49b,
143 0x86cd409542f8487d,
144 0x9ca34ccbb7b640dd,
145 0xd35771193d94918a,
146 ]),
147 Fp::from_raw([
148 0xc52a56612a8c6d14,
149 0x06d36b641f5e41bb,
150 0xf7c4b2d51b542254,
151 0xedadc6f64383dc1d,
152 ]),
153 Fp::ZERO,
154 Fp::ZERO,
155 ],
156 [
157 Fp::from_raw([
158 0xa12f684b8e38e23c,
159 0x2f684bda12f684bd,
160 0x684bda12f684bda1,
161 0x4bda12f684bda12f,
162 ]),
163 Fp::from_raw([
164 0xdffc90fc201d71a3,
165 0x647ab046d686da6f,
166 0xa9d0a54b12a0a6d5,
167 0xc75e0c32d5cb7c0f,
168 ]),
169 Fp::from_raw([
170 0xa765e85a9ecee931,
171 0x722830a201be2018,
172 0x715209ef6512e576,
173 0x29a6194691f91a73,
174 ]),
175 Fp::from_raw([
176 0x84bda12f38e38d84,
177 0xbda12f684bda12f6,
178 0xa12f684bda12f684,
179 0x2f684bda12f684bd,
180 ]),
181 ],
182 [
183 Fp::from_raw([
184 0xfffffffefffff93b,
185 0xffffffffffffffff,
186 0xffffffffffffffff,
187 0xffffffffffffffff,
188 ]),
189 Fp::from_raw([
190 0xdfb425d2685c2573,
191 0x9467c1bfc8e8d978,
192 0xd5e9e6632722c298,
193 0x7a06534bb8bdb49f,
194 ]),
195 Fp::from_raw([
196 0xa7bf8192bfd2a76f,
197 0x0a3d21162f0d6299,
198 0xf3a70c3fa8fe337e,
199 0x6484aa716545ca2c,
200 ]),
201 Fp::ZERO,
202 ],
203 ];
204
205 let z2 = z.square();
206 let z3 = z2 * z;
207
208 let x_num = ((K[1][3] * x + K[1][2] * z) * x + K[1][1] * z2) * x + K[1][0] * z3;
211 let x_den = (z * x + K[2][1] * z2) * x + K[2][0] * z3;
212
213 let y_num = (((K[3][3] * x + K[3][2] * z) * x + K[3][1] * z2) * x + K[3][0] * z3) * y;
214 let y_den = (((x + K[4][2] * z) * x + K[4][1] * z2) * x + K[4][0] * z3) * z;
215
216 let z = x_den * y_den;
217 let x = x_num * y_den;
218 let y = y_num * x_den;
219
220 Secp256k1 { x, y, z }
221}
222
223#[cfg(test)]
224mod test {
225 use group::UncompressedEncoding;
226 use rand_core::OsRng;
227
228 use super::*;
229 use crate::{serde::SerdeObject, tests::curve::TestH2C};
230
231 crate::curve_testing_suite!(Secp256k1);
232 crate::curve_testing_suite!(Secp256k1, "endo_consistency");
233 crate::curve_testing_suite!(Secp256k1, "ecdsa_example");
234 crate::curve_testing_suite!(
235 Secp256k1,
236 "constants",
237 Fp::MODULUS,
238 SECP_A,
239 SECP_B,
240 SECP_GENERATOR_X,
241 SECP_GENERATOR_Y,
242 Fq::MODULUS
243 );
244
245 #[test]
246 fn test_hash_to_curve() {
247 [
250 TestH2C::<Secp256k1Affine>::new(
251 b"",
252 crate::tests::point_from_hex(
253 "c1cae290e291aee617ebaef1be6d73861479c48b841eaba9b7b5852ddfeb1346",
254 "64fa678e07ae116126f08b022a94af6de15985c996c3a91b64c406a960e51067",
255 ),
256 ),
257 TestH2C::<Secp256k1Affine>::new(
258 b"abc",
259 crate::tests::point_from_hex(
260 "3377e01eab42db296b512293120c6cee72b6ecf9f9205760bd9ff11fb3cb2c4b",
261 "7f95890f33efebd1044d382a01b1bee0900fb6116f94688d487c6c7b9c8371f6",
262 ),
263 ),
264 TestH2C::<Secp256k1Affine>::new(
265 b"abcdef0123456789",
266 crate::tests::point_from_hex(
267 "bac54083f293f1fe08e4a70137260aa90783a5cb84d3f35848b324d0674b0e3a",
268 "4436476085d4c3c4508b60fcf4389c40176adce756b398bdee27bca19758d828",
269 ),
270 ),
271 TestH2C::<Secp256k1Affine>::new(
272 b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
273 crate::tests::point_from_hex(
274 "e2167bc785333a37aa562f021f1e881defb853839babf52a7f72b102e41890e9",
275 "f2401dd95cc35867ffed4f367cd564763719fbc6a53e969fb8496a1e6685d873",
276 ),
277 ), TestH2C::<Secp256k1Affine>::new(
279 b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
280 crate::tests::point_from_hex(
281 "e3c8d35aaaf0b9b647e88a0a0a7ee5d5bed5ad38238152e4e6fd8c1f8cb7c998",
282 "8446eeb6181bf12f56a9d24e262221cc2f0c4725c7e3803024b5888ee5823aa6",
283 ),
284 ),
285 ].iter().for_each(|test| {
286 test.run("QUUX-V01-CS02-with-");
287 });
288 }
289}