halo2curves_axiom/pluto_eris/
curve.rs

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    // 0x13576c81faf3a13fd815d0e9bd54b845ee935948b84498b27ca972bfb93722e223c9e276a4ebe7559cfc86dd865f07d64f2b5fe6556f9066
54    c0: Fp::from_raw([
55        0x4f2b5fe6556f9066,
56        0x9cfc86dd865f07d6,
57        0x23c9e276a4ebe755,
58        0x7ca972bfb93722e2,
59        0xee935948b84498b2,
60        0xd815d0e9bd54b845,
61        0x13576c81faf3a13f,
62    ]),
63
64    //0x142164cb875db0465e5092f9380f44f555243d011699b7393029f2d201554727aeb383298fdf5847b9b3dff01bbe8d63fe7c781a8fd7bf21
65    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    //0x2239f7408ead478c58e88d4df1e7418c42fdbb92e64ba85aa4dc17d7dace3f32eb471c004db774bfe78574aca67b3898cd1b78ad106ab9fe
77    c0: Fp::from_raw([
78        0xcd1b78ad106ab9fe,
79        0xe78574aca67b3898,
80        0xeb471c004db774bf,
81        0xa4dc17d7dace3f32,
82        0x42fdbb92e64ba85a,
83        0x58e88d4df1e7418c,
84        0x2239f7408ead478c,
85    ]),
86
87    // 0x1260b04d51136590dbb53dfd7caf450aeca714555bbe4f079ca65d97eb28fc9fc697b4e10bbcd9e0539ef82a731fb88ed49e3c080e6d945d
88    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
101// u + 3
102const 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    /// Constant Z for the Shallue-van de Woestijne map.
155    /// Computed using https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#svdw-z-code
156    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        // cofactor = 2*p - q
178        //0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5d3a8a6c7be4a7d5fe91447fd6a8a7e928a00867971ffffcd300000001
179        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        // self * TRITON_COFACTOR
187        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        // group order = p
205        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        // self * GROUP_ORDER;
212        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    /// Constant Z for the Shallue-van de Woestijne map.
227    /// Computed using https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.html#svdw-z-code
228    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}