substrate_bn/fields/
fq2.rs
1use core::ops::{Add, Mul, Neg, Sub};
2use rand::Rng;
3use crate::fields::{const_fq, FieldElement, Fq};
4use crate::arith::{U256, U512};
5
6#[inline]
7fn fq_non_residue() -> Fq {
8 const_fq([
11 0x68c3488912edefaa,
12 0x8d087f6872aabf4f,
13 0x51e1a24709081231,
14 0x2259d6b14729c0fa,
15 ])
16}
17
18#[inline]
19pub fn fq2_nonresidue() -> Fq2 {
20 Fq2::new(
21 const_fq([
22 0xf60647ce410d7ff7,
23 0x2f3d6f4dd31bd011,
24 0x2943337e3940c6d1,
25 0x1d9598e8a7e39857,
26 ]),
27 const_fq([
28 0xd35d438dc58f0d9d,
29 0x0a78eb28f5c70b3d,
30 0x666ea36f7879462c,
31 0x0e0a77c19a07df2f,
32 ]),
33 )
34}
35
36#[derive(Copy, Clone, Debug, PartialEq, Eq)]
37#[repr(C)]
38pub struct Fq2 {
39 c0: Fq,
40 c1: Fq,
41}
42
43impl Fq2 {
44 pub fn new(c0: Fq, c1: Fq) -> Self {
45 Fq2 { c0: c0, c1: c1 }
46 }
47
48 pub fn scale(&self, by: Fq) -> Self {
49 Fq2 {
50 c0: self.c0 * by,
51 c1: self.c1 * by,
52 }
53 }
54
55 pub fn mul_by_nonresidue(&self) -> Self {
56 *self * fq2_nonresidue()
57 }
58
59 pub fn frobenius_map(&self, power: usize) -> Self {
60 if power % 2 == 0 {
61 *self
62 } else {
63 Fq2 {
64 c0: self.c0,
65 c1: self.c1 * fq_non_residue(),
66 }
67 }
68 }
69
70 pub fn real(&self) -> &Fq {
71 &self.c0
72 }
73
74 pub fn imaginary(&self) -> &Fq {
75 &self.c1
76 }
77}
78
79impl FieldElement for Fq2 {
80 fn zero() -> Self {
81 Fq2 {
82 c0: Fq::zero(),
83 c1: Fq::zero(),
84 }
85 }
86
87 fn one() -> Self {
88 Fq2 {
89 c0: Fq::one(),
90 c1: Fq::zero(),
91 }
92 }
93
94 fn random<R: Rng>(rng: &mut R) -> Self {
95 Fq2 {
96 c0: Fq::random(rng),
97 c1: Fq::random(rng),
98 }
99 }
100
101 fn is_zero(&self) -> bool {
102 self.c0.is_zero() && self.c1.is_zero()
103 }
104
105 fn squared(&self) -> Self {
106 let ab = self.c0 * self.c1;
111
112 Fq2 {
113 c0: (self.c1 * fq_non_residue() + self.c0) * (self.c0 + self.c1) - ab
114 - ab * fq_non_residue(),
115 c1: ab + ab,
116 }
117 }
118
119 fn inverse(self) -> Option<Self> {
120 match (self.c0.squared() - (self.c1.squared() * fq_non_residue())).inverse() {
124 Some(t) => Some(Fq2 {
125 c0: self.c0 * t,
126 c1: -(self.c1 * t),
127 }),
128 None => None,
129 }
130 }
131}
132
133impl Mul for Fq2 {
134 type Output = Fq2;
135
136 fn mul(self, other: Fq2) -> Fq2 {
137 let aa = self.c0 * other.c0;
142 let bb = self.c1 * other.c1;
143
144 Fq2 {
145 c0: bb * fq_non_residue() + aa,
146 c1: (self.c0 + self.c1) * (other.c0 + other.c1) - aa - bb,
147 }
148 }
149}
150
151impl Sub for Fq2 {
152 type Output = Fq2;
153
154 fn sub(self, other: Fq2) -> Fq2 {
155 Fq2 {
156 c0: self.c0 - other.c0,
157 c1: self.c1 - other.c1,
158 }
159 }
160}
161
162impl Add for Fq2 {
163 type Output = Fq2;
164
165 fn add(self, other: Fq2) -> Fq2 {
166 Fq2 {
167 c0: self.c0 + other.c0,
168 c1: self.c1 + other.c1,
169 }
170 }
171}
172
173impl Neg for Fq2 {
174 type Output = Fq2;
175
176 fn neg(self) -> Fq2 {
177 Fq2 {
178 c0: -self.c0,
179 c1: -self.c1,
180 }
181 }
182}
183
184lazy_static::lazy_static! {
185 static ref FQ: U256 = U256::from([
186 0x3c208c16d87cfd47,
187 0x97816a916871ca8d,
188 0xb85045b68181585d,
189 0x30644e72e131a029
190 ]);
191
192 static ref FQ_MINUS3_DIV4: Fq =
193 Fq::new(3.into()).expect("3 is a valid field element and static; qed").neg() *
194 Fq::new(4.into()).expect("4 is a valid field element and static; qed").inverse()
195 .expect("4 has inverse in Fq and is static; qed");
196
197 static ref FQ_MINUS1_DIV2: Fq =
198 Fq::new(1.into()).expect("1 is a valid field element and static; qed").neg() *
199 Fq::new(2.into()).expect("2 is a valid field element and static; qed").inverse()
200 .expect("2 has inverse in Fq and is static; qed");
201}
202
203impl Fq2 {
204 pub fn i() -> Fq2 {
205 Fq2::new(Fq::zero(), Fq::one())
206 }
207
208 pub fn sqrt(&self) -> Option<Self> {
209 let a1 = self.pow::<U256>((*FQ_MINUS3_DIV4).into());
210 let a1a = a1 * *self;
211 let alpha = a1 * a1a;
212 let a0 = alpha.pow(*FQ) * alpha;
213
214 if a0 == Fq2::one().neg() {
215 return None;
216 }
217
218 if alpha == Fq2::one().neg() {
219 Some(Self::i() * a1a)
220 } else {
221 let b = (alpha + Fq2::one()).pow::<U256>((*FQ_MINUS1_DIV2).into());
222 Some(b * a1a)
223 }
224 }
225
226 pub fn to_u512(&self) -> U512 {
227 let c0: U256 = (*self.real()).into();
228 let c1: U256 = (*self.imaginary()).into();
229
230 U512::new(&c1, &c0, &FQ)
231 }
232}
233
234
235#[test]
236fn sqrt_fq2() {
237 let x1 = Fq2::new(
239 Fq::from_str("12844195307879678418043983815760255909500142247603239203345049921980497041944").unwrap(),
240 Fq::from_str("7476417578426924565731404322659619974551724117137577781074613937423560117731").unwrap(),
241 );
242
243 let x2 = Fq2::new(
244 Fq::from_str("3345897230485723946872934576923485762803457692345760237495682347502347589474").unwrap(),
245 Fq::from_str("1234912378405347958234756902345768290345762348957605678245967234857634857676").unwrap(),
246 );
247
248 assert_eq!(x2.sqrt().unwrap(), x1);
249
250 assert_eq!(
252 Fq2::one().neg().sqrt().unwrap(),
253 Fq2::i(),
254 );
255
256 assert!(
258 Fq2::new(Fq::from_str("1").unwrap(), Fq::from_str("2").unwrap()).sqrt().is_none()
259 );
260}