halo2curves_axiom/bn256/
fq2.rs

1use super::fq::{Fq, NEGATIVE_ONE};
2use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
3use crate::ff_ext::Legendre;
4use core::convert::TryInto;
5use core::ops::{Add, Mul, Neg, Sub};
6use rand::RngCore;
7use std::cmp::Ordering;
8use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
9
10#[cfg(feature = "derive_serde")]
11use serde::{Deserialize, Serialize};
12
13/// An element of Fq2, represented by c0 + c1 * u; where u^2 = -1.
14#[derive(Copy, Clone, Debug, Eq, PartialEq)]
15#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
16pub struct Fq2 {
17    pub c0: Fq,
18    pub c1: Fq,
19}
20
21/// `Fq2` elements are ordered lexicographically.
22impl Ord for Fq2 {
23    #[inline(always)]
24    fn cmp(&self, other: &Fq2) -> Ordering {
25        match self.c1.cmp(&other.c1) {
26            Ordering::Greater => Ordering::Greater,
27            Ordering::Less => Ordering::Less,
28            Ordering::Equal => self.c0.cmp(&other.c0),
29        }
30    }
31}
32
33impl PartialOrd for Fq2 {
34    #[inline(always)]
35    fn partial_cmp(&self, other: &Fq2) -> Option<Ordering> {
36        Some(self.cmp(other))
37    }
38}
39
40impl ConditionallySelectable for Fq2 {
41    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
42        Fq2 {
43            c0: Fq::conditional_select(&a.c0, &b.c0, choice),
44            c1: Fq::conditional_select(&a.c1, &b.c1, choice),
45        }
46    }
47}
48
49impl ConstantTimeEq for Fq2 {
50    fn ct_eq(&self, other: &Self) -> Choice {
51        self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1)
52    }
53}
54
55impl Default for Fq2 {
56    #[inline]
57    fn default() -> Self {
58        Self::ZERO
59    }
60}
61
62impl From<Fq2> for [u8; 64] {
63    fn from(value: Fq2) -> [u8; 64] {
64        value.to_bytes()
65    }
66}
67
68impl<'a> From<&'a Fq2> for [u8; 64] {
69    fn from(value: &'a Fq2) -> [u8; 64] {
70        value.to_bytes()
71    }
72}
73
74impl Neg for Fq2 {
75    type Output = Fq2;
76
77    #[inline]
78    fn neg(self) -> Fq2 {
79        -&self
80    }
81}
82
83impl<'a> Neg for &'a Fq2 {
84    type Output = Fq2;
85
86    #[inline]
87    fn neg(self) -> Fq2 {
88        self.neg()
89    }
90}
91
92impl<'a, 'b> Sub<&'b Fq2> for &'a Fq2 {
93    type Output = Fq2;
94
95    #[inline]
96    fn sub(self, rhs: &'b Fq2) -> Fq2 {
97        self.sub(rhs)
98    }
99}
100
101impl<'a, 'b> Add<&'b Fq2> for &'a Fq2 {
102    type Output = Fq2;
103
104    #[inline]
105    fn add(self, rhs: &'b Fq2) -> Fq2 {
106        self.add(rhs)
107    }
108}
109
110impl<'a, 'b> Mul<&'b Fq2> for &'a Fq2 {
111    type Output = Fq2;
112
113    #[inline]
114    fn mul(self, rhs: &'b Fq2) -> Fq2 {
115        self.mul(rhs)
116    }
117}
118
119use crate::{
120    impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
121    impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
122    impl_sum_prod,
123};
124impl_binops_additive!(Fq2, Fq2);
125impl_binops_multiplicative!(Fq2, Fq2);
126impl_sum_prod!(Fq2);
127
128impl Fq2 {
129    #[inline]
130    pub const fn zero() -> Fq2 {
131        Fq2 {
132            c0: Fq::zero(),
133            c1: Fq::zero(),
134        }
135    }
136
137    #[inline]
138    pub const fn one() -> Fq2 {
139        Fq2 {
140            c0: Fq::one(),
141            c1: Fq::zero(),
142        }
143    }
144
145    pub const fn new(c0: Fq, c1: Fq) -> Self {
146        Fq2 { c0, c1 }
147    }
148
149    pub const fn size() -> usize {
150        64
151    }
152    /// Attempts to convert a little-endian byte representation of
153    /// a scalar into a `Fq`, failing if the input is not canonical.
154    pub fn from_bytes(bytes: &[u8; 64]) -> CtOption<Fq2> {
155        let c0 = Fq::from_bytes(bytes[0..32].try_into().unwrap());
156        let c1 = Fq::from_bytes(bytes[32..64].try_into().unwrap());
157        CtOption::new(
158            Fq2 {
159                c0: c0.unwrap(),
160                c1: c1.unwrap(),
161            },
162            c0.is_some() & c1.is_some(),
163        )
164    }
165
166    /// Converts an element of `Fq` into a byte representation in
167    /// little-endian byte order.
168    pub fn to_bytes(&self) -> [u8; 64] {
169        let mut res = [0u8; 64];
170        let c0_bytes = self.c0.to_bytes();
171        let c1_bytes = self.c1.to_bytes();
172        res[0..32].copy_from_slice(&c0_bytes[..]);
173        res[32..64].copy_from_slice(&c1_bytes[..]);
174        res
175    }
176
177    pub fn mul_assign(&mut self, other: &Self) {
178        let mut t0 = self.c0 + self.c1;
179        let mut t1 = self.c0 * other.c0;
180        let t2 = self.c1 * other.c1;
181
182        self.c0 = t1 - t2;
183        self.c1 = other.c0 + other.c1;
184        t1 += t2;
185        t0 *= self.c1;
186        self.c1 = t0 - t1;
187    }
188
189    pub fn square_assign(&mut self) {
190        let ab = self.c0 * self.c1;
191        let c0c1 = self.c0 + self.c1;
192        let mut c0 = -self.c1;
193        c0 += self.c0;
194        c0 *= c0c1;
195        c0 -= ab;
196        self.c1 = ab.double();
197        self.c0 = c0 + ab;
198    }
199
200    pub fn double(&self) -> Self {
201        Self {
202            c0: self.c0.double(),
203            c1: self.c1.double(),
204        }
205    }
206
207    pub fn double_assign(&mut self) {
208        self.c0 = self.c0.double();
209        self.c1 = self.c1.double();
210    }
211
212    pub fn add(&self, other: &Self) -> Self {
213        Self {
214            c0: self.c0.add(&other.c0),
215            c1: self.c1.add(&other.c1),
216        }
217    }
218
219    pub fn sub(&self, other: &Self) -> Self {
220        Self {
221            c0: self.c0.sub(&other.c0),
222            c1: self.c1.sub(&other.c1),
223        }
224    }
225
226    pub fn mul(&self, other: &Self) -> Self {
227        let mut t = *other;
228        t.mul_assign(self);
229        t
230    }
231
232    pub fn square(&self) -> Self {
233        let mut t = *self;
234        t.square_assign();
235        t
236    }
237
238    pub fn neg(&self) -> Self {
239        Self {
240            c0: self.c0.neg(),
241            c1: self.c1.neg(),
242        }
243    }
244
245    // conjucate by negating c1
246    pub fn conjugate(&mut self) {
247        self.c1 = -self.c1;
248    }
249
250    pub fn frobenius_map(&mut self, power: usize) {
251        if power % 2 != 0 {
252            self.conjugate()
253        }
254    }
255
256    /// Multiply this element by quadratic nonresidue 9 + u.
257    pub fn mul_by_nonresidue(&mut self) {
258        // (xu+y)(u+9) = (9x+y)u+(9y-x)
259        let t0 = self.c0;
260        let t1 = self.c1;
261
262        // 8*x*i + 8*y
263        self.double_assign();
264        self.double_assign();
265        self.double_assign();
266
267        // 9*y
268        self.c0 += &t0;
269        // (9*y - x)
270        self.c0 -= &t1;
271
272        // (9*x)u
273        self.c1 += &t1;
274        // (9*x + y)
275        self.c1 += &t0;
276    }
277
278    pub fn invert(&self) -> CtOption<Self> {
279        let mut t1 = self.c1;
280        t1 = t1.square();
281        let mut t0 = self.c0;
282        t0 = t0.square();
283        t0 += &t1;
284        t0.invert().map(|t| {
285            let mut tmp = Fq2 {
286                c0: self.c0,
287                c1: self.c1,
288            };
289            tmp.c0 *= &t;
290            tmp.c1 *= &t;
291            tmp.c1 = -tmp.c1;
292
293            tmp
294        })
295    }
296
297    /// Norm of Fq2 as extension field in i over Fq
298    #[inline]
299    fn norm(&self) -> Fq {
300        let mut t0 = self.c0;
301        let mut t1 = self.c1;
302        t0 = t0.square();
303        t1 = t1.square();
304        t1 + t0
305    }
306}
307
308impl Legendre for Fq2 {
309    fn legendre(&self) -> i64 {
310        self.norm().legendre()
311    }
312}
313
314impl Field for Fq2 {
315    const ZERO: Self = Self::zero();
316    const ONE: Self = Self::one();
317
318    fn random(mut rng: impl RngCore) -> Self {
319        Fq2 {
320            c0: Fq::random(&mut rng),
321            c1: Fq::random(&mut rng),
322        }
323    }
324
325    fn is_zero(&self) -> Choice {
326        self.c0.is_zero() & self.c1.is_zero()
327    }
328
329    fn square(&self) -> Self {
330        self.square()
331    }
332
333    fn double(&self) -> Self {
334        self.double()
335    }
336
337    fn sqrt(&self) -> CtOption<Self> {
338        // Algorithm 9, https://eprint.iacr.org/2012/685.pdf
339
340        if self.is_zero().into() {
341            CtOption::new(Self::ZERO, Choice::from(1))
342        } else {
343            // a1 = self^((q - 3) / 4)
344            // 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f51
345            let u: [u64; 4] = [
346                0x4f082305b61f3f51,
347                0x65e05aa45a1c72a3,
348                0x6e14116da0605617,
349                0x0c19139cb84c680a,
350            ];
351            let mut a1 = self.pow(u);
352            let mut alpha = a1;
353
354            alpha.square_assign();
355            alpha.mul_assign(self);
356            let mut a0 = alpha;
357            a0.frobenius_map(1);
358            a0.mul_assign(&alpha);
359
360            let neg1 = Fq2 {
361                c0: NEGATIVE_ONE,
362                c1: Fq::zero(),
363            };
364
365            if a0 == neg1 {
366                CtOption::new(a0, Choice::from(0))
367            } else {
368                a1.mul_assign(self);
369
370                if alpha == neg1 {
371                    a1.mul_assign(&Fq2 {
372                        c0: Fq::zero(),
373                        c1: Fq::one(),
374                    });
375                } else {
376                    alpha += &Fq2::ONE;
377                    // alpha = alpha^((q - 1) / 2)
378                    // 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3
379                    let u: [u64; 4] = [
380                        0x9e10460b6c3e7ea3,
381                        0xcbc0b548b438e546,
382                        0xdc2822db40c0ac2e,
383                        0x183227397098d014,
384                    ];
385                    alpha = alpha.pow(u);
386                    a1.mul_assign(&alpha);
387                }
388                CtOption::new(a1, Choice::from(1))
389            }
390        }
391    }
392
393    fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
394        ff::helpers::sqrt_ratio_generic(num, div)
395    }
396
397    fn invert(&self) -> CtOption<Self> {
398        self.invert()
399    }
400}
401
402impl From<bool> for Fq2 {
403    fn from(bit: bool) -> Fq2 {
404        if bit {
405            Fq2::ONE
406        } else {
407            Fq2::ZERO
408        }
409    }
410}
411
412impl From<u64> for Fq2 {
413    fn from(val: u64) -> Self {
414        Fq2 {
415            c0: Fq::from(val),
416            c1: Fq::zero(),
417        }
418    }
419}
420
421impl PrimeField for Fq2 {
422    type Repr = Fq2Bytes;
423
424    const MODULUS: &'static str =
425        "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47";
426    const MULTIPLICATIVE_GENERATOR: Self = Fq2 {
427        c0: Fq::from_raw([0x03, 0x0, 0x0, 0x0]),
428        c1: Fq::ZERO,
429    };
430    const NUM_BITS: u32 = 254;
431    const CAPACITY: u32 = 253;
432    const S: u32 = 0;
433    // TODO: Check that we can just 0 this and forget.
434    const ROOT_OF_UNITY: Self = Fq2::zero();
435    const ROOT_OF_UNITY_INV: Self = Fq2 {
436        c0: Fq::zero(),
437        c1: Fq::zero(),
438    };
439    const DELTA: Self = Fq2 {
440        c0: Fq::zero(),
441        c1: Fq::zero(),
442    };
443    const TWO_INV: Self = Fq2 {
444        c0: Fq::from_raw([
445            0x9e10460b6c3e7ea4,
446            0xcbc0b548b438e546,
447            0xdc2822db40c0ac2e,
448            0x183227397098d014,
449        ]),
450        c1: Fq([0, 0, 0, 0]),
451    };
452
453    fn from_repr(repr: Self::Repr) -> CtOption<Self> {
454        let c0 = Fq::from_bytes(&repr.0[..32].try_into().unwrap());
455        let c1 = Fq::from_bytes(&repr.0[32..].try_into().unwrap());
456        // Disallow overflow representation
457        CtOption::new(Fq2::new(c0.unwrap(), c1.unwrap()), Choice::from(1))
458    }
459
460    fn to_repr(&self) -> Self::Repr {
461        Fq2Bytes(self.to_bytes())
462    }
463
464    fn is_odd(&self) -> Choice {
465        Choice::from(self.to_repr().as_ref()[0] & 1)
466    }
467}
468
469impl FromUniformBytes<64> for Fq2 {
470    fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
471        Self::new(Fq::from_uniform_bytes(bytes), Fq::zero())
472    }
473}
474#[derive(Clone, Copy, Debug)]
475pub struct Fq2Bytes([u8; 64]);
476
477impl Default for Fq2Bytes {
478    fn default() -> Self {
479        Self([0u8; 64])
480    }
481}
482
483impl AsMut<[u8]> for Fq2Bytes {
484    fn as_mut(&mut self) -> &mut [u8] {
485        &mut self.0
486    }
487}
488
489impl AsRef<[u8]> for Fq2Bytes {
490    fn as_ref(&self) -> &[u8] {
491        &self.0
492    }
493}
494
495impl crate::serde::SerdeObject for Fq2 {
496    fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self {
497        debug_assert_eq!(bytes.len(), 64);
498        let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes_unchecked(&bytes[i..i + 32]));
499        Self { c0, c1 }
500    }
501    fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
502        if bytes.len() != 64 {
503            return None;
504        }
505        let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes(&bytes[i..i + 32]));
506        c0.zip(c1).map(|(c0, c1)| Self { c0, c1 })
507    }
508    fn to_raw_bytes(&self) -> Vec<u8> {
509        let mut res = Vec::with_capacity(64);
510        for limb in self.c0.0.iter().chain(self.c1.0.iter()) {
511            res.extend_from_slice(&limb.to_le_bytes());
512        }
513        res
514    }
515    fn read_raw_unchecked<R: std::io::Read>(reader: &mut R) -> Self {
516        let [c0, c1] = [(); 2].map(|_| Fq::read_raw_unchecked(reader));
517        Self { c0, c1 }
518    }
519    fn read_raw<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
520        let c0 = Fq::read_raw(reader)?;
521        let c1 = Fq::read_raw(reader)?;
522        Ok(Self { c0, c1 })
523    }
524    fn write_raw<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
525        self.c0.write_raw(writer)?;
526        self.c1.write_raw(writer)
527    }
528}
529
530impl WithSmallOrderMulGroup<3> for Fq2 {
531    // Fq::ZETA ^2
532    const ZETA: Self = Fq2 {
533        c0: Fq::from_raw([
534            0x5763473177fffffe,
535            0xd4f263f1acdb5c4f,
536            0x59e26bcea0d48bac,
537            0x0000000000000000,
538        ]),
539        c1: Fq::zero(),
540    };
541}
542
543#[cfg(test)]
544use rand::SeedableRng;
545#[cfg(test)]
546use rand_xorshift::XorShiftRng;
547
548#[test]
549fn test_ser() {
550    let mut rng = XorShiftRng::from_seed([
551        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
552        0xe5,
553    ]);
554
555    let a0 = Fq2::random(&mut rng);
556    let a_bytes = a0.to_bytes();
557    let a1 = Fq2::from_bytes(&a_bytes).unwrap();
558    assert_eq!(a0, a1);
559}
560
561#[test]
562fn test_fq2_ordering() {
563    let mut a = Fq2 {
564        c0: Fq::zero(),
565        c1: Fq::zero(),
566    };
567
568    let mut b = a;
569
570    assert!(a.cmp(&b) == Ordering::Equal);
571    b.c0 += &Fq::one();
572    assert!(a.cmp(&b) == Ordering::Less);
573    a.c0 += &Fq::one();
574    assert!(a.cmp(&b) == Ordering::Equal);
575    b.c1 += &Fq::one();
576    assert!(a.cmp(&b) == Ordering::Less);
577    a.c0 += &Fq::one();
578    assert!(a.cmp(&b) == Ordering::Less);
579    a.c1 += &Fq::one();
580    assert!(a.cmp(&b) == Ordering::Greater);
581    b.c0 += &Fq::one();
582    assert!(a.cmp(&b) == Ordering::Equal);
583}
584
585#[test]
586fn test_fq2_basics() {
587    assert_eq!(
588        Fq2 {
589            c0: Fq::zero(),
590            c1: Fq::zero(),
591        },
592        Fq2::ZERO
593    );
594    assert_eq!(
595        Fq2 {
596            c0: Fq::one(),
597            c1: Fq::zero(),
598        },
599        Fq2::ONE
600    );
601    assert_eq!(Fq2::ZERO.is_zero().unwrap_u8(), 1);
602    assert_eq!(Fq2::ONE.is_zero().unwrap_u8(), 0);
603    assert_eq!(
604        Fq2 {
605            c0: Fq::zero(),
606            c1: Fq::one(),
607        }
608        .is_zero()
609        .unwrap_u8(),
610        0
611    );
612}
613
614#[test]
615fn test_fq2_squaring() {
616    let mut a = Fq2 {
617        c0: Fq::one(),
618        c1: Fq::one(),
619    }; // u + 1
620    a.square_assign();
621    assert_eq!(
622        a,
623        Fq2 {
624            c0: Fq::zero(),
625            c1: Fq::one() + Fq::one(),
626        }
627    ); // 2u
628
629    let mut a = Fq2 {
630        c0: Fq::zero(),
631        c1: Fq::one(),
632    }; // u
633    a.square_assign();
634    assert_eq!(a, {
635        let neg1 = -Fq::one();
636        Fq2 {
637            c0: neg1,
638            c1: Fq::zero(),
639        }
640    }); // -1
641}
642
643#[test]
644fn test_fq2_mul_nonresidue() {
645    let mut rng = XorShiftRng::from_seed([
646        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
647        0xe5,
648    ]);
649    let nine = Fq::one().double().double().double() + Fq::one();
650    let nqr = Fq2 {
651        c0: nine,
652        c1: Fq::one(),
653    };
654
655    for _ in 0..1000 {
656        let mut a = Fq2::random(&mut rng);
657        let mut b = a;
658        a.mul_by_nonresidue();
659        b.mul_assign(&nqr);
660
661        assert_eq!(a, b);
662    }
663}
664
665#[test]
666pub fn test_sqrt() {
667    let mut rng = XorShiftRng::from_seed([
668        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
669        0xe5,
670    ]);
671
672    for _ in 0..10000 {
673        let a = Fq2::random(&mut rng);
674        if a.legendre() == -1 {
675            assert!(bool::from(a.sqrt().is_none()));
676        }
677    }
678
679    for _ in 0..10000 {
680        let a = Fq2::random(&mut rng);
681        let mut b = a;
682        b.square_assign();
683        assert_eq!(b.legendre(), 1);
684
685        let b = b.sqrt().unwrap();
686        let mut negb = b;
687        negb = negb.neg();
688
689        assert!(a == b || a == negb);
690    }
691
692    let mut c = Fq2::ONE;
693    for _ in 0..10000 {
694        let mut b = c;
695        b.square_assign();
696        assert_eq!(b.legendre(), 1);
697
698        b = b.sqrt().unwrap();
699
700        if b != c {
701            b = b.neg();
702        }
703
704        assert_eq!(b, c);
705
706        c += &Fq2::ONE;
707    }
708}
709
710#[test]
711fn test_frobenius() {
712    let mut rng = XorShiftRng::from_seed([
713        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
714        0xe5,
715    ]);
716
717    for _ in 0..100 {
718        for i in 0..14 {
719            let mut a = Fq2::random(&mut rng);
720            let mut b = a;
721
722            for _ in 0..i {
723                a = a.pow([
724                    0x3c208c16d87cfd47,
725                    0x97816a916871ca8d,
726                    0xb85045b68181585d,
727                    0x30644e72e131a029,
728                ]);
729            }
730            b.frobenius_map(i);
731
732            assert_eq!(a, b);
733        }
734    }
735}
736
737#[test]
738fn test_zeta() {
739    let zeta = Fq2::new(Fq::ZETA.square(), Fq::zero());
740    assert_eq!(zeta, Fq2::ZETA);
741}
742
743#[test]
744fn test_field() {
745    crate::tests::field::random_field_tests::<Fq2>("fq2".to_string());
746}
747
748#[test]
749fn test_serialization() {
750    crate::tests::field::random_serialization_test::<Fq2>("fq2".to_string());
751    #[cfg(feature = "derive_serde")]
752    crate::tests::field::random_serde_test::<Fq2>("fq2".to_string());
753}