Add native secp256r1 lib (#2630)

* add native secp256r1 lib

Signed-off-by: Daniel Lehrner <daniel@io.builders>
pull/2661/head
Daniel Lehrner 3 years ago committed by GitHub
parent f9b17cf92b
commit 0b2b2bacd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 8
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java
  3. 2
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/crypto/SECP256R1AcceptanceTest.java
  4. 6
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  5. 16
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NativeLibraryOptions.java
  6. 4
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  7. 1
      crypto/build.gradle
  8. 85
      crypto/src/main/java/org/hyperledger/besu/crypto/SECP256R1.java
  9. 114
      crypto/src/test/java/org/hyperledger/besu/crypto/SECP256R1Test.java
  10. 6
      crypto/src/test/java/org/hyperledger/besu/crypto/SignatureAlgorithmFactoryTest.java
  11. 3
      gradle/versions.gradle

@ -10,6 +10,8 @@
- Updated onchain permissioning to validate permissions on transaction submission [\#2595](https://github.com/hyperledger/besu/pull/2595)
- Removed deprecated CLI option `--privacy-precompiled-address` [#2605](https://github.com/hyperledger/besu/pull/2605)
- Removed code supporting EIP-1702. [#2657](https://github.com/hyperledger/besu/pull/2657)
- A native library was added for the alternative signature algorithm secp256r1, which will be used by default [#2630](https://github.com/hyperledger/besu/pull/2630)
- The command line option --Xsecp-native-enabled was added as an alias for --Xsecp256k1-native-enabled [#2630](https://github.com/hyperledger/besu/pull/2630)
### Bug Fixes
- Consider effective price and effective priority fee in transaction replacement rules [\#2529](https://github.com/hyperledger/besu/issues/2529)

@ -71,8 +71,8 @@ public class BesuNodeConfigurationBuilder {
private boolean bootnodeEligible = true;
private boolean revertReasonEnabled = false;
private NetworkName network = null;
private boolean secp256K1Native = false;
private boolean altbn128Native = false;
private boolean secp256K1Native = true;
private boolean altbn128Native = true;
private final List<String> plugins = new ArrayList<>();
private final List<String> extraCLIOptions = new ArrayList<>();
private List<String> staticNodes = new ArrayList<>();
@ -371,12 +371,12 @@ public class BesuNodeConfigurationBuilder {
return this;
}
public BesuNodeConfigurationBuilder secp256k1Native() {
public BesuNodeConfigurationBuilder secp256k1Java() {
this.secp256K1Native = true;
return this;
}
public BesuNodeConfigurationBuilder altbn128() {
public BesuNodeConfigurationBuilder altbn128Java() {
this.altbn128Native = true;
return this;
}

@ -66,7 +66,7 @@ public class SECP256R1AcceptanceTest extends AcceptanceTestBase {
otherNode =
besu.createNodeWithNonDefaultSignatureAlgorithm(
"otherNode", GENESIS_FILE, otherNodeKeyPair, List.of(minerNode));
cluster.addNode(otherNode);
noDiscoveryCluster.addNode(otherNode);
}
@Test

@ -1433,12 +1433,12 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
logger.info("Using the Java implementation of alt bn128");
}
if (unstableNativeLibraryOptions.getNativeSecp256k1()
if (unstableNativeLibraryOptions.getNativeSecp()
&& SignatureAlgorithmFactory.getInstance().isNative()) {
logger.info("Using native secp256k1");
logger.info("Using the native implementation of the signature algorithm");
} else {
SignatureAlgorithmFactory.getInstance().disableNative();
logger.info("Using the Java implementation of secp256k1");
logger.info("Using the Java implementation of the signature algorithm");
}
}

@ -20,15 +20,19 @@ public class NativeLibraryOptions {
@CommandLine.Option(
hidden = true,
names = {"--Xsecp256k1-native-enabled"},
description = "Path to PID file (optional)",
names = {"--Xsecp-native-enabled", "--Xsecp256k1-native-enabled"},
description =
"Per default a native library is used for the signature algorithm."
+ "If the Java implementation should be used instead, the parameter of this option has to be set to false",
arity = "1")
private final Boolean nativeSecp256k1 = Boolean.TRUE;
private final Boolean nativeSecp = Boolean.TRUE;
@CommandLine.Option(
hidden = true,
names = {"--Xaltbn128-native-enabled"},
description = "Path to PID file (optional)",
description =
"Per default a native library is used for altbn128."
+ "If the Java implementation should be used instead, the parameter of this option has to be set to false",
arity = "1")
private final Boolean nativeAltbn128 = Boolean.TRUE;
@ -36,8 +40,8 @@ public class NativeLibraryOptions {
return new NativeLibraryOptions();
}
public Boolean getNativeSecp256k1() {
return nativeSecp256k1;
public Boolean getNativeSecp() {
return nativeSecp;
}
public Boolean getNativeAltbn128() {

@ -4287,7 +4287,7 @@ public class BesuCommandTest extends CommandTestAbstract {
SignatureAlgorithmFactory.resetInstance();
parseCommand("--Xsecp256k1-native-enabled", "false");
verify(mockLogger).info("Using the Java implementation of secp256k1");
verify(mockLogger).info("Using the Java implementation of the signature algorithm");
assertThat(SignatureAlgorithmFactory.getInstance().isNative()).isFalse();
}
@ -4308,7 +4308,7 @@ public class BesuCommandTest extends CommandTestAbstract {
parseCommand();
assertThat(SignatureAlgorithmFactory.getInstance().isNative()).isTrue();
verify(mockLogger).info("Using native secp256k1");
verify(mockLogger).info("Using the native implementation of the signature algorithm");
assertThat(AbstractAltBnPrecompiledContract.isNative()).isTrue();
verify(mockLogger).info("Using LibEthPairings native alt bn128");

@ -39,6 +39,7 @@ dependencies {
implementation 'org.apache.tuweni:tuweni-bytes'
implementation 'org.apache.tuweni:tuweni-units'
implementation 'org.hyperledger.besu:secp256k1'
implementation 'org.hyperledger.besu:secp256r1'
runtimeOnly 'org.apache.logging.log4j:log4j-core'

@ -14,6 +14,14 @@
*/
package org.hyperledger.besu.crypto;
import org.hyperledger.besu.nativelib.secp256r1.LibSECP256R1;
import org.hyperledger.besu.nativelib.secp256r1.Signature;
import java.math.BigInteger;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.bouncycastle.crypto.signers.DSAKCalculator;
import org.bouncycastle.crypto.signers.RandomDSAKCalculator;
import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
@ -21,17 +29,21 @@ import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
public class SECP256R1 extends AbstractSECP256 {
public static final String CURVE_NAME = "secp256r1";
private boolean useNative = true;
private final LibSECP256R1 libSECP256R1 = new LibSECP256R1();
public SECP256R1() {
super(CURVE_NAME, SecP256R1Curve.q);
}
@Override
public void disableNative() {}
public void disableNative() {
useNative = false;
}
@Override
public boolean isNative() {
return false;
return useNative;
}
/**
@ -48,4 +60,73 @@ public class SECP256R1 extends AbstractSECP256 {
public String getCurveName() {
return CURVE_NAME;
}
@Override
public SECPSignature sign(final Bytes32 dataHash, final KeyPair keyPair) {
if (useNative) {
return signNative(dataHash, keyPair);
} else {
return super.sign(dataHash, keyPair);
}
}
@Override
public boolean verify(final Bytes data, final SECPSignature signature, final SECPPublicKey pub) {
if (useNative) {
return verifyNative(data, signature, pub);
} else {
return super.verify(data, signature, pub);
}
}
@Override
public Optional<SECPPublicKey> recoverPublicKeyFromSignature(
final Bytes32 dataHash, final SECPSignature signature) {
if (useNative) {
return recoverPublicKeyFromSignatureNative(dataHash, signature);
} else {
return super.recoverPublicKeyFromSignature(dataHash, signature);
}
}
private SECPSignature signNative(final Bytes32 dataHash, final KeyPair keyPair) {
Signature nativeSignature =
libSECP256R1.sign(
dataHash.toArrayUnsafe(),
keyPair.getPrivateKey().getEncoded(),
keyPair.getPublicKey().getEncoded());
return new SECPSignature(
new BigInteger(nativeSignature.getR()),
new BigInteger(nativeSignature.getS()),
nativeSignature.getV());
}
private Optional<SECPPublicKey> recoverPublicKeyFromSignatureNative(
final Bytes32 dataHash, final SECPSignature signature) {
byte[] recoveredKey;
try {
recoveredKey =
libSECP256R1.keyRecovery(
dataHash.toArrayUnsafe(),
signature.getR().toByteArray(),
signature.getS().toByteArray(),
signature.getRecId());
} catch (IllegalArgumentException e) {
return Optional.empty();
}
return Optional.of(SECPPublicKey.create(Bytes.of(recoveredKey), ALGORITHM));
}
private boolean verifyNative(
final Bytes data, final SECPSignature signature, final SECPPublicKey pub) {
return libSECP256R1.verify(
data.toArrayUnsafe(),
signature.getR().toByteArray(),
signature.getS().toByteArray(),
pub.getEncoded());
}
}

@ -24,6 +24,7 @@ import java.nio.file.Files;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
@ -33,6 +34,69 @@ import org.junit.Test;
public class SECP256R1Test {
private final List<SignTestVector> signTestVectors =
List.of(
new SignTestVector(
"519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464",
"1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9",
"5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe165b1a045ee2bcd2e6dca3bdf46c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd28065b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9d791e91491eb3754d03799790fe2d308d16146d5c9b0d0debd97d79ce8"),
new SignTestVector(
"0f56db78ca460b055c500064824bed999a25aaf48ebb519ac201537b85479813",
"e266ddfdc12668db30d4ca3e8f7749432c416044f2d2b8c10bf3d4012aeffa8abfa86404a2e9ffe67d47c587ef7a97a7f456b863b4d02cfc6928973ab5b1cb39",
"c35e2f092553c55772926bdbe87c9796827d17024dbb9233a545366e2e5987dd344deb72df987144b8c6c43bc41b654b94cc856e16b96d7a821c8ec039b503e3d86728c494a967d83011a0e090b5d54cd47f4e366c0912bc808fbb2ea96efac88fb3ebec9342738e225f7c7c2b011ce375b56621a20642b4d36e060db4524af1"),
new SignTestVector(
"e283871239837e13b95f789e6e1af63bf61c918c992e62bca040d64cad1fc2ef",
"74ccd8a62fba0e667c50929a53f78c21b8ff0c3c737b0b40b1750b2302b0bde829074e21f3a0ef88b9efdf10d06aa4c295cc1671f758ca0e4cd108803d0f2614",
"3c054e333a94259c36af09ab5b4ff9beb3492f8d5b4282d16801daccb29f70fe61a0b37ffef5c04cd1b70e85b1f549a1c4dc672985e50f43ea037efa9964f096b5f62f7ffdf8d6bfb2cc859558f5a393cb949dbd48f269343b5263dcdb9c556eca074f2e98e6d94c2c29a677afaf806edf79b15a3fcd46e7067b7669f83188ee"),
new SignTestVector(
"a3d2d3b7596f6592ce98b4bfe10d41837f10027a90d7bb75349490018cf72d07",
"322f80371bf6e044bc49391d97c1714ab87f990b949bc178cb7c43b7c22d89e13c15d54a5cc6b9f09de8457e873eb3deb1fceb54b0b295da6050294fae7fd999",
"0989122410d522af64ceb07da2c865219046b4c3d9d99b01278c07ff63eaf1039cb787ae9e2dd46436cc0415f280c562bebb83a23e639e476a02ec8cff7ea06cd12c86dcc3adefbf1a9e9a9b6646c7599ec631b0da9a60debeb9b3e19324977f3b4f36892c8a38671c8e1cc8e50fcd50f9e51deaf98272f9266fc702e4e57c30"),
new SignTestVector(
"53a0e8a8fe93db01e7ae94e1a9882a102ebd079b3a535827d583626c272d280d",
"1bcec4570e1ec2436596b8ded58f60c3b1ebc6a403bc5543040ba829630572448af62a4c683f096b28558320737bf83b9959a46ad2521004ef74cf85e67494e1",
"dc66e39f9bbfd9865318531ffe9207f934fa615a5b285708a5e9c46b7775150e818d7f24d2a123df3672fff2094e3fd3df6fbe259e3989dd5edfcccbe7d45e26a775a5c4329a084f057c42c13f3248e3fd6f0c76678f890f513c32292dd306eaa84a59abe34b16cb5e38d0e885525d10336ca443e1682aa04a7af832b0eee4e7"),
new SignTestVector(
"4af107e8e2194c830ffb712a65511bc9186a133007855b49ab4b3833aefc4a1d",
"a32e50be3dae2c8ba3f5e4bdae14cf7645420d425ead94036c22dd6c4fc59e00d623bf641160c289d6742c6257ae6ba574446dd1d0e74db3aaa80900b78d4ae9",
"600974e7d8c5508e2c1aab0783ad0d7c4494ab2b4da265c2fe496421c4df238b0be25f25659157c8a225fb03953607f7df996acfd402f147e37aee2f1693e3bf1c35eab3ae360a2bd91d04622ea47f83d863d2dfecb618e8b8bdc39e17d15d672eee03bb4ce2cc5cf6b217e5faf3f336fdd87d972d3a8b8a593ba85955cc9d71"),
new SignTestVector(
"78dfaa09f1076850b3e206e477494cddcfb822aaa0128475053592c48ebaf4ab",
"8bcfe2a721ca6d753968f564ec4315be4857e28bef1908f61a366b1f03c974790f67576a30b8e20d4232d8530b52fb4c89cbc589ede291e499ddd15fe870ab96",
"dfa6cb9b39adda6c74cc8b2a8b53a12c499ab9dee01b4123642b4f11af336a91a5c9ce0520eb2395a6190ecbf6169c4cba81941de8e76c9c908eb843b98ce95e0da29c5d4388040264e05e07030a577cc5d176387154eabae2af52a83e85c61c7c61da930c9b19e45d7e34c8516dc3c238fddd6e450a77455d534c48a152010b"),
new SignTestVector(
"80e692e3eb9fcd8c7d44e7de9f7a5952686407f90025a1d87e52c7096a62618a",
"a88bc8430279c8c0400a77d751f26c0abc93e5de4ad9a4166357952fe041e7672d365a1eef25ead579cc9a069b6abc1b16b81c35f18785ce26a10ba6d1381185",
"51d2547cbff92431174aa7fc7302139519d98071c755ff1c92e4694b58587ea560f72f32fc6dd4dee7d22bb7387381d0256e2862d0644cdf2c277c5d740fa089830eb52bf79d1e75b8596ecf0ea58a0b9df61e0c9754bfcd62efab6ea1bd216bf181c5593da79f10135a9bc6e164f1854bc8859734341aad237ba29a81a3fc8b"),
new SignTestVector(
"5e666c0db0214c3b627a8e48541cc84a8b6fd15f300da4dff5d18aec6c55b881",
"1bc487570f040dc94196c9befe8ab2b6de77208b1f38bdaae28f9645c4d2bc3aec81602abd8345e71867c8210313737865b8aa186851e1b48eaca140320f5d8f",
"558c2ac13026402bad4a0a83ebc9468e50f7ffab06d6f981e5db1d082098065bcff6f21a7a74558b1e8612914b8b5a0aa28ed5b574c36ac4ea5868432a62bb8ef0695d27c1e3ceaf75c7b251c65ddb268696f07c16d2767973d85beb443f211e6445e7fe5d46f0dce70d58a4cd9fe70688c035688ea8c6baec65a5fc7e2c93e8"),
new SignTestVector(
"f73f455271c877c4d5334627e37c278f68d143014b0a05aa62f308b2101c5308",
"b8188bd68701fc396dab53125d4d28ea33a91daf6d21485f4770f6ea8c565dde423f058810f277f8fe076f6db56e9285a1bf2c2a1dae145095edd9c04970bc4a",
"4d55c99ef6bd54621662c3d110c3cb627c03d6311393b264ab97b90a4b15214a5593ba2510a53d63fb34be251facb697c973e11b665cb7920f1684b0031b4dd370cb927ca7168b0bf8ad285e05e9e31e34bc24024739fdc10b78586f29eff94412034e3b606ed850ec2c1900e8e68151fc4aee5adebb066eb6da4eaa5681378e"),
new SignTestVector(
"b20d705d9bd7c2b8dc60393a5357f632990e599a0975573ac67fd89b49187906",
"51f99d2d52d4a6e734484a018b7ca2f895c2929b6754a3a03224d07ae61166ce4737da963c6ef7247fb88d19f9b0c667cac7fe12837fdab88c66f10d3c14cad1",
"f8248ad47d97c18c984f1f5c10950dc1404713c56b6ea397e01e6dd925e903b4fadfe2c9e877169e71ce3c7fe5ce70ee4255d9cdc26f6943bf48687874de64f6cf30a012512e787b88059bbf561162bdcc23a3742c835ac144cc14167b1bd6727e940540a9c99f3cbb41fb1dcb00d76dda04995847c657f4c19d303eb09eb48a"),
new SignTestVector(
"d4234bebfbc821050341a37e1240efe5e33763cbbb2ef76a1c79e24724e5a5e7",
"8fb287f0202ad57ae841aea35f29b2e1d53e196d0ddd9aec24813d64c0922fb71f6daff1aa2dd2d6d3741623eecb5e7b612997a1039aab2e5cf2de969cfea573",
"3b6ee2425940b3d240d35b97b6dcd61ed3423d8e71a0ada35d47b322d17b35ea0472f35edd1d252f87b8b65ef4b716669fc9ac28b00d34a9d66ad118c9d94e7f46d0b4f6c2b2d339fd6bcd351241a387cc82609057048c12c4ec3d85c661975c45b300cb96930d89370a327c98b67defaa89497aa8ef994c77f1130f752f94a4"),
new SignTestVector(
"b58f5211dff440626bb56d0ad483193d606cf21f36d9830543327292f4d25d8c",
"68229b48c2fe19d3db034e4c15077eb7471a66031f28a980821873915298ba76303e8ee3742a893f78b810991da697083dd8f11128c47651c27a56740a80c24c",
"c5204b81ec0a4df5b7e9fda3dc245f98082ae7f4efe81998dcaa286bd4507ca840a53d21b01e904f55e38f78c3757d5a5a4a44b1d5d4e480be3afb5b394a5d2840af42b1b4083d40afbfe22d702f370d32dbfd392e128ea4724d66a3701da41ae2f03bb4d91bb946c7969404cb544f71eb7a49eb4c4ec55799bda1eb545143a7"),
new SignTestVector(
"54c066711cdb061eda07e5275f7e95a9962c6764b84f6f1f3ab5a588e0a2afb1",
"0a7dbb8bf50cb605eb2268b081f26d6b08e012f952c4b70a5a1e6e7d46af98bbf26dd7d799930062480849962ccf5004edcfd307c044f4e8f667c9baa834eeae",
"72e81fe221fb402148d8b7ab03549f1180bcc03d41ca59d7653801f0ba853add1f6d29edd7f9abc621b2d548f8dbf8979bd16608d2d8fc3260b4ebc0dd42482481d548c7075711b5759649c41f439fad69954956c9326841ea6492956829f9e0dc789f73633b40f6ac77bcae6dfc7930cfe89e526d1684365c5b0be2437fdb01"),
new SignTestVector(
"34fa4682bf6cb5b16783adcd18f0e6879b92185f76d7c920409f904f522db4b1",
"105d22d9c626520faca13e7ced382dcbe93498315f00cc0ac39c4821d0d737376c47f3cbbfa97dfcebe16270b8c7d5d3a5900b888c42520d751e8faf3b401ef4",
"21188c3edd5de088dacc1076b9e1bcecd79de1003c2414c3866173054dc82dde85169baa77993adb20c269f60a5226111828578bcc7c29e6e8d2dae81806152c8ba0c6ada1986a1983ebeec1473a73a04795b6319d48662d40881c1723a706f516fe75300f92408aa1dc6ae4288d2046f23c1aa2e54b7fb6448a0da922bd7f34"));
protected SECP256R1 secp256R1;
protected static String suiteStartTime = null;
@ -44,6 +108,8 @@ public class SECP256R1Test {
LocalDateTime.now(ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss"));
suiteName(SECP256R1Test.class);
SignatureAlgorithmFactory.setInstance(SignatureAlgorithmType.create("secp256r1"));
}
@Before
@ -77,17 +143,19 @@ public class SECP256R1Test {
@Test
public void signatureGenerationAndVerification() {
final SECPPrivateKey privateKey =
secp256R1.createPrivateKey(
new BigInteger("a7e8b16ad7ffa26fce80be2b0e00008018aadf1b16dea4ecc913b8c1c4f18531", 16));
final KeyPair keyPair = secp256R1.createKeyPair(privateKey);
final Bytes data = Bytes.wrap("This is an example of a signed message.".getBytes(UTF_8));
final Bytes32 dataHash = keccak256(data);
final SECPSignature signature = secp256R1.sign(dataHash, keyPair);
assertThat(secp256R1.verify(data, signature, keyPair.getPublicKey(), Hash::keccak256)).isTrue();
signTestVectors.forEach(
signTestVector -> {
final SECPPrivateKey privateKey =
secp256R1.createPrivateKey(new BigInteger(signTestVector.getPrivateKey(), 16));
final SECPPublicKey publicKey =
secp256R1.createPublicKey(new BigInteger(signTestVector.getPublicKey(), 16));
final KeyPair keyPair = secp256R1.createKeyPair(privateKey);
final Bytes32 dataHash = keccak256(Bytes.wrap(signTestVector.getData().getBytes(UTF_8)));
final SECPSignature signature = secp256R1.sign(dataHash, keyPair);
assertThat(secp256R1.verify(dataHash, signature, publicKey)).isTrue();
});
}
@Test(expected = IllegalArgumentException.class)
@ -105,4 +173,28 @@ public class SECP256R1Test {
Files.write(tempFile.toPath(), "not\n\nvalid".getBytes(UTF_8));
KeyPairUtil.load(tempFile);
}
private static class SignTestVector {
private final String privateKey;
private final String publicKey;
private final String data;
public SignTestVector(final String privateKey, final String publicKey, final String data) {
this.privateKey = privateKey;
this.publicKey = publicKey;
this.data = data;
}
public String getPrivateKey() {
return privateKey;
}
public String getPublicKey() {
return publicKey;
}
public String getData() {
return data;
}
}
}

@ -16,10 +16,16 @@ package org.hyperledger.besu.crypto;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import org.junit.Before;
import org.junit.Test;
public class SignatureAlgorithmFactoryTest {
@Before
public void setUp() {
SignatureAlgorithmFactory.resetInstance();
}
@Test
public void shouldReturnSECP256K1InstanceByDefault() {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();

@ -127,7 +127,8 @@ dependencyManagement {
dependency 'org.fusesource.jansi:jansi:2.3.4'
dependency 'org.hyperledger.besu:bls12-381:0.3.0'
dependency 'org.hyperledger.besu:secp256k1:0.3.0'
dependency 'org.hyperledger.besu:secp256k1:0.4.1'
dependency 'org.hyperledger.besu:secp256r1:0.4.1'
dependency 'org.immutables:value-annotations:2.8.8'
dependency 'org.immutables:value:2.8.8'

Loading…
Cancel
Save