1use crate::fields::{const_fq, FieldElement, Fq, Fq2};
2use core::ops::{Add, Mul, Neg, Sub};
3use rand::Rng;
4
5fn frobenius_coeffs_c1(n: usize) -> Fq2 {
6 match n % 6 {
7 0 => Fq2::one(),
8 1 => Fq2::new(
9 const_fq([
10 13075984984163199792,
11 3782902503040509012,
12 8791150885551868305,
13 1825854335138010348,
14 ]),
15 const_fq([
16 7963664994991228759,
17 12257807996192067905,
18 13179524609921305146,
19 2767831111890561987,
20 ]),
21 ),
22 2 => Fq2::new(
23 const_fq([
24 3697675806616062876,
25 9065277094688085689,
26 6918009208039626314,
27 2775033306905974752,
28 ]),
29 Fq::zero(),
30 ),
31 3 => Fq2::new(
32 const_fq([
33 14532872967180610477,
34 12903226530429559474,
35 1868623743233345524,
36 2316889217940299650,
37 ]),
38 const_fq([
39 12447993766991532972,
40 4121872836076202828,
41 7630813605053367399,
42 740282956577754197,
43 ]),
44 ),
45 _ => unimplemented!(),
46 }
47}
48fn frobenius_coeffs_c2(n: usize) -> Fq2 {
49 match n % 6 {
50 0 => Fq2::one(),
51 1 => Fq2::new(
52 const_fq([
53 8314163329781907090,
54 11942187022798819835,
55 11282677263046157209,
56 1576150870752482284,
57 ]),
58 const_fq([
59 6763840483288992073,
60 7118829427391486816,
61 4016233444936635065,
62 2630958277570195709,
63 ]),
64 ),
65 2 => Fq2::new(
66 const_fq([
67 8183898218631979349,
68 12014359695528440611,
69 12263358156045030468,
70 3187210487005268291,
71 ]),
72 Fq::zero(),
73 ),
74 3 => Fq2::new(
75 const_fq([
76 4938922280314430175,
77 13823286637238282975,
78 15589480384090068090,
79 481952561930628184,
80 ]),
81 const_fq([
82 3105754162722846417,
83 11647802298615474591,
84 13057042392041828081,
85 1660844386505564338,
86 ]),
87 ),
88 _ => unimplemented!(),
89 }
90}
91
92#[derive(Copy, Clone, Debug, PartialEq, Eq)]
93#[repr(C)]
94pub struct Fq6 {
95 pub c0: Fq2,
96 pub c1: Fq2,
97 pub c2: Fq2,
98}
99
100impl Fq6 {
101 pub fn new(c0: Fq2, c1: Fq2, c2: Fq2) -> Self {
102 Fq6 {
103 c0: c0,
104 c1: c1,
105 c2: c2,
106 }
107 }
108
109 pub fn mul_by_nonresidue(&self) -> Self {
110 Fq6 {
111 c0: self.c2.mul_by_nonresidue(),
112 c1: self.c0,
113 c2: self.c1,
114 }
115 }
116
117 pub fn scale(&self, by: Fq2) -> Self {
118 Fq6 {
119 c0: self.c0 * by,
120 c1: self.c1 * by,
121 c2: self.c2 * by,
122 }
123 }
124
125 pub fn frobenius_map(&self, power: usize) -> Self {
126 Fq6 {
127 c0: self.c0.frobenius_map(power),
128 c1: self.c1.frobenius_map(power) * frobenius_coeffs_c1(power),
129 c2: self.c2.frobenius_map(power) * frobenius_coeffs_c2(power),
130 }
131 }
132}
133
134impl FieldElement for Fq6 {
135 fn zero() -> Self {
136 Fq6 {
137 c0: Fq2::zero(),
138 c1: Fq2::zero(),
139 c2: Fq2::zero(),
140 }
141 }
142
143 fn one() -> Self {
144 Fq6 {
145 c0: Fq2::one(),
146 c1: Fq2::zero(),
147 c2: Fq2::zero(),
148 }
149 }
150
151 fn random<R: Rng>(rng: &mut R) -> Self {
152 Fq6 {
153 c0: Fq2::random(rng),
154 c1: Fq2::random(rng),
155 c2: Fq2::random(rng),
156 }
157 }
158
159 fn is_zero(&self) -> bool {
160 self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero()
161 }
162
163 fn squared(&self) -> Self {
164 let s0 = self.c0.squared();
165 let ab = self.c0 * self.c1;
166 let s1 = ab + ab;
167 let s2 = (self.c0 - self.c1 + self.c2).squared();
168 let bc = self.c1 * self.c2;
169 let s3 = bc + bc;
170 let s4 = self.c2.squared();
171
172 Fq6 {
173 c0: s0 + s3.mul_by_nonresidue(),
174 c1: s1 + s4.mul_by_nonresidue(),
175 c2: s1 + s2 + s3 - s0 - s4,
176 }
177 }
178
179 fn inverse(self) -> Option<Self> {
180 let c0 = self.c0.squared() - self.c1 * self.c2.mul_by_nonresidue();
181 let c1 = self.c2.squared().mul_by_nonresidue() - self.c0 * self.c1;
182 let c2 = self.c1.squared() - self.c0 * self.c2;
183 match ((self.c2 * c1 + self.c1 * c2).mul_by_nonresidue() + self.c0 * c0).inverse() {
184 Some(t) => Some(Fq6 {
185 c0: t * c0,
186 c1: t * c1,
187 c2: t * c2,
188 }),
189 None => None,
190 }
191 }
192}
193
194impl Mul for Fq6 {
195 type Output = Fq6;
196
197 fn mul(self, other: Fq6) -> Fq6 {
198 let a_a = self.c0 * other.c0;
199 let b_b = self.c1 * other.c1;
200 let c_c = self.c2 * other.c2;
201
202 Fq6 {
203 c0: ((self.c1 + self.c2) * (other.c1 + other.c2) - b_b - c_c).mul_by_nonresidue() + a_a,
204 c1: (self.c0 + self.c1) * (other.c0 + other.c1) - a_a - b_b + c_c.mul_by_nonresidue(),
205 c2: (self.c0 + self.c2) * (other.c0 + other.c2) - a_a + b_b - c_c,
206 }
207 }
208}
209
210impl Sub for Fq6 {
211 type Output = Fq6;
212
213 fn sub(self, other: Fq6) -> Fq6 {
214 Fq6 {
215 c0: self.c0 - other.c0,
216 c1: self.c1 - other.c1,
217 c2: self.c2 - other.c2,
218 }
219 }
220}
221
222impl Add for Fq6 {
223 type Output = Fq6;
224
225 fn add(self, other: Fq6) -> Fq6 {
226 Fq6 {
227 c0: self.c0 + other.c0,
228 c1: self.c1 + other.c1,
229 c2: self.c2 + other.c2,
230 }
231 }
232}
233
234impl Neg for Fq6 {
235 type Output = Fq6;
236
237 fn neg(self) -> Fq6 {
238 Fq6 {
239 c0: -self.c0,
240 c1: -self.c1,
241 c2: -self.c2,
242 }
243 }
244}