mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-09 22:07:59 -05:00
Use native secp256k1 and altbn128 if present (#675)
Via JNA use native scep256k1 and altbn128 libraries. This is gated by two feature flags and is disabled by default. * `--Xsecp256k1-native-enabled` enables native secp256k1 across all of besu * `--Xaltbn128-native-enabled` enables native altbn128 in the precompiled contracts Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>
This commit is contained in:
@@ -67,6 +67,7 @@ import org.hyperledger.besu.config.experimental.ExperimentalEIPs;
|
||||
import org.hyperledger.besu.controller.BesuController;
|
||||
import org.hyperledger.besu.controller.BesuControllerBuilder;
|
||||
import org.hyperledger.besu.crypto.KeyPairUtil;
|
||||
import org.hyperledger.besu.crypto.SECP256K1;
|
||||
import org.hyperledger.besu.enclave.EnclaveFactory;
|
||||
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration;
|
||||
@@ -84,6 +85,7 @@ import org.hyperledger.besu.ethereum.core.Wei;
|
||||
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
|
||||
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
|
||||
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
|
||||
import org.hyperledger.besu.ethereum.mainnet.precompiles.AltBN128PairingPrecompiledContract;
|
||||
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
|
||||
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL;
|
||||
import org.hyperledger.besu.ethereum.p2p.peers.StaticNodesParser;
|
||||
@@ -854,6 +856,18 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
description = "Path to PID file (optional)")
|
||||
private final Path pidPath = null;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--Xsecp256k1-native-enabled"},
|
||||
description = "Path to PID file (optional)",
|
||||
arity = "1")
|
||||
private final Boolean nativeSecp256k1 = Boolean.FALSE;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--Xaltbn128-native-enabled"},
|
||||
description = "Path to PID file (optional)",
|
||||
arity = "1")
|
||||
private final Boolean nativeAltbn128 = Boolean.FALSE;
|
||||
|
||||
private EthNetworkConfig ethNetworkConfig;
|
||||
private JsonRpcConfiguration jsonRpcConfiguration;
|
||||
private GraphQLConfiguration graphQLConfiguration;
|
||||
@@ -932,6 +946,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
public void run() {
|
||||
try {
|
||||
configureLogging(true);
|
||||
configureNativeLibs();
|
||||
logger.info("Starting Besu version: {}", BesuInfo.nodeName(identityString));
|
||||
// Need to create vertx after cmdline has been parsed, such that metricSystem is configurable
|
||||
vertx = createVertx(createVertxOptions(metricsSystem.get()));
|
||||
@@ -1102,6 +1117,15 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private void configureNativeLibs() {
|
||||
if (nativeAltbn128) {
|
||||
AltBN128PairingPrecompiledContract.enableNative();
|
||||
}
|
||||
if (nativeSecp256k1) {
|
||||
SECP256K1.enableNative();
|
||||
}
|
||||
}
|
||||
|
||||
private BesuCommand validateOptions() {
|
||||
issueOptionWarnings();
|
||||
|
||||
|
||||
@@ -143,4 +143,8 @@ key-value-storage="rocksdb"
|
||||
target-gas-limit=8000000
|
||||
|
||||
# transaction log bloom filter caching
|
||||
auto-log-bloom-caching-enabled=true
|
||||
auto-log-bloom-caching-enabled=true
|
||||
|
||||
# feature flags
|
||||
Xsecp256k1-native-enabled=false
|
||||
Xaltbn128-native-enabled=false
|
||||
@@ -123,6 +123,7 @@ allprojects {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven {url "https://hyperledger-org.bintray.com/besu-repo"}
|
||||
maven { url "https://consensys.bintray.com/pegasys-repo" }
|
||||
maven { url "https://repo.spring.io/libs-release" }
|
||||
}
|
||||
|
||||
@@ -34,9 +34,11 @@ dependencies {
|
||||
api 'org.bouncycastle:bcprov-jdk15on'
|
||||
|
||||
implementation 'com.google.guava:guava'
|
||||
implementation 'net.java.dev.jna:jna'
|
||||
implementation 'org.apache.logging.log4j:log4j-api'
|
||||
implementation 'org.apache.tuweni:tuweni-bytes'
|
||||
implementation 'org.apache.tuweni:tuweni-units'
|
||||
implementation 'org.hyperledger.besu:secp256k1'
|
||||
|
||||
runtimeOnly 'org.apache.logging.log4j:log4j-core'
|
||||
|
||||
|
||||
@@ -16,8 +16,15 @@ package org.hyperledger.besu.crypto;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.hyperledger.besu.nativelib.secp256k1.LibSecp256k1.SECP256K1_EC_UNCOMPRESSED;
|
||||
|
||||
import org.hyperledger.besu.nativelib.secp256k1.LibSecp256k1;
|
||||
import org.hyperledger.besu.nativelib.secp256k1.LibSecp256k1.secp256k1_ecdsa_recoverable_signature;
|
||||
import org.hyperledger.besu.nativelib.secp256k1.LibSecp256k1.secp256k1_ecdsa_signature;
|
||||
import org.hyperledger.besu.nativelib.secp256k1.LibSecp256k1.secp256k1_pubkey;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.Security;
|
||||
@@ -25,8 +32,14 @@ import java.security.spec.ECGenParameterSpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import com.sun.jna.ptr.LongByReference;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.apache.tuweni.bytes.Bytes32;
|
||||
import org.apache.tuweni.bytes.MutableBytes;
|
||||
@@ -59,6 +72,10 @@ import org.bouncycastle.math.ec.custom.sec.SecP256K1Curve;
|
||||
*/
|
||||
public class SECP256K1 {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
|
||||
private static boolean useNative = false;
|
||||
|
||||
public static final String ALGORITHM = "ECDSA";
|
||||
public static final String CURVE_NAME = "secp256k1";
|
||||
public static final String PROVIDER = "BC";
|
||||
@@ -89,6 +106,38 @@ public class SECP256K1 {
|
||||
}
|
||||
}
|
||||
|
||||
public static void enableNative() {
|
||||
useNative = LibSecp256k1.CONTEXT != null;
|
||||
LOG.info(useNative ? "Using native secp256k1" : "Native secp256k1 requested but not available");
|
||||
}
|
||||
|
||||
public static Signature sign(final Bytes32 dataHash, final KeyPair keyPair) {
|
||||
if (useNative) {
|
||||
return signNative(dataHash, keyPair);
|
||||
} else {
|
||||
return signDefault(dataHash, keyPair);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the given ECDSA signature against the message bytes using the public key bytes.
|
||||
*
|
||||
* <p>When using native ECDSA verification, data must be 32 bytes, and no element may be larger
|
||||
* than 520 bytes.
|
||||
*
|
||||
* @param data Hash of the data to verify.
|
||||
* @param signature ASN.1 encoded signature.
|
||||
* @param pub The public key bytes to use.
|
||||
* @return True if the verification is successful.
|
||||
*/
|
||||
public static boolean verify(final Bytes data, final Signature signature, final PublicKey pub) {
|
||||
if (useNative) {
|
||||
return verifyNative(data, signature, pub);
|
||||
} else {
|
||||
return verifyDefault(data, signature, pub);
|
||||
}
|
||||
}
|
||||
|
||||
/** Decompress a compressed public key (x co-ord and low-bit of y-coord). */
|
||||
private static ECPoint decompressKey(final BigInteger xBN, final boolean yBit) {
|
||||
final X9IntegerConverter x9 = new X9IntegerConverter();
|
||||
@@ -178,7 +227,7 @@ public class SECP256K1 {
|
||||
return new BigInteger(1, Arrays.copyOfRange(qBytes, 1, qBytes.length));
|
||||
}
|
||||
|
||||
public static Signature sign(final Bytes32 dataHash, final KeyPair keyPair) {
|
||||
private static Signature signDefault(final Bytes32 dataHash, final KeyPair keyPair) {
|
||||
final ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
|
||||
|
||||
final ECPrivateKeyParameters privKey =
|
||||
@@ -232,18 +281,8 @@ public class SECP256K1 {
|
||||
return new Signature(nativeR, s, (byte) recId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the given ECDSA signature against the message bytes using the public key bytes.
|
||||
*
|
||||
* <p>When using native ECDSA verification, data must be 32 bytes, and no element may be larger
|
||||
* than 520 bytes.
|
||||
*
|
||||
* @param data Hash of the data to verify.
|
||||
* @param signature ASN.1 encoded signature.
|
||||
* @param pub The public key bytes to use.
|
||||
* @return True if the verification is successful.
|
||||
*/
|
||||
public static boolean verify(final Bytes data, final Signature signature, final PublicKey pub) {
|
||||
private static boolean verifyDefault(
|
||||
final Bytes data, final Signature signature, final PublicKey pub) {
|
||||
final ECDSASigner signer = new ECDSASigner();
|
||||
final Bytes toDecode = Bytes.wrap(Bytes.of((byte) 4), pub.getEncodedBytes());
|
||||
final ECPublicKeyParameters params =
|
||||
@@ -301,6 +340,95 @@ public class SECP256K1 {
|
||||
return UInt256.valueOf(agreed).toBytes();
|
||||
}
|
||||
|
||||
private static Signature signNative(final Bytes32 dataHash, final KeyPair keyPair) {
|
||||
final LibSecp256k1.secp256k1_ecdsa_recoverable_signature signature =
|
||||
new secp256k1_ecdsa_recoverable_signature();
|
||||
// sign in internal form
|
||||
if (LibSecp256k1.secp256k1_ecdsa_sign_recoverable(
|
||||
LibSecp256k1.CONTEXT,
|
||||
signature,
|
||||
dataHash.toArrayUnsafe(),
|
||||
keyPair.privateKey.getEncoded(),
|
||||
null,
|
||||
null)
|
||||
== 0) {
|
||||
throw new RuntimeException(
|
||||
"Could not natively sign. Private Key is invalid or default nonce generation failed.");
|
||||
}
|
||||
|
||||
// encode to compact form
|
||||
final ByteBuffer compactSig = ByteBuffer.allocate(64);
|
||||
final IntByReference recId = new IntByReference(0);
|
||||
LibSecp256k1.secp256k1_ecdsa_recoverable_signature_serialize_compact(
|
||||
LibSecp256k1.CONTEXT, compactSig, recId, signature);
|
||||
compactSig.flip();
|
||||
final byte[] sig = compactSig.array();
|
||||
|
||||
// wrap in signature object
|
||||
final Bytes32 r = Bytes32.wrap(sig, 0);
|
||||
final Bytes32 s = Bytes32.wrap(sig, 32);
|
||||
return Signature.create(
|
||||
r.toUnsignedBigInteger(), s.toUnsignedBigInteger(), (byte) recId.getValue());
|
||||
}
|
||||
|
||||
private static boolean verifyNative(
|
||||
final Bytes data, final Signature signature, final PublicKey pub) {
|
||||
|
||||
// translate signature
|
||||
final LibSecp256k1.secp256k1_ecdsa_signature _signature = new secp256k1_ecdsa_signature();
|
||||
if (LibSecp256k1.secp256k1_ecdsa_signature_parse_compact(
|
||||
LibSecp256k1.CONTEXT, _signature, signature.encodedBytes().toArrayUnsafe())
|
||||
== 0) {
|
||||
throw new IllegalArgumentException("Could not parse signature");
|
||||
}
|
||||
|
||||
// translate key
|
||||
final LibSecp256k1.secp256k1_pubkey _pub = new secp256k1_pubkey();
|
||||
final Bytes encodedPubKey = Bytes.concatenate(Bytes.of(0x04), pub.getEncodedBytes());
|
||||
if (LibSecp256k1.secp256k1_ec_pubkey_parse(
|
||||
LibSecp256k1.CONTEXT, _pub, encodedPubKey.toArrayUnsafe(), encodedPubKey.size())
|
||||
== 0) {
|
||||
throw new IllegalArgumentException("Could not parse public key");
|
||||
}
|
||||
|
||||
return LibSecp256k1.secp256k1_ecdsa_verify(
|
||||
LibSecp256k1.CONTEXT, _signature, data.toArrayUnsafe(), _pub)
|
||||
!= 0;
|
||||
}
|
||||
|
||||
private static Optional<PublicKey> recoverFromSignatureNative(
|
||||
final Bytes32 dataHash, final Signature signature) {
|
||||
|
||||
// parse the sig
|
||||
final LibSecp256k1.secp256k1_ecdsa_recoverable_signature parsedSignature =
|
||||
new LibSecp256k1.secp256k1_ecdsa_recoverable_signature();
|
||||
final Bytes encodedSig = signature.encodedBytes();
|
||||
if (LibSecp256k1.secp256k1_ecdsa_recoverable_signature_parse_compact(
|
||||
LibSecp256k1.CONTEXT,
|
||||
parsedSignature,
|
||||
encodedSig.slice(0, 64).toArrayUnsafe(),
|
||||
encodedSig.get(64))
|
||||
== 0) {
|
||||
throw new IllegalArgumentException("Could not parse signature");
|
||||
}
|
||||
|
||||
// recover the key
|
||||
final LibSecp256k1.secp256k1_pubkey newPubKey = new LibSecp256k1.secp256k1_pubkey();
|
||||
if (LibSecp256k1.secp256k1_ecdsa_recover(
|
||||
LibSecp256k1.CONTEXT, newPubKey, parsedSignature, dataHash.toArrayUnsafe())
|
||||
== 0) {
|
||||
throw new IllegalArgumentException("Could not recover public key");
|
||||
}
|
||||
|
||||
// parse the key
|
||||
final ByteBuffer recoveredKey = ByteBuffer.allocate(65);
|
||||
final LongByReference keySize = new LongByReference(recoveredKey.limit());
|
||||
LibSecp256k1.secp256k1_ec_pubkey_serialize(
|
||||
LibSecp256k1.CONTEXT, recoveredKey, keySize, newPubKey, SECP256K1_EC_UNCOMPRESSED);
|
||||
|
||||
return Optional.of(PublicKey.create(Bytes.wrapByteBuffer(recoveredKey).slice(1)));
|
||||
}
|
||||
|
||||
public static class PrivateKey implements java.security.PrivateKey {
|
||||
|
||||
private final Bytes32 encoded;
|
||||
@@ -319,10 +447,6 @@ public class SECP256K1 {
|
||||
return new PrivateKey(key);
|
||||
}
|
||||
|
||||
public ECPoint asEcPoint() {
|
||||
return CURVE.getCurve().decodePoint(encoded.toArrayUnsafe());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (!(other instanceof PrivateKey)) {
|
||||
@@ -411,10 +535,14 @@ public class SECP256K1 {
|
||||
|
||||
public static Optional<PublicKey> recoverFromSignature(
|
||||
final Bytes32 dataHash, final Signature signature) {
|
||||
final BigInteger publicKeyBI =
|
||||
SECP256K1.recoverFromSignature(
|
||||
signature.getRecId(), signature.getR(), signature.getS(), dataHash);
|
||||
return Optional.ofNullable(publicKeyBI).map(PublicKey::create);
|
||||
if (useNative) {
|
||||
return recoverFromSignatureNative(dataHash, signature);
|
||||
} else {
|
||||
final BigInteger publicKeyBI =
|
||||
SECP256K1.recoverFromSignature(
|
||||
signature.getRecId(), signature.getR(), signature.getS(), dataHash);
|
||||
return Optional.ofNullable(publicKeyBI).map(PublicKey::create);
|
||||
}
|
||||
}
|
||||
|
||||
private PublicKey(final Bytes encoded) {
|
||||
@@ -552,7 +680,9 @@ public class SECP256K1 {
|
||||
private final BigInteger r;
|
||||
private final BigInteger s;
|
||||
|
||||
private Signature(final BigInteger r, final BigInteger s, final byte recId) {
|
||||
private final Supplier<Bytes> encoded = Suppliers.memoize(this::_encodedBytes);
|
||||
|
||||
Signature(final BigInteger r, final BigInteger s, final byte recId) {
|
||||
this.r = r;
|
||||
this.s = s;
|
||||
this.recId = recId;
|
||||
@@ -604,6 +734,10 @@ public class SECP256K1 {
|
||||
}
|
||||
|
||||
public Bytes encodedBytes() {
|
||||
return encoded.get();
|
||||
}
|
||||
|
||||
private Bytes _encodedBytes() {
|
||||
final MutableBytes bytes = MutableBytes.create(BYTES_REQUIRED);
|
||||
UInt256.valueOf(r).toBytes().copyTo(bytes, 0);
|
||||
UInt256.valueOf(s).toBytes().copyTo(bytes, 32);
|
||||
|
||||
@@ -42,9 +42,11 @@ dependencies {
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind'
|
||||
implementation 'com.google.guava:guava'
|
||||
implementation 'io.vertx:vertx-core'
|
||||
implementation 'net.java.dev.jna:jna'
|
||||
implementation 'org.apache.logging.log4j:log4j-api'
|
||||
implementation 'org.apache.tuweni:tuweni-bytes'
|
||||
implementation 'org.apache.tuweni:tuweni-units'
|
||||
implementation 'org.hyperledger.besu:altbn128'
|
||||
|
||||
runtimeOnly 'org.apache.logging.log4j:log4j-core'
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
*/
|
||||
package org.hyperledger.besu.ethereum.mainnet.precompiles;
|
||||
|
||||
import static org.hyperledger.besu.nativelib.altbn128.LibAltbn128.altbn128_add_precompiled;
|
||||
|
||||
import org.hyperledger.besu.crypto.altbn128.AltBn128Point;
|
||||
import org.hyperledger.besu.crypto.altbn128.Fq;
|
||||
import org.hyperledger.besu.ethereum.core.Gas;
|
||||
@@ -24,6 +26,7 @@ import org.hyperledger.besu.ethereum.vm.MessageFrame;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.apache.tuweni.bytes.MutableBytes;
|
||||
|
||||
@@ -51,6 +54,14 @@ public class AltBN128AddPrecompiledContract extends AbstractPrecompiledContract
|
||||
|
||||
@Override
|
||||
public Bytes compute(final Bytes input, final MessageFrame messageFrame) {
|
||||
if (AltBN128PairingPrecompiledContract.useNative) {
|
||||
return computeNative(input);
|
||||
} else {
|
||||
return computeDefault(input);
|
||||
}
|
||||
}
|
||||
|
||||
private static Bytes computeDefault(final Bytes input) {
|
||||
final BigInteger x1 = extractParameter(input, 0, 32);
|
||||
final BigInteger y1 = extractParameter(input, 32, 32);
|
||||
final BigInteger x2 = extractParameter(input, 64, 32);
|
||||
@@ -71,6 +82,16 @@ public class AltBN128AddPrecompiledContract extends AbstractPrecompiledContract
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Bytes computeNative(final Bytes input) {
|
||||
final byte[] output = new byte[64];
|
||||
final IntByReference outputSize = new IntByReference(64);
|
||||
if (altbn128_add_precompiled(input.toArrayUnsafe(), input.size(), output, outputSize) == 0) {
|
||||
return Bytes.wrap(output, 0, outputSize.getValue());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static BigInteger extractParameter(
|
||||
final Bytes input, final int offset, final int length) {
|
||||
if (offset > input.size() || length == 0) {
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
*/
|
||||
package org.hyperledger.besu.ethereum.mainnet.precompiles;
|
||||
|
||||
import static org.hyperledger.besu.nativelib.altbn128.LibAltbn128.altbn128_mul_precompiled;
|
||||
|
||||
import org.hyperledger.besu.crypto.altbn128.AltBn128Point;
|
||||
import org.hyperledger.besu.crypto.altbn128.Fq;
|
||||
import org.hyperledger.besu.ethereum.core.Gas;
|
||||
@@ -24,6 +26,7 @@ import org.hyperledger.besu.ethereum.vm.MessageFrame;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.apache.tuweni.bytes.MutableBytes;
|
||||
|
||||
@@ -55,6 +58,14 @@ public class AltBN128MulPrecompiledContract extends AbstractPrecompiledContract
|
||||
|
||||
@Override
|
||||
public Bytes compute(final Bytes input, final MessageFrame messageFrame) {
|
||||
if (AltBN128PairingPrecompiledContract.useNative) {
|
||||
return computeNative(input);
|
||||
} else {
|
||||
return computeDefault(input);
|
||||
}
|
||||
}
|
||||
|
||||
private static Bytes computeDefault(final Bytes input) {
|
||||
final BigInteger x = extractParameter(input, 0, 32);
|
||||
final BigInteger y = extractParameter(input, 32, 32);
|
||||
final BigInteger n = extractParameter(input, 64, 32);
|
||||
@@ -74,6 +85,16 @@ public class AltBN128MulPrecompiledContract extends AbstractPrecompiledContract
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Bytes computeNative(final Bytes input) {
|
||||
final byte[] output = new byte[64];
|
||||
final IntByReference outputSize = new IntByReference(64);
|
||||
if (altbn128_mul_precompiled(input.toArrayUnsafe(), input.size(), output, outputSize) == 0) {
|
||||
return Bytes.wrap(output, 0, outputSize.getValue());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static BigInteger extractParameter(
|
||||
final Bytes input, final int offset, final int length) {
|
||||
if (offset > input.size() || length == 0) {
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
*/
|
||||
package org.hyperledger.besu.ethereum.mainnet.precompiles;
|
||||
|
||||
import static org.hyperledger.besu.nativelib.altbn128.LibAltbn128.altbn128_pairing_precompiled;
|
||||
|
||||
import org.hyperledger.besu.crypto.altbn128.AltBn128Fq12Pairer;
|
||||
import org.hyperledger.besu.crypto.altbn128.AltBn128Fq2Point;
|
||||
import org.hyperledger.besu.crypto.altbn128.AltBn128Point;
|
||||
@@ -24,16 +26,29 @@ import org.hyperledger.besu.ethereum.core.Gas;
|
||||
import org.hyperledger.besu.ethereum.mainnet.AbstractPrecompiledContract;
|
||||
import org.hyperledger.besu.ethereum.vm.GasCalculator;
|
||||
import org.hyperledger.besu.ethereum.vm.MessageFrame;
|
||||
import org.hyperledger.besu.nativelib.altbn128.LibAltbn128;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
|
||||
public class AltBN128PairingPrecompiledContract extends AbstractPrecompiledContract {
|
||||
|
||||
static boolean useNative = false;
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
|
||||
public static void enableNative() {
|
||||
useNative = LibAltbn128.ENABLED;
|
||||
LOG.info(useNative ? "Using native alt bn128" : "Native alt bn128 requested but not available");
|
||||
}
|
||||
|
||||
private static final int FIELD_LENGTH = 32;
|
||||
private static final int PARAMETER_LENGTH = 192;
|
||||
|
||||
@@ -74,7 +89,14 @@ public class AltBN128PairingPrecompiledContract extends AbstractPrecompiledContr
|
||||
if (input.size() % PARAMETER_LENGTH != 0) {
|
||||
return null;
|
||||
}
|
||||
if (AltBN128PairingPrecompiledContract.useNative) {
|
||||
return computeNative(input);
|
||||
} else {
|
||||
return computeDefault(input);
|
||||
}
|
||||
}
|
||||
|
||||
private static Bytes computeDefault(final Bytes input) {
|
||||
final int parameters = input.size() / PARAMETER_LENGTH;
|
||||
final List<AltBn128Point> a = new ArrayList<>();
|
||||
final List<AltBn128Fq2Point> b = new ArrayList<>();
|
||||
@@ -112,6 +134,17 @@ public class AltBN128PairingPrecompiledContract extends AbstractPrecompiledContr
|
||||
}
|
||||
}
|
||||
|
||||
private static Bytes computeNative(final Bytes input) {
|
||||
final byte[] output = new byte[32];
|
||||
final IntByReference outputSize = new IntByReference(32);
|
||||
if (altbn128_pairing_precompiled(input.toArrayUnsafe(), input.size(), output, outputSize)
|
||||
== 0) {
|
||||
return Bytes.wrap(output, 0, outputSize.getValue());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static BigInteger extractParameter(
|
||||
final Bytes input, final int offset, final int length) {
|
||||
if (offset > input.size() || length == 0) {
|
||||
|
||||
@@ -110,7 +110,11 @@ downloadLicenses {
|
||||
(group('besu.plugins')) : apache,
|
||||
(group('besu.services')) : apache,
|
||||
|
||||
// RocksDB is dual licensed under Apache v2.0 and GPL 2 licenses
|
||||
// JNA is dual licensed under Apache v2.0 or LGPL 2 licenses
|
||||
// Explicitly declare that we are using the Apache v2.0 license
|
||||
(group('net.java.dev.jna')) : apache,
|
||||
|
||||
// RocksDB is dual licensed under Apache v2.0 or GPL 2 licenses
|
||||
// Explicitly declare that we are using the Apache v2.0 license
|
||||
(group('org.rocksdb')) : apache,
|
||||
|
||||
|
||||
@@ -59,7 +59,9 @@ dependencyManagement {
|
||||
|
||||
dependency 'junit:junit:4.13'
|
||||
|
||||
dependency 'net.consensys:orion:1.5.0-SNAPSHOT'
|
||||
dependency 'net.consensys:orion:1.5.0'
|
||||
|
||||
dependency 'net.java.dev.jna:jna:5.5.0'
|
||||
|
||||
dependency 'org.apache.commons:commons-compress:1.20'
|
||||
dependency 'org.apache.commons:commons-text:1.8'
|
||||
@@ -83,6 +85,9 @@ dependencyManagement {
|
||||
dependency 'org.bouncycastle:bcpkix-jdk15on:1.64'
|
||||
dependency 'org.bouncycastle:bcprov-jdk15on:1.64'
|
||||
|
||||
dependency 'org.hyperledger.besu:altbn128:0.1.0'
|
||||
dependency 'org.hyperledger.besu:secp256k1:0.1.0'
|
||||
|
||||
dependency 'org.java-websocket:Java-WebSocket:1.4.0'
|
||||
|
||||
dependency 'org.jupnp:org.jupnp.support:2.5.2'
|
||||
|
||||
Reference in New Issue
Block a user