airbender_crypto/bls12_381/curves/
g1.rs1use ark_ec::{
2 bls12,
3 bls12::Bls12Config,
4 hashing::curve_maps::wb::{IsogenyMap, WBConfig},
5 models::CurveConfig,
6 scalar_mul::glv::GLVConfig,
7 short_weierstrass::{Affine, SWCurveConfig},
8 AffineRepr, PrimeGroup,
9};
10use ark_ff::{AdditiveGroup, One, PrimeField, Zero};
11use ruint::aliases::U512;
12
13#[cfg(any(
14 all(target_arch = "riscv32", feature = "bigint_ops"),
15 test,
16 feature = "proving"
17))]
18use crate::ark_ff_delegation::{BigIntMacro as BigInt, MontFp};
19#[cfg(not(any(
20 all(target_arch = "riscv32", feature = "bigint_ops"),
21 test,
22 feature = "proving"
23)))]
24use ark_ff::{BigInt, MontFp};
25use ark_serialize::{Compress, SerializationError};
26use core::ops::Neg;
27
28use super::g1_swu_iso;
29use crate::{
30 bls12_381::{
31 util::{
32 read_g1_compressed, read_g1_uncompressed, serialize_fq, EncodingFlags,
33 G1_SERIALIZED_SIZE,
34 },
35 Fq, Fr,
36 },
37 glv_decomposition::GLVConfigNoAllocator,
38};
39
40pub type G1Affine = bls12::G1Affine<crate::bls12_381::curves::Config>;
41pub type G1Projective = bls12::G1Projective<crate::bls12_381::curves::Config>;
42
43#[derive(Clone, Default, PartialEq, Eq)]
44pub struct Config;
45
46impl CurveConfig for Config {
47 type BaseField = Fq;
48 type ScalarField = Fr;
49
50 const COFACTOR: &'static [u64] = &[0x8c00aaab0000aaab, 0x396c8c005555e156];
52
53 const COFACTOR_INV: Fr =
56 MontFp!("52435875175126190458656871551744051925719901746859129887267498875565241663483");
57}
58
59impl SWCurveConfig for Config {
60 const COEFF_A: Fq = Fq::ZERO;
62
63 const COEFF_B: Fq = MontFp!("4");
65
66 const GENERATOR: G1Affine = G1Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y);
68
69 #[inline(always)]
70 fn mul_by_a(_: Self::BaseField) -> Self::BaseField {
71 Self::BaseField::zero()
72 }
73
74 #[inline]
75 fn mul_projective(p: &G1Projective, scalar: &[u64]) -> G1Projective {
76 let s = Self::ScalarField::from_sign_and_limbs(true, scalar);
77 GLVConfig::glv_mul_projective(*p, s)
78 }
79
80 #[inline]
81 fn mul_affine(base: &Affine<Self>, scalar: &[u64]) -> G1Projective {
82 Self::mul_projective(&base.into_group(), scalar)
83 }
84
85 #[inline]
86 fn is_in_correct_subgroup_assuming_on_curve(p: &G1Affine) -> bool {
87 let x_times_p = p.mul_bigint(crate::bls12_381::curves::Config::X);
95 if x_times_p.eq(p) && !p.infinity {
96 return false;
97 }
98
99 let minus_x_squared_times_p = x_times_p
100 .mul_bigint(crate::bls12_381::curves::Config::X)
101 .neg();
102 let endomorphism_p = endomorphism(p);
103 minus_x_squared_times_p.eq(&endomorphism_p)
104 }
105
106 #[inline]
107 fn clear_cofactor(p: &G1Affine) -> G1Affine {
108 let h_eff = one_minus_x().into_bigint();
113 Config::mul_affine(&p, h_eff.as_ref()).into()
114 }
115
116 fn deserialize_with_mode<R: ark_serialize::Read>(
117 mut reader: R,
118 compress: ark_serialize::Compress,
119 validate: ark_serialize::Validate,
120 ) -> Result<Affine<Self>, ark_serialize::SerializationError> {
121 let p = if compress == ark_serialize::Compress::Yes {
122 read_g1_compressed(&mut reader)?
123 } else {
124 read_g1_uncompressed(&mut reader)?
125 };
126
127 if validate == ark_serialize::Validate::Yes && !p.is_in_correct_subgroup_assuming_on_curve()
128 {
129 return Err(SerializationError::InvalidData);
130 }
131 Ok(p)
132 }
133
134 fn serialize_with_mode<W: ark_serialize::Write>(
135 item: &Affine<Self>,
136 mut writer: W,
137 compress: ark_serialize::Compress,
138 ) -> Result<(), SerializationError> {
139 let encoding = EncodingFlags {
140 is_compressed: compress == ark_serialize::Compress::Yes,
141 is_infinity: item.is_zero(),
142 is_lexographically_largest: item.y > -item.y,
143 };
144 let mut p = *item;
145 if encoding.is_infinity {
146 p = G1Affine::zero();
147 }
148 let x_bytes = serialize_fq(p.x);
151 if encoding.is_compressed {
152 let mut bytes: [u8; G1_SERIALIZED_SIZE] = x_bytes;
153
154 encoding.encode_flags(&mut bytes);
155 writer.write_all(&bytes)?;
156 } else {
157 let mut bytes = [0u8; 2 * G1_SERIALIZED_SIZE];
158 bytes[0..G1_SERIALIZED_SIZE].copy_from_slice(&x_bytes[..]);
159 bytes[G1_SERIALIZED_SIZE..].copy_from_slice(&serialize_fq(p.y)[..]);
160
161 encoding.encode_flags(&mut bytes);
162 writer.write_all(&bytes)?;
163 };
164
165 Ok(())
166 }
167
168 fn serialized_size(compress: Compress) -> usize {
169 if compress == Compress::Yes {
170 G1_SERIALIZED_SIZE
171 } else {
172 G1_SERIALIZED_SIZE * 2
173 }
174 }
175}
176
177impl GLVConfig for Config {
178 const ENDO_COEFFS: &'static[Self::BaseField] = &[
179 MontFp!("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350")
180 ];
181
182 const LAMBDA: Self::ScalarField =
183 MontFp!("52435875175126190479447740508185965837461563690374988244538805122978187051009");
184
185 const SCALAR_DECOMP_COEFFS: [(bool, <Self::ScalarField as PrimeField>::BigInt); 4] = [
186 (true, BigInt!("228988810152649578064853576960394133504")),
187 (true, BigInt!("1")),
188 (false, BigInt!("1")),
189 (true, BigInt!("228988810152649578064853576960394133503")),
190 ];
191
192 fn endomorphism(p: &G1Projective) -> G1Projective {
193 let mut res = (*p).clone();
194 res.x *= Self::ENDO_COEFFS[0];
195 res
196 }
197
198 fn endomorphism_affine(p: &Affine<Self>) -> Affine<Self> {
199 let mut res = (*p).clone();
200 res.x *= Self::ENDO_COEFFS[0];
201 res
202 }
203
204 fn scalar_decomposition(
205 k: Self::ScalarField,
206 ) -> ((bool, Self::ScalarField), (bool, Self::ScalarField)) {
207 Self::scalar_decomposition_no_allocator(k)
208 }
209}
210
211impl GLVConfigNoAllocator for Config {
212 const BETA_1: (bool, U512) = (
213 true,
214 U512::from_limbs([
215 2263426366270003411,
216 10926721885838854917,
217 11648686701815784454,
218 238326537624862759,
219 7203196592358157870,
220 8965520006802549469,
221 1,
222 0,
223 ]),
224 );
225
226 const BETA_2: (bool, U512) = (
227 false,
228 U512::from_limbs([
229 4788304978035696531,
230 7279011843745230193,
231 4086414915577876179,
232 3841734232051169148,
233 2,
234 0,
235 0,
236 0,
237 ]),
238 );
239}
240
241fn one_minus_x() -> Fr {
242 const X: Fr = Fr::from_sign_and_limbs(
243 !crate::bls12_381::curves::Config::X_IS_NEGATIVE,
244 crate::bls12_381::curves::Config::X,
245 );
246 Fr::one() - X
247}
248
249impl WBConfig for Config {
251 type IsogenousCurve = g1_swu_iso::SwuIsoConfig;
252
253 const ISOGENY_MAP: IsogenyMap<'static, Self::IsogenousCurve, Self> =
254 g1_swu_iso::ISOGENY_MAP_TO_G1;
255}
256
257pub const G1_GENERATOR_X: Fq = MontFp!("3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507");
260
261pub const G1_GENERATOR_Y: Fq = MontFp!("1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569");
264
265pub const BETA: Fq = MontFp!("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350");
267
268pub fn endomorphism(p: &Affine<Config>) -> Affine<Config> {
269 let mut res = (*p).clone();
273 res.x *= BETA;
274 res
275}
276
277#[cfg(test)]
278mod tests {
279 use super::GLVConfigNoAllocator;
280 use super::{Config, CurveConfig, GLVConfig, PrimeField};
281 use proptest::{prop_assert_eq, proptest};
282 type ScalarField = <Config as CurveConfig>::ScalarField;
283
284 #[test]
285 fn compare_scalar_decomposition() {
286 proptest!(|(bytes: [u8; 32])| {
287 let k = ScalarField::from_be_bytes_mod_order(&bytes);
288
289 let (k1, k2) = Config::scalar_decomposition(k.clone());
290 let (k1_ref, k2_ref) = Config::scalar_decomposition_ref(k);
291
292 prop_assert_eq!(k1, k1_ref);
293 prop_assert_eq!(k2, k2_ref);
294 })
295 }
296
297 #[test]
298 fn test_betas() {
299 use ark_std::ops::Neg;
300 use num_bigint::{BigInt, BigUint, Sign};
301 use num_integer::Integer;
302 use ruint::aliases::U512;
303
304 let coeff_bigints: [BigInt; 4] = Config::SCALAR_DECOMP_COEFFS.map(|x| {
305 BigInt::from_biguint(x.0.then_some(Sign::Plus).unwrap_or(Sign::Minus), x.1.into())
306 });
307
308 let [_, n12, _, n22] = coeff_bigints;
309
310 let n = 512u64;
311 let r = BigInt::from(<<Config as CurveConfig>::ScalarField>::MODULUS);
312
313 let beta_1_ref = (n22 << n).div_rem(&r).0;
314
315 let sign = Config::BETA_1
316 .0
317 .then_some(Sign::Plus)
318 .unwrap_or(Sign::Minus);
319 let data = BigUint::from_bytes_be(&Config::BETA_1.1.to_be_bytes::<{ U512::BYTES }>());
320 let beta_1 = BigInt::from_biguint(sign, data);
321 assert_eq!(beta_1, beta_1_ref);
322
323 let beta_2_ref = ((n12 << n).neg()).div_rem(&r).0;
324
325 let sign = Config::BETA_2
326 .0
327 .then_some(Sign::Plus)
328 .unwrap_or(Sign::Minus);
329 let data = BigUint::from_bytes_be(&Config::BETA_2.1.to_be_bytes::<{ U512::BYTES }>());
330 let beta_2 = BigInt::from_biguint(sign, data);
331 assert_eq!(beta_2, beta_2_ref);
332 }
333}