org.ethereum.crypto.zksnark.Fp12 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ethereumj-core Show documentation
Show all versions of ethereumj-core Show documentation
Java implementation of the Ethereum protocol adapted to use for Hedera Smart Contract Service
The newest version!
/*
* Copyright (c) [2016] [ ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see .
*/
package org.ethereum.crypto.zksnark;
import java.math.BigInteger;
/**
* Arithmetic in Fp_12
*
*
* "p" equals 21888242871839275222246405745257275088696311157297823662689037894645226208583,
* elements of Fp_12 are represented with 2 elements of {@link Fp6}
*
*
* Field arithmetic is ported from libff
*
* @author Mikhail Kalinin
* @since 02.09.2017
*/
class Fp12 implements Field {
static final Fp12 ZERO = new Fp12(Fp6.ZERO, Fp6.ZERO);
static final Fp12 _1 = new Fp12(Fp6._1, Fp6.ZERO);
Fp6 a;
Fp6 b;
Fp12 (Fp6 a, Fp6 b) {
this.a = a;
this.b = b;
}
@Override
public Fp12 squared() {
Fp6 ab = a.mul(b);
Fp6 ra = a.add(b).mul(a.add(b.mulByNonResidue())).sub(ab).sub(ab.mulByNonResidue());
Fp6 rb = ab.add(ab);
return new Fp12(ra, rb);
}
@Override
public Fp12 dbl() {
return null;
}
Fp12 mulBy024(Fp2 ell0, Fp2 ellVW, Fp2 ellVV) {
Fp2 z0 = a.a;
Fp2 z1 = a.b;
Fp2 z2 = a.c;
Fp2 z3 = b.a;
Fp2 z4 = b.b;
Fp2 z5 = b.c;
Fp2 x0 = ell0;
Fp2 x2 = ellVV;
Fp2 x4 = ellVW;
Fp2 t0, t1, t2, s0, t3, t4, d0, d2, d4, s1;
d0 = z0.mul(x0);
d2 = z2.mul(x2);
d4 = z4.mul(x4);
t2 = z0.add(z4);
t1 = z0.add(z2);
s0 = z1.add(z3).add(z5);
// For z.a_.a_ = z0.
s1 = z1.mul(x2);
t3 = s1.add(d4);
t4 = Fp6.NON_RESIDUE.mul(t3).add(d0);
z0 = t4;
// For z.a_.b_ = z1
t3 = z5.mul(x4);
s1 = s1.add(t3);
t3 = t3.add(d2);
t4 = Fp6.NON_RESIDUE.mul(t3);
t3 = z1.mul(x0);
s1 = s1.add(t3);
t4 = t4.add(t3);
z1 = t4;
// For z.a_.c_ = z2
t0 = x0.add(x2);
t3 = t1.mul(t0).sub(d0).sub(d2);
t4 = z3.mul(x4);
s1 = s1.add(t4);
t3 = t3.add(t4);
// For z.b_.a_ = z3 (z3 needs z2)
t0 = z2.add(z4);
z2 = t3;
t1 = x2.add(x4);
t3 = t0.mul(t1).sub(d2).sub(d4);
t4 = Fp6.NON_RESIDUE.mul(t3);
t3 = z3.mul(x0);
s1 = s1.add(t3);
t4 = t4.add(t3);
z3 = t4;
// For z.b_.b_ = z4
t3 = z5.mul(x2);
s1 = s1.add(t3);
t4 = Fp6.NON_RESIDUE.mul(t3);
t0 = x0.add(x4);
t3 = t2.mul(t0).sub(d0).sub(d4);
t4 = t4.add(t3);
z4 = t4;
// For z.b_.c_ = z5.
t0 = x0.add(x2).add(x4);
t3 = s0.mul(t0).sub(s1);
z5 = t3;
return new Fp12(new Fp6(z0, z1, z2), new Fp6(z3, z4, z5));
}
@Override
public Fp12 add(Fp12 o) {
return new Fp12(a.add(o.a), b.add(o.b));
}
@Override
public Fp12 mul(Fp12 o) {
Fp6 a2 = o.a, b2 = o.b;
Fp6 a1 = a, b1 = b;
Fp6 a1a2 = a1.mul(a2);
Fp6 b1b2 = b1.mul(b2);
Fp6 ra = a1a2.add(b1b2.mulByNonResidue());
Fp6 rb = a1.add(b1).mul(a2.add(b2)).sub(a1a2).sub(b1b2);
return new Fp12(ra, rb);
}
@Override
public Fp12 sub(Fp12 o) {
return new Fp12(a.sub(o.a), b.sub(o.b));
}
@Override
public Fp12 inverse() {
Fp6 t0 = a.squared();
Fp6 t1 = b.squared();
Fp6 t2 = t0.sub(t1.mulByNonResidue());
Fp6 t3 = t2.inverse();
Fp6 ra = a.mul(t3);
Fp6 rb = b.mul(t3).negate();
return new Fp12(ra, rb);
}
@Override
public Fp12 negate() {
return new Fp12(a.negate(), b.negate());
}
@Override
public boolean isZero() {
return this.equals(ZERO);
}
@Override
public boolean isValid() {
return a.isValid() && b.isValid();
}
Fp12 frobeniusMap(int power) {
Fp6 ra = a.frobeniusMap(power);
Fp6 rb = b.frobeniusMap(power).mul(FROBENIUS_COEFFS_B[power % 12]);
return new Fp12(ra, rb);
}
Fp12 cyclotomicSquared() {
Fp2 z0 = a.a;
Fp2 z4 = a.b;
Fp2 z3 = a.c;
Fp2 z2 = b.a;
Fp2 z1 = b.b;
Fp2 z5 = b.c;
Fp2 t0, t1, t2, t3, t4, t5, tmp;
// t0 + t1*y = (z0 + z1*y)^2 = a^2
tmp = z0.mul(z1);
t0 = z0.add(z1).mul(z0.add(Fp6.NON_RESIDUE.mul(z1))).sub(tmp).sub(Fp6.NON_RESIDUE.mul(tmp));
t1 = tmp.add(tmp);
// t2 + t3*y = (z2 + z3*y)^2 = b^2
tmp = z2.mul(z3);
t2 = z2.add(z3).mul(z2.add(Fp6.NON_RESIDUE.mul(z3))).sub(tmp).sub(Fp6.NON_RESIDUE.mul(tmp));
t3 = tmp.add(tmp);
// t4 + t5*y = (z4 + z5*y)^2 = c^2
tmp = z4.mul(z5);
t4 = z4.add(z5).mul(z4.add(Fp6.NON_RESIDUE.mul(z5))).sub(tmp).sub(Fp6.NON_RESIDUE.mul(tmp));
t5 = tmp.add(tmp);
// for A
// z0 = 3 * t0 - 2 * z0
z0 = t0.sub(z0);
z0 = z0.add(z0);
z0 = z0.add(t0);
// z1 = 3 * t1 + 2 * z1
z1 = t1.add(z1);
z1 = z1.add(z1);
z1 = z1.add(t1);
// for B
// z2 = 3 * (xi * t5) + 2 * z2
tmp = Fp6.NON_RESIDUE.mul(t5);
z2 = tmp.add(z2);
z2 = z2.add(z2);
z2 = z2.add(tmp);
// z3 = 3 * t4 - 2 * z3
z3 = t4.sub(z3);
z3 = z3.add(z3);
z3 = z3.add(t4);
// for C
// z4 = 3 * t2 - 2 * z4
z4 = t2.sub(z4);
z4 = z4.add(z4);
z4 = z4.add(t2);
// z5 = 3 * t3 + 2 * z5
z5 = t3.add(z5);
z5 = z5.add(z5);
z5 = z5.add(t3);
return new Fp12(new Fp6(z0, z4, z3), new Fp6(z2, z1, z5));
}
Fp12 cyclotomicExp(BigInteger pow) {
Fp12 res = _1;
for (int i = pow.bitLength() - 1; i >=0; i--) {
res = res.cyclotomicSquared();
if (pow.testBit(i)) {
res = res.mul(this);
}
}
return res;
}
Fp12 unitaryInverse() {
Fp6 ra = a;
Fp6 rb = b.negate();
return new Fp12(ra, rb);
}
Fp12 negExp(BigInteger exp) {
return this.cyclotomicExp(exp).unitaryInverse();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Fp12)) return false;
Fp12 fp12 = (Fp12) o;
if (a != null ? !a.equals(fp12.a) : fp12.a != null) return false;
return !(b != null ? !b.equals(fp12.b) : fp12.b != null);
}
@Override
public String toString() {
return String.format(
"Fp12 (%s; %s)\n" +
" (%s; %s)\n" +
" (%s; %s)\n" +
" (%s; %s)\n" +
" (%s; %s)\n" +
" (%s; %s)\n",
a.a.a, a.a.b,
a.b.a, a.b.b,
a.c.a, a.c.b,
b.a.a, b.a.b,
b.b.a, b.b.b,
b.c.a, b.c.b
);
}
static final Fp2[] FROBENIUS_COEFFS_B = new Fp2[] {
new Fp2(BigInteger.ONE,
BigInteger.ZERO),
new Fp2(new BigInteger("8376118865763821496583973867626364092589906065868298776909617916018768340080"),
new BigInteger("16469823323077808223889137241176536799009286646108169935659301613961712198316")),
new Fp2(new BigInteger("21888242871839275220042445260109153167277707414472061641714758635765020556617"),
BigInteger.ZERO),
new Fp2(new BigInteger("11697423496358154304825782922584725312912383441159505038794027105778954184319"),
new BigInteger("303847389135065887422783454877609941456349188919719272345083954437860409601")),
new Fp2(new BigInteger("21888242871839275220042445260109153167277707414472061641714758635765020556616"),
BigInteger.ZERO),
new Fp2(new BigInteger("3321304630594332808241809054958361220322477375291206261884409189760185844239"),
new BigInteger("5722266937896532885780051958958348231143373700109372999374820235121374419868")),
new Fp2(new BigInteger("21888242871839275222246405745257275088696311157297823662689037894645226208582"),
BigInteger.ZERO),
new Fp2(new BigInteger("13512124006075453725662431877630910996106405091429524885779419978626457868503"),
new BigInteger("5418419548761466998357268504080738289687024511189653727029736280683514010267")),
new Fp2(new BigInteger("2203960485148121921418603742825762020974279258880205651966"),
BigInteger.ZERO),
new Fp2(new BigInteger("10190819375481120917420622822672549775783927716138318623895010788866272024264"),
new BigInteger("21584395482704209334823622290379665147239961968378104390343953940207365798982")),
new Fp2(new BigInteger("2203960485148121921418603742825762020974279258880205651967"),
BigInteger.ZERO),
new Fp2(new BigInteger("18566938241244942414004596690298913868373833782006617400804628704885040364344"),
new BigInteger("16165975933942742336466353786298926857552937457188450663314217659523851788715"))
};
}