diff --git a/CHANGELOG.md b/CHANGELOG.md index 68ab6412b4..1d92ac6c38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. The changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## next +- add BLAKE2b-256 hashing support ## [0.6.102] - 01-Apr-2025 diff --git a/core/README.md b/core/README.md index e0b47c7d85..2a9907a545 100644 --- a/core/README.md +++ b/core/README.md @@ -2,7 +2,8 @@ [![Build Status](https://travis-ci.org/NemProject/nem.core.svg?branch=dev)](https://travis-ci.org/NemProject/nem.core) -This Java package provides the cryptographic and serialization base methods used by [NEM](https://nemproject.github.io/nem-docs) nodes. To deploy a complete node please examine the [build script](../infra/docker). +This Java package provides the cryptographic and serialization base methods used by [NEM](https://nemproject.github.io/nem-docs) nodes. To deploy a complete node please examine the [build script](../infra/docker). +It now includes support for the modern BLAKE2b-256 hashing algorithm. ## Package Organization diff --git a/core/src/main/java/org/nem/core/crypto/Hashes.java b/core/src/main/java/org/nem/core/crypto/Hashes.java index c31bcc81ee..0879085526 100644 --- a/core/src/main/java/org/nem/core/crypto/Hashes.java +++ b/core/src/main/java/org/nem/core/crypto/Hashes.java @@ -42,9 +42,20 @@ public static byte[] sha3_512(final byte[]... inputs) { * @return The hash of the concatenated inputs. * @throws CryptoException if the hash operation failed. */ - public static byte[] ripemd160(final byte[]... inputs) { - return hash("RIPEMD160", inputs); - } + public static byte[] ripemd160(final byte[]... inputs) { + return hash("RIPEMD160", inputs); + } + + /** + * Performs a BLAKE2b-256 hash of the concatenated inputs. + * + * @param inputs The byte arrays to concatenate and hash. + * @return The hash of the concatenated inputs. + * @throws CryptoException if the hash operation failed. + */ + public static byte[] blake2b_256(final byte[]... inputs) { + return hash("BLAKE2B-256", inputs); + } private static byte[] hash(final String algorithm, final byte[]... inputs) { return ExceptionUtils.propagate(() -> { diff --git a/core/src/test/java/org/nem/core/crypto/HashesTest.java b/core/src/test/java/org/nem/core/crypto/HashesTest.java index a1ffbf4d4e..8fe42c36e2 100644 --- a/core/src/test/java/org/nem/core/crypto/HashesTest.java +++ b/core/src/test/java/org/nem/core/crypto/HashesTest.java @@ -10,7 +10,8 @@ public class HashesTest { private static final HashTester SHA3_256_TESTER = new HashTester(Hashes::sha3_256, 32); private static final HashTester SHA3_512_TESTER = new HashTester(Hashes::sha3_512, 64); - private static final HashTester RIPEMD160_TESTER = new HashTester(Hashes::ripemd160, 20); + private static final HashTester RIPEMD160_TESTER = new HashTester(Hashes::ripemd160, 20); + private static final HashTester BLAKE2B_256_TESTER = new HashTester(Hashes::blake2b_256, 32); // region sha3_256 @@ -89,12 +90,40 @@ public void ripemd160GeneratesSameHashForSameMergedInputs() { } @Test - public void ripemd160GeneratesDifferentHashForDifferentInputs() { - // Assert: - RIPEMD160_TESTER.assertHashIsDifferentForDifferentInputs(); - } + public void ripemd160GeneratesDifferentHashForDifferentInputs() { + // Assert: + RIPEMD160_TESTER.assertHashIsDifferentForDifferentInputs(); + } - // endregion + // endregion + + // region blake2b_256 + + @Test + public void blake2b_256HashHasExpectedByteLength() { + // Assert: + BLAKE2B_256_TESTER.assertHashHasExpectedLength(); + } + + @Test + public void blake2b_256GeneratesSameHashForSameInputs() { + // Assert: + BLAKE2B_256_TESTER.assertHashIsSameForSameInputs(); + } + + @Test + public void blake2b_256GeneratesSameHashForSameMergedInputs() { + // Assert: + BLAKE2B_256_TESTER.assertHashIsSameForSplitInputs(); + } + + @Test + public void blake2b_256GeneratesDifferentHashForDifferentInputs() { + // Assert: + BLAKE2B_256_TESTER.assertHashIsDifferentForDifferentInputs(); + } + + // endregion // region different hash algorithm @@ -110,11 +139,23 @@ public void sha3_256AndSha3_512GenerateDifferentHashForSameInputs() { assertHashesAreDifferent(Hashes::sha3_256, Hashes::sha3_512); } - @Test - public void sha3_512AndRipemd160GenerateDifferentHashForSameInputs() { - // Assert: - assertHashesAreDifferent(Hashes::sha3_512, Hashes::ripemd160); - } + @Test + public void sha3_512AndRipemd160GenerateDifferentHashForSameInputs() { + // Assert: + assertHashesAreDifferent(Hashes::sha3_512, Hashes::ripemd160); + } + + @Test + public void blake2b_256AndSha3_256GenerateDifferentHashForSameInputs() { + // Assert: + assertHashesAreDifferent(Hashes::blake2b_256, Hashes::sha3_256); + } + + @Test + public void blake2b_256AndRipemd160GenerateDifferentHashForSameInputs() { + // Assert: + assertHashesAreDifferent(Hashes::blake2b_256, Hashes::ripemd160); + } private static void assertHashesAreDifferent(final Function hashFunction1, final Function hashFunction2) { diff --git a/init.sh b/init.sh index 7cf7f45a9d..c465adfb74 100755 --- a/init.sh +++ b/init.sh @@ -1,10 +1,41 @@ #!/bin/bash -set -ex +set -euo pipefail -git submodule update --init +# Цветной вывод для информативности +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +echo -e "${GREEN}Инициализация git submodule...${NC}" +git submodule update --init --recursive + +# Проверка наличия директории _symbol +if [[ ! -d "_symbol" ]]; then + echo -e "${RED}Ошибка: директория _symbol не найдена!${NC}" + exit 1 +fi + +echo -e "${GREEN}Включаем sparse checkout для _symbol...${NC}" git -C _symbol config core.sparseCheckout true -echo 'jenkins/*' >> .git/modules/_symbol/info/sparse-checkout -echo 'linters/*' >> .git/modules/_symbol/info/sparse-checkout -echo 'tests/*' >> .git/modules/_symbol/info/sparse-checkout + +SPARSE_FILE=".git/modules/_symbol/info/sparse-checkout" + +# Создаем sparse-checkout файл, если его нет +if [[ ! -f "$SPARSE_FILE" ]]; then + mkdir -p "$(dirname "$SPARSE_FILE")" + touch "$SPARSE_FILE" +fi + +# Добавляем нужные директории, избегая дублирования +for dir in "jenkins/*" "linters/*" "tests/*"; do + if ! grep -qxF "$dir" "$SPARSE_FILE"; then + echo "$dir" >> "$SPARSE_FILE" + echo -e "${GREEN}Добавлено для sparse checkout: $dir${NC}" + fi +done + +echo -e "${GREEN}Применяем sparse checkout...${NC}" git submodule update --force --checkout _symbol + +echo -e "${GREEN}Инициализация завершена успешно!${NC}" diff --git a/nis/src/main/java/org/nem/nis/boot/PeerNetworkScheduler.java b/nis/src/main/java/org/nem/nis/boot/PeerNetworkScheduler.java index b387235227..c165699633 100644 --- a/nis/src/main/java/org/nem/nis/boot/PeerNetworkScheduler.java +++ b/nis/src/main/java/org/nem/nis/boot/PeerNetworkScheduler.java @@ -52,19 +52,31 @@ public class PeerNetworkScheduler implements AutoCloseable { private final TimeProvider timeProvider; private final HarvestingTask harvestingTask; private final List timerVisitors = new ArrayList<>(); - private final List timers = new ArrayList<>(); - private final Executor executor = Executors.newCachedThreadPool(); - - /** - * Creates a new scheduler. - * - * @param timeProvider The time provider. - * @param harvestingTask The harvesting task. - */ - public PeerNetworkScheduler(final TimeProvider timeProvider, final HarvestingTask harvestingTask) { - this.timeProvider = timeProvider; - this.harvestingTask = harvestingTask; - } + private final List timers = new ArrayList<>(); + private final Executor executor; + + /** + * Creates a new scheduler. + * + * @param timeProvider The time provider. + * @param harvestingTask The harvesting task. + */ + public PeerNetworkScheduler(final TimeProvider timeProvider, final HarvestingTask harvestingTask) { + this(timeProvider, harvestingTask, Runtime.getRuntime().availableProcessors()); + } + + /** + * Creates a new scheduler specifying the executor thread count. + * + * @param timeProvider The time provider. + * @param harvestingTask The harvesting task. + * @param threadCount The executor thread count. + */ + public PeerNetworkScheduler(final TimeProvider timeProvider, final HarvestingTask harvestingTask, final int threadCount) { + this.timeProvider = timeProvider; + this.harvestingTask = harvestingTask; + this.executor = Executors.newFixedThreadPool(threadCount); + } /** * Gets all timer visitors.