Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(precompiles): optimize native implementation of the bn128 precompiles #5611

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ src/test/java/org/tron/consensus2
src/main/java/META-INF/
src/main/resources/META-INF/
/bin/
bin

# Eclipse IDE specific files and folders
/.project
Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ subprojects {
compile group: 'org.apache.commons', name: 'commons-math', version: '2.2'
compile "org.apache.commons:commons-collections4:4.1"
compile group: 'joda-time', name: 'joda-time', version: '2.3'
implementation 'javax.annotation:javax.annotation-api:1.3.2'

}

Expand Down
15 changes: 0 additions & 15 deletions crypto/src/main/java/org/tron/common/crypto/zksnark/BN128.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,21 +220,6 @@ public boolean isZero() {
return z.isZero();
}

protected boolean isValid() {

// check whether coordinates belongs to the Field
if (!x.isValid() || !y.isValid() || !z.isValid()) {
return false;
}

// check whether point is on the curve
if (!isOnCurve()) {
return false;
}

return true;
}

@Override
public String toString() {
return String.format("(%s; %s; %s)", x.toString(), y.toString(), z.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public static BN128<Fp> create(byte[] xx, byte[] yy) {
Fp x = Fp.create(xx);
Fp y = Fp.create(yy);

if (x == null || y == null) {
// It means that one or both coordinates are not elements of Fp
return null;
}

// check for point at infinity
if (x.isZero() && y.isZero()) {
return ZERO;
Expand All @@ -55,7 +60,7 @@ public static BN128<Fp> create(byte[] xx, byte[] yy) {
BN128<Fp> p = new BN128Fp(x, y, Fp._1);

// check whether point is a valid one
if (p.isValid()) {
if (p.isOnCurve()) {
return p;
} else {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public static BN128<Fp2> create(byte[] aa, byte[] bb, byte[] cc, byte[] dd) {
Fp2 x = Fp2.create(aa, bb);
Fp2 y = Fp2.create(cc, dd);

if (x == null || y == null) {
// It means that one or both coordinates are not elements of Fp
return null;
}

// check for point at infinity
if (x.isZero() && y.isZero()) {
return ZERO;
Expand All @@ -60,7 +65,7 @@ public static BN128<Fp2> create(byte[] aa, byte[] bb, byte[] cc, byte[] dd) {
BN128<Fp2> p = new BN128Fp2(x, y, Fp2._1);

// check whether point is a valid one
if (p.isValid()) {
if (p.isOnCurve()) {
return p;
} else {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,4 @@ interface Field<T> {
T negate();

boolean isZero();

boolean isValid();
}
129 changes: 105 additions & 24 deletions crypto/src/main/java/org/tron/common/crypto/zksnark/Fp.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,70 @@
*/
package org.tron.common.crypto.zksnark;

import static org.tron.common.crypto.zksnark.Params.P;

import java.math.BigInteger;

/**
* Arithmetic in F_p, p = 21888242871839275222246405745257275088696311157297823662689037894645226208583
*
* This class stores elements of F_p in the Montgomery form: a*r mod p.
*
* @author Mikhail Kalinin
* @since 01.09.2017
*/
public class Fp implements Field<Fp> {
/**
* "p" field parameter of F_p, F_p2, F_p6 and F_p12
*/
protected static final BigInteger P = new BigInteger(
"21888242871839275222246405745257275088696311157297823662689037894645226208583");

static final Fp ZERO = new Fp(BigInteger.ZERO);
static final Fp _1 = new Fp(BigInteger.ONE);
static final Fp NON_RESIDUE = new Fp(new BigInteger(
/**
* This value is equal to 2^256. It should be greater than {@link #P} and coprime to it.
* Field elements are represented in Montgomery form as a*{@link #REDUCER} mod {@link #P}.
* This specific value of {@link #REDUCER} is selected to facilitate efficient division
* by {@link #REDUCER} through simple shifting.
* This field is not used in the code but can be helpful for understanding
*/
@SuppressWarnings("unused")
private static final BigInteger REDUCER = new BigInteger(
"115792089237316195423570985008687907853269984665640564039457584007913129639936");

/**
* The number of bits in the {@link #REDUCER} value.
*/
private static final int REDUCER_BITS = 256;

/**
* A precomputed value of {@link #REDUCER}^2 mod {@link #P}.
*/
private static final BigInteger REDUCER_SQUARED = new BigInteger(
"3096616502983703923843567936837374451735540968419076528771170197431451843209");

/**
* A precomputed value of {@link #REDUCER}^3 mod {@link #P}.
*/
private static final BigInteger REDUCER_CUBED = new BigInteger(
"14921786541159648185948152738563080959093619838510245177710943249661917737183");

/**
* A precomputed value of -{@link #P}^{-1} mod {@link #REDUCER}.
*/
private static final BigInteger FACTOR = new BigInteger(
"111032442853175714102588374283752698368366046808579839647964533820976443843465");

/**
* The MASK value is set to 2^256 - 1 and is utilized to replace the operation % 2^256
* with a bitwise AND using this value. This choice ensures that only the lower 256 bits
* of a result are retained, effectively simulating the modulus operation.
*/
private static final BigInteger MASK = new BigInteger(
"115792089237316195423570985008687907853269984665640564039457584007913129639935");

protected static final Fp ZERO = Fp.create(BigInteger.ZERO);
protected static final Fp _1 = Fp.create(BigInteger.ONE);
protected static final Fp NON_RESIDUE = Fp.create(new BigInteger(
"21888242871839275222246405745257275088696311157297823662689037894645226208582"));

static final Fp _2_INV = new Fp(BigInteger.valueOf(2).modInverse(P));
protected static final Fp _2_INV = Fp.create(BigInteger.valueOf(2).modInverse(P));

BigInteger v;

Expand All @@ -43,41 +89,52 @@ public class Fp implements Field<Fp> {
}

static Fp create(byte[] v) {
return new Fp(new BigInteger(1, v));
BigInteger value = new BigInteger(1, v);
if (value.compareTo(P) >= 0) {
// Only the positive values less than P are valid
return null;
}
return new Fp(toMontgomery(value));
}

static Fp create(BigInteger v) {
return new Fp(v);
if (v.compareTo(P) >= 0 || v.signum() == -1) {
// Only the positive values less than P are valid
return null;
}
return new Fp(toMontgomery(v));
}

@Override
public Fp add(Fp o) {
return new Fp(this.v.add(o.v).mod(P));
BigInteger r = v.add(o.v);
return new Fp(r.compareTo(P) < 0 ? r : r.subtract(P));
}

@Override
public Fp mul(Fp o) {
return new Fp(this.v.multiply(o.v).mod(P));
return new Fp(redc(v.multiply(o.v)));
}

@Override
public Fp sub(Fp o) {
return new Fp(this.v.subtract(o.v).mod(P));
BigInteger r = v.subtract(o.v);
return new Fp(r.compareTo(BigInteger.ZERO) < 0 ? r.add(P) : r);
}

@Override
public Fp squared() {
return new Fp(v.multiply(v).mod(P));
return new Fp(redc(v.multiply(v)));
}

@Override
public Fp dbl() {
return new Fp(v.add(v).mod(P));
return add(this);
}

@Override
public Fp inverse() {
return new Fp(v.modInverse(P));
return new Fp(redc(v.modInverse(P).multiply(REDUCER_CUBED)));
}

@Override
Expand All @@ -90,20 +147,12 @@ public boolean isZero() {
return v.compareTo(BigInteger.ZERO) == 0;
}

/**
* Checks if provided value is a valid Fp member
*/
@Override
public boolean isValid() {
return v.compareTo(P) < 0;
}

Fp2 mul(Fp2 o) {
return new Fp2(o.a.mul(this), o.b.mul(this));
}

public byte[] bytes() {
return v.toByteArray();
return fromMontgomery(v).toByteArray();
}

@Override
Expand All @@ -129,4 +178,36 @@ public int hashCode() {
public String toString() {
return v.toString();
}

/**
* Converts a value in normal representation to Montgomery form.
*
* @param n value in normal form
* @return value in Montgomery form
*/
private static BigInteger toMontgomery(BigInteger n) {
return redc(n.multiply(REDUCER_SQUARED));
}

/**
* Converts a value in Montgomery form to a normal representation.
*
* @param n value in Montgomery form
* @return value in normal form
*/
private static BigInteger fromMontgomery(BigInteger n) {
return redc(n);
}

/**
* Montgomery reduction; given a value x, computes x*{@link #REDUCER}^{-1} mod {@link #P}
*
* @param x value to reduce
* @return x*{@link #REDUCER}^{-1} mod {@link #P}
*/
private static BigInteger redc(BigInteger x) {
BigInteger temp = x.multiply(FACTOR).and(MASK);
BigInteger reduced = temp.multiply(P).add(x).shiftRight(REDUCER_BITS);
return reduced.compareTo(P) < 0 ? reduced : reduced.subtract(P);
}
}
29 changes: 12 additions & 17 deletions crypto/src/main/java/org/tron/common/crypto/zksnark/Fp12.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,53 +36,53 @@ class Fp12 implements Field<Fp12> {
static final Fp12 _1 = new Fp12(Fp6._1, Fp6.ZERO);
static final Fp2[] FROBENIUS_COEFFS_B = new Fp2[]{

new Fp2(BigInteger.ONE,
Fp2.create(BigInteger.ONE,
BigInteger.ZERO),

new Fp2(new BigInteger(
Fp2.create(new BigInteger(
"8376118865763821496583973867626364092589906065868298776909617916018768340080"),
new BigInteger(
"16469823323077808223889137241176536799009286646108169935659301613961712198316")),

new Fp2(new BigInteger(
Fp2.create(new BigInteger(
"21888242871839275220042445260109153167277707414472061641714758635765020556617"),
BigInteger.ZERO),

new Fp2(new BigInteger(
Fp2.create(new BigInteger(
"11697423496358154304825782922584725312912383441159505038794027105778954184319"),
new BigInteger(
"303847389135065887422783454877609941456349188919719272345083954437860409601")),

new Fp2(new BigInteger(
Fp2.create(new BigInteger(
"21888242871839275220042445260109153167277707414472061641714758635765020556616"),
BigInteger.ZERO),

new Fp2(new BigInteger(
Fp2.create(new BigInteger(
"3321304630594332808241809054958361220322477375291206261884409189760185844239"),
new BigInteger(
"5722266937896532885780051958958348231143373700109372999374820235121374419868")),

new Fp2(new BigInteger(
Fp2.create(new BigInteger(
"21888242871839275222246405745257275088696311157297823662689037894645226208582"),
BigInteger.ZERO),

new Fp2(new BigInteger(
Fp2.create(new BigInteger(
"13512124006075453725662431877630910996106405091429524885779419978626457868503"),
new BigInteger(
"5418419548761466998357268504080738289687024511189653727029736280683514010267")),

new Fp2(new BigInteger("2203960485148121921418603742825762020974279258880205651966"),
Fp2.create(new BigInteger("2203960485148121921418603742825762020974279258880205651966"),
BigInteger.ZERO),

new Fp2(new BigInteger(
Fp2.create(new BigInteger(
"10190819375481120917420622822672549775783927716138318623895010788866272024264"),
new BigInteger(
"21584395482704209334823622290379665147239961968378104390343953940207365798982")),

new Fp2(new BigInteger("2203960485148121921418603742825762020974279258880205651967"),
Fp2.create(new BigInteger("2203960485148121921418603742825762020974279258880205651967"),
BigInteger.ZERO),

new Fp2(new BigInteger(
Fp2.create(new BigInteger(
"18566938241244942414004596690298913868373833782006617400804628704885040364344"),
new BigInteger(
"16165975933942742336466353786298926857552937457188450663314217659523851788715"))
Expand Down Expand Up @@ -233,11 +233,6 @@ 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);
Expand Down
Loading