halo2curves_axiom/pluto_eris/fields/
fq.rs

1use crate::arithmetic::{adc, mac, sbb};
2use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
3use crate::{
4    extend_field_legendre, field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs,
5    impl_from_u64_7_limbs,
6};
7use crate::{
8    impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
9    impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
10    impl_sum_prod,
11};
12use core::convert::TryInto;
13use core::fmt;
14use core::ops::{Add, Mul, Neg, Sub};
15use rand::RngCore;
16use std::slice::Iter;
17use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
18
19#[cfg(feature = "derive_serde")]
20use serde::{Deserialize, Serialize};
21
22/// This represents an element of $\mathbb{F}_q$ where
23///
24/// `q = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001`
25///
26/// is the scalar field of the Pluto curve (and the base field of the Eris curve).
27/// The internal representation of this type is seven 64-bit unsigned
28/// integers in little-endian order which account for the 446 bits required to be represented.
29/// `Fq` values are always in Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^448.
30#[derive(Clone, Copy, PartialEq, Eq, Hash)]
31#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
32pub struct Fq(pub(crate) [u64; 7]);
33
34/// Size of `Fq` element in bytes
35const SIZE: usize = 56;
36
37/// Constant representing the modulus
38/// `p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001`
39const MODULUS: Fq = Fq([
40    0x1ffffcd300000001,
41    0x9ca7e85d60050af4,
42    0xe4a775fe8e177fd6,
43    0x443f9a5c7a8a6c7b,
44    0xa803ca76f439266f,
45    0x0130e0000d7f70e4,
46    0x2400000000002400,
47]);
48
49/// The modulus as u32 limbs.
50#[cfg(not(target_pointer_width = "64"))]
51const MODULUS_LIMBS_32: [u32; 14] = [
52    0x00000001, 0x1ffffcd3, 0x60050af4, 0x9ca7e85d, 0x8e177fd6, 0xe4a775fe, 0x7a8a6c7b, 0x443f9a5c,
53    0xf439266f, 0xa803ca76, 0x0d7f70e4, 0x0130e000, 0x00002400, 0x24000000,
54];
55
56const MODULUS_STR: &str = "0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001";
57
58/// INV = -(q^{-1} mod 2^64) mod 2^64
59/// `0x1ffffcd2ffffffff`
60const INV: u64 = 0x1ffffcd2ffffffff;
61
62/// Let M be the power of `2^64` nearest to `Self::MODULUS_BITS`. Then `R = M % Self::MODULUS`.
63/// `R = 2^448 mod q`
64/// `0x3ffffffffff03fff7a9dfffa183e9bf67e576bf526ff2f52242c778a637089cbf6bc60a1d5b8121b768a5725fdcb3532000163afffffff9`
65const R: Fq = Fq([
66    0x2000163afffffff9,
67    0xb768a5725fdcb353,
68    0xbf6bc60a1d5b8121,
69    0x2242c778a637089c,
70    0x67e576bf526ff2f5,
71    0xf7a9dfffa183e9bf,
72    0x3ffffffffff03ff,
73]);
74
75/// `R^2 = 2^896 mod q`
76/// `0x50d7c998f46144ee436895a5a630ff544d51e923f64695651da4da1c97f716419bd905e6e4ff6c2bc64e865fe4552ad740808c831022522`
77const R2: Fq = Fq([
78    0x740808c831022522,
79    0xbc64e865fe4552ad,
80    0x19bd905e6e4ff6c2,
81    0x51da4da1c97f7164,
82    0x44d51e923f646956,
83    0xe436895a5a630ff5,
84    0x050d7c998f46144e,
85]);
86
87/// `R^3 = 2^1792 mod q`
88/// `0x2f2c41fb476072baa10b8225e69f7de3b2c1031e6d01279e65191fab1f6ce25295c3c8bd6945406c89b51b218477a6f7252704d7495b38a`
89const R3: Fq = Fq([
90    0x7252704d7495b38a,
91    0xc89b51b218477a6f,
92    0x295c3c8bd6945406,
93    0xe65191fab1f6ce25,
94    0x3b2c1031e6d01279,
95    0xaa10b8225e69f7de,
96    0x02f2c41fb476072b,
97]);
98
99/// `GENERATOR = 7 mod q` is a generator of the `q - 1` order multiplicative
100/// subgroup, or in other words a primitive root of the field.
101const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
102
103/// Size of the 2-adic sub-group of the field.
104const S: u32 = 32;
105
106/// GENERATOR^t where t * 2^s + 1 = q
107/// with t odd. In other words, this is a 2^s root of unity.
108/// `0x0a5e6f78289fd24b1c64c90821c44cdce9ba1b3e90f2e88957f869667f6dfdbdbce6bb9ed38a8c2382fa11e3d3810fcc3c7bb406ec7bce04`
109
110const ROOT_OF_UNITY: Fq = Fq::from_raw([
111    0x3c7bb406ec7bce04,
112    0x82fa11e3d3810fcc,
113    0xbce6bb9ed38a8c23,
114    0x57f869667f6dfdbd,
115    0xe9ba1b3e90f2e889,
116    0x1c64c90821c44cdc,
117    0x0a5e6f78289fd24b,
118]);
119
120/// 1 / ROOT_OF_UNITY mod q
121/// `0x1a8c636e293fe9928f85aa6ec68f950ebb57e3f0502dd05667c990c1c2f57128c77768be1824fd3f60869f410287a1879ec16a35ca69b6fb`
122
123const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([
124    0x9ec16a35ca69b6fb,
125    0x60869f410287a187,
126    0xc77768be1824fd3f,
127    0x67c990c1c2f57128,
128    0xbb57e3f0502dd056,
129    0x8f85aa6ec68f950e,
130    0x1a8c636e293fe992,
131]);
132
133/// 1 / 2 mod q
134/// `0x12000000000012000098700006bfb8725401e53b7a1c9337a21fcd2e3d45363df253baff470bbfeb4e53f42eb002857a0ffffe6980000001`
135const TWO_INV: Fq = Fq::from_raw([
136    0x0ffffe6980000001,
137    0x4e53f42eb002857a,
138    0xf253baff470bbfeb,
139    0xa21fcd2e3d45363d,
140    0x5401e53b7a1c9337,
141    0x0098700006bfb872,
142    0x1200000000001200,
143]);
144
145/// GENERATOR^{2^s} where t * 2^s + 1 = q with t odd. In other words, this is a t root of unity.
146/// 0x657946fe07116ceca983fe28713a2b257ab7a7866c95121e727f3776c3e84cb0a14f6a7f83f8cdaeadb479c657bdf2de4589640faf72e67
147const DELTA: Fq = Fq::from_raw([
148    0xe4589640faf72e67,
149    0xeadb479c657bdf2d,
150    0x0a14f6a7f83f8cda,
151    0xe727f3776c3e84cb,
152    0x57ab7a7866c95121,
153    0xca983fe28713a2b2,
154    0x657946fe07116ce,
155]);
156
157/// `ZETA^3 = 1 mod q` where `ZETA^2 != 1 mod q`
158/// `0x9000000000006c000392a0001afee1c9500792ae3039253e641ba35817a29ffaf50be000032cfffffffe`
159
160const ZETA: Fq = Fq::from_raw([
161    0xe000032cfffffffe,
162    0xa35817a29ffaf50b,
163    0x92ae3039253e641b,
164    0xa0001afee1c95007,
165    0x000000006c000392,
166    0x0000000000009000,
167    0x0000000000000000,
168]);
169
170impl_binops_additive!(Fq, Fq);
171impl_binops_multiplicative!(Fq, Fq);
172field_common_7_limbs!(
173    Fq,
174    FqRepr,
175    MODULUS,
176    INV,
177    MODULUS_STR,
178    TWO_INV,
179    ROOT_OF_UNITY_INV,
180    DELTA,
181    ZETA,
182    R,
183    R2,
184    R3
185);
186impl_sum_prod!(Fq);
187impl_from_u64_7_limbs!(Fq, R2);
188field_arithmetic_7_limbs!(Fq, MODULUS, INV, sparse);
189
190#[cfg(target_pointer_width = "64")]
191field_bits_7_limbs!(Fq, MODULUS);
192#[cfg(not(target_pointer_width = "64"))]
193field_bits_7_limbs!(Fq, MODULUS, MODULUS_LIMBS_32);
194
195extend_field_legendre!(Fq);
196
197impl Fq {
198    /// Return field element size in bytes.
199    pub const fn size() -> usize {
200        SIZE
201    }
202}
203
204impl ff::Field for Fq {
205    const ZERO: Self = Self::zero();
206    const ONE: Self = Self::one();
207
208    fn random(mut rng: impl RngCore) -> Self {
209        Self::from_u512([
210            rng.next_u64(),
211            rng.next_u64(),
212            rng.next_u64(),
213            rng.next_u64(),
214            rng.next_u64(),
215            rng.next_u64(),
216            rng.next_u64(),
217            rng.next_u64(),
218        ])
219    }
220
221    fn double(&self) -> Self {
222        self.double()
223    }
224
225    #[inline(always)]
226    fn square(&self) -> Self {
227        self.square()
228    }
229
230    /// Computes the multiplicative inverse of this element,
231    /// failing if the element is zero.
232    fn invert(&self) -> CtOption<Self> {
233        // self^(q - 2)
234        let tmp = self.pow_vartime([
235            0x1ffffcd2ffffffff,
236            0x9ca7e85d60050af4,
237            0xe4a775fe8e177fd6,
238            0x443f9a5c7a8a6c7b,
239            0xa803ca76f439266f,
240            0x0130e0000d7f70e4,
241            0x2400000000002400,
242        ]);
243
244        CtOption::new(tmp, !self.ct_eq(&Self::zero()))
245    }
246
247    fn sqrt(&self) -> CtOption<Self> {
248        /// `(t - 1) // 2` where t * 2^s + 1 = q with t odd.
249        const T_MINUS1_OVER2: [u64; 7] = [
250            0xb002857a0ffffe69,
251            0x470bbfeb4e53f42e,
252            0x3d45363df253baff,
253            0x7a1c9337a21fcd2e,
254            0x06bfb8725401e53b,
255            0x0000120000987000,
256            0x0000000012000000,
257        ];
258        ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2)
259    }
260
261    fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
262        ff::helpers::sqrt_ratio_generic(num, div)
263    }
264}
265
266#[derive(Clone, Copy, Debug)]
267/// Canonical little-endian representation of a `Fq` element.
268pub struct FqRepr {
269    pub repr: [u8; SIZE],
270}
271
272impl FqRepr {
273    /// Returns an iterator over the bytes of the canoncial representation of the element.
274    pub fn iter(&self) -> Iter<'_, u8> {
275        self.repr.iter()
276    }
277}
278
279impl Default for FqRepr {
280    fn default() -> Self {
281        FqRepr { repr: [0u8; SIZE] }
282    }
283}
284
285impl AsRef<[u8]> for FqRepr {
286    fn as_ref(&self) -> &[u8] {
287        self.repr.as_ref()
288    }
289}
290
291impl AsMut<[u8]> for FqRepr {
292    fn as_mut(&mut self) -> &mut [u8] {
293        self.repr.as_mut()
294    }
295}
296impl From<[u8; SIZE]> for FqRepr {
297    fn from(repr: [u8; SIZE]) -> Self {
298        Self { repr }
299    }
300}
301
302impl ff::PrimeField for Fq {
303    type Repr = FqRepr;
304
305    const NUM_BITS: u32 = 446;
306    const CAPACITY: u32 = 445;
307    const MODULUS: &'static str = MODULUS_STR;
308    const MULTIPLICATIVE_GENERATOR: Self = GENERATOR;
309    const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
310    const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
311    const TWO_INV: Self = TWO_INV;
312    const DELTA: Self = DELTA;
313    const S: u32 = S;
314
315    fn from_repr(repr: Self::Repr) -> CtOption<Self> {
316        let mut tmp = Self([0, 0, 0, 0, 0, 0, 0]);
317        let repr = repr.repr;
318
319        tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
320        tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
321        tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
322        tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
323        tmp.0[4] = u64::from_le_bytes(repr[32..40].try_into().unwrap());
324        tmp.0[5] = u64::from_le_bytes(repr[40..48].try_into().unwrap());
325        tmp.0[6] = u64::from_le_bytes(repr[48..56].try_into().unwrap());
326
327        // Try to subtract the modulus
328        let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
329        let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
330        let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
331        let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
332        let (_, borrow) = sbb(tmp.0[4], MODULUS.0[4], borrow);
333        let (_, borrow) = sbb(tmp.0[5], MODULUS.0[5], borrow);
334        let (_, borrow) = sbb(tmp.0[6], MODULUS.0[6], borrow);
335
336        // If the element is smaller than MODULUS then the
337        // subtraction will underflow, producing a borrow value
338        // of 0xffff...ffff. Otherwise, it'll be zero.
339        let is_some = (borrow as u8) & 1;
340
341        // Convert to Montgomery form by computing
342        // (a.R^0 * R^2) / R = a.R
343        tmp *= &R2;
344
345        CtOption::new(tmp, Choice::from(is_some))
346    }
347
348    fn to_repr(&self) -> Self::Repr {
349        // Turn into canonical form by computing
350        // (a.R) / R = a
351        let tmp = Self::montgomery_reduce(&[
352            self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], 0, 0, 0,
353            0, 0, 0, 0,
354        ]);
355
356        let mut res = [0; SIZE];
357        res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
358        res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
359        res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
360        res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
361        res[32..40].copy_from_slice(&tmp.0[4].to_le_bytes());
362        res[40..48].copy_from_slice(&tmp.0[5].to_le_bytes());
363        res[48..56].copy_from_slice(&tmp.0[6].to_le_bytes());
364        res.into()
365    }
366
367    fn is_odd(&self) -> Choice {
368        Choice::from(self.to_repr().repr[0] & 1)
369    }
370}
371
372impl FromUniformBytes<64> for Fq {
373    /// Converts a 512-bit little endian integer into
374    /// an `Fq` by reducing by the modulus.
375    fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
376        Self::from_u512([
377            u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
378            u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
379            u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
380            u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
381            u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
382            u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
383            u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
384            u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
385        ])
386    }
387}
388
389impl WithSmallOrderMulGroup<3> for Fq {
390    const ZETA: Self = ZETA;
391}
392
393#[cfg(test)]
394mod test {
395    use crate::serde::SerdeObject;
396
397    use super::*;
398    use ark_std::{end_timer, start_timer};
399    use ff::Field;
400    use rand::SeedableRng;
401    use rand_core::OsRng;
402    use rand_xorshift::XorShiftRng;
403
404    #[test]
405    fn test_sqrt() {
406        let v = (Fq::TWO_INV).square().sqrt().unwrap();
407        assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV);
408
409        for _ in 0..10000 {
410            let a = Fq::random(OsRng);
411            let mut b = a;
412            b = b.square();
413
414            let b = b.sqrt().unwrap();
415            let mut negb = b;
416            negb = negb.neg();
417
418            assert!(a == b || a == negb);
419        }
420    }
421
422    #[test]
423    fn test_field() {
424        crate::tests::field::random_field_tests::<Fq>("Pluto scalar".to_string());
425    }
426
427    #[test]
428    fn test_zeta() {
429        assert_eq!(Fq::ZETA * Fq::ZETA * Fq::ZETA, Fq::ONE);
430        assert_ne!(Fq::ZETA * Fq::ZETA, Fq::ONE);
431    }
432
433    #[test]
434    fn test_delta() {
435        assert_eq!(Fq::DELTA, GENERATOR.pow([1u64 << Fq::S]));
436        assert_eq!(Fq::DELTA, Fq::MULTIPLICATIVE_GENERATOR.pow([1u64 << Fq::S]));
437    }
438
439    #[test]
440    fn test_from_u512() {
441        const N_VECS: usize = 10;
442        let expected_results = [
443            Fq::from_raw([
444                0x93638251ffeffed3,
445                0xb17ab6ae332352b4,
446                0xbf2731af91057325,
447                0x7b700ef5a22260d0,
448                0xc97c59318d325250,
449                0xd7bc83d286537318,
450                0x01d4a87b24f91154,
451            ]),
452            Fq::from_raw([
453                0x63e0a8f1beefc612,
454                0x080f69572a9ddaae,
455                0xb9ff1cf0e1f7c067,
456                0xd8d8bf5b522bc48b,
457                0xa7607085c7065359,
458                0x617d8b0cda3f6328,
459                0x03096ea964e009c0,
460            ]),
461            Fq::from_raw([
462                0x5eaedbda63b3e431,
463                0x90ebbfa6f11a9266,
464                0x4528cf4d506c9f9b,
465                0x8c6ac679e9ac3856,
466                0x001666755d9c2c57,
467                0x9f7f457a48d6d322,
468                0x20b2fadc6bf4004d,
469            ]),
470            Fq::from_raw([
471                0xeeea9cbd68b174cf,
472                0x84af9e4ce5a781a5,
473                0x3578772b5b482647,
474                0x6b202eb54b7df723,
475                0x55f541b1436b7660,
476                0x2045de539849b035,
477                0x1d5d7b5f6e8cc333,
478            ]),
479            Fq::from_raw([
480                0xe73df0f69b71a763,
481                0xbccfb84010979d9d,
482                0x1ce3c87be8bf3247,
483                0x695fde61877cb617,
484                0x5006663bd0944209,
485                0xd7ead2b7c71e460d,
486                0x0f7c36b781cba9ed,
487            ]),
488            Fq::from_raw([
489                0xaeed10e8f00b189d,
490                0x5190807038915743,
491                0x90b840c0a13b0307,
492                0x20fa8cc52c3a9a28,
493                0xc3f229646be29c1d,
494                0xb1d2bb5373270c43,
495                0x0e18a3597be61302,
496            ]),
497            Fq::from_raw([
498                0xffbbc6b3e494ca68,
499                0x30d4a100158c1751,
500                0x0328dae560dff403,
501                0x1495c3ce50cce340,
502                0x93efc4d4d6ea0079,
503                0x0a791ad7698655a7,
504                0x22b10d5c1090eec8,
505            ]),
506            Fq::from_raw([
507                0xd96eec60211ad67b,
508                0x4d081a969b3d8488,
509                0x57c9b5abbeec4cf0,
510                0x13ced15637e4b0eb,
511                0xb98a559f49b0071c,
512                0x819ba919d0b6e9b5,
513                0x20f73876330a90e8,
514            ]),
515            Fq::from_raw([
516                0xbade57a48e2d9868,
517                0xc688e43e21f9d2fc,
518                0x848a82da9e1d75dc,
519                0xae5f4536b9d60aa7,
520                0x7957f2028c96467b,
521                0xf850f49359458652,
522                0x17ba9f9aa08b9ee2,
523            ]),
524            Fq::from_raw([
525                0xd0239c8282ccc372,
526                0x4a777ad0b66181ea,
527                0x53737d5f19e61bfc,
528                0x5340b579fe7c4c83,
529                0x8406f69a0f89f90a,
530                0xd7d5d8bc4497465a,
531                0x08ce8bee1323d4f9,
532            ]),
533        ];
534
535        let mut seeded_rng = XorShiftRng::seed_from_u64(0u64);
536        let uniform_bytes = std::iter::from_fn(|| {
537            let mut bytes = [0u8; 64];
538            seeded_rng.fill_bytes(&mut bytes);
539            Some(bytes)
540        })
541        .take(N_VECS)
542        .collect::<Vec<_>>();
543
544        for i in 0..N_VECS {
545            let q = Fq::from_uniform_bytes(&uniform_bytes[i]);
546            assert_eq!(expected_results[i], q);
547        }
548    }
549
550    #[test]
551    #[cfg(feature = "bits")]
552    fn test_bits() {
553        crate::tests::field::random_bits_tests::<Fq>("Fq".to_string());
554    }
555
556    #[test]
557    fn test_serialization() {
558        crate::tests::field::random_serialization_test::<Fq>("Fq".to_string());
559        #[cfg(feature = "derive_serde")]
560        crate::tests::field::random_serde_test::<Fq>("Fq".to_string());
561    }
562
563    fn is_less_than(x: &[u64; 7], y: &[u64; 7]) -> bool {
564        match x[6].cmp(&y[6]) {
565            core::cmp::Ordering::Less => return true,
566            core::cmp::Ordering::Greater => return false,
567            _ => {}
568        }
569        match x[5].cmp(&y[5]) {
570            core::cmp::Ordering::Less => return true,
571            core::cmp::Ordering::Greater => return false,
572            _ => {}
573        }
574        match x[4].cmp(&y[4]) {
575            core::cmp::Ordering::Less => return true,
576            core::cmp::Ordering::Greater => return false,
577            _ => {}
578        }
579        match x[3].cmp(&y[3]) {
580            core::cmp::Ordering::Less => return true,
581            core::cmp::Ordering::Greater => return false,
582            _ => {}
583        }
584        match x[2].cmp(&y[2]) {
585            core::cmp::Ordering::Less => return true,
586            core::cmp::Ordering::Greater => return false,
587            _ => {}
588        }
589        match x[1].cmp(&y[1]) {
590            core::cmp::Ordering::Less => return true,
591            core::cmp::Ordering::Greater => return false,
592            _ => {}
593        }
594        x[0].lt(&y[0])
595    }
596
597    #[test]
598    fn test_serialization_check() {
599        let mut rng = XorShiftRng::from_seed([
600            0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
601            0xbc, 0xe5,
602        ]);
603        let start = start_timer!(|| "serialize Fq");
604        // failure check
605        for _ in 0..1000000 {
606            let rand_word = [(); 7].map(|_| rng.next_u64());
607            let a = Fq(rand_word);
608            let rand_bytes = a.to_raw_bytes();
609            match is_less_than(&rand_word, &MODULUS.0) {
610                false => {
611                    assert!(Fq::from_raw_bytes(&rand_bytes).is_none());
612                }
613                _ => {
614                    assert_eq!(Fq::from_raw_bytes(&rand_bytes), Some(a));
615                }
616            }
617        }
618        end_timer!(start);
619    }
620}