Skip to content

Commit cecac05

Browse files
State Proof Builder and Verifier Utilities
Signed-off-by: Edward Wertz <[email protected]>
1 parent 9d91890 commit cecac05

File tree

13 files changed

+1922
-13
lines changed

13 files changed

+1922
-13
lines changed

hedera-node/hapi-utils/build.gradle.kts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,23 @@ plugins { id("org.hiero.gradle.module.library") }
33

44
description = "Hedera Services API Utilities"
55

6+
dependencies {
7+
testImplementation(testFixtures(project(":swirlds-state-impl")))
8+
testImplementation(testFixtures(project(":swirlds-state-api")))
9+
testImplementation(testFixtures(project(":swirlds-merkledb")))
10+
testImplementation(project(":hapi"))
11+
}
12+
613
mainModuleInfo { annotationProcessor("dagger.compiler") }
714

815
testModuleInfo {
916
requires("org.junit.jupiter.api")
1017
requires("org.junit.jupiter.params")
1118
requires("org.mockito")
1219
requires("org.assertj.core")
20+
requires("com.hedera.node.hapi")
21+
requires("com.swirlds.state.impl.test.fixtures")
22+
requires("com.swirlds.state.api.test.fixtures")
23+
requires("com.swirlds.merkledb.test.fixtures")
24+
requires("com.swirlds.virtualmap")
1325
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
package com.hedera.node.app.hapi.utils.blocks;
3+
4+
import static java.util.Objects.requireNonNull;
5+
6+
import com.hedera.hapi.node.state.blockstream.MerkleLeaf;
7+
import java.security.MessageDigest;
8+
import java.security.NoSuchAlgorithmException;
9+
10+
/**
11+
* Shared hashing helpers for Merkle path construction and verification.
12+
*
13+
* <p>This utility class provides methods for computing cryptographic hashes used in Merkle trees,
14+
* with domain separation prefixes to prevent collision attacks between different node types:
15+
* <ul>
16+
* <li>Leaf nodes: prefixed with 0x00</li>
17+
* <li>Single-child (internal) nodes: prefixed with 0x01</li>
18+
* <li>Two-child (internal) nodes: prefixed with 0x02</li>
19+
* </ul>
20+
*
21+
* <p>All hashing uses SHA-384 for security and consistency with the broader Hedera ecosystem.
22+
*/
23+
final class HashUtils {
24+
25+
private static final String HASH_ALGORITHM = "SHA-384";
26+
static final int HASH_SIZE_BYTES = 48;
27+
28+
private HashUtils() {
29+
throw new UnsupportedOperationException("Utility class");
30+
}
31+
32+
static MessageDigest newMessageDigest() {
33+
try {
34+
return MessageDigest.getInstance(HASH_ALGORITHM);
35+
} catch (NoSuchAlgorithmException e) {
36+
throw new RuntimeException(HASH_ALGORITHM + " algorithm not found", e);
37+
}
38+
}
39+
40+
static byte[] computeLeafHash(final MessageDigest digest, final MerkleLeaf leaf) {
41+
requireNonNull(digest, "digest must not be null");
42+
requireNonNull(leaf, "leaf must not be null");
43+
digest.reset();
44+
digest.update((byte) 0x00);
45+
digest.update(MerkleLeaf.PROTOBUF.toBytes(leaf).toByteArray());
46+
return digest.digest();
47+
}
48+
49+
static byte[] computeSingleChildHash(final MessageDigest digest, final byte[] childHash) {
50+
requireNonNull(digest, "digest must not be null");
51+
requireNonNull(childHash, "childHash must not be null");
52+
digest.reset();
53+
digest.update((byte) 0x01);
54+
digest.update(childHash);
55+
return digest.digest();
56+
}
57+
58+
static byte[] joinHashes(final MessageDigest digest, final byte[] left, final byte[] right) {
59+
requireNonNull(digest, "digest must not be null");
60+
requireNonNull(left, "left must not be null");
61+
requireNonNull(right, "right must not be null");
62+
digest.reset();
63+
digest.update((byte) 0x02);
64+
digest.update(left);
65+
digest.update(right);
66+
return digest.digest();
67+
}
68+
}

0 commit comments

Comments
 (0)