Coverage Summary for Class: Fp12 (co.rsk.crypto.altbn128java)
Class |
Class, %
|
Method, %
|
Line, %
|
Fp12 |
0%
(0/1)
|
0%
(0/22)
|
0%
(0/145)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2019 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package co.rsk.crypto.altbn128java;
21
22 import java.math.BigInteger;
23 import java.util.Objects;
24
25 /**
26 * Arithmetic in Fp_12 <br/>
27 * <br/>
28 *
29 * "p" equals 21888242871839275222246405745257275088696311157297823662689037894645226208583, <br/>
30 * elements of Fp_12 are represented with 2 elements of {@link Fp6} <br/>
31 * <br/>
32 *
33 * Field arithmetic is ported from <a href="https://github.com/scipr-lab/libff/blob/master/libff/algebra/fields/fp12_2over3over2.tcc">libff</a>
34 *
35 * @author Mikhail Kalinin
36 * @since 02.09.2017
37 */
38 class Fp12 implements Field<Fp12> {
39
40 public static final Fp12 ZERO = new Fp12(Fp6.ZERO, Fp6.ZERO);
41 public static final Fp12 _1 = new Fp12(Fp6._1, Fp6.ZERO);
42
43 private Fp6 a;
44
45 public Fp6 a() {
46 return a;
47 }
48
49 public Fp6 b() {
50 return b;
51 }
52
53 private Fp6 b;
54
55 Fp12 (Fp6 a, Fp6 b) {
56 this.a = a;
57 this.b = b;
58 }
59
60 @Override
61 public Fp12 squared() {
62
63 Fp6 ab = a.mul(b);
64
65 Fp6 ra = a.add(b).mul(a.add(b.mulByNonResidue())).sub(ab).sub(ab.mulByNonResidue());
66 Fp6 rb = ab.add(ab);
67
68 return new Fp12(ra, rb);
69 }
70
71 @Override
72 public Fp12 dbl() {
73 return null;
74 }
75
76 Fp12 mulBy024(Fp2 ell0, Fp2 ellVW, Fp2 ellVV) {
77
78 Fp2 z0 = a.a();
79 Fp2 z1 = a.b();
80 Fp2 z2 = a.c();
81 Fp2 z3 = b.a();
82 Fp2 z4 = b.b();
83 Fp2 z5 = b.c();
84
85 Fp2 x0 = ell0;
86 Fp2 x2 = ellVV;
87 Fp2 x4 = ellVW;
88
89 Fp2 t0, t1, t2, s0, t3, t4, d0, d2, d4, s1;
90
91 d0 = z0.mul(x0);
92 d2 = z2.mul(x2);
93 d4 = z4.mul(x4);
94 t2 = z0.add(z4);
95 t1 = z0.add(z2);
96 s0 = z1.add(z3).add(z5);
97
98 // For z.a_.a_ = z0.
99 s1 = z1.mul(x2);
100 t3 = s1.add(d4);
101 t4 = Fp6.NON_RESIDUE.mul(t3).add(d0);
102 z0 = t4;
103
104 // For z.a_.b_ = z1
105 t3 = z5.mul(x4);
106 s1 = s1.add(t3);
107 t3 = t3.add(d2);
108 t4 = Fp6.NON_RESIDUE.mul(t3);
109 t3 = z1.mul(x0);
110 s1 = s1.add(t3);
111 t4 = t4.add(t3);
112 z1 = t4;
113
114 // For z.a_.c_ = z2
115 t0 = x0.add(x2);
116 t3 = t1.mul(t0).sub(d0).sub(d2);
117 t4 = z3.mul(x4);
118 s1 = s1.add(t4);
119 t3 = t3.add(t4);
120
121 // For z.b_.a_ = z3 (z3 needs z2)
122 t0 = z2.add(z4);
123 z2 = t3;
124 t1 = x2.add(x4);
125 t3 = t0.mul(t1).sub(d2).sub(d4);
126 t4 = Fp6.NON_RESIDUE.mul(t3);
127 t3 = z3.mul(x0);
128 s1 = s1.add(t3);
129 t4 = t4.add(t3);
130 z3 = t4;
131
132 // For z.b_.b_ = z4
133 t3 = z5.mul(x2);
134 s1 = s1.add(t3);
135 t4 = Fp6.NON_RESIDUE.mul(t3);
136 t0 = x0.add(x4);
137 t3 = t2.mul(t0).sub(d0).sub(d4);
138 t4 = t4.add(t3);
139 z4 = t4;
140
141 // For z.b_.c_ = z5.
142 t0 = x0.add(x2).add(x4);
143 t3 = s0.mul(t0).sub(s1);
144 z5 = t3;
145
146 return new Fp12(new Fp6(z0, z1, z2), new Fp6(z3, z4, z5));
147 }
148
149 @Override
150 public Fp12 add(Fp12 o) {
151 return new Fp12(a.add(o.a), b.add(o.b));
152 }
153
154 @Override
155 public Fp12 mul(Fp12 o) {
156
157 Fp6 a2 = o.a, b2 = o.b;
158 Fp6 a1 = a, b1 = b;
159
160 Fp6 a1a2 = a1.mul(a2);
161 Fp6 b1b2 = b1.mul(b2);
162
163 Fp6 ra = a1a2.add(b1b2.mulByNonResidue());
164 Fp6 rb = a1.add(b1).mul(a2.add(b2)).sub(a1a2).sub(b1b2);
165
166 return new Fp12(ra, rb);
167 }
168
169 @Override
170 public Fp12 sub(Fp12 o) {
171 return new Fp12(a.sub(o.a), b.sub(o.b));
172 }
173
174 @Override
175 public Fp12 inverse() {
176
177 Fp6 t0 = a.squared();
178 Fp6 t1 = b.squared();
179 Fp6 t2 = t0.sub(t1.mulByNonResidue());
180 Fp6 t3 = t2.inverse();
181
182 Fp6 ra = a.mul(t3);
183 Fp6 rb = b.mul(t3).negate();
184
185 return new Fp12(ra, rb);
186 }
187
188 @Override
189 public Fp12 negate() {
190 return new Fp12(a.negate(), b.negate());
191 }
192
193 @Override
194 public boolean isZero() {
195 return this.equals(ZERO);
196 }
197
198 @Override
199 public boolean isValid() {
200 return a.isValid() && b.isValid();
201 }
202
203 Fp12 frobeniusMap(int power) {
204
205 Fp6 ra = a.frobeniusMap(power);
206 Fp6 rb = b.frobeniusMap(power).mul(FROBENIUS_COEFFS_B[power % 12]);
207
208 return new Fp12(ra, rb);
209 }
210
211 Fp12 cyclotomicSquared() {
212
213 Fp2 z0 = a.a();
214 Fp2 z4 = a.b();
215 Fp2 z3 = a.c();
216 Fp2 z2 = b.a();
217 Fp2 z1 = b.b();
218 Fp2 z5 = b.c();
219
220 Fp2 t0, t1, t2, t3, t4, t5, tmp;
221
222 // t0 + t1*y = (z0 + z1*y)^2 = a^2
223 tmp = z0.mul(z1);
224 t0 = z0.add(z1).mul(z0.add(Fp6.NON_RESIDUE.mul(z1))).sub(tmp).sub(Fp6.NON_RESIDUE.mul(tmp));
225 t1 = tmp.add(tmp);
226 // t2 + t3*y = (z2 + z3*y)^2 = b^2
227 tmp = z2.mul(z3);
228 t2 = z2.add(z3).mul(z2.add(Fp6.NON_RESIDUE.mul(z3))).sub(tmp).sub(Fp6.NON_RESIDUE.mul(tmp));
229 t3 = tmp.add(tmp);
230 // t4 + t5*y = (z4 + z5*y)^2 = c^2
231 tmp = z4.mul(z5);
232 t4 = z4.add(z5).mul(z4.add(Fp6.NON_RESIDUE.mul(z5))).sub(tmp).sub(Fp6.NON_RESIDUE.mul(tmp));
233 t5 = tmp.add(tmp);
234
235 // for A
236
237 // z0 = 3 * t0 - 2 * z0
238 z0 = t0.sub(z0);
239 z0 = z0.add(z0);
240 z0 = z0.add(t0);
241 // z1 = 3 * t1 + 2 * z1
242 z1 = t1.add(z1);
243 z1 = z1.add(z1);
244 z1 = z1.add(t1);
245
246 // for B
247
248 // z2 = 3 * (xi * t5) + 2 * z2
249 tmp = Fp6.NON_RESIDUE.mul(t5);
250 z2 = tmp.add(z2);
251 z2 = z2.add(z2);
252 z2 = z2.add(tmp);
253
254 // z3 = 3 * t4 - 2 * z3
255 z3 = t4.sub(z3);
256 z3 = z3.add(z3);
257 z3 = z3.add(t4);
258
259 // for C
260
261 // z4 = 3 * t2 - 2 * z4
262 z4 = t2.sub(z4);
263 z4 = z4.add(z4);
264 z4 = z4.add(t2);
265
266 // z5 = 3 * t3 + 2 * z5
267 z5 = t3.add(z5);
268 z5 = z5.add(z5);
269 z5 = z5.add(t3);
270
271 return new Fp12(new Fp6(z0, z4, z3), new Fp6(z2, z1, z5));
272 }
273
274 Fp12 cyclotomicExp(BigInteger pow) {
275
276 Fp12 res = _1;
277
278 for (int i = pow.bitLength() - 1; i >=0; i--) {
279 res = res.cyclotomicSquared();
280
281 if (pow.testBit(i)) {
282 res = res.mul(this);
283 }
284 }
285
286 return res;
287 }
288
289 Fp12 unitaryInverse() {
290
291 Fp6 ra = a;
292 Fp6 rb = b.negate();
293
294 return new Fp12(ra, rb);
295 }
296
297 Fp12 negExp(BigInteger exp) {
298 return this.cyclotomicExp(exp).unitaryInverse();
299 }
300
301 @Override
302 public boolean equals(Object o) {
303 if (this == o) {return true;}
304 if (!(o instanceof Fp12)) {return false;}
305
306 Fp12 fp12 = (Fp12) o;
307
308 if (a != null ? !a.equals(fp12.a) : fp12.a != null) {return false;}
309 return !(b != null ? !b.equals(fp12.b) : fp12.b != null);
310
311 }
312
313 @Override
314 public int hashCode() {
315 return Objects.hash(a,b);
316 }
317
318 @Override
319 public String toString() {
320 return String.format(
321 "Fp12 (%s; %s)\n" +
322 " (%s; %s)\n" +
323 " (%s; %s)\n" +
324 " (%s; %s)\n" +
325 " (%s; %s)\n" +
326 " (%s; %s)\n",
327
328 a.a().a(), a.a().b(),
329 a.b().a(), a.b().b(),
330 a.c().a(), a.c().b(),
331 b.a().a(), b.a().b(),
332 b.b().a(), b.b().b(),
333 b.c().a(), b.c().b()
334 );
335 }
336
337 private static final Fp2[] FROBENIUS_COEFFS_B = new Fp2[] {
338
339 new Fp2(BigInteger.ONE,
340 BigInteger.ZERO),
341
342 new Fp2(new BigInteger("8376118865763821496583973867626364092589906065868298776909617916018768340080"),
343 new BigInteger("16469823323077808223889137241176536799009286646108169935659301613961712198316")),
344
345 new Fp2(new BigInteger("21888242871839275220042445260109153167277707414472061641714758635765020556617"),
346 BigInteger.ZERO),
347
348 new Fp2(new BigInteger("11697423496358154304825782922584725312912383441159505038794027105778954184319"),
349 new BigInteger("303847389135065887422783454877609941456349188919719272345083954437860409601")),
350
351 new Fp2(new BigInteger("21888242871839275220042445260109153167277707414472061641714758635765020556616"),
352 BigInteger.ZERO),
353
354 new Fp2(new BigInteger("3321304630594332808241809054958361220322477375291206261884409189760185844239"),
355 new BigInteger("5722266937896532885780051958958348231143373700109372999374820235121374419868")),
356
357 new Fp2(new BigInteger("21888242871839275222246405745257275088696311157297823662689037894645226208582"),
358 BigInteger.ZERO),
359
360 new Fp2(new BigInteger("13512124006075453725662431877630910996106405091429524885779419978626457868503"),
361 new BigInteger("5418419548761466998357268504080738289687024511189653727029736280683514010267")),
362
363 new Fp2(new BigInteger("2203960485148121921418603742825762020974279258880205651966"),
364 BigInteger.ZERO),
365
366 new Fp2(new BigInteger("10190819375481120917420622822672549775783927716138318623895010788866272024264"),
367 new BigInteger("21584395482704209334823622290379665147239961968378104390343953940207365798982")),
368
369 new Fp2(new BigInteger("2203960485148121921418603742825762020974279258880205651967"),
370 BigInteger.ZERO),
371
372 new Fp2(new BigInteger("18566938241244942414004596690298913868373833782006617400804628704885040364344"),
373 new BigInteger("16165975933942742336466353786298926857552937457188450663314217659523851788715"))
374 };
375 }