diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 01b610238..b2ab6fb6c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -25,6 +25,7 @@ env:
LC_ALL: C.UTF-8
GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }}
GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }}
+ CG_EXEC: ionice -c 2 -n 2 nice -n 19
jobs:
build:
@@ -38,6 +39,13 @@ jobs:
- name: Checkout Code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ fetch-depth: "0"
+
+ - name: Setup NodeJS
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
+ with:
+ node-version: 18
- name: Setup Java
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
@@ -51,8 +59,91 @@ jobs:
cache-read-only: false
- name: Build SDK & Javadoc
+ id: gradle-build
run: ./gradlew assemble
+ - name: Setup Snyk
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
+ if: >-
+ ${{
+ steps.gradle-build.conclusion == 'success' &&
+ (
+ github.event.pull_request.head.repo.full_name == github.repository ||
+ github.event_name == 'push'
+ ) &&
+ !cancelled()
+ }}
+ run: ${CG_EXEC} npm install -g snyk snyk-to-html @wcj/html-to-markdown-cli
+
+ - name: Snyk Scan
+ id: snyk
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
+ if: >-
+ ${{
+ steps.gradle-build.conclusion == 'success' &&
+ (
+ github.event.pull_request.head.repo.full_name == github.repository ||
+ github.event_name == 'push'
+ ) &&
+ !cancelled()
+ }}
+ run: ${CG_EXEC} snyk test --all-projects --severity-threshold=high --policy-path=.snyk --json-file-output=snyk-test.json --org=hiero-client-sdks
+
+ - name: Snyk Code
+ id: snyk-code
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
+ if: >-
+ ${{
+ steps.gradle-build.conclusion == 'success' &&
+ (
+ github.event.pull_request.head.repo.full_name == github.repository ||
+ github.event_name == 'push'
+ ) &&
+ !cancelled()
+ }}
+ run: ${CG_EXEC} snyk code test --severity-threshold=high --json-file-output=snyk-code.json --org=hiero-client-sdks --policy-path=.snyk
+
+ - name: Publish Snyk Results
+ if: >-
+ ${{
+ steps.gradle-build.conclusion == 'success' &&
+ (
+ github.event.pull_request.head.repo.full_name == github.repository ||
+ github.event_name == 'push'
+ ) &&
+ !cancelled()
+ }}
+ run: |
+ if [[ -f "snyk-test.json" && -n "$(cat snyk-test.json | tr -d '[:space:]')" ]]; then
+ snyk-to-html -i snyk-test.json -o snyk-test.html --summary
+ html-to-markdown snyk-test.html -o snyk
+ cat snyk/snyk-test.html.md >> $GITHUB_STEP_SUMMARY
+ fi
+
+ if [[ -f "snyk-code.json" && -n "$(cat snyk-code.json | tr -d '[:space:]')" ]]; then
+ snyk-to-html -i snyk-code.json -o snyk-code.html --summary
+ html-to-markdown snyk-code.html -o snyk
+ cat snyk/snyk-code.html.md >> $GITHUB_STEP_SUMMARY
+ fi
+
+ - name: Check Snyk Files
+ if: ${{ always() }}
+ run: |
+ echo "::group::Snyk File List"
+ ls -lah snyk* || true
+ echo "::endgroup::"
+
+ echo "::group::Snyk Test Contents"
+ cat snyk-test.json || true
+ echo "::endgroup::"
+
+ echo "::group::Snyk Code Contents"
+ cat snyk-code.json || true
+ echo "::endgroup::"
+
test:
name: Unit and Integration Tests
runs-on: hiero-client-sdk-linux-medium
diff --git a/.github/workflows/snyk-monitor.yml b/.github/workflows/snyk-monitor.yml
new file mode 100644
index 000000000..7a2f41ff6
--- /dev/null
+++ b/.github/workflows/snyk-monitor.yml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: Apache-2.0
+name: "Snyk Monitor"
+
+on:
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ security-events: write
+
+jobs:
+ snyk:
+ name: Snyk Monitor
+ runs-on: hiero-client-sdk-linux-medium
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
+ with:
+ egress-policy: audit
+
+ - name: Checkout
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+ - name: Setup Java
+ uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
+ with:
+ distribution: temurin
+ java-version: "17.0.13"
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
+ with:
+ gradle-version: wrapper
+
+ - name: Disable Gradle Configuration Cache
+ run: sed -i 's/^org.gradle.configuration-cache=.*$/org.gradle.configuration-cache=false/' gradle.properties
+
+ - name: Compile
+ run: ./gradlew assemble
+
+ - name: Setup NodeJS
+ uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
+ with:
+ node-version: 18
+
+ - name: Setup Snyk
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
+ run: npm install -g snyk
+
+ - name: Run Snyk Monitor
+ continue-on-error: true
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
+ run: snyk monitor --all-projects --policy-path=.snyk --trust-policies
diff --git a/.gitignore b/.gitignore
index 22fa8f6f0..b292fe90f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,6 @@ gradle.properties
.DS_Store
/examples/address-book.proto.bin
local.properties
+
+.dccache
+snyk-test.json
\ No newline at end of file
diff --git a/.snyk b/.snyk
new file mode 100644
index 000000000..afed15d29
--- /dev/null
+++ b/.snyk
@@ -0,0 +1,16 @@
+# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
+version: v1.25.0
+# ignores vulnerabilities until expiry date; change duration by modifying expiry date
+ignore:
+ SNYK-JAVA-NETMINIDEV-8689573:
+ - '*':
+ reason: No net-minidev version with a fix is available
+ expires: 2025-06-30T00:00:00.000Z
+ created: 2025-02-12T14:49:55Z
+patch: {}
+exclude:
+ global:
+ - >-
+ sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java
+ - >-
+ sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java
\ No newline at end of file
diff --git a/examples/settings.gradle.kts b/examples/settings.gradle.kts
index 0780aa45e..cfe4004c2 100644
--- a/examples/settings.gradle.kts
+++ b/examples/settings.gradle.kts
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
-plugins { id("org.hiero.gradle.build") version "0.3.0" }
+plugins { id("org.hiero.gradle.build") version "0.3.4" }
@Suppress("UnstableApiUsage") dependencyResolutionManagement { repositories.mavenCentral() }
diff --git a/hiero-dependency-versions/build.gradle.kts b/hiero-dependency-versions/build.gradle.kts
index 2bba192c7..53769e72d 100644
--- a/hiero-dependency-versions/build.gradle.kts
+++ b/hiero-dependency-versions/build.gradle.kts
@@ -9,11 +9,14 @@ plugins {
group = "org.hiero"
val bouncycastle = "1.80"
-val grpc = "1.69.1"
+val grpc = "1.70.0"
val protobuf = "4.29.3"
val slf4j = "2.0.16"
-dependencies { api(platform("org.springframework.boot:spring-boot-dependencies:3.4.2")) }
+dependencies {
+ api(platform("org.springframework.boot:spring-boot-dependencies:3.4.2"))
+ api(platform("io.netty:netty-bom:4.1.118.Final"))
+}
dependencies.constraints {
api("com.esaulpaugh:headlong:12.3.3") { because("com.esaulpaugh.headlong") }
diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts
index ced6ffc1c..bd93e342b 100644
--- a/sdk/build.gradle.kts
+++ b/sdk/build.gradle.kts
@@ -31,8 +31,6 @@ testModuleInfo {
requires("org.junit.jupiter.params")
requires("org.mockito")
- requiresStatic("java.annotation")
-
runtimeOnly("io.grpc.netty.shaded")
runtimeOnly("org.slf4j.simple")
}
diff --git a/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java b/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java
index 383386475..477e2fa41 100644
--- a/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java
+++ b/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java
@@ -163,6 +163,16 @@ public PrivateKey derive(int index) {
/**
* Create an ECDSA key from seed.
+ * Implement the published algorithm as defined in BIP32 in order to derive the primary account key from the
+ * original (and never stored) master key.
+ * The original master key, which is a secure key generated according to the BIP39 specification, is input to this
+ * operation, and provides the base cryptographic seed material required to ensure the output is sufficiently random
+ * to maintain strong cryptographic assurances.
+ * The fromSeed() method must be provided with cryptographically secure material; otherwise, it will produce
+ * insecure output.
+ *
+ * @see BIP-32 Definition
+ * @see BIP-39 Definition
*
* @param seed the seed bytes
* @return the new key
@@ -180,6 +190,19 @@ public static PrivateKey fromSeed(byte[] seed) {
/**
* Create a derived key.
+ * The industry standard protocol for deriving an active ECDSA keypair from a BIP39 master key is described in
+ * BIP32. By using this deterministic mechanism to derive cryptographically secure keypairs from a single original
+ * secret, the user maintains secure access to their wallet, even if they lose access to a particular system or
+ * wallet local data store.
+ * The active keypair can always be re-derived from the original master key.
+ * The use of the fixed "key" values in this code is defined by this deterministic protocol, and this data is mixed,
+ * in a deterministic but cryptographically secure manner, with the original master key and/or other derived keys
+ * "higher" in the tree to produce a cryptographically secure derived key.
+ * This "Key Derivation Function" makes use of secure hash algorithm and a secure hash based message authentication
+ * code to produce an initialization vector, and then produces the actual key from a portion of that vector.
+ *
+ * @see BIP-32 Definition
+ * @see BIP-39 Definition
*
* @param deriveData data to derive the key
* @return the new key
diff --git a/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java b/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java
index 7a5544818..30c490a8a 100644
--- a/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java
+++ b/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java
@@ -69,12 +69,23 @@ static PrivateKeyED25519 fromPrivateKeyInfoInternal(PrivateKeyInfo privateKeyInf
/**
* Create an ED25519 key from seed.
+ * Implement the published algorithm as defined in BIP32 in order to derive the primary account key from the
+ * original (and never stored) master key.
+ * The original master key, which is a secure key generated according to the BIP39 specification, is input to this
+ * operation, and provides the base cryptographic seed material required to ensure the output is sufficiently random
+ * to maintain strong cryptographic assurances.
+ * The fromSeed() method must be provided with cryptographically secure material; otherwise, it will produce
+ * insecure output.
+ *
+ * @see BIP-32 Definition
+ * @see BIP-39 Definition
*
* @param seed the seed bytes
* @return the new key
*/
public static PrivateKey fromSeed(byte[] seed) {
var hmacSha512 = new HMac(new SHA512Digest());
+
hmacSha512.init(new KeyParameter("ed25519 seed".getBytes(StandardCharsets.UTF_8)));
hmacSha512.update(seed, 0, seed.length);
@@ -86,6 +97,20 @@ public static PrivateKey fromSeed(byte[] seed) {
/**
* Create a derived key.
+ * The industry standard protocol for deriving an active ed25519 keypair from a BIP39 master key is described in
+ * BIP32. By using this deterministic mechanism to derive cryptographically secure keypairs from a single original
+ * secret, the user maintains secure access to their wallet, even if they lose access to a particular system or
+ * wallet local data store.
+ * The active keypair can always be re-derived from the original master key.
+ * The use of the fixed "key" values in this code is defined by this deterministic protocol, and this data is mixed,
+ * in a deterministic but cryptographically secure manner, with the original master key and/or other derived keys
+ * "higher" in the tree to produce a cryptographically secure derived key.
+ * This "Key Derivation Function" makes use of secure hash algorithm and a secure hash
+ * based message authentication code to produce an initialization vector, and then
+ * produces the actual key from a portion of that vector.
+ *
+ * @see BIP-32 Definition
+ * @see BIP-39 Definition
*
* @param deriveData data to derive the key
* @return the new key
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 6cbbcdcb3..0523c1d0f 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
-plugins { id("org.hiero.gradle.build") version "0.3.1" }
+plugins { id("org.hiero.gradle.build") version "0.3.4" }
rootProject.name = "hedera-sdk-java"