1#[cfg(feature = "asm")]
2use crate::bn256::assembly::field_arithmetic_asm;
3#[cfg(not(feature = "asm"))]
4use crate::{arithmetic::macx, field_arithmetic, field_specific};
5
6use crate::arithmetic::{adc, bigint_geq, mac, sbb};
7use crate::extend_field_legendre;
8use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
9use crate::{
10 field_bits, field_common, impl_add_binop_specify_output, impl_binops_additive,
11 impl_binops_additive_specify_output, impl_binops_multiplicative,
12 impl_binops_multiplicative_mixed, impl_from_u64, impl_sub_binop_specify_output, impl_sum_prod,
13};
14use core::convert::TryInto;
15use core::fmt;
16use core::ops::{Add, Mul, Neg, Sub};
17use rand::RngCore;
18use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
19
20#[derive(Clone, Copy, PartialEq, Eq, Hash)]
29pub struct Fq(pub(crate) [u64; 4]);
30
31#[cfg(feature = "derive_serde")]
32crate::serialize_deserialize_32_byte_primefield!(Fq);
33
34const MODULUS: Fq = Fq([
37 0x3c208c16d87cfd47,
38 0x97816a916871ca8d,
39 0xb85045b68181585d,
40 0x30644e72e131a029,
41]);
42
43#[cfg(not(target_pointer_width = "64"))]
45const MODULUS_LIMBS_32: [u32; 8] = [
46 0xd87c_fd47,
47 0x3c20_8c16,
48 0x6871_ca8d,
49 0x9781_6a91,
50 0x8181_585d,
51 0xb850_45b6,
52 0xe131_a029,
53 0x3064_4e72,
54];
55
56const INV: u64 = 0x87d20782e4866389;
58
59const R: Fq = Fq([
61 0xd35d438dc58f0d9d,
62 0x0a78eb28f5c70b3d,
63 0x666ea36f7879462c,
64 0x0e0a77c19a07df2f,
65]);
66
67const R2: Fq = Fq([
69 0xf32cfc5b538afa89,
70 0xb5e71911d44501fb,
71 0x47ab1eff0a417ff6,
72 0x06d89f71cab8351f,
73]);
74
75const R3: Fq = Fq([
77 0xb1cd6dafda1530df,
78 0x62f210e6a7283db6,
79 0xef7f0b0c0ada0afb,
80 0x20fd6e902d592544,
81]);
82
83pub const NEGATIVE_ONE: Fq = Fq([
84 0x68c3488912edefaa,
85 0x8d087f6872aabf4f,
86 0x51e1a24709081231,
87 0x2259d6b14729c0fa,
88]);
89
90const MODULUS_STR: &str = "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47";
91
92const MULTIPLICATIVE_GENERATOR: Fq = Fq::from_raw([0x03, 0x0, 0x0, 0x0]);
95
96const TWO_INV: Fq = Fq::from_raw([
97 0x9e10460b6c3e7ea4,
98 0xcbc0b548b438e546,
99 0xdc2822db40c0ac2e,
100 0x183227397098d014,
101]);
102
103const ROOT_OF_UNITY: Fq = Fq::from_raw([
105 0x3c208c16d87cfd46,
106 0x97816a916871ca8d,
107 0xb85045b68181585d,
108 0x30644e72e131a029,
109]);
110
111const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([
113 0x3c208c16d87cfd46,
114 0x97816a916871ca8d,
115 0xb85045b68181585d,
116 0x30644e72e131a029,
117]);
118
119const DELTA: Fq = Fq::from_raw([0x9, 0, 0, 0]);
121
122const ZETA: Fq = Fq::from_raw([
124 0xe4bd44e5607cfd48,
125 0xc28f069fbb966e3d,
126 0x5e6dd9e7e0acccb0,
127 0x30644e72e131a029,
128]);
129
130impl_binops_additive!(Fq, Fq);
131impl_binops_multiplicative!(Fq, Fq);
132field_common!(
133 Fq,
134 MODULUS,
135 INV,
136 MODULUS_STR,
137 TWO_INV,
138 ROOT_OF_UNITY_INV,
139 DELTA,
140 ZETA,
141 R,
142 R2,
143 R3
144);
145impl_sum_prod!(Fq);
146impl_from_u64!(Fq, R2);
147
148#[cfg(not(feature = "asm"))]
149field_arithmetic!(Fq, MODULUS, INV, sparse);
150#[cfg(feature = "asm")]
151field_arithmetic_asm!(Fq, MODULUS, INV);
152
153#[cfg(target_pointer_width = "64")]
154field_bits!(Fq, MODULUS);
155#[cfg(not(target_pointer_width = "64"))]
156field_bits!(Fq, MODULUS, MODULUS_LIMBS_32);
157
158impl Fq {
159 pub const fn size() -> usize {
160 32
161 }
162}
163
164extend_field_legendre!(Fq);
165
166impl ff::Field for Fq {
167 const ZERO: Self = Self::zero();
168 const ONE: Self = Self::one();
169
170 fn random(mut rng: impl RngCore) -> Self {
171 let mut random_bytes = [0; 64];
172 rng.fill_bytes(&mut random_bytes[..]);
173
174 Self::from_uniform_bytes(&random_bytes)
175 }
176
177 fn double(&self) -> Self {
178 self.double()
179 }
180
181 #[inline(always)]
182 fn square(&self) -> Self {
183 self.square()
184 }
185
186 fn sqrt(&self) -> CtOption<Self> {
188 let tmp = self.pow([
189 0x4f082305b61f3f52,
190 0x65e05aa45a1c72a3,
191 0x6e14116da0605617,
192 0x0c19139cb84c680a,
193 ]);
194
195 CtOption::new(tmp, tmp.square().ct_eq(self))
196 }
197
198 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
199 ff::helpers::sqrt_ratio_generic(num, div)
200 }
201
202 fn invert(&self) -> CtOption<Self> {
205 self.invert()
206 }
207}
208
209impl ff::PrimeField for Fq {
210 type Repr = [u8; 32];
211
212 const NUM_BITS: u32 = 254;
213 const CAPACITY: u32 = 253;
214 const MODULUS: &'static str = MODULUS_STR;
215 const MULTIPLICATIVE_GENERATOR: Self = MULTIPLICATIVE_GENERATOR;
216 const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
217 const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
218 const TWO_INV: Self = TWO_INV;
219 const DELTA: Self = DELTA;
220 const S: u32 = 0;
221
222 fn from_repr(repr: Self::Repr) -> CtOption<Self> {
223 let mut tmp = Fq([0, 0, 0, 0]);
224
225 tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
226 tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
227 tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
228 tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
229
230 let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
232 let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
233 let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
234 let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
235
236 let is_some = (borrow as u8) & 1;
240
241 tmp *= &R2;
244
245 CtOption::new(tmp, Choice::from(is_some))
246 }
247
248 fn to_repr(&self) -> Self::Repr {
249 let tmp: [u64; 4] = (*self).into();
250 let mut res = [0; 32];
251 res[0..8].copy_from_slice(&tmp[0].to_le_bytes());
252 res[8..16].copy_from_slice(&tmp[1].to_le_bytes());
253 res[16..24].copy_from_slice(&tmp[2].to_le_bytes());
254 res[24..32].copy_from_slice(&tmp[3].to_le_bytes());
255
256 res
257 }
258
259 fn is_odd(&self) -> Choice {
260 Choice::from(self.to_repr()[0] & 1)
261 }
262}
263
264impl FromUniformBytes<64> for Fq {
265 fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
268 Self::from_u512([
269 u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
270 u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
271 u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
272 u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
273 u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
274 u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
275 u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
276 u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
277 ])
278 }
279}
280
281impl WithSmallOrderMulGroup<3> for Fq {
282 const ZETA: Self = ZETA;
283}
284
285#[cfg(test)]
286mod test {
287 use super::*;
288 use crate::ff_ext::Legendre;
289 use ff::Field;
290 use rand_core::OsRng;
291
292 #[test]
293 fn test_sqrt_fq() {
294 let v = (Fq::TWO_INV).square().sqrt().unwrap();
295 assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV);
296
297 for _ in 0..10000 {
298 let a = Fq::random(OsRng);
299 let mut b = a;
300 b = b.square();
301 assert_eq!(b.legendre(), 1);
302
303 let b = b.sqrt().unwrap();
304 let mut negb = b;
305 negb = negb.neg();
306
307 assert!(a == b || a == negb);
308 }
309
310 let mut c = Fq::one();
311 for _ in 0..10000 {
312 let mut b = c;
313 b = b.square();
314 assert_eq!(b.legendre(), 1);
315
316 b = b.sqrt().unwrap();
317
318 if b != c {
319 b = b.neg();
320 }
321
322 assert_eq!(b, c);
323
324 c += &Fq::one();
325 }
326 }
327
328 #[test]
329 fn test_from_u512() {
330 assert_eq!(
331 Fq::from_raw([
332 0x1f8905a172affa8a,
333 0xde45ad177dcf3306,
334 0xaaa7987907d73ae2,
335 0x24d349431d468e30,
336 ]),
337 Fq::from_u512([
338 0xaaaaaaaaaaaaaaaa,
339 0xaaaaaaaaaaaaaaaa,
340 0xaaaaaaaaaaaaaaaa,
341 0xaaaaaaaaaaaaaaaa,
342 0xaaaaaaaaaaaaaaaa,
343 0xaaaaaaaaaaaaaaaa,
344 0xaaaaaaaaaaaaaaaa,
345 0xaaaaaaaaaaaaaaaa
346 ])
347 );
348 }
349
350 #[test]
351 fn test_field() {
352 crate::tests::field::random_field_tests::<Fq>("fq".to_string());
353 }
354
355 #[test]
356 fn test_conversion() {
357 crate::tests::field::random_conversion_tests::<Fq>("fq".to_string());
358 }
359
360 #[test]
361 #[cfg(feature = "bits")]
362 fn test_bits() {
363 crate::tests::field::random_bits_tests::<Fq>("fq".to_string());
364 }
365
366 #[test]
367 fn test_serialization() {
368 crate::tests::field::random_serialization_test::<Fq>("fq".to_string());
369 #[cfg(feature = "derive_serde")]
370 crate::tests::field::random_serde_test::<Fq>("fq".to_string());
371 }
372}