From f518b31ae968369b18152f570102757605418687 Mon Sep 17 00:00:00 2001 From: federico Date: Tue, 2 Jun 2026 12:32:42 +0800 Subject: [PATCH 1/3] test(crypto): add BN128 curve and pairing regression baseline Add direct unit coverage for the alt_bn128 (BN254) primitives behind the ecAdd/ecMul/ecPairing precompiles: BN128Fp/BN128G1/BN128G2 point validation, G1 order-r / subgroup behaviour, the G1-vs-G2 subgroup-check asymmetry, and PairingCheck correctness against the EIP-197 generators. Previously these classes had no direct tests; only gas accounting was exercised via Solidity in IstanbulTest. Closes the high-priority gap noted in the Q2 crypto test baseline and related to HackerOne #3769516. --- .../tron/common/crypto/zksnark/BN128Test.java | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 framework/src/test/java/org/tron/common/crypto/zksnark/BN128Test.java diff --git a/framework/src/test/java/org/tron/common/crypto/zksnark/BN128Test.java b/framework/src/test/java/org/tron/common/crypto/zksnark/BN128Test.java new file mode 100644 index 00000000000..6fb074e8809 --- /dev/null +++ b/framework/src/test/java/org/tron/common/crypto/zksnark/BN128Test.java @@ -0,0 +1,154 @@ +package org.tron.common.crypto.zksnark; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.math.BigInteger; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Test; + +/** + * Regression baseline for the alt_bn128 (BN254) curve primitives used by the + * ecAdd / ecMul / ecPairing precompiles (addresses 0x06 / 0x07 / 0x08). + * + *

Prior to this class the BN128 stack ({@link BN128Fp}, {@link BN128G1}, + * {@link BN128G2}, {@link PairingCheck}) had no direct unit coverage — only the + * gas-accounting paths were exercised through Solidity contracts in IstanbulTest. + * These tests lock in point validation, generator membership, the G1 vs G2 + * subgroup-check asymmetry, and pairing correctness against known generators. + * + *

The G1 subgroup behaviour is the core of HackerOne report #3769516: because + * the alt_bn128 G1 cofactor is 1, the on-curve check performed by + * {@code BN128Fp.create} is itself the subgroup check, so every on-curve G1 point + * is a valid group member and no separate isGroupMember() call is required. + */ +public class BN128Test { + + // 32-byte big-endian coordinates, parsed by Fp.create via new BigInteger(1, v). + + // G1 generator (1, 2) + private static final byte[] G1_X = + Hex.decode("0000000000000000000000000000000000000000000000000000000000000001"); + private static final byte[] G1_Y = + Hex.decode("0000000000000000000000000000000000000000000000000000000000000002"); + // -G1 = (1, p - 2): affine negation, p is the F_p modulus. + private static final byte[] G1_NEG_Y = + Hex.decode("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45"); + + // Subgroup order r of the alt_bn128 G1/G2 groups. + private static final BigInteger R = new BigInteger( + "21888242871839275222246405745257275088548364400416034343698204186575808495617"); + + // G2 generator: x = a + b*i, y = c + d*i (EIP-197 standard generator). + // BN128G2.create(a, b, c, d) expects this coordinate order. + private static final byte[] G2_A = + Hex.decode("1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed"); + private static final byte[] G2_B = + Hex.decode("198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2"); + private static final byte[] G2_C = + Hex.decode("12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa"); + private static final byte[] G2_D = + Hex.decode("090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b"); + + private static byte[] word(long v) { + byte[] w = new byte[32]; + for (int i = 0; i < 8; i++) { + w[31 - i] = (byte) (v >>> (8 * i)); + } + return w; + } + + // ---- BN128Fp / point-on-curve validation ---------------------------------- + + @Test + public void testG1GeneratorIsOnCurve() { + assertNotNull("G1 generator (1,2) must be accepted", BN128G1.create(G1_X, G1_Y)); + } + + @Test + public void testPointAtInfinityAccepted() { + // (0, 0) encodes the point at infinity and must be accepted. + assertNotNull(BN128G1.create(word(0), word(0))); + } + + @Test + public void testOffCurvePointRejected() { + // (1, 1): y^2 = 1, x^3 + 3 = 4, not on the curve -> rejected. + assertNull(BN128G1.create(word(1), word(1))); + } + + @Test + public void testCoordinateAboveFieldModulusRejected() { + // x = p (the field modulus) is not a valid F_p element together with y = 2. + byte[] pBytes = + Hex.decode("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"); + assertNull(BN128G1.create(pBytes, G1_Y)); + } + + // ---- G1 subgroup behaviour (HackerOne #3769516) --------------------------- + + @Test + public void testG1GeneratorHasOrderR() { + // alt_bn128 G1 cofactor == 1, so any on-curve point is in the order-r + // subgroup. Confirm the generator genuinely has order r: r * G == O. + BN128G1 g = BN128G1.create(G1_X, G1_Y); + assertNotNull(g); + assertEquals("r * G must be the point at infinity", true, g.mul(R).isZero()); + } + + // ---- BN128G2 / subgroup check --------------------------------------------- + + @Test + public void testG2GeneratorIsGroupMember() { + assertNotNull("G2 generator must pass the subgroup check", + BN128G2.create(G2_A, G2_B, G2_C, G2_D)); + } + + @Test + public void testG2OffCurveRejected() { + // All-ones coordinates are not on the twist curve -> rejected. + byte[] one = word(1); + assertNull(BN128G2.create(one, one, one, one)); + } + + // ---- PairingCheck correctness --------------------------------------------- + + @Test + public void testPairingEmptyIsOne() { + // The empty product is the identity; ecPairing of no pairs returns 1. + PairingCheck check = PairingCheck.create(); + check.run(); + assertEquals(1, check.result()); + } + + @Test + public void testPairingNegationCancels() { + // e(G1, G2) * e(-G1, G2) == 1, the canonical pairing sanity check + // (mirrors pairing([P1, -P1], [P2, P2]) == true). + BN128G1 g1 = BN128G1.create(G1_X, G1_Y); + BN128G1 negG1 = BN128G1.create(G1_X, G1_NEG_Y); + BN128G2 g2 = BN128G2.create(G2_A, G2_B, G2_C, G2_D); + assertNotNull(g1); + assertNotNull(negG1); + assertNotNull(g2); + + PairingCheck check = PairingCheck.create(); + check.addPair(g1, g2); + check.addPair(negG1, g2); + check.run(); + assertEquals("e(G1,G2)*e(-G1,G2) must equal 1", 1, check.result()); + } + + @Test + public void testPairingSinglePairIsNotOne() { + // e(G1, G2) alone is a non-trivial element, so the check returns 0. + BN128G1 g1 = BN128G1.create(G1_X, G1_Y); + BN128G2 g2 = BN128G2.create(G2_A, G2_B, G2_C, G2_D); + + PairingCheck check = PairingCheck.create(); + check.addPair(g1, g2); + check.run(); + assertEquals(0, check.result()); + } +} From 2f8bdb30dc3e6ea3fdd25731723d2096576873fe Mon Sep 17 00:00:00 2001 From: federico Date: Tue, 2 Jun 2026 14:11:30 +0800 Subject: [PATCH 2/3] test(vm): add ECRECOVER and BLAKE2F precompile regression tests Add direct execute() coverage for two crypto precompiles that previously had no asserting unit test: - ECRecoverTest (0x01): recovered address matches the signer on the success path; bad recovery id, non-zero v padding, zero r/s, and short input all return an empty result without throwing. - Blake2FTest (EIP-152, 0x09): pins the canonical vector 4 input/output pair, plus length / finalization-flag validation and round-count gas pricing. Extends the Q2 crypto precompile test baseline (signature, verification). --- .../tron/common/runtime/vm/Blake2FTest.java | 100 +++++++++++++++ .../tron/common/runtime/vm/ECRecoverTest.java | 120 ++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 framework/src/test/java/org/tron/common/runtime/vm/Blake2FTest.java create mode 100644 framework/src/test/java/org/tron/common/runtime/vm/ECRecoverTest.java diff --git a/framework/src/test/java/org/tron/common/runtime/vm/Blake2FTest.java b/framework/src/test/java/org/tron/common/runtime/vm/Blake2FTest.java new file mode 100644 index 00000000000..134edcbb82e --- /dev/null +++ b/framework/src/test/java/org/tron/common/runtime/vm/Blake2FTest.java @@ -0,0 +1,100 @@ +package org.tron.common.runtime.vm; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.apache.commons.lang3.tuple.Pair; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Test; +import org.tron.core.vm.PrecompiledContracts.Blake2F; + +/** + * Direct execution regression baseline for the BLAKE2 F-compression precompile + * (EIP-152, address 0x09 on the compatible-EVM path). + * + *

The precompile was previously only exercised indirectly through a Solidity + * contract. These tests pin the canonical EIP-152 "vector 4" input/output pair + * and the input-validation rules: the input must be exactly 213 bytes and the + * final flag byte must be 0x00 or 0x01. + * + *

Input layout (213 bytes): rounds(4) | h(64) | m(128) | t(16) | f(1). + */ +public class Blake2FTest { + + private static final Blake2F BLAKE2F = new Blake2F(); + + // EIP-152 test vector 4: rounds = 12, f = 1. + private static final byte[] VECTOR_4_INPUT = Hex.decode( + "0000000c" + + "48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5" + + "d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b" + + "6162630000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "03000000000000000000000000000000" + + "01"); + + private static final byte[] VECTOR_4_OUTPUT = Hex.decode( + "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1" + + "7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"); + + @Test + public void matchesEip152Vector4() { + Pair result = BLAKE2F.execute(VECTOR_4_INPUT); + + assertTrue(result.getLeft()); + assertEquals("output must be 64 bytes", 64, result.getRight().length); + assertArrayEquals("must match EIP-152 vector 4", VECTOR_4_OUTPUT, result.getRight()); + } + + @Test + public void energyEqualsRounds() { + // Gas cost equals the round count (0x0000000c = 12) for well-formed input. + assertEquals(12L, BLAKE2F.getEnergyForData(VECTOR_4_INPUT)); + } + + @Test + public void zeroRoundsIsAllowed() { + byte[] input = VECTOR_4_INPUT.clone(); + input[0] = 0; + input[1] = 0; + input[2] = 0; + input[3] = 0; + + Pair result = BLAKE2F.execute(input); + assertTrue(result.getLeft()); + assertEquals(64, result.getRight().length); + assertEquals(0L, BLAKE2F.getEnergyForData(input)); + } + + @Test + public void rejectsWrongLength() { + // 212 bytes — one short of the required 213. + byte[] input = new byte[212]; + Pair result = BLAKE2F.execute(input); + assertFalse("incorrect length must fail", result.getLeft()); + } + + @Test + public void rejectsInvalidFinalFlag() { + byte[] input = VECTOR_4_INPUT.clone(); + input[212] = 0x02; // flag must be 0x00 or 0x01 + + Pair result = BLAKE2F.execute(input); + assertFalse("invalid finalization flag must fail", result.getLeft()); + assertEquals("invalid flag must price to zero", 0L, BLAKE2F.getEnergyForData(input)); + } + + @Test + public void nonFinalBlockFlagZeroAccepted() { + byte[] input = VECTOR_4_INPUT.clone(); + input[212] = 0x00; // f = 0 is valid (non-final block) + + Pair result = BLAKE2F.execute(input); + assertTrue(result.getLeft()); + assertEquals(64, result.getRight().length); + } +} diff --git a/framework/src/test/java/org/tron/common/runtime/vm/ECRecoverTest.java b/framework/src/test/java/org/tron/common/runtime/vm/ECRecoverTest.java new file mode 100644 index 00000000000..d5159627537 --- /dev/null +++ b/framework/src/test/java/org/tron/common/runtime/vm/ECRecoverTest.java @@ -0,0 +1,120 @@ +package org.tron.common.runtime.vm; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.util.Arrays; +import org.apache.commons.lang3.tuple.Pair; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Test; +import org.tron.common.crypto.ECKey; +import org.tron.common.crypto.ECKey.ECDSASignature; +import org.tron.core.vm.PrecompiledContracts.ECRecover; + +/** + * Direct execution regression baseline for the ECRECOVER precompile (address 0x01). + * + *

Before this class the precompile body had no asserting test — it was only + * invoked once without checking the recovered address, plus a non-asserting + * microbenchmark. These tests exercise the success path (recovered address must + * match the signer) and the failure paths (bad v, malformed r/s, short input), + * all of which must return an empty result rather than throw. + * + *

ECDSA signing here is deterministic (RFC 6979), so a fixed private key + * yields a stable signature and the test needs no externally pinned r/s vector. + */ +public class ECRecoverTest { + + private static final ECRecover EC_RECOVER = new ECRecover(); + + // Fixed placeholder private key — deterministic so the recovered address is stable. + private static final BigInteger PRIV = + new BigInteger("c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4", 16); + private static final byte[] HASH = + Hex.decode("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"); + + private static byte[] fixed32(BigInteger b) { + byte[] x = b.toByteArray(); + byte[] out = new byte[32]; + if (x.length > 32) { + System.arraycopy(x, x.length - 32, out, 0, 32); + } else { + System.arraycopy(x, 0, out, 32 - x.length, x.length); + } + return out; + } + + /** Build a 128-byte ECRECOVER input: hash(32) | v(32, right-aligned) | r(32) | s(32). */ + private static byte[] buildInput(byte[] hash, ECDSASignature sig, byte v) { + byte[] input = new byte[128]; + System.arraycopy(hash, 0, input, 0, 32); + input[63] = v; + System.arraycopy(fixed32(sig.r), 0, input, 64, 32); + System.arraycopy(fixed32(sig.s), 0, input, 96, 32); + return input; + } + + @Test + public void recoversSignerAddress() { + ECKey key = ECKey.fromPrivate(PRIV); + ECDSASignature sig = key.sign(HASH); + + Pair result = EC_RECOVER.execute(buildInput(HASH, sig, sig.v)); + + assertTrue(result.getLeft()); + assertEquals("recovered output must be a 32-byte word", 32, result.getRight().length); + + // The precompile left-pads the 21-byte TRON address into a 32-byte word. + byte[] expected = key.getAddress(); + byte[] tail = Arrays.copyOfRange(result.getRight(), 32 - expected.length, 32); + assertArrayEquals("recovered address must match the signer", expected, tail); + } + + @Test + public void rejectsInvalidRecoveryId() { + ECKey key = ECKey.fromPrivate(PRIV); + ECDSASignature sig = key.sign(HASH); + + // v = 17 is not a valid recovery id; recovery must fail -> empty result. + Pair result = EC_RECOVER.execute(buildInput(HASH, sig, (byte) 17)); + + assertTrue(result.getLeft()); + assertEquals("invalid v must yield empty output", 0, result.getRight().length); + } + + @Test + public void rejectsNonZeroVPadding() { + ECKey key = ECKey.fromPrivate(PRIV); + ECDSASignature sig = key.sign(HASH); + + // The 32-byte v word must be zero except its last byte; pollute a high byte. + byte[] input = buildInput(HASH, sig, sig.v); + input[32] = 0x01; + + Pair result = EC_RECOVER.execute(input); + assertEquals("non-zero v padding must yield empty output", 0, result.getRight().length); + } + + @Test + public void rejectsZeroSignatureComponents() { + // r = s = 0 is not a valid signature; must fail gracefully. + byte[] input = new byte[128]; + System.arraycopy(HASH, 0, input, 0, 32); + input[63] = 27; + + Pair result = EC_RECOVER.execute(input); + assertTrue(result.getLeft()); + assertEquals("zero r/s must yield empty output", 0, result.getRight().length); + } + + @Test + public void handlesShortInputWithoutThrowing() { + // Truncated input must not throw — the precompile swallows the exception + // and returns an empty result. + Pair result = EC_RECOVER.execute(new byte[64]); + assertTrue(result.getLeft()); + assertEquals(0, result.getRight().length); + } +} From 1208409e8d346643364fc0e10b8f12a543ed4e0f Mon Sep 17 00:00:00 2001 From: federico Date: Tue, 2 Jun 2026 14:30:39 +0800 Subject: [PATCH 3/3] test(vm): add consolidated precompile test vectors for BN128 and BLAKE2F --- .../runtime/vm/PrecompileVectorTest.java | 105 ++++++++++++++++++ .../precompiles/blake2f_test_vectors.json | 26 +++++ .../precompiles/bn128add_test_vectors.json | 20 ++++ .../precompiles/bn128mul_test_vectors.json | 20 ++++ .../bn128pairing_test_vectors.json | 20 ++++ 5 files changed, 191 insertions(+) create mode 100644 framework/src/test/java/org/tron/common/runtime/vm/PrecompileVectorTest.java create mode 100644 framework/src/test/resources/precompiles/blake2f_test_vectors.json create mode 100644 framework/src/test/resources/precompiles/bn128add_test_vectors.json create mode 100644 framework/src/test/resources/precompiles/bn128mul_test_vectors.json create mode 100644 framework/src/test/resources/precompiles/bn128pairing_test_vectors.json diff --git a/framework/src/test/java/org/tron/common/runtime/vm/PrecompileVectorTest.java b/framework/src/test/java/org/tron/common/runtime/vm/PrecompileVectorTest.java new file mode 100644 index 00000000000..46b5a6b7b3c --- /dev/null +++ b/framework/src/test/java/org/tron/common/runtime/vm/PrecompileVectorTest.java @@ -0,0 +1,105 @@ +package org.tron.common.runtime.vm; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.InputStream; +import java.util.List; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.tron.common.utils.ByteArray; +import org.tron.core.vm.PrecompiledContracts.BN128Addition; +import org.tron.core.vm.PrecompiledContracts.BN128Multiplication; +import org.tron.core.vm.PrecompiledContracts.BN128Pairing; +import org.tron.core.vm.PrecompiledContracts.Blake2F; +import org.tron.core.vm.PrecompiledContracts.PrecompiledContract; +import org.tron.core.vm.config.VMConfig; + +/** + * Consolidated, data-driven regression baseline for the cryptographic precompiles. + * + *

Each precompile is exercised against a JSON vector file under + * {@code resources/precompiles/}, following the same {@code {Input, Expected, Gas, + * Name}} schema already used by {@code p256verify_test_vectors.json}. This keeps the + * official / computed vectors in one place so they can be reviewed, extended, and + * reused, rather than being scattered as inline literals across test classes. + * + *

Vector sources: + *

+ * + *

An empty {@code Expected} means the precompile is expected to return an empty + * byte array (failure / no output) without reverting. + */ +public class PrecompileVectorTest { + + public static class TestCase { + public String Input; + public String Expected; + public String Name; + public long Gas; + } + + @Before + public void enableIstanbul() { + // BN128 Istanbul gas schedule (EIP-1108) is gated behind this flag. + VMConfig.initAllowTvmIstanbul(1); + } + + @After + public void resetIstanbul() { + VMConfig.initAllowTvmIstanbul(0); + } + + private static void runVectors(String resource, PrecompiledContract contract) + throws Exception { + ObjectMapper mapper = new ObjectMapper(); + List cases; + try (InputStream is = PrecompileVectorTest.class.getResourceAsStream(resource)) { + Assert.assertNotNull("vector resource missing: " + resource, is); + cases = mapper.readerForListOf(TestCase.class).readValue(is); + } + Assert.assertFalse("vector list empty: " + resource, cases.isEmpty()); + + for (TestCase tc : cases) { + byte[] input = tc.Input == null || tc.Input.isEmpty() + ? new byte[0] + : ByteArray.fromHexString(tc.Input); + byte[] expected = tc.Expected == null || tc.Expected.isEmpty() + ? new byte[0] + : ByteArray.fromHexString(tc.Expected); + + Pair result = contract.execute(input); + + Assert.assertTrue(tc.Name + ": precompile must not revert", result.getLeft()); + Assert.assertArrayEquals(tc.Name + ": output mismatch", expected, result.getRight()); + Assert.assertEquals(tc.Name + ": gas mismatch", + tc.Gas, contract.getEnergyForData(input)); + } + } + + @Test + public void bn128AddVectors() throws Exception { + runVectors("/precompiles/bn128add_test_vectors.json", new BN128Addition()); + } + + @Test + public void bn128MulVectors() throws Exception { + runVectors("/precompiles/bn128mul_test_vectors.json", new BN128Multiplication()); + } + + @Test + public void bn128PairingVectors() throws Exception { + runVectors("/precompiles/bn128pairing_test_vectors.json", new BN128Pairing()); + } + + @Test + public void blake2fVectors() throws Exception { + runVectors("/precompiles/blake2f_test_vectors.json", new Blake2F()); + } +} diff --git a/framework/src/test/resources/precompiles/blake2f_test_vectors.json b/framework/src/test/resources/precompiles/blake2f_test_vectors.json new file mode 100644 index 00000000000..85aa991704e --- /dev/null +++ b/framework/src/test/resources/precompiles/blake2f_test_vectors.json @@ -0,0 +1,26 @@ +[ + { + "Input": "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "Expected": "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", + "Gas": 12, + "Name": "EIP-152 vector 4 (rounds=12, f=1)" + }, + { + "Input": "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000", + "Expected": "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735", + "Gas": 12, + "Name": "EIP-152 vector 5 (rounds=12, f=0)" + }, + { + "Input": "0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "Expected": "b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421", + "Gas": 1, + "Name": "EIP-152 vector 6 (rounds=1, f=1)" + }, + { + "Input": "0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "Expected": "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b", + "Gas": 0, + "Name": "EIP-152 vector 7 (rounds=0, f=1)" + } +] diff --git a/framework/src/test/resources/precompiles/bn128add_test_vectors.json b/framework/src/test/resources/precompiles/bn128add_test_vectors.json new file mode 100644 index 00000000000..eb9d5365dd1 --- /dev/null +++ b/framework/src/test/resources/precompiles/bn128add_test_vectors.json @@ -0,0 +1,20 @@ +[ + { + "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Expected": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + "Gas": 150, + "Name": "ecAdd G + G = 2G" + }, + { + "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Gas": 150, + "Name": "ecAdd G + O = G (identity)" + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Gas": 150, + "Name": "ecAdd G + (-G) = O" + } +] diff --git a/framework/src/test/resources/precompiles/bn128mul_test_vectors.json b/framework/src/test/resources/precompiles/bn128mul_test_vectors.json new file mode 100644 index 00000000000..ade5ae9e8a7 --- /dev/null +++ b/framework/src/test/resources/precompiles/bn128mul_test_vectors.json @@ -0,0 +1,20 @@ +[ + { + "Input": "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002", + "Expected": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + "Gas": 6000, + "Name": "ecMul 2 * G = 2G" + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Gas": 6000, + "Name": "ecMul 0 * G = O" + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Gas": 6000, + "Name": "ecMul 1 * G = G" + } +] diff --git a/framework/src/test/resources/precompiles/bn128pairing_test_vectors.json b/framework/src/test/resources/precompiles/bn128pairing_test_vectors.json new file mode 100644 index 00000000000..447936a1174 --- /dev/null +++ b/framework/src/test/resources/precompiles/bn128pairing_test_vectors.json @@ -0,0 +1,20 @@ +[ + { + "Input": "", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Gas": 45000, + "Name": "ecPairing empty input = 1" + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Gas": 113000, + "Name": "ecPairing e(G1,G2)*e(-G1,G2) = 1" + }, + { + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000", + "Gas": 79000, + "Name": "ecPairing e(G1,G2) != 1" + } +]