halo2curves_axiom/bn256/
fq.rs

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/// This represents an element of $\mathbb{F}_q$ where
21///
22/// `p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47`
23///
24/// is the base field of the BN254 curve.
25// The internal representation of this type is four 64-bit unsigned
26// integers in little-endian order. `Fq` values are always in
27// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256.
28#[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
34/// Constant representing the modulus
35/// q = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47
36const MODULUS: Fq = Fq([
37    0x3c208c16d87cfd47,
38    0x97816a916871ca8d,
39    0xb85045b68181585d,
40    0x30644e72e131a029,
41]);
42
43/// The modulus as u32 limbs.
44#[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
56/// INV = -(q^{-1} mod 2^64) mod 2^64
57const INV: u64 = 0x87d20782e4866389;
58
59/// R = 2^256 mod q
60const R: Fq = Fq([
61    0xd35d438dc58f0d9d,
62    0x0a78eb28f5c70b3d,
63    0x666ea36f7879462c,
64    0x0e0a77c19a07df2f,
65]);
66
67/// R^2 = 2^512 mod q
68const R2: Fq = Fq([
69    0xf32cfc5b538afa89,
70    0xb5e71911d44501fb,
71    0x47ab1eff0a417ff6,
72    0x06d89f71cab8351f,
73]);
74
75/// R^3 = 2^768 mod q
76const 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
92/// Obtained with:
93/// `sage: GF(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47).primitive_element()`
94const 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
103/// `0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46`
104const ROOT_OF_UNITY: Fq = Fq::from_raw([
105    0x3c208c16d87cfd46,
106    0x97816a916871ca8d,
107    0xb85045b68181585d,
108    0x30644e72e131a029,
109]);
110
111/// `0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46`
112const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([
113    0x3c208c16d87cfd46,
114    0x97816a916871ca8d,
115    0xb85045b68181585d,
116    0x30644e72e131a029,
117]);
118
119// `0x9`
120const DELTA: Fq = Fq::from_raw([0x9, 0, 0, 0]);
121
122/// `ZETA^3 = 1 mod r` where `ZETA^2 != 1 mod r`
123const 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    /// Computes the square root of this element, if it exists.
187    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    /// Returns the multiplicative inverse of the
203    /// element. If it is zero, the method fails.
204    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        // Try to subtract the modulus
231        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        // If the element is smaller than MODULUS then the
237        // subtraction will underflow, producing a borrow value
238        // of 0xffff...ffff. Otherwise, it'll be zero.
239        let is_some = (borrow as u8) & 1;
240
241        // Convert to Montgomery form by computing
242        // (a.R^0 * R^2) / R = a.R
243        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    /// Converts a 512-bit little endian integer into
266    /// an `Fq` by reducing by the modulus.
267    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}