halo2curves_axiom/bn256/
fr.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
6#[cfg(feature = "bn256-table")]
7#[rustfmt::skip]
8mod table;
9#[cfg(feature = "bn256-table")]
10#[cfg(test)]
11mod table_tests;
12
13#[cfg(feature = "bn256-table")]
14// This table should have being generated by `build.rs`;
15// and stored in `src/bn256/fr/table.rs`.
16pub use table::FR_TABLE;
17
18#[cfg(not(feature = "bn256-table"))]
19use crate::impl_from_u64;
20
21use crate::arithmetic::{adc, bigint_geq, mac, sbb};
22use crate::extend_field_legendre;
23use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
24use crate::{
25    field_bits, field_common, impl_add_binop_specify_output, impl_binops_additive,
26    impl_binops_additive_specify_output, impl_binops_multiplicative,
27    impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, impl_sum_prod,
28};
29use core::convert::TryInto;
30use core::fmt;
31use core::ops::{Add, Mul, Neg, Sub};
32use rand::RngCore;
33use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
34
35/// This represents an element of $\mathbb{F}_r$ where
36///
37/// `r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001`
38///
39/// is the scalar field of the BN254 curve.
40// The internal representation of this type is four 64-bit unsigned
41// integers in little-endian order. `Fr` values are always in
42// Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256.
43#[derive(Clone, Copy, PartialEq, Eq, Hash)]
44pub struct Fr(pub(crate) [u64; 4]);
45
46#[cfg(feature = "derive_serde")]
47crate::serialize_deserialize_32_byte_primefield!(Fr);
48
49/// Constant representing the modulus
50/// r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
51const MODULUS: Fr = Fr([
52    0x43e1f593f0000001,
53    0x2833e84879b97091,
54    0xb85045b68181585d,
55    0x30644e72e131a029,
56]);
57
58/// The modulus as u32 limbs.
59#[cfg(not(target_pointer_width = "64"))]
60const MODULUS_LIMBS_32: [u32; 8] = [
61    0xf000_0001,
62    0x43e1_f593,
63    0x79b9_7091,
64    0x2833_e848,
65    0x8181_585d,
66    0xb850_45b6,
67    0xe131_a029,
68    0x3064_4e72,
69];
70
71const MODULUS_STR: &str = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001";
72
73/// INV = -(r^{-1} mod 2^64) mod 2^64
74const INV: u64 = 0xc2e1f593efffffff;
75
76/// `R = 2^256 mod r`
77/// `0xe0a77c19a07df2f666ea36f7879462e36fc76959f60cd29ac96341c4ffffffb`
78const R: Fr = Fr([
79    0xac96341c4ffffffb,
80    0x36fc76959f60cd29,
81    0x666ea36f7879462e,
82    0x0e0a77c19a07df2f,
83]);
84
85/// `R^2 = 2^512 mod r`
86/// `0x216d0b17f4e44a58c49833d53bb808553fe3ab1e35c59e31bb8e645ae216da7`
87const R2: Fr = Fr([
88    0x1bb8e645ae216da7,
89    0x53fe3ab1e35c59e3,
90    0x8c49833d53bb8085,
91    0x0216d0b17f4e44a5,
92]);
93
94/// `R^3 = 2^768 mod r`
95/// `0xcf8594b7fcc657c893cc664a19fcfed2a489cbe1cfbb6b85e94d8e1b4bf0040`
96const R3: Fr = Fr([
97    0x5e94d8e1b4bf0040,
98    0x2a489cbe1cfbb6b8,
99    0x893cc664a19fcfed,
100    0x0cf8594b7fcc657c,
101]);
102
103/// `GENERATOR = 7 mod r` is a generator of the `r - 1` order multiplicative
104/// subgroup, or in other words a primitive root of the field.
105const GENERATOR: Fr = Fr::from_raw([0x07, 0x00, 0x00, 0x00]);
106
107const S: u32 = 28;
108
109/// GENERATOR^t where t * 2^s + 1 = r
110/// with t odd. In other words, this
111/// is a 2^s root of unity.
112/// `0x3ddb9f5166d18b798865ea93dd31f743215cf6dd39329c8d34f1ed960c37c9c`
113const ROOT_OF_UNITY: Fr = Fr::from_raw([
114    0xd34f1ed960c37c9c,
115    0x3215cf6dd39329c8,
116    0x98865ea93dd31f74,
117    0x03ddb9f5166d18b7,
118]);
119
120/// 1 / 2 mod r
121const TWO_INV: Fr = Fr::from_raw([
122    0xa1f0fac9f8000001,
123    0x9419f4243cdcb848,
124    0xdc2822db40c0ac2e,
125    0x183227397098d014,
126]);
127
128/// 1 / ROOT_OF_UNITY mod r
129const ROOT_OF_UNITY_INV: Fr = Fr::from_raw([
130    0x0ed3e50a414e6dba,
131    0xb22625f59115aba7,
132    0x1bbe587180f34361,
133    0x048127174daabc26,
134]);
135
136/// GENERATOR^{2^s} where t * 2^s + 1 = r with t odd. In other words, this is a t root of unity.
137/// 0x09226b6e22c6f0ca64ec26aad4c86e715b5f898e5e963f25870e56bbe533e9a2
138const DELTA: Fr = Fr::from_raw([
139    0x870e56bbe533e9a2,
140    0x5b5f898e5e963f25,
141    0x64ec26aad4c86e71,
142    0x09226b6e22c6f0ca,
143]);
144
145/// `ZETA^3 = 1 mod r` where `ZETA^2 != 1 mod r`
146const ZETA: Fr = Fr::from_raw([
147    0xb8ca0b2d36636f23,
148    0xcc37a73fec2bc5e9,
149    0x048b6e193fd84104,
150    0x30644e72e131a029,
151]);
152
153impl_binops_additive!(Fr, Fr);
154impl_binops_multiplicative!(Fr, Fr);
155field_common!(
156    Fr,
157    MODULUS,
158    INV,
159    MODULUS_STR,
160    TWO_INV,
161    ROOT_OF_UNITY_INV,
162    DELTA,
163    ZETA,
164    R,
165    R2,
166    R3
167);
168impl_sum_prod!(Fr);
169extend_field_legendre!(Fr);
170
171#[cfg(not(feature = "bn256-table"))]
172impl_from_u64!(Fr, R2);
173#[cfg(feature = "bn256-table")]
174// A field element is represented in the montgomery form -- this allows for cheap mul_mod operations.
175// The catch is, if we build an Fr element, regardless of its format, we need to perform one big integer multiplication:
176//
177//      Fr([val, 0, 0, 0]) * R2
178//
179// When the "bn256-table" feature is enabled, we read the Fr element directly from the table.
180// This avoids a big integer multiplication.
181//
182// We use a table with 2^16 entries when the element is smaller than 2^16.
183impl From<u64> for Fr {
184    fn from(val: u64) -> Fr {
185        if val < 65536 {
186            FR_TABLE[val as usize]
187        } else {
188            Fr([val, 0, 0, 0]) * R2
189        }
190    }
191}
192
193#[cfg(not(feature = "asm"))]
194field_arithmetic!(Fr, MODULUS, INV, sparse);
195#[cfg(feature = "asm")]
196field_arithmetic_asm!(Fr, MODULUS, INV);
197
198#[cfg(target_pointer_width = "64")]
199field_bits!(Fr, MODULUS);
200#[cfg(not(target_pointer_width = "64"))]
201field_bits!(Fr, MODULUS, MODULUS_LIMBS_32);
202
203impl Fr {
204    pub const fn size() -> usize {
205        32
206    }
207}
208
209impl ff::Field for Fr {
210    const ZERO: Self = Self::zero();
211    const ONE: Self = Self::one();
212
213    fn random(mut rng: impl RngCore) -> Self {
214        Self::from_u512([
215            rng.next_u64(),
216            rng.next_u64(),
217            rng.next_u64(),
218            rng.next_u64(),
219            rng.next_u64(),
220            rng.next_u64(),
221            rng.next_u64(),
222            rng.next_u64(),
223        ])
224    }
225
226    fn double(&self) -> Self {
227        self.double()
228    }
229
230    #[inline(always)]
231    fn square(&self) -> Self {
232        self.square()
233    }
234
235    /// Returns the multiplicative inverse of the
236    /// element. If it is zero, the method fails.
237    fn invert(&self) -> CtOption<Self> {
238        self.invert()
239    }
240
241    fn sqrt(&self) -> CtOption<Self> {
242        /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd.
243        const T_MINUS1_OVER2: [u64; 4] = [
244            0xcdcb848a1f0fac9f,
245            0x0c0ac2e9419f4243,
246            0x098d014dc2822db4,
247            0x0000000183227397,
248        ];
249        ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2)
250    }
251
252    fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
253        ff::helpers::sqrt_ratio_generic(num, div)
254    }
255}
256
257impl ff::PrimeField for Fr {
258    type Repr = [u8; 32];
259
260    const NUM_BITS: u32 = 254;
261    const CAPACITY: u32 = 253;
262    const MODULUS: &'static str = MODULUS_STR;
263    const MULTIPLICATIVE_GENERATOR: Self = GENERATOR;
264    const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
265    const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
266    const TWO_INV: Self = TWO_INV;
267    const DELTA: Self = DELTA;
268    const S: u32 = S;
269
270    fn from_repr(repr: Self::Repr) -> CtOption<Self> {
271        let mut tmp = Fr([0, 0, 0, 0]);
272
273        tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
274        tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
275        tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
276        tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
277
278        // Try to subtract the modulus
279        let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
280        let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
281        let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
282        let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
283
284        // If the element is smaller than MODULUS then the
285        // subtraction will underflow, producing a borrow value
286        // of 0xffff...ffff. Otherwise, it'll be zero.
287        let is_some = (borrow as u8) & 1;
288
289        // Convert to Montgomery form by computing
290        // (a.R^0 * R^2) / R = a.R
291        tmp *= &R2;
292
293        CtOption::new(tmp, Choice::from(is_some))
294    }
295
296    fn to_repr(&self) -> Self::Repr {
297        let tmp: [u64; 4] = (*self).into();
298        let mut res = [0; 32];
299        res[0..8].copy_from_slice(&tmp[0].to_le_bytes());
300        res[8..16].copy_from_slice(&tmp[1].to_le_bytes());
301        res[16..24].copy_from_slice(&tmp[2].to_le_bytes());
302        res[24..32].copy_from_slice(&tmp[3].to_le_bytes());
303
304        res
305    }
306
307    fn is_odd(&self) -> Choice {
308        Choice::from(self.to_repr()[0] & 1)
309    }
310}
311
312impl FromUniformBytes<64> for Fr {
313    /// Converts a 512-bit little endian integer into
314    /// an `Fr` by reducing by the modulus.
315    fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
316        Self::from_u512([
317            u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
318            u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
319            u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
320            u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
321            u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
322            u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
323            u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
324            u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
325        ])
326    }
327}
328
329impl WithSmallOrderMulGroup<3> for Fr {
330    const ZETA: Self = ZETA;
331}
332
333#[cfg(test)]
334mod test {
335    use crate::serde::SerdeObject;
336
337    use super::*;
338    use ark_std::{end_timer, start_timer};
339    use ff::Field;
340    use rand::SeedableRng;
341    use rand_core::OsRng;
342    use rand_xorshift::XorShiftRng;
343
344    #[test]
345    fn test_sqrt() {
346        let v = (Fr::TWO_INV).square().sqrt().unwrap();
347        assert!(v == Fr::TWO_INV || (-v) == Fr::TWO_INV);
348
349        for _ in 0..10000 {
350            let a = Fr::random(OsRng);
351            let mut b = a;
352            b = b.square();
353
354            let b = b.sqrt().unwrap();
355            let mut negb = b;
356            negb = negb.neg();
357
358            assert!(a == b || a == negb);
359        }
360    }
361
362    #[test]
363    fn test_field() {
364        crate::tests::field::random_field_tests::<Fr>("bn256 scalar".to_string());
365    }
366
367    #[test]
368    fn test_delta() {
369        assert_eq!(Fr::DELTA, GENERATOR.pow([1u64 << Fr::S]));
370        assert_eq!(Fr::DELTA, Fr::MULTIPLICATIVE_GENERATOR.pow([1u64 << Fr::S]));
371    }
372
373    #[test]
374    fn test_from_u512() {
375        assert_eq!(
376            Fr::from_raw([
377                0x7e7140b5196b9e6f,
378                0x9abac9e4157b6172,
379                0xf04bc41062fd7322,
380                0x1185fa9c9fef6326,
381            ]),
382            Fr::from_u512([
383                0xaaaaaaaaaaaaaaaa,
384                0xaaaaaaaaaaaaaaaa,
385                0xaaaaaaaaaaaaaaaa,
386                0xaaaaaaaaaaaaaaaa,
387                0xaaaaaaaaaaaaaaaa,
388                0xaaaaaaaaaaaaaaaa,
389                0xaaaaaaaaaaaaaaaa,
390                0xaaaaaaaaaaaaaaaa
391            ])
392        );
393    }
394
395    #[test]
396    fn test_conversion() {
397        crate::tests::field::random_conversion_tests::<Fr>("fr".to_string());
398    }
399
400    #[test]
401    #[cfg(feature = "bits")]
402    fn test_bits() {
403        crate::tests::field::random_bits_tests::<Fr>("fr".to_string());
404    }
405
406    #[test]
407    fn test_serialization() {
408        crate::tests::field::random_serialization_test::<Fr>("fr".to_string());
409        #[cfg(feature = "derive_serde")]
410        crate::tests::field::random_serde_test::<Fr>("fr".to_string());
411    }
412
413    fn is_less_than(x: &[u64; 4], y: &[u64; 4]) -> bool {
414        match x[3].cmp(&y[3]) {
415            core::cmp::Ordering::Less => return true,
416            core::cmp::Ordering::Greater => return false,
417            _ => {}
418        }
419        match x[2].cmp(&y[2]) {
420            core::cmp::Ordering::Less => return true,
421            core::cmp::Ordering::Greater => return false,
422            _ => {}
423        }
424        match x[1].cmp(&y[1]) {
425            core::cmp::Ordering::Less => return true,
426            core::cmp::Ordering::Greater => return false,
427            _ => {}
428        }
429        x[0].lt(&y[0])
430    }
431
432    #[test]
433    fn test_serialization_check() {
434        let mut rng = XorShiftRng::from_seed([
435            0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
436            0xbc, 0xe5,
437        ]);
438        let start = start_timer!(|| "serialize fr");
439        // failure check
440        for _ in 0..1000000 {
441            let rand_word = [(); 4].map(|_| rng.next_u64());
442            let a = Fr(rand_word);
443            let rand_bytes = a.to_raw_bytes();
444            match is_less_than(&rand_word, &MODULUS.0) {
445                false => {
446                    assert!(Fr::from_raw_bytes(&rand_bytes).is_none());
447                }
448                _ => {
449                    assert_eq!(Fr::from_raw_bytes(&rand_bytes), Some(a));
450                }
451            }
452        }
453        end_timer!(start);
454    }
455
456    #[test]
457    fn bench_fr_from_u16() {
458        let repeat = 10000000;
459        let mut rng = ark_std::test_rng();
460        let base = (0..repeat).map(|_| (rng.next_u32() % (1 << 16)) as u64);
461
462        let timer = start_timer!(|| format!("generate {repeat} Bn256 scalar field elements"));
463        let _res: Vec<_> = base.map(Fr::from).collect();
464
465        end_timer!(timer);
466    }
467
468    #[test]
469    fn test_quadratic_residue() {
470        crate::tests::field::random_quadratic_residue_test::<Fr>();
471    }
472}