/** * @fileoverview IncrementalMerkleTree — a frontier-based incremental Merkle tree * built over SHA3-512 entry hashes. * * The tree supports O(log N) appends via a frontier (right-spine hashes) and * maintains the full leaf list for proof generation. All binary data uses * Uint8Array (no Node.js Buffer) for browser compatibility. * * @see Design: Merkle Tree Commitment Layer — IncrementalMerkleTree * @see Requirements 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.1, 2.2, 14.1, 15.1, 15.2 */ import { IConsistencyProof } from '../interfaces/ledger/consistencyProof'; import { IMerkleProof } from '../interfaces/ledger/merkleProof'; import { ChecksumService } from '../services/checksum.service'; import { Checksum } from '../types/checksum'; /** * Incremental Merkle tree using frontier-based O(log N) appends. * * Leaves are the entryHash (SHA3-512, 64 bytes) of each ledger entry. * Internal nodes are SHA3-512(left_child || right_child). * The frontier stores the root hashes of the perfect binary subtrees * that compose the current tree. */ export declare class IncrementalMerkleTree { private readonly checksumService; /** All leaf hashes, in order. */ private leaves; /** Frontier: right-spine hashes for incremental root computation. */ private frontier; /** Cached current root. */ private cachedRoot; /** * Tracked size, independent of leaves.length. * For frontier-only trees (restored via fromFrontier), leaves may be empty * while _size reflects the actual number of leaves the frontier represents. */ private _size; constructor(checksumService: ChecksumService); /** * Current Merkle root. SHA3-512 of empty bytes if tree is empty. * Returns the leaf hash when there is a single leaf. */ get root(): Checksum; /** Number of leaves in the tree. */ get size(): number; /** Current frontier (right-spine hashes). Returns a copy. */ get currentFrontier(): Checksum[]; /** * Append a new leaf hash. Updates frontier and root in O(log N). * * Algorithm (trailing-ones merge): * 1. Push leafHash onto frontier * 2. Increment size * 3. Count trailing 1-bits in binary(size) = mergeCount * 4. For mergeCount iterations: pop right, pop left, push SHA3-512(left || right) * 5. Recompute cachedRoot from frontier */ append(leafHash: Checksum): void; /** * Generate an inclusion proof for the leaf at the given index. * * Uses the RFC 6962 recursive decomposition: split the N leaves into * a left subtree of size k (largest power of 2 < N) and a right subtree * of size N-k. Recurse into whichever subtree contains the target leaf, * recording the sibling subtree's hash at each level. * * This guarantees path length = ceil(log2(N)), or 0 when N = 1. * * @param leafIndex - Zero-based index of the leaf * @returns An IMerkleProof with the authentication path from leaf to root * @throws LedgerError(MerkleProofFailed) if leafIndex is out of range * * @see Requirements 3.1, 3.2, 3.3, 3.4, 14.2 */ getInclusionProof(leafIndex: number): IMerkleProof; /** * Generate a consistency proof between an earlier tree size M and the current * tree size N. * * Follows RFC 6962 Section 2.1.2: SUBPROOF(m, D[0:n], b). * * - M=0 or M=N → empty proof (trivially consistent) * - M > N → throw LedgerError(ConsistencyProofFailed) * - 0 < M < N → return minimal set of intermediate hashes * * @param earlierSize - The earlier tree size M * @returns An IConsistencyProof with the intermediate hashes * @throws LedgerError(ConsistencyProofFailed) if earlierSize > current size * * @see Requirements 5.1, 5.2, 5.3, 5.4, 14.3 */ getConsistencyProof(earlierSize: number): IConsistencyProof; /** * Batch-construct a tree from a list of leaf hashes. * Produces the same root as appending each leaf one at a time. * * @param leaves - Array of leaf hashes (SHA3-512 Checksums) * @param checksumService - ChecksumService for hashing * @returns A fully populated IncrementalMerkleTree * * @see Requirements 2.3, 2.4, 8.2, 14.5 */ static fromLeaves(leaves: Checksum[], checksumService: ChecksumService): IncrementalMerkleTree; /** * Restore a tree from a persisted frontier and size. * Creates a tree that can compute the root and accept further appends, * but cannot generate inclusion or consistency proofs (no leaves stored). * * @param frontier - The persisted frontier (right-spine hashes) * @param size - The number of leaves the frontier represents * @param checksumService - ChecksumService for hashing * @returns An IncrementalMerkleTree with frontier and size set, but no leaves * * @see Requirements 2.3, 2.4, 8.2, 14.5 */ static fromFrontier(frontier: Checksum[], size: number, checksumService: ChecksumService): IncrementalMerkleTree; /** * Compute the Merkle root for a given set of leaves without creating * a full tree instance. Pure function for verification. * * @param leaves - Array of leaf hashes (SHA3-512 Checksums) * @param checksumService - ChecksumService for hashing * @returns The Merkle root Checksum * * @see Requirements 2.3, 2.4, 8.2, 14.5 */ static computeRoot(leaves: Checksum[], checksumService: ChecksumService): Checksum; /** * RFC 6962 Section 2.1.2 SUBPROOF(m, leaves, startFromOldRoot). * * Recursively decomposes the tree to produce the minimal set of hashes * needed to prove consistency between tree sizes m and |leaves|. * * @param m - The earlier tree size within this subtree * @param leaves - The leaves of the current subtree * @param startFromOldRoot - If true, omit the hash when m == |leaves| * (because the verifier can compute it from the earlier root) * @param hashes - Accumulator for the proof hashes */ private buildConsistencyProof; /** * Recursively build the inclusion proof path using RFC 6962 decomposition. * * Split leaves into left (size k = largest power of 2 < n) and right (n-k). * Record the sibling subtree hash and recurse into the subtree containing * the target leaf. */ private buildInclusionPath; /** * Compute the Merkle hash of a subtree given its leaves. * Uses the same RFC 6962 recursive decomposition. */ private computeSubtreeHash; /** * Returns the largest power of 2 that is strictly less than n. * For n=2, returns 1. For n=3, returns 2. For n=5, returns 4. */ private largestPowerOf2LessThan; /** * Compute the root from the frontier by folding right-to-left. * SHA3-512(frontier[i] || result) for i from second-to-last down to 0. */ private computeRootFromFrontier; /** * Hash two child nodes: SHA3-512(left || right). * Concatenates the 64-byte left and right hashes, then hashes the 128-byte result. */ private hashPair; /** * Count the number of trailing 1-bits in the binary representation of n. */ private trailingOnes; /** * Count the number of trailing 0-bits in the binary representation of n. * For n=0, returns 0. */ private trailingZeros; } //# sourceMappingURL=incrementalMerkleTree.d.ts.map