From 465d7f24c63fc24deefbf23a8d5622690341b4b1 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 23 Aug 2022 11:57:56 +0200 Subject: [PATCH] Use Blake2bf native implementation if available by default (#4264) Signed-off-by: Fabio Di Fabio Co-authored-by: Antoine Toulme --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 9 ++ .../unstable/NativeLibraryOptions.java | 13 +++ crypto/build.gradle | 1 + .../besu/crypto/Blake2bfMessageDigest.java | 85 ++++++++++--------- .../crypto/Blake2bfMessageDigestTest.java | 28 +++++- .../besu/crypto/eip152TestCases.csv | 6 ++ gradle/versions.gradle | 7 +- 8 files changed, 105 insertions(+), 45 deletions(-) create mode 100644 crypto/src/test/resources/org/hyperledger/besu/crypto/eip152TestCases.csv diff --git a/CHANGELOG.md b/CHANGELOG.md index 18127f5c3f4..52e4bce8f35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 22.7.2 ### Additions and Improvements +- Upgrade besu-native to 0.6.0 and use Blake2bf native implementation if available by default [#4264](https://github.com/hyperledger/besu/pull/4264) ### Bug Fixes diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index d1ec8d28b15..d5fc6fe06ef 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -92,6 +92,7 @@ import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfigurationProvider; import org.hyperledger.besu.controller.BesuController; import org.hyperledger.besu.controller.BesuControllerBuilder; +import org.hyperledger.besu.crypto.Blake2bfMessageDigest; import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.KeyPairSecurityModule; import org.hyperledger.besu.crypto.KeyPairUtil; @@ -1718,6 +1719,14 @@ private void configureNativeLibs() { SignatureAlgorithmFactory.getInstance().disableNative(); logger.info("Using the Java implementation of the signature algorithm"); } + + if (unstableNativeLibraryOptions.getNativeBlake2bf() + && Blake2bfMessageDigest.Blake2bfDigest.isNative()) { + logger.info("Using the native implementation of the blake2bf algorithm"); + } else { + Blake2bfMessageDigest.Blake2bfDigest.disableNative(); + logger.info("Using the Java implementation of the blake2bf algorithm"); + } } private void validateOptions() { diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NativeLibraryOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NativeLibraryOptions.java index a016e777698..776a582ca8b 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NativeLibraryOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NativeLibraryOptions.java @@ -36,6 +36,15 @@ public class NativeLibraryOptions { arity = "1") private final Boolean nativeAltbn128 = Boolean.TRUE; + @CommandLine.Option( + hidden = true, + names = {"--Xblake2bf-native-enabled"}, + description = + "Per default a native library is used for blake2bf if present. " + + "If the Java implementation should be used instead, this option must be set to false", + arity = "1") + private final Boolean nativeBlake2bf = Boolean.TRUE; + public static NativeLibraryOptions create() { return new NativeLibraryOptions(); } @@ -47,4 +56,8 @@ public Boolean getNativeSecp() { public Boolean getNativeAltbn128() { return nativeAltbn128; } + + public Boolean getNativeBlake2bf() { + return nativeBlake2bf; + } } diff --git a/crypto/build.gradle b/crypto/build.gradle index 0374108eec5..5eac9e6d3de 100644 --- a/crypto/build.gradle +++ b/crypto/build.gradle @@ -38,6 +38,7 @@ dependencies { implementation 'org.apache.tuweni:tuweni-units' implementation 'org.hyperledger.besu:secp256k1' implementation 'org.hyperledger.besu:secp256r1' + implementation 'org.hyperledger.besu:blake2bf' testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' diff --git a/crypto/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java b/crypto/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java index 7b472ac9cf6..00901696206 100644 --- a/crypto/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java +++ b/crypto/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java @@ -16,12 +16,17 @@ import static java.util.Arrays.copyOfRange; +import org.hyperledger.besu.nativelib.blake2bf.LibBlake2bf; + import org.bouncycastle.crypto.Digest; import org.bouncycastle.jcajce.provider.digest.BCMessageDigest; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable { + private static final Logger LOG = LoggerFactory.getLogger(Blake2bfMessageDigest.class); public Blake2bfMessageDigest() { super(new Blake2bfDigest()); @@ -37,7 +42,6 @@ public Blake2bfMessageDigest() { *

Optimized for 64-bit platforms */ public static class Blake2bfDigest implements Digest { - public static final int MESSAGE_LENGTH_BYTES = 213; private static final long[] IV = { @@ -76,8 +80,13 @@ public static class Blake2bfDigest implements Digest { private long rounds; // unsigned integer represented as long private final long[] v; + private static boolean useNative = LibBlake2bf.ENABLED; Blake2bfDigest() { + if (!useNative) { + LOG.info("Native blake2bf not available"); + } + buffer = new byte[MESSAGE_LENGTH_BYTES]; bufferPos = 0; @@ -90,20 +99,12 @@ public static class Blake2bfDigest implements Digest { v = new long[16]; } - // for tests - Blake2bfDigest( - final long[] h, final long[] m, final long[] t, final boolean f, final long rounds) { - assert rounds <= 4294967295L; // uint max value - buffer = new byte[MESSAGE_LENGTH_BYTES]; - bufferPos = 0; - - this.h = h; - this.m = m; - this.t = t; - this.f = f; - this.rounds = rounds; + public static void disableNative() { + useNative = false; + } - v = new long[16]; + public static boolean isNative() { + return useNative; } @Override @@ -123,16 +124,10 @@ public int getDigestSize() { */ @Override public void update(final byte in) { - - if (bufferPos == MESSAGE_LENGTH_BYTES) { // full buffer - throw new IllegalArgumentException(); - } else { - buffer[bufferPos] = in; - bufferPos++; - if (bufferPos == MESSAGE_LENGTH_BYTES) { - initialize(); - } - } + checkSize(1); + buffer[bufferPos] = in; + bufferPos++; + maybeInitialize(); } /** @@ -148,6 +143,15 @@ public void update(final byte[] in, final int offset, final int len) { return; } + checkSize(len); + + System.arraycopy(in, offset, buffer, bufferPos, len); + bufferPos += len; + + maybeInitialize(); + } + + private void checkSize(final int len) { if (len > MESSAGE_LENGTH_BYTES - bufferPos) { throw new IllegalArgumentException( "Attempting to update buffer with " @@ -156,12 +160,10 @@ public void update(final byte[] in, final int offset, final int len) { + (MESSAGE_LENGTH_BYTES - bufferPos) + " byte(s) left to fill"); } + } - System.arraycopy(in, offset, buffer, bufferPos, len); - - bufferPos += len; - - if (bufferPos == MESSAGE_LENGTH_BYTES) { + private void maybeInitialize() { + if (!useNative && bufferPos == MESSAGE_LENGTH_BYTES) { initialize(); } } @@ -178,10 +180,13 @@ public int doFinal(final byte[] out, final int offset) { throw new IllegalStateException("The buffer must be filled with 213 bytes"); } - compress(); - - for (int i = 0; i < h.length; i++) { - System.arraycopy(Pack.longToLittleEndian(h[i]), 0, out, i * 8, 8); + if (useNative) { + LibBlake2bf.blake2bf_eip152(out, buffer); + } else { + compress(); + for (int i = 0; i < h.length; i++) { + System.arraycopy(Pack.longToLittleEndian(h[i]), 0, out, i * 8, 8); + } } reset(); @@ -194,12 +199,14 @@ public int doFinal(final byte[] out, final int offset) { public void reset() { bufferPos = 0; Arrays.fill(buffer, (byte) 0); - Arrays.fill(h, 0); - Arrays.fill(m, (byte) 0); - Arrays.fill(t, 0); - f = false; - rounds = 12; - Arrays.fill(v, 0); + if (!useNative) { + Arrays.fill(h, 0); + Arrays.fill(m, (byte) 0); + Arrays.fill(t, 0); + f = false; + rounds = 12; + Arrays.fill(v, 0); + } } private void initialize() { diff --git a/crypto/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java b/crypto/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java index deb4de81f3a..bd00dc7dae1 100644 --- a/crypto/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java +++ b/crypto/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java @@ -18,8 +18,10 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.bouncycastle.util.Pack; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvFileSource; /** * Test vectors adapted from @@ -47,7 +49,7 @@ public class Blake2bfMessageDigestTest { -61, 120, -93, -42, -38 }; - @Before + @BeforeEach public void setUp() { messageDigest = new Blake2bfMessageDigest(); } @@ -121,4 +123,24 @@ public void throwsIfEmptyBufferUpdatedLargeByteArray() { }) .isInstanceOf(IllegalArgumentException.class); } + + @ParameterizedTest + @CsvFileSource(resources = "eip152TestCases.csv", numLinesToSkip = 1) + public void eip152TestCases(final String hexIn, final String hexExpected) { + System.out.println("in=" + hexIn); + byte[] in = hexStringToByteArray(hexIn); + byte[] expected = hexStringToByteArray(hexExpected); + messageDigest.update(in, 0, 213); + assertThat(messageDigest.digest()).isEqualTo(expected); + } + + private static byte[] hexStringToByteArray(final String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = + (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } } diff --git a/crypto/src/test/resources/org/hyperledger/besu/crypto/eip152TestCases.csv b/crypto/src/test/resources/org/hyperledger/besu/crypto/eip152TestCases.csv new file mode 100644 index 00000000000..3591d53af8f --- /dev/null +++ b/crypto/src/test/resources/org/hyperledger/besu/crypto/eip152TestCases.csv @@ -0,0 +1,6 @@ +input,expected +0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001,08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b +0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001,ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923 +0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000,75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735 +0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001,b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421 +ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001,fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615 \ No newline at end of file diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 5232957ab25..86ae9871d73 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -147,9 +147,10 @@ dependencyManagement { dependency 'org.fusesource.jansi:jansi:2.4.0' - dependency 'org.hyperledger.besu:bls12-381:0.5.0' - dependency 'org.hyperledger.besu:secp256k1:0.5.0' - dependency 'org.hyperledger.besu:secp256r1:0.5.0' + dependency 'org.hyperledger.besu:bls12-381:0.6.0' + dependency 'org.hyperledger.besu:secp256k1:0.6.0' + dependency 'org.hyperledger.besu:secp256r1:0.6.0' + dependency 'org.hyperledger.besu:blake2bf:0.6.0' dependency 'org.immutables:value-annotations:2.9.0' dependency 'org.immutables:value:2.9.0'