Class MerkleTree
A Merkle tree provides a compact cryptographic commitment to an ordered set of transactions. Given only the 32-byte root, any third party can verify that a specific transaction is included in the set without downloading all transactions (FR-CRYPTO-06, FR-CRYPTO-07).
Hash function
Each node storesSHA-256(left || right) (concatenation of lowercase
hex strings). Leaf nodes store SHA-256(txId). This is consistent with
the convention used in Bitcoin.
Odd-node handling
When a level has an odd number of nodes, the last node is duplicated (Bitcoin / BIP-34 convention) to form a complete binary tree.Usage
List<String> txIds = block.getTransactions()
.stream()
.map(tx -> tx.getId().toString())
.collect(Collectors.toList());
String root = MerkleTree.buildRoot(txIds);
MerkleProof p = MerkleTree.getProof(txIds, targetTxId);
boolean ok = MerkleTree.verifyProof(p, root, targetTxId);
- Since:
- 1.0.0
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classImmutable Merkle inclusion proof for a single transaction. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringCanonical root returned when the transaction list is empty. -
Method Summary
Modifier and TypeMethodDescriptionstatic StringBuilds the Merkle root of an ordered list of transaction IDs.static MerkleTree.MerkleProofGenerates a Merkle inclusion proof for the given transaction ID.static booleanverifyProof(MerkleTree.MerkleProof proof, String expectedRoot, String txId) Verifies that aMerkleTree.MerkleProofestablishes inclusion of a transaction in a block whose Merkle root isexpectedRoot.
-
Field Details
-
EMPTY_ROOT
Canonical root returned when the transaction list is empty. This is the same 64-zero sentinel used for the genesis block's Merkle root.
-
-
Method Details
-
buildRoot
Builds the Merkle root of an ordered list of transaction IDs.Returns
EMPTY_ROOTwhen the list is empty (genesis block behavior). The root changes deterministically if any transaction ID changes or the order changes, providing tamper evidence for the entire transaction set.- Parameters:
txIds- ordered list of transaction ID strings (non-null; may be empty)- Returns:
- 64-character lowercase hex Merkle root
- Throws:
NullPointerException- if txIds is null or any element is nullIllegalArgumentException- if any txId is blank
-
getProof
Generates a Merkle inclusion proof for the given transaction ID.The proof is a list of (sibling hash, position) pairs that, together with the leaf hash of
targetTxId, allow reconstruction of the Merkle root without knowing any other transaction in the block.- Parameters:
txIds- the complete, ordered list of transaction IDs in the block (non-null)targetTxId- the transaction ID for which to generate the proof (non-null, non-blank)- Returns:
- a
MerkleTree.MerkleProofcontaining the sibling path; never null - Throws:
NullPointerException- if txIds or targetTxId is nullIllegalArgumentException- if targetTxId is blank or not found in txIds
-
verifyProof
Verifies that aMerkleTree.MerkleProofestablishes inclusion of a transaction in a block whose Merkle root isexpectedRoot.Only the proof and the expected root are required — no other transaction data is needed. This allows lightweight clients to verify inclusion without downloading the full block.
- Parameters:
proof- the proof returned bygetProof(java.util.List<java.lang.String>, java.lang.String)(non-null)expectedRoot- the Merkle root stored in the block header (non-null, non-blank)txId- the transaction ID whose inclusion is being proven (non-null, non-blank)- Returns:
trueif the proof is valid andtxIdis in the block;falseotherwise- Throws:
NullPointerException- if proof, expectedRoot, or txId is nullIllegalArgumentException- if expectedRoot or txId is blank
-