pairing_plus/bls12_381/
fq6.rs

1use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2};
2use super::fq2::Fq2;
3use ff::Field;
4use rand_core::RngCore;
5
6/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
7#[derive(Copy, Clone, Debug, Eq, PartialEq)]
8pub struct Fq6 {
9    pub c0: Fq2,
10    pub c1: Fq2,
11    pub c2: Fq2,
12}
13
14impl ::std::fmt::Display for Fq6 {
15    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
16        write!(f, "Fq6({} + {} * v, {} * v^2)", self.c0, self.c1, self.c2)
17    }
18}
19
20impl Fq6 {
21    /// Multiply by quadratic nonresidue v.
22    pub fn mul_by_nonresidue(&mut self) {
23        use std::mem::swap;
24        swap(&mut self.c0, &mut self.c1);
25        swap(&mut self.c0, &mut self.c2);
26
27        self.c0.mul_by_nonresidue();
28    }
29
30    pub fn mul_by_1(&mut self, c1: &Fq2) {
31        let mut b_b = self.c1;
32        b_b.mul_assign(c1);
33
34        let mut t1 = *c1;
35        {
36            let mut tmp = self.c1;
37            tmp.add_assign(&self.c2);
38
39            t1.mul_assign(&tmp);
40            t1.sub_assign(&b_b);
41            t1.mul_by_nonresidue();
42        }
43
44        let mut t2 = *c1;
45        {
46            let mut tmp = self.c0;
47            tmp.add_assign(&self.c1);
48
49            t2.mul_assign(&tmp);
50            t2.sub_assign(&b_b);
51        }
52
53        self.c0 = t1;
54        self.c1 = t2;
55        self.c2 = b_b;
56    }
57
58    pub fn mul_by_01(&mut self, c0: &Fq2, c1: &Fq2) {
59        let mut a_a = self.c0;
60        let mut b_b = self.c1;
61        a_a.mul_assign(c0);
62        b_b.mul_assign(c1);
63
64        let mut t1 = *c1;
65        {
66            let mut tmp = self.c1;
67            tmp.add_assign(&self.c2);
68
69            t1.mul_assign(&tmp);
70            t1.sub_assign(&b_b);
71            t1.mul_by_nonresidue();
72            t1.add_assign(&a_a);
73        }
74
75        let mut t3 = *c0;
76        {
77            let mut tmp = self.c0;
78            tmp.add_assign(&self.c2);
79
80            t3.mul_assign(&tmp);
81            t3.sub_assign(&a_a);
82            t3.add_assign(&b_b);
83        }
84
85        let mut t2 = *c0;
86        t2.add_assign(c1);
87        {
88            let mut tmp = self.c0;
89            tmp.add_assign(&self.c1);
90
91            t2.mul_assign(&tmp);
92            t2.sub_assign(&a_a);
93            t2.sub_assign(&b_b);
94        }
95
96        self.c0 = t1;
97        self.c1 = t2;
98        self.c2 = t3;
99    }
100}
101
102impl Field for Fq6 {
103    fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
104        Fq6 {
105            c0: Fq2::random(rng),
106            c1: Fq2::random(rng),
107            c2: Fq2::random(rng),
108        }
109    }
110    fn zero() -> Self {
111        Fq6 {
112            c0: Fq2::zero(),
113            c1: Fq2::zero(),
114            c2: Fq2::zero(),
115        }
116    }
117
118    fn one() -> Self {
119        Fq6 {
120            c0: Fq2::one(),
121            c1: Fq2::zero(),
122            c2: Fq2::zero(),
123        }
124    }
125
126    fn is_zero(&self) -> bool {
127        self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero()
128    }
129
130    fn double(&mut self) {
131        self.c0.double();
132        self.c1.double();
133        self.c2.double();
134    }
135
136    fn negate(&mut self) {
137        self.c0.negate();
138        self.c1.negate();
139        self.c2.negate();
140    }
141
142    fn add_assign(&mut self, other: &Self) {
143        self.c0.add_assign(&other.c0);
144        self.c1.add_assign(&other.c1);
145        self.c2.add_assign(&other.c2);
146    }
147
148    fn sub_assign(&mut self, other: &Self) {
149        self.c0.sub_assign(&other.c0);
150        self.c1.sub_assign(&other.c1);
151        self.c2.sub_assign(&other.c2);
152    }
153
154    fn frobenius_map(&mut self, power: usize) {
155        self.c0.frobenius_map(power);
156        self.c1.frobenius_map(power);
157        self.c2.frobenius_map(power);
158
159        self.c1.mul_assign(&FROBENIUS_COEFF_FQ6_C1[power % 6]);
160        self.c2.mul_assign(&FROBENIUS_COEFF_FQ6_C2[power % 6]);
161    }
162
163    fn square(&mut self) {
164        let mut s0 = self.c0;
165        s0.square();
166        let mut ab = self.c0;
167        ab.mul_assign(&self.c1);
168        let mut s1 = ab;
169        s1.double();
170        let mut s2 = self.c0;
171        s2.sub_assign(&self.c1);
172        s2.add_assign(&self.c2);
173        s2.square();
174        let mut bc = self.c1;
175        bc.mul_assign(&self.c2);
176        let mut s3 = bc;
177        s3.double();
178        let mut s4 = self.c2;
179        s4.square();
180
181        self.c0 = s3;
182        self.c0.mul_by_nonresidue();
183        self.c0.add_assign(&s0);
184
185        self.c1 = s4;
186        self.c1.mul_by_nonresidue();
187        self.c1.add_assign(&s1);
188
189        self.c2 = s1;
190        self.c2.add_assign(&s2);
191        self.c2.add_assign(&s3);
192        self.c2.sub_assign(&s0);
193        self.c2.sub_assign(&s4);
194    }
195
196    fn mul_assign(&mut self, other: &Self) {
197        let mut a_a = self.c0;
198        let mut b_b = self.c1;
199        let mut c_c = self.c2;
200        a_a.mul_assign(&other.c0);
201        b_b.mul_assign(&other.c1);
202        c_c.mul_assign(&other.c2);
203
204        let mut t1 = other.c1;
205        t1.add_assign(&other.c2);
206        {
207            let mut tmp = self.c1;
208            tmp.add_assign(&self.c2);
209
210            t1.mul_assign(&tmp);
211            t1.sub_assign(&b_b);
212            t1.sub_assign(&c_c);
213            t1.mul_by_nonresidue();
214            t1.add_assign(&a_a);
215        }
216
217        let mut t3 = other.c0;
218        t3.add_assign(&other.c2);
219        {
220            let mut tmp = self.c0;
221            tmp.add_assign(&self.c2);
222
223            t3.mul_assign(&tmp);
224            t3.sub_assign(&a_a);
225            t3.add_assign(&b_b);
226            t3.sub_assign(&c_c);
227        }
228
229        let mut t2 = other.c0;
230        t2.add_assign(&other.c1);
231        {
232            let mut tmp = self.c0;
233            tmp.add_assign(&self.c1);
234
235            t2.mul_assign(&tmp);
236            t2.sub_assign(&a_a);
237            t2.sub_assign(&b_b);
238            c_c.mul_by_nonresidue();
239            t2.add_assign(&c_c);
240        }
241
242        self.c0 = t1;
243        self.c1 = t2;
244        self.c2 = t3;
245    }
246
247    fn inverse(&self) -> Option<Self> {
248        let mut c0 = self.c2;
249        c0.mul_by_nonresidue();
250        c0.mul_assign(&self.c1);
251        c0.negate();
252        {
253            let mut c0s = self.c0;
254            c0s.square();
255            c0.add_assign(&c0s);
256        }
257        let mut c1 = self.c2;
258        c1.square();
259        c1.mul_by_nonresidue();
260        {
261            let mut c01 = self.c0;
262            c01.mul_assign(&self.c1);
263            c1.sub_assign(&c01);
264        }
265        let mut c2 = self.c1;
266        c2.square();
267        {
268            let mut c02 = self.c0;
269            c02.mul_assign(&self.c2);
270            c2.sub_assign(&c02);
271        }
272
273        let mut tmp1 = self.c2;
274        tmp1.mul_assign(&c1);
275        let mut tmp2 = self.c1;
276        tmp2.mul_assign(&c2);
277        tmp1.add_assign(&tmp2);
278        tmp1.mul_by_nonresidue();
279        tmp2 = self.c0;
280        tmp2.mul_assign(&c0);
281        tmp1.add_assign(&tmp2);
282
283        match tmp1.inverse() {
284            Some(t) => {
285                let mut tmp = Fq6 {
286                    c0: t,
287                    c1: t,
288                    c2: t,
289                };
290                tmp.c0.mul_assign(&c0);
291                tmp.c1.mul_assign(&c1);
292                tmp.c2.mul_assign(&c2);
293
294                Some(tmp)
295            }
296            None => None,
297        }
298    }
299}
300
301#[cfg(test)]
302use rand_core::SeedableRng;
303//use rand::{SeedableRng, XorShiftRng};
304
305#[test]
306fn test_fq6_mul_nonresidue() {
307    let mut rng = rand_xorshift::XorShiftRng::from_seed([
308        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
309        0xe5,
310    ]);
311    let nqr = Fq6 {
312        c0: Fq2::zero(),
313        c1: Fq2::one(),
314        c2: Fq2::zero(),
315    };
316
317    for _ in 0..1000 {
318        let mut a = Fq6::random(&mut rng);
319        let mut b = a;
320        a.mul_by_nonresidue();
321        b.mul_assign(&nqr);
322
323        assert_eq!(a, b);
324    }
325}
326
327#[test]
328fn test_fq6_mul_by_1() {
329    let mut rng = rand_xorshift::XorShiftRng::from_seed([
330        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
331        0xe5,
332    ]);
333    for _ in 0..1000 {
334        let c1 = Fq2::random(&mut rng);
335        let mut a = Fq6::random(&mut rng);
336        let mut b = a;
337
338        a.mul_by_1(&c1);
339        b.mul_assign(&Fq6 {
340            c0: Fq2::zero(),
341            c1,
342            c2: Fq2::zero(),
343        });
344
345        assert_eq!(a, b);
346    }
347}
348
349#[test]
350fn test_fq6_mul_by_01() {
351    let mut rng = rand_xorshift::XorShiftRng::from_seed([
352        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
353        0xe5,
354    ]);
355    for _ in 0..1000 {
356        let c0 = Fq2::random(&mut rng);
357        let c1 = Fq2::random(&mut rng);
358        let mut a = Fq6::random(&mut rng);
359        let mut b = a;
360
361        a.mul_by_01(&c0, &c1);
362        b.mul_assign(&Fq6 {
363            c0,
364            c1,
365            c2: Fq2::zero(),
366        });
367
368        assert_eq!(a, b);
369    }
370}
371
372#[test]
373fn fq6_field_tests() {
374    use ff::PrimeField;
375
376    ::tests::field::random_field_tests::<Fq6>();
377    ::tests::field::random_frobenius_tests::<Fq6, _>(super::fq::Fq::char(), 13);
378}