pairing_plus/bls12_381/
fq12.rs

1use super::fq::FROBENIUS_COEFF_FQ12_C1;
2use super::fq2::Fq2;
3use super::fq6::Fq6;
4use ff::Field;
5use rand_core::RngCore;
6
7/// An element of Fq12, represented by c0 + c1 * w.
8#[derive(Copy, Clone, Debug, Eq, PartialEq)]
9pub struct Fq12 {
10    pub c0: Fq6,
11    pub c1: Fq6,
12}
13
14impl ::std::fmt::Display for Fq12 {
15    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
16        write!(f, "Fq12({} + {} * w)", self.c0, self.c1)
17    }
18}
19
20impl Fq12 {
21    pub fn conjugate(&mut self) {
22        self.c1.negate();
23    }
24
25    pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) {
26        let mut aa = self.c0;
27        aa.mul_by_01(c0, c1);
28        let mut bb = self.c1;
29        bb.mul_by_1(c4);
30        let mut o = *c1;
31        o.add_assign(c4);
32        self.c1.add_assign(&self.c0);
33        self.c1.mul_by_01(c0, &o);
34        self.c1.sub_assign(&aa);
35        self.c1.sub_assign(&bb);
36        self.c0 = bb;
37        self.c0.mul_by_nonresidue();
38        self.c0.add_assign(&aa);
39    }
40}
41
42impl Field for Fq12 {
43    fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
44        Fq12 {
45            c0: Fq6::random(rng),
46            c1: Fq6::random(rng),
47        }
48    }
49    fn zero() -> Self {
50        Fq12 {
51            c0: Fq6::zero(),
52            c1: Fq6::zero(),
53        }
54    }
55
56    fn one() -> Self {
57        Fq12 {
58            c0: Fq6::one(),
59            c1: Fq6::zero(),
60        }
61    }
62
63    fn is_zero(&self) -> bool {
64        self.c0.is_zero() && self.c1.is_zero()
65    }
66
67    fn double(&mut self) {
68        self.c0.double();
69        self.c1.double();
70    }
71
72    fn negate(&mut self) {
73        self.c0.negate();
74        self.c1.negate();
75    }
76
77    fn add_assign(&mut self, other: &Self) {
78        self.c0.add_assign(&other.c0);
79        self.c1.add_assign(&other.c1);
80    }
81
82    fn sub_assign(&mut self, other: &Self) {
83        self.c0.sub_assign(&other.c0);
84        self.c1.sub_assign(&other.c1);
85    }
86
87    fn frobenius_map(&mut self, power: usize) {
88        self.c0.frobenius_map(power);
89        self.c1.frobenius_map(power);
90
91        self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
92        self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
93        self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
94    }
95
96    fn square(&mut self) {
97        let mut ab = self.c0;
98        ab.mul_assign(&self.c1);
99        let mut c0c1 = self.c0;
100        c0c1.add_assign(&self.c1);
101        let mut c0 = self.c1;
102        c0.mul_by_nonresidue();
103        c0.add_assign(&self.c0);
104        c0.mul_assign(&c0c1);
105        c0.sub_assign(&ab);
106        self.c1 = ab;
107        self.c1.add_assign(&ab);
108        ab.mul_by_nonresidue();
109        c0.sub_assign(&ab);
110        self.c0 = c0;
111    }
112
113    fn mul_assign(&mut self, other: &Self) {
114        let mut aa = self.c0;
115        aa.mul_assign(&other.c0);
116        let mut bb = self.c1;
117        bb.mul_assign(&other.c1);
118        let mut o = other.c0;
119        o.add_assign(&other.c1);
120        self.c1.add_assign(&self.c0);
121        self.c1.mul_assign(&o);
122        self.c1.sub_assign(&aa);
123        self.c1.sub_assign(&bb);
124        self.c0 = bb;
125        self.c0.mul_by_nonresidue();
126        self.c0.add_assign(&aa);
127    }
128
129    fn inverse(&self) -> Option<Self> {
130        let mut c0s = self.c0;
131        c0s.square();
132        let mut c1s = self.c1;
133        c1s.square();
134        c1s.mul_by_nonresidue();
135        c0s.sub_assign(&c1s);
136
137        c0s.inverse().map(|t| {
138            let mut tmp = Fq12 { c0: t, c1: t };
139            tmp.c0.mul_assign(&self.c0);
140            tmp.c1.mul_assign(&self.c1);
141            tmp.c1.negate();
142
143            tmp
144        })
145    }
146}
147
148#[cfg(test)]
149use rand_core::SeedableRng;
150//use rand::{SeedableRng, XorShiftRng};
151
152#[test]
153fn test_fq12_mul_by_014() {
154    let mut rng = rand_xorshift::XorShiftRng::from_seed([
155        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
156        0xe5,
157    ]);
158    for _ in 0..1000 {
159        let c0 = Fq2::random(&mut rng);
160        let c1 = Fq2::random(&mut rng);
161        let c5 = Fq2::random(&mut rng);
162        let mut a = Fq12::random(&mut rng);
163        let mut b = a;
164
165        a.mul_by_014(&c0, &c1, &c5);
166        b.mul_assign(&Fq12 {
167            c0: Fq6 {
168                c0,
169                c1,
170                c2: Fq2::zero(),
171            },
172            c1: Fq6 {
173                c0: Fq2::zero(),
174                c1: c5,
175                c2: Fq2::zero(),
176            },
177        });
178
179        assert_eq!(a, b);
180    }
181}
182
183#[test]
184fn fq12_field_tests() {
185    use ff::PrimeField;
186
187    ::tests::field::random_field_tests::<Fq12>();
188    ::tests::field::random_frobenius_tests::<Fq12, _>(super::fq::Fq::char(), 13);
189}