1use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2};
2use super::fq2::Fq2;
3use ff::Field;
4use rand_core::RngCore;
5
6#[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 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#[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}