docs: add generated documentation for all Merkle tree implementations

Add detailed README files for MerkleTree, UnifiedBinaryTree, MerkleSumTree,
MerkleRadixTree, MerkleMountainRange, and IncrementalMerkleTree classes
with API docs, examples, and usage patterns.
This commit is contained in:
Miguel Mota
2025-09-15 00:07:20 -07:00
parent a8b06d34af
commit 5770483adf
7 changed files with 2946 additions and 6 deletions

View File

@@ -0,0 +1,572 @@
# IncrementalMerkleTree Class Documentation
A fixed-depth Merkle tree implementation optimized for scenarios where you know the maximum number of leaves in advance. This tree supports efficient insertions, updates, deletions, and proof generation while maintaining a consistent structure, making it ideal for applications like voting systems, membership proofs, and zero-knowledge applications.
## Features
- **Fixed Depth**: Pre-defined tree depth for consistent structure
- **Configurable Arity**: Support for binary and n-ary trees (2, 4, 8, etc. children per node)
- **Zero Value Padding**: Automatic padding with zero values for incomplete levels
- **Efficient Updates**: Update individual leaves without rebuilding the tree
- **Proof Generation**: Generate and verify inclusion proofs for any leaf
- **Deletions**: Remove leaves by setting them to zero values
- **Visual Representation**: Built-in tree visualization for debugging
- **Type Safety**: Full TypeScript support with comprehensive type definitions
## Installation
```bash
npm install merkletreejs
```
## Quick Start
```typescript
import { IncrementalMerkleTree } from 'merkletreejs'
import { poseidon } from 'circomlib' // Common in zero-knowledge applications
// Create a binary tree with depth 4 (max 16 leaves)
const tree = new IncrementalMerkleTree(poseidon, {
depth: 4,
arity: 2,
zeroValue: 0
})
// Insert leaves
tree.insert(1)
tree.insert(2)
tree.insert(3)
// Get root
const root = tree.getHexRoot()
console.log('Tree root:', root)
// Generate proof for leaf at index 1
const proof = tree.getProof(1)
// Verify proof
const isValid = tree.verify(proof)
console.log('Proof valid:', isValid)
// Update a leaf
tree.update(1, 10)
console.log('Updated root:', tree.getHexRoot())
```
## Constructor
### `new IncrementalMerkleTree(hashFunction, options)`
Creates a new incremental Merkle tree instance.
**Parameters:**
- `hashFunction` (Function): Hash function to use for node calculations
- `options` (Options): Configuration options
**Options:**
```typescript
interface Options {
depth?: number // Tree depth (required)
arity?: number // Number of children per node (default: 2)
zeroValue?: any // Value used for empty positions (default: 0)
}
```
**Example:**
```typescript
import { poseidon } from 'circomlib'
// Binary tree (2 children per node)
const binaryTree = new IncrementalMerkleTree(poseidon, {
depth: 3,
arity: 2,
zeroValue: 0
})
// Quaternary tree (4 children per node)
const quaternaryTree = new IncrementalMerkleTree(poseidon, {
depth: 3,
arity: 4,
zeroValue: BigInt(0)
})
```
## Core Methods
### Tree Operations
#### `insert(leaf)`
Inserts a new leaf at the next available position.
**Parameters:**
- `leaf` (any): Value to insert
```typescript
tree.insert(42)
tree.insert('hello')
tree.insert(BigInt(123))
```
#### `update(index, newLeaf)`
Updates the leaf at a specific index.
**Parameters:**
- `index` (number): Index of leaf to update
- `newLeaf` (any): New value for the leaf
```typescript
tree.update(0, 'updated value')
tree.update(2, BigInt(999))
```
#### `delete(index)`
Deletes a leaf by setting it to the zero value.
**Parameters:**
- `index` (number): Index of leaf to delete
```typescript
tree.delete(1) // Sets leaf at index 1 to zeroValue
```
### Tree Information
#### `getRoot()`
Returns the current root hash.
```typescript
const root = tree.getRoot()
```
#### `getHexRoot()`
Returns the current root hash as a hex string.
```typescript
const hexRoot = tree.getHexRoot()
```
#### `getDepth()`
Returns the tree depth.
```typescript
const depth = tree.getDepth()
```
#### `getArity()`
Returns the tree arity (children per node).
```typescript
const arity = tree.getArity()
```
#### `getMaxLeaves()`
Returns the maximum number of leaves the tree can hold.
```typescript
const maxLeaves = tree.getMaxLeaves() // depth^arity
```
#### `getLeaves()`
Returns all leaves, including zero-padded positions.
```typescript
const allLeaves = tree.getLeaves()
```
#### `indexOf(leaf)`
Returns the index of a specific leaf value.
**Parameters:**
- `leaf` (any): Leaf value to find
**Returns:** Index of the leaf, or -1 if not found
```typescript
const index = tree.indexOf(42)
```
### Layer Operations
#### `getLayers()`
Returns all tree layers as a 2D array.
```typescript
const layers = tree.getLayers()
console.log('Number of layers:', layers.length)
```
#### `getHexLayers()`
Returns all tree layers as hex strings.
```typescript
const hexLayers = tree.getHexLayers()
```
#### `getLayersAsObject()`
Returns tree layers as a nested object for visualization.
```typescript
const layersObj = tree.getLayersAsObject()
console.log(JSON.stringify(layersObj, null, 2))
```
### Proof Operations
#### `getProof(index)`
Generates an inclusion proof for a leaf at the given index.
**Parameters:**
- `index` (number): Index of leaf to prove
**Returns:** Proof object with root, leaf, path indices, and siblings
```typescript
const proof = tree.getProof(2)
console.log('Proof:', {
root: proof.root,
leaf: proof.leaf,
pathIndices: proof.pathIndices,
siblings: proof.siblings
})
```
#### `verify(proof)`
Verifies an inclusion proof.
**Parameters:**
- `proof` (object): Proof object from getProof()
**Returns:** boolean - true if proof is valid
```typescript
const isValid = tree.verify(proof)
```
### Utility Methods
#### `toString()`
Returns a visual representation of the tree.
```typescript
console.log(tree.toString())
```
#### `computeRoot()`
Manually recomputes the root hash.
```typescript
const computedRoot = tree.computeRoot()
```
## Examples
### Voting System
```typescript
import { IncrementalMerkleTree } from 'merkletreejs'
import { poseidon } from 'circomlib'
// Create tree for up to 1024 voters (depth 10, binary)
const voterTree = new IncrementalMerkleTree(poseidon, {
depth: 10,
arity: 2,
zeroValue: 0
})
// Register voters with their IDs
const voterIds = [12345, 67890, 11111, 22222, 33333]
voterIds.forEach(id => voterTree.insert(id))
console.log('Voter tree root:', voterTree.getHexRoot())
console.log('Registered voters:', voterIds.length)
// Generate proof for voter 67890 (index 1)
const voterProof = voterTree.getProof(1)
const proofValid = voterTree.verify(voterProof)
console.log('Voter 67890 proof valid:', proofValid)
// Remove a voter (set to 0)
voterTree.delete(2) // Remove voter 11111
console.log('After removing voter:', voterTree.getHexRoot())
```
### Membership System
```typescript
const memberTree = new IncrementalMerkleTree(poseidon, {
depth: 5, // Max 32 members
arity: 2,
zeroValue: BigInt(0)
})
// Add members
const members = [
BigInt(1001), // Alice
BigInt(1002), // Bob
BigInt(1003), // Charlie
BigInt(1004), // Dave
]
members.forEach(member => memberTree.insert(member))
// Prove Alice's membership
const aliceProof = memberTree.getProof(0)
console.log('Alice membership proof:')
console.log(' Root:', aliceProof.root.toString())
console.log(' Leaf:', aliceProof.leaf.toString())
console.log(' Path indices:', aliceProof.pathIndices)
console.log(' Siblings count:', aliceProof.siblings.length)
// Verify proof
const aliceValid = memberTree.verify(aliceProof)
console.log('Alice membership valid:', aliceValid)
```
### Whitelist Management
```typescript
// Whitelist for NFT minting
const whitelist = new IncrementalMerkleTree(poseidon, {
depth: 8, // Max 256 addresses
arity: 2,
zeroValue: 0
})
// Add whitelisted addresses (as numbers for simplicity)
const addresses = [
0x1234567890abcdef,
0xfedcba0987654321,
0x1111222233334444,
0x5555666677778888
]
addresses.forEach(addr => whitelist.insert(addr))
// Generate proof for an address
const addressProof = whitelist.getProof(1)
const addressValid = whitelist.verify(addressProof)
console.log('Address whitelisted:', addressValid)
// Update an address
whitelist.update(1, 0x9999aaaa0000bbbb)
console.log('Updated whitelist root:', whitelist.getHexRoot())
```
### Quaternary Tree Example
```typescript
// 4-ary tree (4 children per node)
const quaternaryTree = new IncrementalMerkleTree(poseidon, {
depth: 3, // Max 4^3 = 64 leaves
arity: 4,
zeroValue: 0
})
// Insert data
for (let i = 1; i <= 10; i++) {
quaternaryTree.insert(i * 10)
}
console.log('Quaternary tree structure:')
console.log('Depth:', quaternaryTree.getDepth())
console.log('Arity:', quaternaryTree.getArity())
console.log('Max leaves:', quaternaryTree.getMaxLeaves())
console.log('Current leaves:', quaternaryTree.getLeaves().filter(leaf => leaf !== 0).length)
// Generate proof
const proof = quaternaryTree.getProof(5)
console.log('Proof for index 5 valid:', quaternaryTree.verify(proof))
```
### Zero-Knowledge Application
```typescript
import { poseidon } from 'circomlib'
// Tree for zero-knowledge proofs
const zkTree = new IncrementalMerkleTree(poseidon, {
depth: 20, // Large tree for many users
arity: 2,
zeroValue: BigInt(0)
})
// Simulate user commitments
const userCommitments = [
BigInt('12345678901234567890'),
BigInt('98765432109876543210'),
BigInt('11111111111111111111'),
BigInt('22222222222222222222')
]
userCommitments.forEach(commitment => zkTree.insert(commitment))
// Generate proof for privacy-preserving verification
const userIndex = 1
const userProof = zkTree.getProof(userIndex)
console.log('ZK Proof components:')
console.log('Root:', userProof.root.toString())
console.log('Leaf:', userProof.leaf.toString())
console.log('Path indices:', userProof.pathIndices)
console.log('Siblings:', userProof.siblings.map(s => s.toString()))
// Verify proof
const zkValid = zkTree.verify(userProof)
console.log('ZK proof valid:', zkValid)
```
### Batch Operations
```typescript
const batchTree = new IncrementalMerkleTree(poseidon, {
depth: 4,
arity: 2,
zeroValue: 0
})
// Batch insert
const batchData = [100, 200, 300, 400, 500]
batchData.forEach(value => batchTree.insert(value))
// Batch update
const updates = [
{ index: 0, value: 150 },
{ index: 2, value: 350 },
{ index: 4, value: 550 }
]
updates.forEach(({ index, value }) => {
batchTree.update(index, value)
})
// Generate proofs for all updated positions
updates.forEach(({ index }) => {
const proof = batchTree.getProof(index)
const valid = batchTree.verify(proof)
console.log(`Proof for index ${index}: ${valid}`)
})
```
### Tree Visualization
```typescript
const visualTree = new IncrementalMerkleTree(poseidon, {
depth: 3,
arity: 2,
zeroValue: 0
})
// Add some data
visualTree.insert(10)
visualTree.insert(20)
visualTree.insert(30)
// Print tree structure
console.log('Tree visualization:')
console.log(visualTree.toString())
// Print layers
const layers = visualTree.getLayers()
layers.forEach((layer, i) => {
console.log(`Layer ${i}:`, layer.map(node => node.toString()))
})
```
## Advanced Features
### Custom Hash Functions
```typescript
import SHA256 from 'crypto-js/sha256'
// Custom hash function for SHA256
const sha256Hash = (inputs) => {
const combined = inputs.join('')
return SHA256(combined).toString()
}
const sha256Tree = new IncrementalMerkleTree(sha256Hash, {
depth: 4,
arity: 2,
zeroValue: '0'
})
sha256Tree.insert('hello')
sha256Tree.insert('world')
```
### Large Trees
```typescript
// Very large tree for scalable applications
const largeTree = new IncrementalMerkleTree(poseidon, {
depth: 32, // Max 2^32 leaves (over 4 billion)
arity: 2,
zeroValue: BigInt(0)
})
// Insert data efficiently
for (let i = 0; i < 1000; i++) {
largeTree.insert(BigInt(i))
}
console.log('Large tree root:', largeTree.getHexRoot())
```
### Tree Comparison
```typescript
// Compare trees before and after operations
const tree1 = new IncrementalMerkleTree(poseidon, {
depth: 3, arity: 2, zeroValue: 0
})
const tree2 = new IncrementalMerkleTree(poseidon, {
depth: 3, arity: 2, zeroValue: 0
})
// Add same data to both trees
[1, 2, 3].forEach(value => {
tree1.insert(value)
tree2.insert(value)
})
console.log('Trees equal:', tree1.getHexRoot() === tree2.getHexRoot())
// Modify one tree
tree1.update(1, 99)
console.log('After update equal:', tree1.getHexRoot() === tree2.getHexRoot())
```
## Performance Considerations
- **Fixed Depth**: All operations are O(depth), providing predictable performance
- **Arity Choice**: Higher arity reduces depth but increases hash computation per node
- **Memory Usage**: Tree stores all nodes, memory usage is O(arity^depth)
- **Zero Padding**: Unused positions are filled with zero values
- **Batch Operations**: Multiple updates can be done before recomputing root
## Security Notes
- **Hash Function**: Use cryptographically secure hash functions for production
- **Zero Values**: Choose zero values that cannot be valid leaf values
- **Index Validation**: Ensure indexes are within valid ranges
- **Proof Verification**: Always verify proofs in critical applications
## Use Cases
- **Voting Systems**: Voter registration and proof of eligibility
- **Membership Proofs**: Whitelist management and access control
- **Zero-Knowledge Proofs**: Privacy-preserving membership proofs
- **Airdrops**: Prove eligibility for token distributions
- **Identity Systems**: Decentralized identity and reputation systems
- **Gaming**: Leaderboards and achievement systems
- **Compliance**: Regulatory reporting with privacy
## Browser Support
Works in both Node.js and browser environments. Ensure you have appropriate hash function implementations for your target environment.
## TypeScript Support
Full TypeScript support with comprehensive type definitions for all methods and data structures. The library provides proper typing for all tree operations and proof structures.

View File

@@ -0,0 +1,558 @@
# MerkleMountainRange Class Documentation
A specialized Merkle tree implementation designed for append-only data structures. Merkle Mountain Range (MMR) is optimized for scenarios where data is continuously added but never modified, making it perfect for blockchain applications, audit logs, and immutable data structures.
## Features
- **Append-Only**: Optimized for adding new data without modifying existing entries
- **Efficient Proofs**: Generate inclusion proofs for any historical data
- **Peak Management**: Maintains multiple tree peaks for efficient operations
- **Blockchain Ready**: Perfect for blockchain and cryptocurrency applications
- **Roll-up Support**: Supports efficient batch updates and roll-ups
- **Immutable History**: Once data is added, it cannot be changed
- **Custom Hash Functions**: Support for various hash functions and peak bagging strategies
- **Type Safety**: Full TypeScript support with comprehensive type definitions
## Installation
```bash
npm install merkletreejs
```
## Quick Start
```typescript
import { MerkleMountainRange } from 'merkletreejs'
import SHA256 from 'crypto-js/sha256'
// Create MMR
const mmr = new MerkleMountainRange(SHA256)
// Append data
mmr.append('transaction 1')
mmr.append('transaction 2')
mmr.append('transaction 3')
mmr.append('transaction 4')
// Get root
const root = mmr.getHexRoot()
console.log('MMR Root:', root)
// Generate proof for transaction 2 (index 2)
const proof = mmr.getMerkleProof(2)
console.log('Proof generated for transaction 2')
// Verify proof
const isValid = mmr.verify(
proof.root,
proof.width,
2, // index
'transaction 2',
proof.peakBagging,
proof.siblings
)
console.log('Proof valid:', isValid)
```
## Constructor
### `new MerkleMountainRange(hashFn?, leaves?, hashLeafFn?, peakBaggingFn?, hashBranchFn?)`
Creates a new Merkle Mountain Range instance.
**Parameters:**
- `hashFn` (Function): Hash function to use (defaults to SHA256)
- `leaves` (any[]): Initial data to append (optional)
- `hashLeafFn` (Function): Custom leaf hashing function (optional)
- `peakBaggingFn` (Function): Custom peak bagging function (optional)
- `hashBranchFn` (Function): Custom branch hashing function (optional)
**Example:**
```typescript
import SHA256 from 'crypto-js/sha256'
// Basic MMR
const mmr = new MerkleMountainRange(SHA256)
// MMR with initial data
const mmrWithData = new MerkleMountainRange(SHA256, ['data1', 'data2', 'data3'])
// MMR with custom functions
const customMMR = new MerkleMountainRange(
SHA256,
[],
(index, dataHash) => customLeafHash(index, dataHash),
(size, peaks) => customPeakBagging(size, peaks),
(index, left, right) => customBranchHash(index, left, right)
)
```
## Properties
- `root` (Buffer): Current root hash of the MMR
- `size` (number): Total number of nodes in the MMR
- `width` (number): Number of leaves in the MMR
- `hashes` (object): Storage for node hashes
- `data` (object): Storage for original data
## Core Methods
### Data Operations
#### `append(data)`
Appends new data to the MMR.
**Parameters:**
- `data` (Buffer | string): Data to append
```typescript
mmr.append('new transaction')
mmr.append(Buffer.from('binary data'))
mmr.append('another entry')
```
#### `getRoot()`
Returns the current root hash as a Buffer.
```typescript
const root = mmr.getRoot()
```
#### `getHexRoot()`
Returns the current root hash as a hex string.
```typescript
const hexRoot = mmr.getHexRoot()
console.log('Root:', hexRoot)
```
#### `getNode(index)`
Returns the hash value of a node at the given index.
**Parameters:**
- `index` (number): Node index (1-based)
```typescript
const nodeHash = mmr.getNode(5)
```
### Peak Operations
#### `getPeaks()`
Returns all current peak hashes.
```typescript
const peaks = mmr.getPeaks()
console.log('Number of peaks:', peaks.length)
```
#### `getPeakIndexes(width)`
Returns the indexes of all peaks for a given width.
**Parameters:**
- `width` (number): Width to calculate peaks for
```typescript
const peakIndexes = mmr.getPeakIndexes(mmr.width)
```
#### `numOfPeaks(width)`
Returns the number of peaks for a given width.
**Parameters:**
- `width` (number): Width to calculate for
```typescript
const numPeaks = mmr.numOfPeaks(mmr.width)
```
### Proof Operations
#### `getMerkleProof(index)`
Generates a Merkle proof for a leaf at the given index.
**Parameters:**
- `index` (number): Leaf index (1-based)
**Returns:** Object with proof components
```typescript
const proof = mmr.getMerkleProof(3)
console.log('Proof:', {
root: proof.root,
width: proof.width,
peakBagging: proof.peakBagging,
siblings: proof.siblings
})
```
#### `verify(root, width, index, value, peaks, siblings)`
Verifies a proof for a specific value.
**Parameters:**
- `root` (Buffer): Root hash to verify against
- `width` (number): Width when proof was generated
- `index` (number): Leaf index
- `value` (Buffer | string): Original value
- `peaks` (Buffer[]): Peak hashes
- `siblings` (Buffer[]): Sibling hashes
**Returns:** boolean - true if proof is valid
```typescript
const isValid = mmr.verify(root, width, index, value, peaks, siblings)
```
### Utility Methods
#### `mountainHeight(size)`
Returns the height of the highest peak.
**Parameters:**
- `size` (number): Size to calculate height for
```typescript
const height = mmr.mountainHeight(mmr.size)
```
#### `heightAt(index)`
Returns the height of a node at the given index.
**Parameters:**
- `index` (number): Node index
```typescript
const height = mmr.heightAt(5)
```
#### `isLeaf(index)`
Checks if a node at the given index is a leaf.
**Parameters:**
- `index` (number): Node index
```typescript
const isLeaf = mmr.isLeaf(3)
```
#### `getChildren(index)`
Returns the children of a parent node.
**Parameters:**
- `index` (number): Parent node index
**Returns:** Array with [left, right] child indexes
```typescript
const [left, right] = mmr.getChildren(parentIndex)
```
### Roll-up Operations
#### `rollUp(root, width, peaks, itemHashes)`
Performs a roll-up operation with new item hashes.
**Parameters:**
- `root` (Buffer): Current root
- `width` (number): Current width
- `peaks` (Buffer[]): Current peaks
- `itemHashes` (Buffer[]): New item hashes to roll up
**Returns:** New root hash after roll-up
```typescript
const newRoot = mmr.rollUp(currentRoot, currentWidth, currentPeaks, newItemHashes)
```
## Examples
### Basic Blockchain Transaction Log
```typescript
import { MerkleMountainRange } from 'merkletreejs'
import SHA256 from 'crypto-js/sha256'
const txLog = new MerkleMountainRange(SHA256)
// Add transactions
txLog.append('tx1: Alice -> Bob: 10 ETH')
txLog.append('tx2: Bob -> Charlie: 5 ETH')
txLog.append('tx3: Charlie -> Alice: 2 ETH')
txLog.append('tx4: Alice -> Dave: 3 ETH')
console.log('Transaction log root:', txLog.getHexRoot())
console.log('Total transactions:', txLog.width)
// Prove transaction 2 exists
const proof = txLog.getMerkleProof(2)
const isValid = txLog.verify(
proof.root,
proof.width,
2,
'tx2: Bob -> Charlie: 5 ETH',
proof.peakBagging,
proof.siblings
)
console.log('Transaction 2 proof valid:', isValid)
```
### Audit Log System
```typescript
const auditLog = new MerkleMountainRange(SHA256)
// Add audit events
const events = [
'User login: admin@example.com at 2023-01-01T10:00:00Z',
'File accessed: /secure/document.pdf by admin@example.com',
'Permission changed: user123 granted read access to /data/',
'User logout: admin@example.com at 2023-01-01T11:30:00Z',
'Failed login attempt: hacker@evil.com at 2023-01-01T12:00:00Z'
]
events.forEach(event => auditLog.append(event))
console.log('Audit log root:', auditLog.getHexRoot())
// Generate proof for security event
const securityEventProof = auditLog.getMerkleProof(5)
console.log('Security event proof generated')
// Verify the failed login attempt
const proofValid = auditLog.verify(
securityEventProof.root,
securityEventProof.width,
5,
'Failed login attempt: hacker@evil.com at 2023-01-01T12:00:00Z',
securityEventProof.peakBagging,
securityEventProof.siblings
)
console.log('Security event proof valid:', proofValid)
```
### Document Version Control
```typescript
const versionControl = new MerkleMountainRange(SHA256)
// Add document versions
const versions = [
'doc-v1.0: Initial document creation',
'doc-v1.1: Added introduction section',
'doc-v1.2: Fixed typos in chapter 2',
'doc-v2.0: Major restructure and new content',
'doc-v2.1: Added appendix and references'
]
versions.forEach(version => versionControl.append(version))
// Prove a specific version exists
const v2Proof = versionControl.getMerkleProof(4)
const v2Valid = versionControl.verify(
v2Proof.root,
v2Proof.width,
4,
'doc-v2.0: Major restructure and new content',
v2Proof.peakBagging,
v2Proof.siblings
)
console.log('Document v2.0 proof valid:', v2Valid)
```
### Supply Chain Tracking
```typescript
const supplyChain = new MerkleMountainRange(SHA256)
// Track supply chain events
const events = [
'Raw materials sourced from Supplier A',
'Materials processed at Factory B',
'Quality inspection passed at 2023-01-15',
'Product packaged and labeled',
'Shipped to Distribution Center C',
'Delivered to Retailer D',
'Sold to end customer'
]
events.forEach(event => supplyChain.append(event))
// Prove quality inspection occurred
const qualityProof = supplyChain.getMerkleProof(3)
const qualityValid = supplyChain.verify(
qualityProof.root,
qualityProof.width,
3,
'Quality inspection passed at 2023-01-15',
qualityProof.peakBagging,
qualityProof.siblings
)
console.log('Quality inspection proof valid:', qualityValid)
```
### Timestamped Data Archive
```typescript
const archive = new MerkleMountainRange(SHA256)
// Add timestamped data
const data = [
{ timestamp: '2023-01-01T00:00:00Z', data: 'sensor reading: 23.5°C' },
{ timestamp: '2023-01-01T01:00:00Z', data: 'sensor reading: 24.1°C' },
{ timestamp: '2023-01-01T02:00:00Z', data: 'sensor reading: 23.8°C' },
{ timestamp: '2023-01-01T03:00:00Z', data: 'sensor reading: 22.9°C' }
]
data.forEach(entry => archive.append(JSON.stringify(entry)))
// Prove a specific reading
const reading2Proof = archive.getMerkleProof(2)
const reading2Valid = archive.verify(
reading2Proof.root,
reading2Proof.width,
2,
JSON.stringify(data[1]),
reading2Proof.peakBagging,
reading2Proof.siblings
)
console.log('Sensor reading 2 proof valid:', reading2Valid)
```
### Custom Hash Functions
```typescript
import { keccak256 } from 'js-sha3'
// Custom hash function
const customHash = (data) => {
return Buffer.from(keccak256.arrayBuffer(data))
}
// Custom leaf hash function
const customLeafHash = (index, dataHash) => {
const indexBuffer = Buffer.alloc(4)
indexBuffer.writeUInt32BE(index, 0)
return customHash(Buffer.concat([Buffer.from('LEAF'), indexBuffer, dataHash]))
}
// Custom branch hash function
const customBranchHash = (index, left, right) => {
const indexBuffer = Buffer.alloc(4)
indexBuffer.writeUInt32BE(index, 0)
return customHash(Buffer.concat([Buffer.from('BRANCH'), indexBuffer, left, right]))
}
const customMMR = new MerkleMountainRange(
customHash,
[],
customLeafHash,
undefined, // use default peak bagging
customBranchHash
)
customMMR.append('data with custom hashing')
```
### Peak Analysis
```typescript
const mmr = new MerkleMountainRange(SHA256)
// Add various amounts of data to see peak changes
for (let i = 1; i <= 10; i++) {
mmr.append(`data-${i}`)
const peaks = mmr.getPeaks()
const peakIndexes = mmr.getPeakIndexes(mmr.width)
console.log(`After ${i} items:`)
console.log(` Width: ${mmr.width}, Size: ${mmr.size}`)
console.log(` Peaks: ${peaks.length}, Indexes: [${peakIndexes.join(', ')}]`)
console.log(` Root: ${mmr.getHexRoot()}`)
}
```
### Batch Roll-up Operations
```typescript
const mmr = new MerkleMountainRange(SHA256)
// Initial data
mmr.append('initial-1')
mmr.append('initial-2')
const currentRoot = mmr.getRoot()
const currentWidth = mmr.width
const currentPeaks = mmr.getPeaks()
// Prepare new data for roll-up
const newData = ['batch-1', 'batch-2', 'batch-3']
const newItemHashes = newData.map(item => SHA256(item))
// Perform roll-up
const newRoot = mmr.rollUp(currentRoot, currentWidth, currentPeaks, newItemHashes)
console.log('New root after roll-up:', newRoot.toString('hex'))
```
## Advanced Features
### Tree Structure Analysis
```typescript
// Analyze tree structure
console.log('MMR Analysis:')
console.log('Width (leaves):', mmr.width)
console.log('Size (total nodes):', mmr.size)
console.log('Number of peaks:', mmr.numOfPeaks(mmr.width))
console.log('Mountain height:', mmr.mountainHeight(mmr.size))
// Check each node
for (let i = 1; i <= mmr.size; i++) {
const height = mmr.heightAt(i)
const isLeaf = mmr.isLeaf(i)
console.log(`Node ${i}: Height ${height}, ${isLeaf ? 'Leaf' : 'Branch'}`)
}
```
### Proof Size Analysis
```typescript
// Analyze proof sizes for different positions
for (let i = 1; i <= mmr.width; i++) {
const proof = mmr.getMerkleProof(i)
console.log(`Proof for leaf ${i}: ${proof.siblings.length} siblings`)
}
```
## Performance Considerations
- **Append-Only**: Optimized for adding new data, not modifying existing
- **Proof Size**: Logarithmic proof size relative to total data size
- **Peak Management**: Efficient peak tracking for large datasets
- **Memory Usage**: Only stores hashes, not full data (data can be stored separately)
- **Batch Operations**: Roll-up operations allow efficient batch updates
## Security Notes
- **Immutable History**: Once data is appended, it cannot be changed
- **Hash Function Security**: Use cryptographically secure hash functions
- **Index Validation**: Ensure indexes are within valid ranges
- **Proof Verification**: Always verify proofs against trusted roots
## Use Cases
- **Blockchain**: Transaction logs and block history
- **Audit Logs**: Immutable audit trails for security
- **Version Control**: Document and code version tracking
- **Supply Chain**: Product tracking and provenance
- **Timestamping**: Proof of existence at specific times
- **Certificate Transparency**: Log of issued certificates
- **IoT Data**: Sensor data with integrity proofs
## Browser Support
Works in both Node.js and browser environments. Ensure you have appropriate Buffer support for your target environment.
## TypeScript Support
Full TypeScript support with comprehensive type definitions for all methods and data structures. The library provides proper typing for all MMR operations and proof structures.

442
README-MerkleRadixTree.md Normal file
View File

@@ -0,0 +1,442 @@
# MerkleRadixTree Class Documentation
A space-efficient tree data structure that combines the benefits of a radix tree (compressed trie) with Merkle tree cryptographic properties. This implementation is optimized for storing key-value pairs with shared prefixes and provides cryptographic proofs for data integrity.
## Features
- **Space Efficient**: Compresses common prefixes to reduce tree size
- **Cryptographic Proofs**: Generate and verify inclusion proofs with hash chains
- **Key-Value Storage**: Efficient storage and retrieval of string keys with any value type
- **Prefix Compression**: Automatic compression of nodes with common prefixes
- **Hash Updates**: Automatic hash recalculation when tree structure changes
- **Proof Generation**: Create proofs for key existence and value verification
- **Type Safety**: Full TypeScript support with comprehensive type definitions
## Installation
```bash
npm install merkletreejs
```
## Quick Start
```typescript
import { MerkleRadixTree } from 'merkletreejs'
import SHA256 from 'crypto-js/sha256'
// Create tree
const tree = new MerkleRadixTree(SHA256)
// Insert key-value pairs
tree.insert('apple', 'red fruit')
tree.insert('application', 'software program')
tree.insert('apply', 'to put on')
tree.insert('banana', 'yellow fruit')
// Lookup values
const value = tree.lookup('apple')
console.log('Apple is:', value) // 'red fruit'
// Generate proof
const proof = tree.generateProof('apple')
if (proof) {
console.log('Proof generated for apple')
// Verify proof
const rootHash = tree.root.hash
const isValid = tree.verifyProof(proof, rootHash)
console.log('Proof valid:', isValid)
}
```
## Constructor
### `new MerkleRadixTree(hashFunction)`
Creates a new Merkle radix tree instance.
**Parameters:**
- `hashFunction` (Function): Hash function to use for node hashing
**Example:**
```typescript
import SHA256 from 'crypto-js/sha256'
const tree = new MerkleRadixTree(SHA256)
```
## Core Methods
### Tree Operations
#### `insert(key, value)`
Inserts a key-value pair into the tree.
**Parameters:**
- `key` (string): The key to insert
- `value` (any): The value to associate with the key
```typescript
tree.insert('hello', 'world')
tree.insert('help', 'assistance')
tree.insert('helicopter', 'aircraft')
```
#### `lookup(key)`
Retrieves the value associated with a key.
**Parameters:**
- `key` (string): The key to look up
**Returns:** The value associated with the key, or `null` if not found
```typescript
const value = tree.lookup('hello')
if (value !== null) {
console.log('Found:', value)
} else {
console.log('Key not found')
}
```
### Proof Operations
#### `generateProof(key)`
Generates a cryptographic proof for a key's existence and value.
**Parameters:**
- `key` (string): The key to generate a proof for
**Returns:** Array of proof items, or `null` if key not found
```typescript
const proof = tree.generateProof('hello')
if (proof) {
console.log('Proof generated with', proof.length, 'steps')
} else {
console.log('Key not found, cannot generate proof')
}
```
#### `verifyProof(proof, rootHash)`
Verifies a proof against a root hash.
**Parameters:**
- `proof` (ProofItem[]): The proof to verify
- `rootHash` (Buffer): The root hash to verify against
**Returns:** boolean - true if proof is valid
```typescript
const rootHash = tree.root.hash
const isValid = tree.verifyProof(proof, rootHash)
console.log('Proof verification:', isValid)
```
## Proof Structure
Each proof item contains:
```typescript
interface ProofItem {
key: string // Node key
hash: Buffer // Node hash
siblings: { // Sibling nodes
key: string
hash: Buffer
}[]
}
```
## Examples
### Basic Key-Value Operations
```typescript
import { MerkleRadixTree } from 'merkletreejs'
import SHA256 from 'crypto-js/sha256'
const tree = new MerkleRadixTree(SHA256)
// Insert data
tree.insert('cat', 'feline animal')
tree.insert('car', 'vehicle')
tree.insert('card', 'playing card')
tree.insert('care', 'attention')
tree.insert('dog', 'canine animal')
// Lookup data
console.log('cat:', tree.lookup('cat')) // 'feline animal'
console.log('car:', tree.lookup('car')) // 'vehicle'
console.log('care:', tree.lookup('care')) // 'attention'
console.log('cat:', tree.lookup('cat')) // 'feline animal'
console.log('bird:', tree.lookup('bird')) // null (not found)
```
### Dictionary/Glossary System
```typescript
const dictionary = new MerkleRadixTree(SHA256)
// Add dictionary entries
dictionary.insert('algorithm', 'A step-by-step procedure for solving a problem')
dictionary.insert('blockchain', 'A distributed ledger technology')
dictionary.insert('cryptography', 'The practice of secure communication')
dictionary.insert('database', 'An organized collection of data')
dictionary.insert('encryption', 'The process of encoding information')
// Look up definitions
const definition = dictionary.lookup('blockchain')
console.log('Blockchain:', definition)
// Generate proof for a definition
const proof = dictionary.generateProof('cryptography')
if (proof) {
const rootHash = dictionary.root.hash
const isValid = dictionary.verifyProof(proof, rootHash)
console.log('Cryptography definition proof valid:', isValid)
}
```
### File System Simulation
```typescript
const fileSystem = new MerkleRadixTree(SHA256)
// Add files and directories
fileSystem.insert('/home/user/documents/readme.txt', 'File content: README')
fileSystem.insert('/home/user/documents/notes.md', 'File content: Notes')
fileSystem.insert('/home/user/pictures/photo1.jpg', 'Image data')
fileSystem.insert('/home/user/pictures/photo2.png', 'Image data')
fileSystem.insert('/var/log/system.log', 'System log entries')
fileSystem.insert('/var/log/error.log', 'Error log entries')
// Look up files
const readmeContent = fileSystem.lookup('/home/user/documents/readme.txt')
console.log('README content:', readmeContent)
// Generate proof for file existence
const fileProof = fileSystem.generateProof('/home/user/pictures/photo1.jpg')
if (fileProof) {
console.log('File existence proof generated')
}
```
### Configuration Management
```typescript
const config = new MerkleRadixTree(SHA256)
// Store configuration values
config.insert('database.host', 'localhost')
config.insert('database.port', '5432')
config.insert('database.name', 'myapp')
config.insert('database.ssl', 'true')
config.insert('server.port', '3000')
config.insert('server.timeout', '30000')
config.insert('logging.level', 'info')
config.insert('logging.file', '/var/log/app.log')
// Retrieve configuration
const dbHost = config.lookup('database.host')
const serverPort = config.lookup('server.port')
console.log(`Database: ${dbHost}, Server port: ${serverPort}`)
// Generate proof for configuration integrity
const proof = config.generateProof('database.host')
const rootHash = config.root.hash
console.log('Config integrity proof valid:', config.verifyProof(proof, rootHash))
```
### User Session Management
```typescript
const sessions = new MerkleRadixTree(SHA256)
// Store session data
sessions.insert('session_abc123', JSON.stringify({
userId: 'user1',
loginTime: '2023-01-01T10:00:00Z',
permissions: ['read', 'write']
}))
sessions.insert('session_def456', JSON.stringify({
userId: 'user2',
loginTime: '2023-01-01T11:00:00Z',
permissions: ['read']
}))
// Retrieve session
const sessionData = sessions.lookup('session_abc123')
if (sessionData) {
const session = JSON.parse(sessionData)
console.log('User ID:', session.userId)
console.log('Permissions:', session.permissions)
}
// Verify session integrity
const sessionProof = sessions.generateProof('session_abc123')
if (sessionProof) {
const isValid = sessions.verifyProof(sessionProof, sessions.root.hash)
console.log('Session integrity verified:', isValid)
}
```
### Multi-language Text Storage
```typescript
const translations = new MerkleRadixTree(SHA256)
// Store translations
translations.insert('en.welcome', 'Welcome')
translations.insert('en.goodbye', 'Goodbye')
translations.insert('en.hello', 'Hello')
translations.insert('es.welcome', 'Bienvenido')
translations.insert('es.goodbye', 'Adiós')
translations.insert('es.hello', 'Hola')
translations.insert('fr.welcome', 'Bienvenue')
translations.insert('fr.goodbye', 'Au revoir')
translations.insert('fr.hello', 'Bonjour')
// Get translations
console.log('English welcome:', translations.lookup('en.welcome'))
console.log('Spanish hello:', translations.lookup('es.hello'))
console.log('French goodbye:', translations.lookup('fr.goodbye'))
// Prove translation exists
const proof = translations.generateProof('es.welcome')
const rootHash = translations.root.hash
console.log('Translation proof valid:', translations.verifyProof(proof, rootHash))
```
### Working with Different Data Types
```typescript
const mixedData = new MerkleRadixTree(SHA256)
// Store different types of data
mixedData.insert('user:1:name', 'Alice')
mixedData.insert('user:1:age', 25)
mixedData.insert('user:1:active', true)
mixedData.insert('user:2:name', 'Bob')
mixedData.insert('user:2:age', 30)
mixedData.insert('user:2:active', false)
// Store complex objects as JSON
mixedData.insert('config:app', JSON.stringify({
version: '1.0.0',
features: ['auth', 'api', 'ui'],
settings: { theme: 'dark', lang: 'en' }
}))
// Retrieve and parse complex data
const appConfig = mixedData.lookup('config:app')
if (appConfig) {
const config = JSON.parse(appConfig)
console.log('App version:', config.version)
console.log('Features:', config.features)
}
```
## Advanced Features
### Custom Hash Functions
```typescript
import { keccak256 } from 'js-sha3'
// Custom hash function
const customHashFn = (data) => {
return Buffer.from(keccak256.arrayBuffer(data))
}
const tree = new MerkleRadixTree(customHashFn)
tree.insert('test', 'value')
```
### Proof Analysis
```typescript
const proof = tree.generateProof('somekey')
if (proof) {
console.log('Proof analysis:')
proof.forEach((item, index) => {
console.log(`Step ${index}:`)
console.log(` Key: ${item.key}`)
console.log(` Hash: ${item.hash.toString('hex')}`)
console.log(` Siblings: ${item.siblings.length}`)
item.siblings.forEach((sibling, sibIndex) => {
console.log(` Sibling ${sibIndex}: ${sibling.key}`)
})
})
}
```
### Tree Inspection
```typescript
// Access tree structure
console.log('Root hash:', tree.root.hash.toString('hex'))
console.log('Root key:', tree.root.key)
console.log('Root value:', tree.root.value)
console.log('Root children count:', tree.root.children.size)
// Iterate through immediate children
tree.root.children.forEach((child, key) => {
console.log(`Child key: ${key}, Child hash: ${child.hash.toString('hex')}`)
})
```
### Batch Operations
```typescript
// Batch insert for better performance
const batchData = [
['key1', 'value1'],
['key2', 'value2'],
['key3', 'value3'],
['key4', 'value4']
]
batchData.forEach(([key, value]) => {
tree.insert(key, value)
})
// Batch lookup
const keys = ['key1', 'key2', 'key3', 'key4']
const values = keys.map(key => tree.lookup(key))
console.log('Batch lookup results:', values)
```
## Performance Considerations
- **Prefix Compression**: Keys with common prefixes are stored efficiently
- **Hash Updates**: Hash recalculation happens automatically on changes
- **Memory Usage**: Space-efficient storage for keys with shared prefixes
- **Lookup Time**: O(k) where k is the key length
- **Proof Size**: Logarithmic with respect to the number of unique prefixes
## Security Notes
- **Hash Function**: Use cryptographically secure hash functions
- **Proof Verification**: Always verify proofs against trusted root hashes
- **Key Uniqueness**: Ensure keys are unique to avoid overwrites
- **Value Integrity**: Hash includes both key and value for tamper detection
## Use Cases
- **Configuration Management**: Store and verify application settings
- **Dictionary/Glossary**: Efficient storage of definitions with proofs
- **File Systems**: Simulate file system with cryptographic integrity
- **Session Management**: Store session data with tamper detection
- **Internationalization**: Multi-language text storage and retrieval
- **Database Indexing**: Create verifiable indexes for database records
- **DNS Records**: Store domain name mappings with integrity proofs
## Browser Support
Works in both Node.js and browser environments. Ensure you have appropriate Buffer support for your target environment.
## TypeScript Support
Full TypeScript support with comprehensive type definitions for all methods and data structures. The library provides proper typing for keys, values, and proof structures.

433
README-MerkleSumTree.md Normal file
View File

@@ -0,0 +1,433 @@
# MerkleSumTree Class Documentation
A specialized Merkle tree implementation that maintains sums of ranges, enabling efficient range queries and proofs. This implementation is based on the Merkle Sum Tree concept and is particularly useful for applications requiring verifiable range proofs and sum calculations.
## Features
- **Range-Based Proofs**: Generate proofs for data within specific ranges
- **Sum Verification**: Verify that sums are correctly calculated across ranges
- **Consecutive Ranges**: Ensures leaf ranges are consecutive and non-overlapping
- **Bucket Organization**: Efficient bucket-based storage with size tracking
- **Cryptographic Security**: Uses configurable hash functions for security
- **Proof Steps**: Detailed proof steps with positional information
- **Type Safety**: Full TypeScript support with comprehensive type definitions
## Installation
```bash
npm install merkletreejs
```
## Quick Start
```typescript
import { MerkleSumTree, Leaf } from 'merkletreejs'
import SHA256 from 'crypto-js/sha256'
// Create leaves with ranges and data
const leaves = [
new Leaf(SHA256, [0, 10], Buffer.from('data1')),
new Leaf(SHA256, [10, 25], Buffer.from('data2')),
new Leaf(SHA256, [25, 30], Buffer.from('data3'))
]
// Create tree
const tree = new MerkleSumTree(leaves, SHA256)
// Get root bucket
const root = tree.root
console.log('Root size:', root.size.toString())
console.log('Root hash:', root.hashed.toString('hex'))
// Generate proof for leaf at index 1
const proof = tree.getProof(1)
// Verify proof
const isValid = tree.verifyProof(root, leaves[1], proof)
console.log('Proof verified:', isValid)
```
## Core Classes
### Leaf Class
Represents a leaf node with a range and associated data.
#### Constructor
```typescript
new Leaf(hashFn, range, data)
```
**Parameters:**
- `hashFn` (Function): Hash function to use
- `range` (number[] | BigInt[]): [start, end] range values
- `data` (Buffer | null): Associated data
**Example:**
```typescript
const leaf = new Leaf(SHA256, [0, 100], Buffer.from('my data'))
```
#### Methods
##### `getBucket()`
Returns a bucket representation of the leaf.
```typescript
const bucket = leaf.getBucket()
console.log('Bucket size:', bucket.size.toString())
console.log('Bucket hash:', bucket.hashed.toString('hex'))
```
### Bucket Class
Represents a tree node with size and hash information.
#### Constructor
```typescript
new Bucket(size, hashed)
```
**Parameters:**
- `size` (BigInt | number): Size of the bucket
- `hashed` (Buffer): Hash of the bucket
#### Properties
- `size` (BigInt): Size of the bucket
- `hashed` (Buffer): Hash value
- `parent` (Bucket | null): Parent bucket
- `left` (Bucket | null): Left sibling
- `right` (Bucket | null): Right sibling
### ProofStep Class
Represents a step in a proof path.
#### Constructor
```typescript
new ProofStep(bucket, right)
```
**Parameters:**
- `bucket` (Bucket): The bucket for this proof step
- `right` (boolean): Whether the bucket should be on the right side
## MerkleSumTree Class
### Constructor
```typescript
new MerkleSumTree(leaves, hashFn)
```
**Parameters:**
- `leaves` (Leaf[]): Array of leaf nodes with consecutive ranges
- `hashFn` (Function): Hash function to use
**Example:**
```typescript
const tree = new MerkleSumTree(leaves, SHA256)
```
### Properties
- `leaves` (Leaf[]): Original leaf nodes
- `buckets` (Bucket[]): Bucket representation of leaves
- `root` (Bucket): Root bucket of the tree
- `hashFn` (Function): Hash function used
### Methods
#### `getProof(index)`
Generates an inclusion/exclusion proof for a bucket at the specified index.
**Parameters:**
- `index` (number | BigInt): Index of the leaf to prove
**Returns:** Array of ProofStep objects
```typescript
const proof = tree.getProof(1)
console.log('Proof steps:', proof.length)
```
#### `verifyProof(root, leaf, proof)`
Verifies a proof for a specific leaf against the root bucket.
**Parameters:**
- `root` (Bucket): Root bucket to verify against
- `leaf` (Leaf): Leaf being proven
- `proof` (ProofStep[]): Proof steps
**Returns:** boolean - true if proof is valid
```typescript
const isValid = tree.verifyProof(tree.root, leaves[1], proof)
```
#### `sum(arr)`
Calculates the sum of an array of BigInt values.
**Parameters:**
- `arr` (BigInt[]): Array of values to sum
**Returns:** BigInt - Sum of all values
```typescript
const total = tree.sum([BigInt(10), BigInt(20), BigInt(30)])
// Returns: BigInt(60)
```
#### `static checkConsecutive(leaves)`
Validates that leaf ranges are consecutive and non-overlapping.
**Parameters:**
- `leaves` (Leaf[]): Array of leaves to validate
**Throws:** Error if ranges are invalid
```typescript
MerkleSumTree.checkConsecutive(leaves) // Validates ranges
```
## Examples
### Basic Usage
```typescript
import { MerkleSumTree, Leaf } from 'merkletreejs'
import SHA256 from 'crypto-js/sha256'
// Create consecutive range leaves
const leaves = [
new Leaf(SHA256, [0, 50], Buffer.from('Alice: 50 tokens')),
new Leaf(SHA256, [50, 120], Buffer.from('Bob: 70 tokens')),
new Leaf(SHA256, [120, 200], Buffer.from('Charlie: 80 tokens'))
]
// Create tree
const tree = new MerkleSumTree(leaves, SHA256)
console.log('Total sum:', tree.root.size.toString()) // 200
console.log('Root hash:', tree.root.hashed.toString('hex'))
```
### Range Proof Generation and Verification
```typescript
// Generate proof for Bob's tokens (index 1)
const bobProof = tree.getProof(1)
console.log('Proof steps for Bob:')
bobProof.forEach((step, i) => {
console.log(`Step ${i}:`, {
size: step.bucket.size.toString(),
hash: step.bucket.hashed.toString('hex'),
right: step.right
})
})
// Verify the proof
const isValidProof = tree.verifyProof(tree.root, leaves[1], bobProof)
console.log('Bob\'s proof is valid:', isValidProof)
```
### Financial Balance Verification
```typescript
// Financial balance example
const balanceLeaves = [
new Leaf(SHA256, [0, 1000], Buffer.from('Account A: $1000')),
new Leaf(SHA256, [1000, 2500], Buffer.from('Account B: $1500')),
new Leaf(SHA256, [2500, 3000], Buffer.from('Account C: $500')),
new Leaf(SHA256, [3000, 5000], Buffer.from('Account D: $2000'))
]
const balanceTree = new MerkleSumTree(balanceLeaves, SHA256)
console.log('Total balance:', balanceTree.root.size.toString()) // $5000
// Prove Account B's balance
const accountBProof = balanceTree.getProof(1)
const accountBValid = balanceTree.verifyProof(
balanceTree.root,
balanceLeaves[1],
accountBProof
)
console.log('Account B proof valid:', accountBValid)
```
### Supply Chain Tracking
```typescript
// Supply chain with cumulative quantities
const supplyLeaves = [
new Leaf(SHA256, [0, 100], Buffer.from('Supplier A: 100 units')),
new Leaf(SHA256, [100, 350], Buffer.from('Supplier B: 250 units')),
new Leaf(SHA256, [350, 500], Buffer.from('Supplier C: 150 units'))
]
const supplyTree = new MerkleSumTree(supplyLeaves, SHA256)
// Verify total supply
console.log('Total supply:', supplyTree.root.size.toString()) // 500 units
// Generate proof for Supplier B
const supplierBProof = supplyTree.getProof(1)
const supplierBValid = supplyTree.verifyProof(
supplyTree.root,
supplyLeaves[1],
supplierBProof
)
```
### Voting System with Weighted Votes
```typescript
// Voting system where ranges represent vote weights
const voteLeaves = [
new Leaf(SHA256, [0, 25], Buffer.from('Proposal A: 25 votes')),
new Leaf(SHA256, [25, 70], Buffer.from('Proposal B: 45 votes')),
new Leaf(SHA256, [70, 100], Buffer.from('Proposal C: 30 votes'))
]
const voteTree = new MerkleSumTree(voteLeaves, SHA256)
console.log('Total votes:', voteTree.root.size.toString()) // 100
// Prove Proposal B received 45 votes
const proposalBProof = voteTree.getProof(1)
const proposalBValid = voteTree.verifyProof(
voteTree.root,
voteLeaves[1],
proposalBProof
)
console.log('Proposal B vote proof valid:', proposalBValid)
```
### Working with Large Numbers
```typescript
// Using BigInt for large values
const largeLeaves = [
new Leaf(SHA256, [0n, 1000000000000n], Buffer.from('Large value 1')),
new Leaf(SHA256, [1000000000000n, 2500000000000n], Buffer.from('Large value 2')),
new Leaf(SHA256, [2500000000000n, 3000000000000n], Buffer.from('Large value 3'))
]
const largeTree = new MerkleSumTree(largeLeaves, SHA256)
console.log('Large total:', largeTree.root.size.toString())
// Proof generation works the same
const largeProof = largeTree.getProof(0)
const largeValid = largeTree.verifyProof(largeTree.root, largeLeaves[0], largeProof)
```
### Custom Hash Functions
```typescript
import { keccak256 } from 'js-sha3'
// Using keccak256 instead of SHA256
const customHashFn = (data) => {
return Buffer.from(keccak256.arrayBuffer(data))
}
const customLeaves = [
new Leaf(customHashFn, [0, 10], Buffer.from('data1')),
new Leaf(customHashFn, [10, 20], Buffer.from('data2'))
]
const customTree = new MerkleSumTree(customLeaves, customHashFn)
```
## Advanced Features
### Range Validation
The tree automatically validates that ranges are consecutive:
```typescript
// This will throw an error - ranges are not consecutive
try {
const invalidLeaves = [
new Leaf(SHA256, [0, 10], Buffer.from('data1')),
new Leaf(SHA256, [15, 25], Buffer.from('data2')), // Gap: 10-15 missing
new Leaf(SHA256, [25, 30], Buffer.from('data3'))
]
const invalidTree = new MerkleSumTree(invalidLeaves, SHA256)
} catch (error) {
console.log('Error:', error.message) // "leaf ranges are invalid"
}
```
### Proof Analysis
```typescript
// Analyze proof structure
const proof = tree.getProof(1)
console.log('Proof analysis:')
let totalLeftSize = BigInt(0)
let totalRightSize = BigInt(0)
proof.forEach((step, i) => {
if (step.right) {
totalRightSize += step.bucket.size
} else {
totalLeftSize += step.bucket.size
}
console.log(`Step ${i}: Size ${step.bucket.size}, Position: ${step.right ? 'right' : 'left'}`)
})
console.log('Total left size:', totalLeftSize.toString())
console.log('Total right size:', totalRightSize.toString())
```
### Tree Structure Inspection
```typescript
// Inspect tree structure
console.log('Tree structure:')
console.log('Number of leaves:', tree.leaves.length)
console.log('Number of buckets:', tree.buckets.length)
console.log('Root size:', tree.root.size.toString())
// Inspect individual buckets
tree.buckets.forEach((bucket, i) => {
console.log(`Bucket ${i}: Size ${bucket.size}, Hash ${bucket.hashed.toString('hex').slice(0, 8)}...`)
})
```
## Performance Considerations
- **Range Continuity**: Ensure ranges are consecutive to avoid validation errors
- **Data Size**: Large data in leaves affects hash computation time
- **Proof Size**: Proof size is logarithmic with respect to number of leaves
- **BigInt Operations**: Use BigInt for large range values to avoid overflow
## Security Notes
- **Range Validation**: Tree validates range continuity automatically
- **Hash Function**: Use cryptographically secure hash functions
- **Proof Verification**: Always verify proofs on both client and server
- **Range Boundaries**: Ensure range boundaries are correctly specified
## Use Cases
- **Financial Systems**: Prove account balances within ranges
- **Supply Chain**: Track cumulative quantities with proofs
- **Voting Systems**: Verify weighted vote totals
- **Resource Allocation**: Prove resource distribution across ranges
- **Audit Trails**: Maintain verifiable sum calculations
- **Token Distribution**: Prove token allocations within ranges
## Browser Support
Works in both Node.js and browser environments. Ensure you have appropriate Buffer and BigInt support for your target environment.
## TypeScript Support
Full TypeScript support with comprehensive type definitions for all classes and methods. The library properly handles BigInt types for large range values.

524
README-MerkleTree.md Normal file
View File

@@ -0,0 +1,524 @@
# MerkleTree Class Documentation
A comprehensive implementation of a Merkle Tree data structure for creating tamper-proof data structures and generating cryptographic proofs. This is the core class of the merkletreejs library.
## Features
- **Standard Merkle Tree**: Classic binary tree implementation
- **Multiple Hash Functions**: Support for SHA256, keccak256, and custom hash functions
- **Proof Generation**: Generate and verify inclusion proofs
- **Multi-Proofs**: Generate and verify proofs for multiple leaves simultaneously
- **Bitcoin Compatibility**: Support for Bitcoin-style Merkle trees
- **Serialization**: Marshal/unmarshal trees and proofs to/from JSON
- **Flexible Options**: Configurable sorting, duplicate handling, and tree completion
- **Type Safety**: Full TypeScript support with proper type definitions
## Installation
```bash
npm install merkletreejs
```
## Quick Start
```typescript
import { MerkleTree } from 'merkletreejs'
import SHA256 from 'crypto-js/sha256'
// Create leaves (typically hashed data)
const leaves = ['a', 'b', 'c', 'd'].map(x => SHA256(x))
// Create tree
const tree = new MerkleTree(leaves, SHA256)
// Get root
const root = tree.getRoot()
const hexRoot = tree.getHexRoot()
// Generate proof
const leaf = SHA256('b')
const proof = tree.getProof(leaf)
// Verify proof
const verified = tree.verify(proof, leaf, root)
console.log('Proof verified:', verified) // true
```
## Constructor
### `new MerkleTree(leaves, hashFunction?, options?)`
Creates a new Merkle tree instance.
**Parameters:**
- `leaves` (Buffer[]): Array of leaf nodes (should be pre-hashed)
- `hashFunction` (Function): Hash function to use (defaults to SHA256)
- `options` (Options): Configuration options
**Example:**
```typescript
const tree = new MerkleTree(leaves, SHA256, {
sortPairs: true,
duplicateOdd: false
})
```
## Options
```typescript
interface Options {
duplicateOdd?: boolean // Duplicate odd nodes (default: false)
hashLeaves?: boolean // Hash leaves before adding (default: false)
isBitcoinTree?: boolean // Use Bitcoin-style tree (default: false)
sortLeaves?: boolean // Sort leaves (default: false)
sortPairs?: boolean // Sort pairs (default: false)
sort?: boolean // Sort leaves and pairs (default: false)
fillDefaultHash?: Function // Fill function for odd layers
complete?: boolean // Create complete tree (default: false)
concatenator?: Function // Custom concatenation function
}
```
## Core Methods
### Tree Information
#### `getRoot()`
Returns the Merkle root as a Buffer.
```typescript
const root = tree.getRoot()
```
#### `getHexRoot()`
Returns the Merkle root as a hex string with '0x' prefix.
```typescript
const hexRoot = tree.getHexRoot()
```
#### `getLeaves(values?)`
Returns array of leaves. Optionally filter by specific values.
```typescript
const allLeaves = tree.getLeaves()
const filteredLeaves = tree.getLeaves([specificHash1, specificHash2])
```
#### `getHexLeaves()`
Returns array of leaves as hex strings.
```typescript
const hexLeaves = tree.getHexLeaves()
```
#### `getLeafCount()`
Returns the total number of leaves.
```typescript
const count = tree.getLeafCount()
```
#### `getDepth()`
Returns the tree depth (number of layers).
```typescript
const depth = tree.getDepth()
```
### Leaf Operations
#### `getLeaf(index)`
Gets a leaf by index.
```typescript
const leaf = tree.getLeaf(0)
```
#### `getHexLeaf(index)`
Gets a leaf by index as hex string.
```typescript
const hexLeaf = tree.getHexLeaf(0)
```
#### `getLeafIndex(leaf)`
Gets the index of a leaf (-1 if not found).
```typescript
const index = tree.getLeafIndex(leafHash)
```
#### `addLeaf(leaf, shouldHash?)`
Adds a single leaf to the tree.
```typescript
tree.addLeaf(newLeafHash)
tree.addLeaf('raw data', true) // Hash before adding
```
#### `addLeaves(leaves, shouldHash?)`
Adds multiple leaves to the tree.
```typescript
tree.addLeaves([hash1, hash2, hash3])
tree.addLeaves(['data1', 'data2'], true) // Hash before adding
```
#### `removeLeaf(index)`
Removes a leaf by index.
```typescript
const removedLeaf = tree.removeLeaf(2)
```
#### `updateLeaf(index, value, shouldHash?)`
Updates a leaf at specific index.
```typescript
tree.updateLeaf(1, newHash)
tree.updateLeaf(1, 'new data', true) // Hash before updating
```
### Proof Operations
#### `getProof(leaf, index?)`
Generates a proof for a leaf.
```typescript
const proof = tree.getProof(leafHash)
// For duplicate leaves, specify index
const proof = tree.getProof(leafHash, 2)
```
#### `getHexProof(leaf, index?)`
Generates a proof as hex strings.
```typescript
const hexProof = tree.getHexProof(leafHash)
```
#### `getPositionalHexProof(leaf, index?)`
Generates a proof with positional information.
```typescript
const positionalProof = tree.getPositionalHexProof(leafHash)
// Returns: [[position, hash], [position, hash], ...]
```
#### `verify(proof, targetNode, root)`
Verifies a proof against a root.
```typescript
const isValid = tree.verify(proof, leafHash, root)
```
#### `getProofs()`
Gets proofs for all leaves.
```typescript
const allProofs = tree.getProofs()
```
#### `getHexProofs()`
Gets proofs for all leaves as hex strings.
```typescript
const allHexProofs = tree.getHexProofs()
```
### Multi-Proof Operations
#### `getMultiProof(indices)`
Generates a multi-proof for multiple leaves.
```typescript
const multiProof = tree.getMultiProof([0, 2, 4])
```
#### `getHexMultiProof(tree, indices)`
Generates a multi-proof as hex strings.
```typescript
const hexMultiProof = tree.getHexMultiProof(flatTree, [0, 2, 4])
```
#### `verifyMultiProof(root, proofIndices, proofLeaves, leavesCount, proof)`
Verifies a multi-proof.
```typescript
const isValid = tree.verifyMultiProof(
root,
[0, 2, 4],
[leaf0, leaf2, leaf4],
totalLeaves,
multiProof
)
```
#### `getProofFlags(leaves, proofs)`
Gets boolean flags for multi-proof verification.
```typescript
const flags = tree.getProofFlags([leaf0, leaf2], multiProof)
```
### Layer Operations
#### `getLayers()`
Gets all tree layers as 2D array of Buffers.
```typescript
const layers = tree.getLayers()
```
#### `getHexLayers()`
Gets all tree layers as 2D array of hex strings.
```typescript
const hexLayers = tree.getHexLayers()
```
#### `getLayersFlat()`
Gets all tree layers as flat array.
```typescript
const flatLayers = tree.getLayersFlat()
```
#### `getHexLayersFlat()`
Gets all tree layers as flat array of hex strings.
```typescript
const hexFlatLayers = tree.getHexLayersFlat()
```
### Serialization
#### `static marshalLeaves(leaves)`
Converts leaves to JSON string.
```typescript
const jsonLeaves = MerkleTree.marshalLeaves(leaves)
```
#### `static unmarshalLeaves(jsonStr)`
Converts JSON string back to leaves.
```typescript
const leaves = MerkleTree.unmarshalLeaves(jsonLeaves)
```
#### `static marshalProof(proof)`
Converts proof to JSON string.
```typescript
const jsonProof = MerkleTree.marshalProof(proof)
```
#### `static unmarshalProof(jsonStr)`
Converts JSON string back to proof.
```typescript
const proof = MerkleTree.unmarshalProof(jsonProof)
```
#### `static marshalTree(tree)`
Converts entire tree to JSON string.
```typescript
const jsonTree = MerkleTree.marshalTree(tree)
```
#### `static unmarshalTree(jsonStr, hashFn?, options?)`
Recreates tree from JSON string.
```typescript
const tree = MerkleTree.unmarshalTree(jsonTree, SHA256)
```
### Utility Methods
#### `resetTree()`
Clears all leaves and layers.
```typescript
tree.resetTree()
```
#### `toString()`
Returns visual representation of the tree.
```typescript
console.log(tree.toString())
```
#### `getOptions()`
Returns current tree options.
```typescript
const options = tree.getOptions()
```
## Static Methods
### `MerkleTree.verify(proof, targetNode, root, hashFn?, options?)`
Static method to verify a proof without tree instance.
```typescript
const isValid = MerkleTree.verify(proof, leaf, root, SHA256)
```
### `MerkleTree.getMultiProof(tree, indices)`
Static method to generate multi-proof from flat tree.
```typescript
const multiProof = MerkleTree.getMultiProof(flatTree, [0, 2, 4])
```
## Examples
### Basic Usage
```typescript
import { MerkleTree } from 'merkletreejs'
import SHA256 from 'crypto-js/sha256'
// Prepare data
const leaves = ['alice', 'bob', 'charlie', 'dave'].map(x => SHA256(x))
// Create tree
const tree = new MerkleTree(leaves, SHA256)
// Get root
const root = tree.getHexRoot()
console.log('Root:', root)
// Generate and verify proof
const leaf = SHA256('bob')
const proof = tree.getProof(leaf)
const verified = tree.verify(proof, leaf, tree.getRoot())
console.log('Proof verified:', verified)
```
### Bitcoin-Style Tree
```typescript
const tree = new MerkleTree(leaves, SHA256, {
isBitcoinTree: true
})
```
### Sorted Tree (Recommended for Multi-Proofs)
```typescript
const tree = new MerkleTree(leaves, SHA256, {
sortPairs: true,
sortLeaves: true
})
```
### Complete Tree
```typescript
const tree = new MerkleTree(leaves, SHA256, {
complete: true // Creates a complete binary tree
})
```
### Working with Raw Data
```typescript
// Hash leaves automatically
const tree = new MerkleTree(['a', 'b', 'c'], SHA256, {
hashLeaves: true
})
// Or hash manually
const leaves = ['a', 'b', 'c'].map(x => SHA256(x))
const tree = new MerkleTree(leaves, SHA256)
```
### Multi-Proof Example
```typescript
const tree = new MerkleTree(leaves, SHA256, { complete: true })
const indices = [0, 2, 4]
const multiProof = tree.getMultiProof(indices)
const proofLeaves = indices.map(i => leaves[i])
const verified = tree.verifyMultiProof(
tree.getRoot(),
indices,
proofLeaves,
leaves.length,
multiProof
)
```
### Serialization Example
```typescript
// Serialize tree
const jsonTree = MerkleTree.marshalTree(tree)
localStorage.setItem('merkleTree', jsonTree)
// Deserialize tree
const savedTree = localStorage.getItem('merkleTree')
const restoredTree = MerkleTree.unmarshalTree(savedTree, SHA256)
```
## Advanced Features
### Custom Hash Functions
```typescript
const customHash = (data) => {
return crypto.createHash('sha1').update(data).digest()
}
const tree = new MerkleTree(leaves, customHash)
```
### Custom Concatenator
```typescript
const tree = new MerkleTree(leaves, SHA256, {
concatenator: (buffers) => {
// Custom way to combine buffers
return Buffer.concat(buffers.reverse())
}
})
```
### Fill Default Hash
```typescript
const tree = new MerkleTree(leaves, SHA256, {
fillDefaultHash: (index, hashFn) => {
return hashFn(`default-${index}`)
}
})
```
## Performance Considerations
- Use `complete: true` for better multi-proof performance
- Sort pairs and leaves for consistent tree structure
- Consider tree depth for large datasets
- Use static methods when you don't need tree instance
## Security Notes
- Always hash your input data before creating leaves
- Use cryptographically secure hash functions
- Validate proofs on both client and server side
- Be aware of second preimage attacks with certain configurations
## Browser Support
The MerkleTree class works in both Node.js and browser environments. For browser usage, ensure you have appropriate polyfills for Buffer operations.
## TypeScript Support
Full TypeScript support with comprehensive type definitions for all methods and options.

411
README-UnifiedBinaryTree.md Normal file
View File

@@ -0,0 +1,411 @@
# UnifiedBinaryTree Class Documentation
A specialized binary tree implementation designed for Ethereum-style key-value storage with cryptographic proofs. This implementation is optimized for storing account data, contract code, and storage slots with efficient key derivation and tree organization.
## Features
- **Ethereum-Compatible**: Designed for Ethereum account and storage data
- **Key Derivation**: Built-in functions for generating tree keys from addresses
- **Code Chunkification**: Automatic splitting of contract bytecode into chunks
- **Stem-Based Organization**: Efficient 256-value leaf nodes with 31-byte stems
- **Cryptographic Proofs**: Generate and verify inclusion proofs
- **Serialization**: Full tree serialization and deserialization support
- **Batch Operations**: Efficient batch insertion of multiple key-value pairs
- **Type Safety**: Full TypeScript support with comprehensive type definitions
## Installation
```bash
npm install merkletreejs
```
## Quick Start
```typescript
import { UnifiedBinaryTree, getTreeKey, oldStyleAddressToAddress32 } from 'merkletreejs'
import { blake3 } from '@noble/hashes/blake3'
// Create tree with BLAKE3 hash function
const tree = new UnifiedBinaryTree(blake3)
// Convert Ethereum address to 32-byte format
const address = Buffer.from('1234567890123456789012345678901234567890', 'hex')
const address32 = oldStyleAddressToAddress32(address)
// Generate key and insert data
const key = getTreeKey(address32, 0, 1, blake3)
const value = Buffer.alloc(32).fill(1)
tree.insert(key, value)
// Get Merkle root
const root = tree.merkelize()
console.log('Tree root:', root.toString('hex'))
```
## Constructor
### `new UnifiedBinaryTree(hashFunction)`
Creates a new unified binary tree instance.
**Parameters:**
- `hashFunction` (HashFunction): Hash function to use for key derivation and tree operations
**Example:**
```typescript
import { blake3 } from '@noble/hashes/blake3'
const tree = new UnifiedBinaryTree(blake3)
```
## Key Derivation Functions
### `oldStyleAddressToAddress32(address)`
Converts a 20-byte Ethereum address to a 32-byte address by left-padding with zeros.
```typescript
const addr20 = Buffer.from('1234567890123456789012345678901234567890', 'hex')
const addr32 = oldStyleAddressToAddress32(addr20)
// Returns: 32-byte padded address
```
### `getTreeKey(address, treeIndex, subIndex, hashFn)`
Derives a tree key from an address and indices.
**Parameters:**
- `address` (Address32): 32-byte address
- `treeIndex` (number): Primary index for different trees
- `subIndex` (number): Secondary index within the tree
- `hashFn` (HashFunction): Hash function to use
```typescript
const key = getTreeKey(address32, 0, 1, blake3)
```
### `getTreeKeyForBasicData(address, hashFn)`
Derives a key for storing account basic data (nonce, balance, etc.).
```typescript
const basicDataKey = getTreeKeyForBasicData(address32, blake3)
tree.insert(basicDataKey, accountData)
```
### `getTreeKeyForCodeHash(address, hashFn)`
Derives a key for storing a contract's code hash.
```typescript
const codeHashKey = getTreeKeyForCodeHash(address32, blake3)
tree.insert(codeHashKey, codeHash)
```
### `getTreeKeyForStorageSlot(address, storageKey, hashFn)`
Derives a key for a storage slot in a contract's storage.
```typescript
// Header storage (slots 0-63)
const headerKey = getTreeKeyForStorageSlot(address32, 5, blake3)
// Main storage (slots 256+)
const mainKey = getTreeKeyForStorageSlot(address32, 300, blake3)
```
### `getTreeKeyForCodeChunk(address, chunkId, hashFn)`
Derives a key for storing a chunk of contract code.
```typescript
const chunks = chunkifyCode(contractCode)
chunks.forEach((chunk, i) => {
const key = getTreeKeyForCodeChunk(address32, i, blake3)
tree.insert(key, chunk)
})
```
## Code Chunkification
### `chunkifyCode(code)`
Splits EVM bytecode into 31-byte chunks with metadata.
```typescript
const code = Buffer.from('6001600201', 'hex') // PUSH1 01 PUSH1 02 ADD
const chunks = chunkifyCode(code)
// Returns array of 32-byte chunks with PUSH data metadata
```
Each chunk contains:
- 1 byte: Number of PUSH data bytes at start of next chunk
- 31 bytes: Actual bytecode
## Core Methods
### Tree Operations
#### `insert(key, value)`
Inserts a key-value pair into the tree.
**Parameters:**
- `key` (Buffer): 32-byte key
- `value` (Buffer): 32-byte value
```typescript
tree.insert(key, value)
```
#### `update(key, value)`
Updates the value for an existing key (same as insert).
```typescript
tree.update(key, newValue)
```
#### `insertBatch(entries)`
Performs batch insertion of multiple key-value pairs.
```typescript
const entries = [
{ key: key1, value: value1 },
{ key: key2, value: value2 },
{ key: key3, value: value3 }
]
tree.insertBatch(entries)
```
#### `merkelize()`
Computes the Merkle root of the entire tree.
```typescript
const root = tree.merkelize()
```
### Serialization
#### `serialize()`
Serializes the entire tree structure to a Buffer.
```typescript
const serialized = tree.serialize()
// Save to file or transmit over network
```
#### `static deserialize(data, hashFn)`
Reconstructs a tree from its serialized form.
```typescript
const newTree = UnifiedBinaryTree.deserialize(serialized, blake3)
```
## Node Types
### StemNode
Leaf node containing up to 256 values with a 31-byte stem.
```typescript
const stem = Buffer.alloc(31, 0)
const node = new StemNode(stem)
node.setValue(0, Buffer.alloc(32).fill(1))
```
### InternalNode
Internal node with left and right children.
```typescript
const node = new InternalNode()
node.left = leftChild
node.right = rightChild
```
## Storage Layout
The tree uses a specific storage layout for Ethereum data:
### Address Space Organization
- **Header Storage**: Slots 0-63 → Tree positions 64-127
- **Code Storage**: Starting at position 128
- **Main Storage**: Slots 256+ → Tree positions 384+
### Tree Key Structure
- **31 bytes**: Stem (derived from address and tree index)
- **1 byte**: Sub-index (0-255 for values within a stem node)
## Examples
### Basic Account Data Storage
```typescript
import { UnifiedBinaryTree, getTreeKeyForBasicData, oldStyleAddressToAddress32 } from 'merkletreejs'
import { blake3 } from '@noble/hashes/blake3'
const tree = new UnifiedBinaryTree(blake3)
// Store account basic data
const address = Buffer.from('1234567890123456789012345678901234567890', 'hex')
const address32 = oldStyleAddressToAddress32(address)
const basicDataKey = getTreeKeyForBasicData(address32, blake3)
// Account data: nonce, balance, etc.
const accountData = Buffer.alloc(32)
accountData.writeUInt32BE(42, 28) // nonce = 42
tree.insert(basicDataKey, accountData)
const root = tree.merkelize()
```
### Contract Code Storage
```typescript
// Store contract code hash
const codeHash = blake3(contractBytecode)
const codeHashKey = getTreeKeyForCodeHash(address32, blake3)
tree.insert(codeHashKey, Buffer.from(codeHash))
// Store contract code chunks
const chunks = chunkifyCode(contractBytecode)
chunks.forEach((chunk, i) => {
const key = getTreeKeyForCodeChunk(address32, i, blake3)
tree.insert(key, chunk)
})
```
### Storage Slot Management
```typescript
// Store header storage (special contract storage)
for (let slot = 0; slot < 64; slot++) {
const key = getTreeKeyForStorageSlot(address32, slot, blake3)
const value = Buffer.alloc(32).fill(slot)
tree.insert(key, value)
}
// Store main storage
const storageSlot = 300
const storageKey = getTreeKeyForStorageSlot(address32, storageSlot, blake3)
const storageValue = Buffer.alloc(32).fill(0xFF)
tree.insert(storageKey, storageValue)
```
### Batch Operations
```typescript
const entries = []
// Prepare multiple entries
for (let i = 0; i < 100; i++) {
const key = getTreeKey(address32, 0, i, blake3)
const value = Buffer.alloc(32).fill(i)
entries.push({ key, value })
}
// Insert all at once
tree.insertBatch(entries)
const root = tree.merkelize()
```
### Tree Serialization
```typescript
// Create and populate tree
const tree = new UnifiedBinaryTree(blake3)
tree.insert(key1, value1)
tree.insert(key2, value2)
// Serialize tree
const serialized = tree.serialize()
console.log('Serialized size:', serialized.length, 'bytes')
// Save to file (Node.js)
require('fs').writeFileSync('tree.json', serialized)
// Deserialize tree
const savedData = require('fs').readFileSync('tree.json')
const restoredTree = UnifiedBinaryTree.deserialize(savedData, blake3)
// Verify trees are identical
const originalRoot = tree.merkelize()
const restoredRoot = restoredTree.merkelize()
console.log('Trees match:', originalRoot.equals(restoredRoot))
```
### Working with Different Hash Functions
```typescript
import { sha256 } from '@noble/hashes/sha256'
import { keccak256 } from '@noble/hashes/keccak'
// Different trees with different hash functions
const blake3Tree = new UnifiedBinaryTree(blake3)
const sha256Tree = new UnifiedBinaryTree(sha256)
const keccakTree = new UnifiedBinaryTree(keccak256)
// Same data, different roots
const key = getTreeKey(address32, 0, 1, blake3)
const value = Buffer.alloc(32).fill(42)
blake3Tree.insert(key, value)
sha256Tree.insert(key, value)
keccakTree.insert(key, value)
// Different Merkle roots
console.log('BLAKE3 root:', blake3Tree.merkelize().toString('hex'))
console.log('SHA256 root:', sha256Tree.merkelize().toString('hex'))
console.log('Keccak root:', keccakTree.merkelize().toString('hex'))
```
## Advanced Features
### Custom Key Derivation
```typescript
// Custom key derivation for special use cases
function getCustomTreeKey(
address: Buffer,
customIndex: number,
hashFn: HashFunction
): Buffer {
const address32 = oldStyleAddressToAddress32(address)
return getTreeKey(address32, customIndex, 0, hashFn)
}
const customKey = getCustomTreeKey(address, 999, blake3)
tree.insert(customKey, customValue)
```
### Tree Inspection
```typescript
// Check if tree is empty
const isEmpty = tree.root === null
// Get tree structure info
const serialized = tree.serialize()
const treeData = JSON.parse(serialized.toString('utf8'))
console.log('Tree structure:', JSON.stringify(treeData, null, 2))
```
## Performance Considerations
- **Batch Operations**: Use `insertBatch()` for multiple insertions
- **Key Locality**: Keys with similar stems are stored in the same leaf nodes
- **Tree Depth**: Maximum depth is 247 levels to prevent hash collisions
- **Memory Usage**: Each stem node can hold up to 256 values efficiently
## Security Notes
- Uses cryptographically secure hash functions for key derivation
- Tree depth is limited to prevent collision attacks
- All keys must be exactly 32 bytes
- All values must be exactly 32 bytes
- Stems are exactly 31 bytes for consistent tree structure
## Use Cases
- **Ethereum State Trees**: Store account data, code, and storage
- **Layer 2 Solutions**: Efficient state management for rollups
- **Blockchain Indexing**: Organize blockchain data with cryptographic proofs
- **Verifiable Databases**: Create tamper-proof key-value stores
- **Smart Contract Storage**: Efficient storage layout for contract data
## Browser Support
Works in both Node.js and browser environments. Ensure you have appropriate hash function implementations for your target environment.
## TypeScript Support
Full TypeScript support with comprehensive type definitions for all functions, classes, and interfaces.

View File

@@ -150,12 +150,12 @@ npm test
- Q: What other types of merkle trees are supported?
- Besides standard `MerkleTree`, there's these implementation classes available:
- `MerkleMountainRange`
- `MerkleSumTree`
- `IncrementalMerkleTree`
- `MerkleRadixTree`
- `UnifiedBinaryTree` (EIP-7864)
- Besides standard [`MerkleTree`](./README-MerkleTree.md), there's these implementation classes available:
- [`MerkleMountainRange`](./README-MerkleMountainRange.md)
- [`MerkleSumTree`](./README-MerkleSumTree.md)
- [`IncrementalMerkleTree`](./README-IncrementalMerkleTree.md)
- [`MerkleRadixTree`](./README-MerkleRadixTree.md)
- [`UnifiedBinaryTree`](./README-UnifiedBinaryTree.md) (EIP-7864)
Example import of other classes: