substrate_bn/fields/
fq6.rs

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}