1use core::{
2 cmp,
3 fmt::Debug,
4 iter::Sum,
5 ops::{Add, Mul, Neg, Sub},
6};
7
8use group::cofactor::CofactorGroup;
9use rand::RngCore;
10use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
11
12use super::{fp::Fp, fp2::Fp2, fq::Fq};
13use crate::{
14 ff::{Field, PrimeField, WithSmallOrderMulGroup},
15 group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding},
16 impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
17 impl_binops_multiplicative_mixed, new_curve_impl, Coordinates, CurveAffine, CurveExt,
18};
19
20const G1_GENERATOR_X: Fp = Fp::from_raw([
21 0x9ffffcd2ffffffff,
22 0xa2a7e8c30006b945,
23 0xe4a7a5fe8fadffd6,
24 0x443f9a5cda8a6c7b,
25 0xa803ca76f439266f,
26 0x0130e0000d7f70e4,
27 0x2400000000002400,
28]);
29const G1_GENERATOR_Y: Fp = Fp::from_raw([0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
30
31const PLUTO_A: Fp = Fp::ZERO;
32const PLUTO_B: Fp = Fp::from_raw([0x39, 0, 0, 0, 0, 0, 0]);
33
34const ERIS_GENERATOR_X: Fq = Fq::from_raw([
35 0x1ffffcd2ffffffff,
36 0x9ca7e85d60050af4,
37 0xe4a775fe8e177fd6,
38 0x443f9a5c7a8a6c7b,
39 0xa803ca76f439266f,
40 0x0130e0000d7f70e4,
41 0x2400000000002400,
42]);
43const ERIS_GENERATOR_Y: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
44
45const ERIS_A: Fq = Fq::ZERO;
46const ERIS_B: Fq = Fq::from_raw([0x39, 0, 0, 0, 0, 0, 0]);
47
48const G2_GENERATOR_X: Fp2 = Fp2 {
49 c0: Fp::from_raw([
51 0x4f2b5fe6556f9066,
52 0x9cfc86dd865f07d6,
53 0x23c9e276a4ebe755,
54 0x7ca972bfb93722e2,
55 0xee935948b84498b2,
56 0xd815d0e9bd54b845,
57 0x13576c81faf3a13f,
58 ]),
59
60 c1: Fp::from_raw([
62 0xfe7c781a8fd7bf21,
63 0xb9b3dff01bbe8d63,
64 0xaeb383298fdf5847,
65 0x3029f2d201554727,
66 0x55243d011699b739,
67 0x5e5092f9380f44f5,
68 0x142164cb875db046,
69 ]),
70};
71const G2_GENERATOR_Y: Fp2 = Fp2 {
72 c0: Fp::from_raw([
74 0xcd1b78ad106ab9fe,
75 0xe78574aca67b3898,
76 0xeb471c004db774bf,
77 0xa4dc17d7dace3f32,
78 0x42fdbb92e64ba85a,
79 0x58e88d4df1e7418c,
80 0x2239f7408ead478c,
81 ]),
82
83 c1: Fp::from_raw([
85 0xd49e3c080e6d945d,
86 0x539ef82a731fb88e,
87 0xc697b4e10bbcd9e0,
88 0x9ca65d97eb28fc9f,
89 0xeca714555bbe4f07,
90 0xdbb53dfd7caf450a,
91 0x1260b04d51136590,
92 ]),
93};
94
95const TRITON_A: Fp2 = Fp2::ZERO;
96
97const TRITON_B: Fp2 = Fp2 {
99 c0: Fp::from_raw([0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
100 c1: Fp::ONE,
101};
102
103impl CofactorGroup for G1 {
104 type Subgroup = G1;
105
106 fn clear_cofactor(&self) -> Self {
107 *self
108 }
109
110 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
111 CtOption::new(self, 1.into())
112 }
113
114 fn is_torsion_free(&self) -> Choice {
115 1.into()
116 }
117}
118
119new_curve_impl!(
120 (pub),
121 G1,
122 G1Affine,
123 Fp,
124 Fq,
125 (G1_GENERATOR_X,G1_GENERATOR_Y),
126 PLUTO_A,
127 PLUTO_B,
128 "pluto",
129 |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, G1::default_hash_to_curve_suite()),
130 crate::serde::CompressedFlagConfig::TwoSpare,
131 standard_sign
132);
133
134impl group::cofactor::CofactorGroup for Eris {
135 type Subgroup = Eris;
136
137 fn clear_cofactor(&self) -> Self {
138 *self
139 }
140
141 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
142 CtOption::new(self, 1.into())
143 }
144
145 fn is_torsion_free(&self) -> Choice {
146 1.into()
147 }
148}
149
150impl G1 {
151 const SVDW_Z: Fp = Fp::ONE;
154
155 fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite<Self, sha2::Sha256, 72> {
156 crate::hash_to_curve::Suite::<Self, sha2::Sha256, 72>::new(
157 b"pluto_XMD:SHA-256_SVDW_RO_",
158 Self::SVDW_Z,
159 crate::hash_to_curve::Method::SVDW,
160 )
161 }
162}
163
164new_curve_impl!(
165 (pub),
166 Eris,
167 ErisAffine,
168 Fq,
169 Fp,
170 (ERIS_GENERATOR_X,ERIS_GENERATOR_Y),
171 ERIS_A,
172 ERIS_B,
173 "eris",
174 |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, Eris::default_hash_to_curve_suite()),
175 crate::serde::CompressedFlagConfig::TwoSpare,
176 standard_sign
177);
178
179impl CofactorGroup for G2 {
180 type Subgroup = G2;
181
182 fn clear_cofactor(&self) -> Self {
183 let e: [u8; 56] = [
186 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x30, 0xe0, 0x00, 0x0d, 0x7f,
187 0x70, 0xe4, 0xa8, 0x03, 0xca, 0x76, 0xf4, 0x39, 0x26, 0x6f, 0x44, 0x3f, 0x9a, 0x5d,
188 0x3a, 0x8a, 0x6c, 0x7b, 0xe4, 0xa7, 0xd5, 0xfe, 0x91, 0x44, 0x7f, 0xd6, 0xa8, 0xa7,
189 0xe9, 0x28, 0xa0, 0x08, 0x67, 0x97, 0x1f, 0xff, 0xfc, 0xd3, 0x00, 0x00, 0x00, 0x01,
190 ];
191
192 let mut acc = G2::identity();
194 for bit in e
195 .iter()
196 .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
197 .skip(1)
198 {
199 acc = acc.double();
200 acc = G2::conditional_select(&acc, &(acc + self), bit);
201 }
202 acc
203 }
204
205 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
206 CtOption::new(self.clear_cofactor(), 1.into())
208 }
209
210 fn is_torsion_free(&self) -> Choice {
211 let e: [u8; 56] = [
213 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x30, 0xe0, 0x00, 0x0d, 0x7f,
214 0x70, 0xe4, 0xa8, 0x03, 0xca, 0x76, 0xf4, 0x39, 0x26, 0x6f, 0x44, 0x3f, 0x9a, 0x5c,
215 0x7a, 0x8a, 0x6c, 0x7b, 0xe4, 0xa7, 0x75, 0xfe, 0x8e, 0x17, 0x7f, 0xd6, 0x9c, 0xa7,
216 0xe8, 0x5d, 0x60, 0x05, 0x0a, 0xf4, 0x1f, 0xff, 0xfc, 0xd3, 0x00, 0x00, 0x00, 0x01,
217 ];
218 let mut acc = G2::identity();
220 for bit in e
221 .iter()
222 .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
223 .skip(1)
224 {
225 acc = acc.double();
226 acc = G2::conditional_select(&acc, &(acc + self), bit);
227 }
228 acc.is_identity()
229 }
230}
231
232impl Eris {
233 const SVDW_Z: Fq = Fq::ONE;
236
237 fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite<Self, sha2::Sha256, 72> {
238 crate::hash_to_curve::Suite::<Eris, sha2::Sha256, 72>::new(
239 b"eris_XMD:SHA-256_SVDW_RO_",
240 Self::SVDW_Z,
241 crate::hash_to_curve::Method::SVDW,
242 )
243 }
244}
245
246impl crate::serde::endian::EndianRepr for Fp2 {
247 const ENDIAN: crate::serde::endian::Endian = Fq::ENDIAN;
248
249 fn to_bytes(&self) -> Vec<u8> {
250 self.to_bytes().to_vec()
251 }
252
253 fn from_bytes(bytes: &[u8]) -> subtle::CtOption<Self> {
254 Fp2::from_bytes(bytes[..Fp2::SIZE].try_into().unwrap())
255 }
256}
257
258new_curve_impl!(
259 (pub),
260 G2,
261 G2Affine,
262 Fp2,
263 Fq,
264 (G2_GENERATOR_X,G2_GENERATOR_Y),
265 TRITON_A,
266 TRITON_B,
267 "triton",
268 |_| unimplemented!(),
269 crate::serde::CompressedFlagConfig::TwoSpare,
270 standard_sign
271);
272
273#[cfg(test)]
274mod test {
275 use group::UncompressedEncoding;
276 use rand_core::OsRng;
277
278 use super::*;
279 use crate::serde::SerdeObject;
280
281 crate::curve_testing_suite!(G2, "clear_cofactor");
282 crate::curve_testing_suite!(G1, Eris, G2);
283 crate::curve_testing_suite!(G1, Eris, "hash_to_curve");
284 crate::curve_testing_suite!(G1, Eris, "endo_consistency");
285 crate::curve_testing_suite!(
286 G1,
287 "constants",
288 Fp::MODULUS,
289 PLUTO_A,
290 PLUTO_B,
291 G1_GENERATOR_X,
292 G1_GENERATOR_Y,
293 Fq::MODULUS
294 );
295 crate::curve_testing_suite!(
296 Eris,
297 "constants",
298 Fq::MODULUS,
299 ERIS_A,
300 ERIS_B,
301 ERIS_GENERATOR_X,
302 ERIS_GENERATOR_Y,
303 Fp::MODULUS
304 );
305 crate::curve_testing_suite!(
306 G2,
307 "constants",
308 Fp2::MODULUS,
309 TRITON_A,
310 TRITON_B,
311 G2_GENERATOR_X,
312 G2_GENERATOR_Y,
313 Fq::MODULUS
314 );
315}