1use super::fields::{fp::Fp, fp2::Fp2, fq::Fq};
2use crate::ff::WithSmallOrderMulGroup;
3use crate::ff::{Field, PrimeField};
4use crate::group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding};
5use crate::hash_to_curve::svdw_hash_to_curve;
6use crate::{Coordinates, CurveAffine, CurveAffineExt, CurveExt};
7use core::cmp;
8use core::fmt::Debug;
9use core::iter::Sum;
10use core::ops::{Add, Mul, Neg, Sub};
11use group::cofactor::CofactorGroup;
12use rand::RngCore;
13use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
14
15#[cfg(feature = "derive_serde")]
16use serde::{Deserialize, Serialize};
17
18use crate::{
19 impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
20 impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
21 new_curve_impl,
22};
23
24const G1_GENERATOR_X: Fp = Fp::from_raw([
25 0x9ffffcd2ffffffff,
26 0xa2a7e8c30006b945,
27 0xe4a7a5fe8fadffd6,
28 0x443f9a5cda8a6c7b,
29 0xa803ca76f439266f,
30 0x0130e0000d7f70e4,
31 0x2400000000002400,
32]);
33const G1_GENERATOR_Y: Fp = Fp::from_raw([0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
34
35const PLUTO_A: Fp = Fp::ZERO;
36const PLUTO_B: Fp = Fp::from_raw([0x39, 0, 0, 0, 0, 0, 0]);
37
38const ERIS_GENERATOR_X: Fq = Fq::from_raw([
39 0x1ffffcd2ffffffff,
40 0x9ca7e85d60050af4,
41 0xe4a775fe8e177fd6,
42 0x443f9a5c7a8a6c7b,
43 0xa803ca76f439266f,
44 0x0130e0000d7f70e4,
45 0x2400000000002400,
46]);
47const ERIS_GENERATOR_Y: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
48
49const ERIS_A: Fq = Fq::ZERO;
50const ERIS_B: Fq = Fq::from_raw([0x39, 0, 0, 0, 0, 0, 0]);
51
52const G2_GENERATOR_X: Fp2 = Fp2 {
53 c0: Fp::from_raw([
55 0x4f2b5fe6556f9066,
56 0x9cfc86dd865f07d6,
57 0x23c9e276a4ebe755,
58 0x7ca972bfb93722e2,
59 0xee935948b84498b2,
60 0xd815d0e9bd54b845,
61 0x13576c81faf3a13f,
62 ]),
63
64 c1: Fp::from_raw([
66 0xfe7c781a8fd7bf21,
67 0xb9b3dff01bbe8d63,
68 0xaeb383298fdf5847,
69 0x3029f2d201554727,
70 0x55243d011699b739,
71 0x5e5092f9380f44f5,
72 0x142164cb875db046,
73 ]),
74};
75const G2_GENERATOR_Y: Fp2 = Fp2 {
76 c0: Fp::from_raw([
78 0xcd1b78ad106ab9fe,
79 0xe78574aca67b3898,
80 0xeb471c004db774bf,
81 0xa4dc17d7dace3f32,
82 0x42fdbb92e64ba85a,
83 0x58e88d4df1e7418c,
84 0x2239f7408ead478c,
85 ]),
86
87 c1: Fp::from_raw([
89 0xd49e3c080e6d945d,
90 0x539ef82a731fb88e,
91 0xc697b4e10bbcd9e0,
92 0x9ca65d97eb28fc9f,
93 0xeca714555bbe4f07,
94 0xdbb53dfd7caf450a,
95 0x1260b04d51136590,
96 ]),
97};
98
99const TRITON_A: Fp2 = Fp2::ZERO;
100
101const TRITON_B: Fp2 = Fp2 {
103 c0: Fp::from_raw([0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
104 c1: Fp::ONE,
105};
106
107impl CofactorGroup for G1 {
108 type Subgroup = G1;
109
110 fn clear_cofactor(&self) -> Self {
111 *self
112 }
113
114 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
115 CtOption::new(self, 1.into())
116 }
117
118 fn is_torsion_free(&self) -> Choice {
119 1.into()
120 }
121}
122
123new_curve_impl!(
124 (pub),
125 G1,
126 G1Affine,
127 false,
128 Fp,
129 Fq,
130 (G1_GENERATOR_X,G1_GENERATOR_Y),
131 PLUTO_A,
132 PLUTO_B,
133 "pluto",
134 |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z),
135);
136
137impl group::cofactor::CofactorGroup for Eris {
138 type Subgroup = Eris;
139
140 fn clear_cofactor(&self) -> Self {
141 *self
142 }
143
144 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
145 CtOption::new(self, 1.into())
146 }
147
148 fn is_torsion_free(&self) -> Choice {
149 1.into()
150 }
151}
152
153impl G1 {
154 const SVDW_Z: Fp = Fp::ONE;
157}
158
159new_curve_impl!(
160 (pub),
161 Eris,
162 ErisAffine,
163 false,
164 Fq,
165 Fp,
166 (ERIS_GENERATOR_X,ERIS_GENERATOR_Y),
167 ERIS_A,
168 ERIS_B,
169 "eris",
170 |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, Eris::SVDW_Z),
171);
172
173impl CofactorGroup for G2 {
174 type Subgroup = G2;
175
176 fn clear_cofactor(&self) -> Self {
177 let e: [u8; 56] = [
180 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x30, 0xe0, 0x00, 0x0d, 0x7f,
181 0x70, 0xe4, 0xa8, 0x03, 0xca, 0x76, 0xf4, 0x39, 0x26, 0x6f, 0x44, 0x3f, 0x9a, 0x5d,
182 0x3a, 0x8a, 0x6c, 0x7b, 0xe4, 0xa7, 0xd5, 0xfe, 0x91, 0x44, 0x7f, 0xd6, 0xa8, 0xa7,
183 0xe9, 0x28, 0xa0, 0x08, 0x67, 0x97, 0x1f, 0xff, 0xfc, 0xd3, 0x00, 0x00, 0x00, 0x01,
184 ];
185
186 let mut acc = G2::identity();
188 for bit in e
189 .iter()
190 .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
191 .skip(1)
192 {
193 acc = acc.double();
194 acc = G2::conditional_select(&acc, &(acc + self), bit);
195 }
196 acc
197 }
198
199 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
200 CtOption::new(self.clear_cofactor(), 1.into())
201 }
202
203 fn is_torsion_free(&self) -> Choice {
204 let e: [u8; 56] = [
206 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x30, 0xe0, 0x00, 0x0d, 0x7f,
207 0x70, 0xe4, 0xa8, 0x03, 0xca, 0x76, 0xf4, 0x39, 0x26, 0x6f, 0x44, 0x3f, 0x9a, 0x5c,
208 0xda, 0x8a, 0x6c, 0x7b, 0xe4, 0xa7, 0xa5, 0xfe, 0x8f, 0xad, 0xff, 0xd6, 0xa2, 0xa7,
209 0xe8, 0xc3, 0x00, 0x06, 0xb9, 0x45, 0x9f, 0xff, 0xfc, 0xd3, 0x00, 0x00, 0x00, 0x01,
210 ];
211 let mut acc = G2::identity();
213 for bit in e
214 .iter()
215 .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
216 .skip(1)
217 {
218 acc = acc.double();
219 acc = G2::conditional_select(&acc, &(acc + self), bit);
220 }
221 acc.is_identity()
222 }
223}
224
225impl Eris {
226 const SVDW_Z: Fq = Fq::ONE;
229}
230
231new_curve_impl!(
232 (pub),
233 G2,
234 G2Affine,
235 false,
236 Fp2,
237 Fq,
238 (G2_GENERATOR_X,G2_GENERATOR_Y),
239 TRITON_A,
240 TRITON_B,
241 "triton",
242 |_, _| unimplemented!(),
243);
244
245#[test]
246fn test_curve_pluto() {
247 crate::tests::curve::curve_tests::<G1>();
248}
249#[test]
250fn test_curve_eris() {
251 crate::tests::curve::curve_tests::<Eris>();
252}
253#[test]
254fn test_curve_triton() {
255 crate::tests::curve::curve_tests::<G2>();
256}
257
258#[test]
259fn test_serialization() {
260 crate::tests::curve::random_serialization_test::<G1>();
261 crate::tests::curve::random_serialization_test::<Eris>();
262 crate::tests::curve::random_serialization_test::<G2>();
263 #[cfg(feature = "derive_serde")]
264 crate::tests::curve::random_serde_test::<G1>();
265 #[cfg(feature = "derive_serde")]
266 crate::tests::curve::random_serde_test::<Eris>();
267 #[cfg(feature = "derive_serde")]
268 crate::tests::curve::random_serde_test::<G2>();
269}
270
271#[test]
272fn test_hash_to_curve() {
273 crate::tests::curve::hash_to_curve_test::<G1>();
274 crate::tests::curve::hash_to_curve_test::<Eris>();
275}
276
277#[test]
278fn test_endo_consistency() {
279 let g = Eris::generator();
280 assert_eq!(g * Fp::ZETA, g.endo());
281
282 let g = G1::generator();
283 assert_eq!(g * Fq::ZETA, g.endo());
284
285 let g = G2::generator();
286 assert_eq!(g * Fq::ZETA, g.endo());
287}