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
42// Parameters in montgomery form taken from
43// https://github.com/AztecProtocol/barretenberg/blob/97ccf76c42db581a8b8f8bfbcffe8ca015a3dd22/cpp/src/barretenberg/ecc/curves/grumpkin/grumpkin.hpp#L14
44const 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
59// Generated using https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/utils.go
60// with `bn256::Fq::ZETA`
61// See https://github.com/demining/Endomorphism-Secp256k1/blob/main/README.md
62// to have more details about the endomorphism.
63const 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}