Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ Wallet
/vm_trace/

/framework/propPath

bin
58 changes: 30 additions & 28 deletions actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,16 @@
import org.tron.common.crypto.Hash;
import org.tron.common.crypto.SignUtils;
import org.tron.common.crypto.SignatureInterface;
import org.tron.common.crypto.zksnark.BN128;
import org.tron.common.crypto.zksnark.BN128Fp;
import org.tron.common.crypto.zksnark.BN128G1;
import org.tron.common.crypto.zksnark.BN128G2;
import org.tron.common.crypto.zksnark.Fp;
import org.tron.common.crypto.zksnark.PairingCheck;
import org.tron.common.parameter.CommonParameter;
import org.tron.common.runtime.ProgramResult;
import org.tron.common.runtime.vm.DataWord;
import org.tron.common.utils.BIUtil;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.ByteUtil;
import org.tron.common.utils.Sha256Hash;
import org.tron.common.zksnark.JLibarkworks;
import org.tron.common.zksnark.JLibrustzcash;
import org.tron.common.zksnark.LibrustzcashParam;
import org.tron.core.capsule.AccountCapsule;
Expand Down Expand Up @@ -742,19 +739,22 @@ public Pair<Boolean, byte[]> execute(byte[] data) {
byte[] x2 = parseWord(data, 2);
byte[] y2 = parseWord(data, 3);

BN128<Fp> p1 = BN128Fp.create(x1, y1);
if (p1 == null) {

if (!JLibarkworks.libarkworksG1IsValid(x1, y1)) {
return Pair.of(false, EMPTY_BYTE_ARRAY);
}
byte[] p1 = ArrayUtils.addAll(x1, y1);

BN128<Fp> p2 = BN128Fp.create(x2, y2);
if (p2 == null) {
if (!JLibarkworks.libarkworksG1IsValid(x2, y2)) {
return Pair.of(false, EMPTY_BYTE_ARRAY);
}
byte[] p2 = ArrayUtils.addAll(x2, y2);

BN128<Fp> res = p1.add(p2).toEthNotation();

return Pair.of(true, encodeRes(res.x().bytes(), res.y().bytes()));
byte[] res = JLibarkworks.libarkworksAddG1(p1, p2);
if (res == null) {
return Pair.of(false, EMPTY_BYTE_ARRAY);
}
return Pair.of(true, res);
}
}

Expand Down Expand Up @@ -795,14 +795,16 @@ public Pair<Boolean, byte[]> execute(byte[] data) {

byte[] s = parseWord(data, 2);

BN128<Fp> p = BN128Fp.create(x, y);
if (p == null) {
if (!JLibarkworks.libarkworksG1IsValid(x, y)) {
return Pair.of(false, EMPTY_BYTE_ARRAY);
}
byte[] p = ArrayUtils.addAll(x, y);

BN128<Fp> res = p.mul(BIUtil.toBI(s)).toEthNotation();

return Pair.of(true, encodeRes(res.x().bytes(), res.y().bytes()));
byte[] res = JLibarkworks.libarkworksMulG1(p, s);
if (res == null) {
return Pair.of(false, EMPTY_BYTE_ARRAY);
}
return Pair.of(true, res);
}
}

Expand Down Expand Up @@ -854,38 +856,39 @@ public Pair<Boolean, byte[]> execute(byte[] data) {
return Pair.of(false, EMPTY_BYTE_ARRAY);
}

PairingCheck check = PairingCheck.create();
int pairs = data.length / PAIR_SIZE;

// iterating over all pairs
byte[] g1s = new byte[0];
byte[] g2s = new byte[0];
for (int offset = 0; offset < data.length; offset += PAIR_SIZE) {

Pair<BN128G1, BN128G2> pair = decodePair(data, offset);
Pair<byte[], byte[]> pair = decodePair(data, offset);

// fail if decoding has failed
if (pair == null) {
return Pair.of(false, EMPTY_BYTE_ARRAY);
}

check.addPair(pair.getLeft(), pair.getRight());
g1s = ArrayUtils.addAll(g1s, pair.getLeft());
g2s = ArrayUtils.addAll(g2s, pair.getRight());
}

check.run();
int result = check.result();
int result = JLibarkworks.libarkworksPairingCheck(g1s, g2s, pairs) ? 1 : 0;

return Pair.of(true, new DataWord(result).getData());
}

private Pair<BN128G1, BN128G2> decodePair(byte[] in, int offset) {
private Pair<byte[], byte[]> decodePair(byte[] in, int offset) {

byte[] x = parseWord(in, offset, 0);
byte[] y = parseWord(in, offset, 1);

BN128G1 p1 = BN128G1.create(x, y);

// fail if point is invalid
if (p1 == null) {
if (!JLibarkworks.libarkworksG1IsValid(x, y)) {
return null;
}
byte[] p1 = ArrayUtils.addAll(x, y);

// (b, a)
byte[] b = parseWord(in, offset, 2);
Expand All @@ -895,12 +898,11 @@ private Pair<BN128G1, BN128G2> decodePair(byte[] in, int offset) {
byte[] d = parseWord(in, offset, 4);
byte[] c = parseWord(in, offset, 5);

BN128G2 p2 = BN128G2.create(a, b, c, d);

// fail if point is invalid
if (p2 == null) {
if (!JLibarkworks.libarkworksG2IsValid(a, b, c, d)) {
return null;
}
byte[] p2 = ArrayUtils.addAll(ArrayUtils.addAll(a, b), ArrayUtils.addAll(c, d));

return Pair.of(p1, p2);
}
Expand Down
7 changes: 6 additions & 1 deletion chainbase/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dependencies {
compile "org.fusesource.jansi:jansi:$jansiVersion"
compile group: 'org.rocksdb', name: 'rocksdbjni', version: '5.15.10'
compile group: 'com.typesafe', name: 'config', version: '1.3.2'
compile 'io.github.tronprotocol:zksnark-java-sdk:1.0.0'
compile 'com.github.zkbob:zksnark-java-sdk:arkworks-SNAPSHOT'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.8.5'
compile project(":protocol")
compile project(":common")
Expand Down Expand Up @@ -109,4 +109,9 @@ jacocoTestReport {
}
}

repositories {
// ...
maven { url "https://jitpack.io" }
}

build.dependsOn jacocoTestReport
37 changes: 37 additions & 0 deletions chainbase/src/main/java/org/tron/common/zksnark/JLibarkworks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.tron.common.zksnark;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class JLibarkworks {

public static boolean libarkworksG1IsValid(byte[] x, byte[] y) {
return LibarkworksWrapper.getInstance().libarkworksG1IsValid(x, y);
}

public static boolean libarkworksG2IsValid(byte[] a, byte[] b, byte[] c, byte[] d) {
return LibarkworksWrapper.getInstance().libarkworksG2IsValid(a, b, c, d);
}

public static byte[] libarkworksAddG1(byte[] a, byte[] b) {
byte[] result = new byte[64];
boolean success = LibarkworksWrapper.getInstance().libarkworksAddG1(a, b, result);
if (!success) {
return null;
}
return result;
}

public static byte[] libarkworksMulG1(byte[] p, byte[] s) {
byte[] result = new byte[64];
boolean success = LibarkworksWrapper.getInstance().libarkworksMulG1(p, s, result);
if (!success) {
return null;
}
return result;
}

public static boolean libarkworksPairingCheck(byte[] g1s, byte[] g2s, int pairs) {
return LibarkworksWrapper.getInstance().libarkworksPairingCheck(g1s, g2s, pairs);
}
}
2 changes: 1 addition & 1 deletion common/src/main/java/org/tron/common/utils/ByteUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ public static int numberOfLeadingZeros(byte[] bytes) {
public static byte[] parseBytes(byte[] input, int offset, int len) {

if (offset >= input.length || len == 0) {
return EMPTY_BYTE_ARRAY;
return new byte[len];
}

byte[] bytes = new byte[len];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package org.tron.common.runtime.vm;

import static org.junit.Assert.assertArrayEquals;
import static org.tron.common.utils.ByteUtil.stripLeadingZeroes;
import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCED_INTERVAL;
import static org.tron.core.db.TransactionTrace.convertToTronAddress;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.google.protobuf.Any;
import com.google.protobuf.ByteString;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.bouncycastle.util.Arrays;
Expand Down Expand Up @@ -40,6 +49,7 @@
import org.tron.core.vm.config.VMConfig;
import org.tron.core.vm.repository.Repository;
import org.tron.core.vm.repository.RepositoryImpl;
import org.tron.core.zksnark.SendCoinShieldTest;
import org.tron.protos.Protocol;
import org.tron.protos.Protocol.AccountType;
import org.tron.protos.Protocol.Proposal.State;
Expand Down Expand Up @@ -95,6 +105,14 @@ public class PrecompiledContractsTest extends BaseTest {
private static final DataWord totalAcquiredResourceAddr = new DataWord(
"0000000000000000000000000000000000000000000000000000000001000015");

// bn128
private static final DataWord altBN128AddAddr = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000006");
private static final DataWord altBN128MulAddr = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000007");
private static final DataWord altBN128PairingAddr = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000008");

private static final String ACCOUNT_NAME = "account";
private static final String OWNER_ADDRESS;
private static final String WITNESS_NAME = "witness";
Expand Down Expand Up @@ -1127,6 +1145,49 @@ public void totalAcquiredResourceTest() {
Assert.assertEquals(0, ByteArray.toLong(res.getRight()));
}

@Test
public void bn128AdditionTest() throws Exception {
PrecompiledContract bn128Add = createPrecompiledContract(altBN128AddAddr, OWNER_ADDRESS);
JSONArray testCases = readJsonFile("bn256Add.json");
for (int i = 0; i < testCases.size(); i++) {
JSONObject testCase = testCases.getJSONObject(i);
String name = testCase.getString("Name");
byte[] input = Hex.decode(testCase.getString("Input"));
byte[] expected = Hex.decode(testCase.getString("Expected"));
byte[] actual = bn128Add.execute(input).getRight();
assertArrayEquals(String.format("BN128Add test %s failed", name), expected, actual);
}
}

@Test
public void bn128MultiplicationTest() throws Exception {
PrecompiledContract bn128Mul = createPrecompiledContract(altBN128MulAddr, OWNER_ADDRESS);
JSONArray testCases = readJsonFile("bn256ScalarMul.json");
for (int i = 0; i < testCases.size(); i++) {
JSONObject testCase = testCases.getJSONObject(i);
String name = testCase.getString("Name");
byte[] input = Hex.decode(testCase.getString("Input"));
byte[] expected = Hex.decode(testCase.getString("Expected"));
byte[] actual = bn128Mul.execute(input).getRight();
assertArrayEquals(String.format("bn128Mul test %s failed", name), expected, actual);
}
}

@Test
public void bn128PairingTest() throws Exception {
PrecompiledContract bn128Pairing =
createPrecompiledContract(altBN128PairingAddr, OWNER_ADDRESS);
JSONArray testCases = readJsonFile("bn256Pairing.json");
for (int i = 0; i < testCases.size(); i++) {
JSONObject testCase = testCases.getJSONObject(i);
String name = testCase.getString("Name");
byte[] input = Hex.decode(testCase.getString("Input"));
byte[] expected = Hex.decode(testCase.getString("Expected"));
byte[] actual = bn128Pairing.execute(input).getRight();
assertArrayEquals(String.format("bn128Pairing test %s failed", name), expected, actual);
}
}

//@Test
public void convertFromTronBase58AddressNative() {
// 27WnTihwXsqCqpiNedWvtKCZHsLjDt4Hfmf TestNet address
Expand Down Expand Up @@ -1166,4 +1227,13 @@ private static byte[] encodeMultiWord(byte[]... words) {
return res;
}

private JSONArray readJsonFile(String fileName) throws Exception {
String file1 = SendCoinShieldTest.class.getClassLoader()
.getResource("json" + File.separator + fileName).getFile();
List<String> readLines = Files.readLines(new File(file1),
Charsets.UTF_8);

return JSONArray
.parseArray(readLines.stream().reduce((s, s2) -> s + s2).get());
}
}
Loading