halo2curves_axiom/grumpkin/
curve.rs
1use crate::arithmetic::mul_512;
2use crate::arithmetic::sbb;
3use crate::arithmetic::EndoParameters;
4use crate::arithmetic::{CurveAffineExt, CurveEndo};
5use crate::ff::WithSmallOrderMulGroup;
6use crate::ff::{Field, PrimeField};
7use crate::group::Curve;
8use crate::group::{prime::PrimeCurveAffine, Group, GroupEncoding};
9use crate::grumpkin::Fq;
10use crate::grumpkin::Fr;
11use crate::hash_to_curve::svdw_hash_to_curve;
12use crate::{
13 endo, impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
14 impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
15 new_curve_impl,
16};
17use crate::{Coordinates, CurveAffine, CurveExt};
18use core::cmp;
19use core::fmt::Debug;
20use core::iter::Sum;
21use core::ops::{Add, Mul, Neg, Sub};
22use rand::RngCore;
23use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
24
25#[cfg(feature = "derive_serde")]
26use serde::{Deserialize, Serialize};
27
28new_curve_impl!(
29 (pub),
30 G1,
31 G1Affine,
32 false,
33 Fq,
34 Fr,
35 (G1_GENERATOR_X, G1_GENERATOR_Y),
36 G1_A,
37 G1_B,
38 "grumpkin_g1",
39 |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z),
40);
41
42const G1_GENERATOR_X: Fq = Fq::one();
45const G1_GENERATOR_Y: Fq = Fq([
46 0x11b2dff1448c41d8,
47 0x23d3446f21c77dc3,
48 0xaa7b8cf435dfafbb,
49 0x14b34cf69dc25d68,
50]);
51const G1_A: Fq = Fq::zero();
52const G1_B: Fq = Fq([
53 0xdd7056026000005a,
54 0x223fa97acb319311,
55 0xcc388229877910c0,
56 0x034394632b724eaa,
57]);
58
59const ENDO_PARAMS_GRUMPKIN: EndoParameters = EndoParameters {
64 gamma1: [0xd91d232ec7e0b3d2, 0x2, 0, 0],
65 gamma2: [0x5398fd0300ff655f, 0x4ccef014a773d2d2, 0x02, 0],
66 b1: [0x89d3256894d213e2, 0, 0, 0],
67 b2: [0x0be4e1541221250b, 0x6f4d8248eeb859fd, 0, 0],
68};
69
70endo!(G1, Fr, ENDO_PARAMS_GRUMPKIN);
71
72impl group::cofactor::CofactorGroup for G1 {
73 type Subgroup = G1;
74
75 fn clear_cofactor(&self) -> Self {
76 *self
77 }
78
79 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
80 CtOption::new(self, 1.into())
81 }
82
83 fn is_torsion_free(&self) -> Choice {
84 1.into()
85 }
86}
87
88impl G1 {
89 const SVDW_Z: Fq = Fq::ONE;
90}
91
92#[cfg(test)]
93mod tests {
94 use crate::arithmetic::CurveEndo;
95 use crate::grumpkin::{Fr, G1};
96 use crate::CurveExt;
97 use ff::{Field, PrimeField, WithSmallOrderMulGroup};
98 use rand_core::OsRng;
99
100 #[test]
101 fn test_hash_to_curve() {
102 crate::tests::curve::hash_to_curve_test::<G1>();
103 }
104
105 #[test]
106 fn test_curve() {
107 crate::tests::curve::curve_tests::<G1>();
108 }
109
110 #[test]
111 fn test_endo() {
112 let z_impl = Fr::ZETA;
113 let z_other = Fr::from_raw([
114 0xe4bd44e5607cfd48,
115 0xc28f069fbb966e3d,
116 0x5e6dd9e7e0acccb0,
117 0x30644e72e131a029,
118 ]);
119
120 assert_eq!(z_impl * z_impl + z_impl, -Fr::ONE);
121 assert_eq!(z_other * z_other + z_other, -Fr::ONE);
122
123 let g = G1::generator();
124 assert_eq!(g * Fr::ZETA, g.endo());
125
126 for _ in 0..100000 {
127 let k = Fr::random(OsRng);
128 let (k1, k1_neg, k2, k2_neg) = G1::decompose_scalar(&k);
129 if k1_neg & k2_neg {
130 assert_eq!(k, -Fr::from_u128(k1) + Fr::ZETA * Fr::from_u128(k2))
131 } else if k1_neg {
132 assert_eq!(k, -Fr::from_u128(k1) - Fr::ZETA * Fr::from_u128(k2))
133 } else if k2_neg {
134 assert_eq!(k, Fr::from_u128(k1) + Fr::ZETA * Fr::from_u128(k2))
135 } else {
136 assert_eq!(k, Fr::from_u128(k1) - Fr::ZETA * Fr::from_u128(k2))
137 }
138 }
139 }
140
141 #[test]
142 fn test_serialization() {
143 crate::tests::curve::random_serialization_test::<G1>();
144 #[cfg(feature = "derive_serde")]
145 crate::tests::curve::random_serde_test::<G1>();
146 }
147}