Project

merkle

0.0
No release in over 3 years
A Ruby library for Merkle trees
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies
 Project Readme

Merkle

A Ruby library for Merkle tree construction and proof generation with support for multiple tree structures and hashing algorithms.

Features

  • Multiple tree structures: Binary Tree (Bitcoin-compatible), Adaptive Tree, and Custom Tree implementations
  • Flexible configuration: Support for different hash algorithms (SHA256, Double SHA256) and tagged hashing
  • Proof generation and verification: Generate and verify Merkle proofs for any leaf
  • Sorted hashing support: Optional lexicographical sorting for deterministic tree construction

Installation

Add this line to your application's Gemfile:

gem 'merkle'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install merkle

Usage

Basic Example

require 'merkle'

# Create configuration
config = Merkle::Config.new(hash_type: :sha256)

# Method 1: Using pre-hashed leaves
leaves = [
  'a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3',
  'b3a8e0e1f9ab1bfe3a36f231f676f78bb30a519d2b21e6c530c0eee8ebb4a5d0',
  'c3c9bc9a6c7c5b4e8c3b6b5a2a8c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c'
]

# Create binary tree (Bitcoin-compatible)
tree = Merkle::BinaryTree.new(config: config, leaves: leaves)

# Compute merkle root
root = tree.compute_root
puts "Merkle root: #{root}"

# Generate proof for leaf at index 1
proof = tree.generate_proof(1)
puts "Proof siblings: #{proof.siblings}"
puts "Proof directions: #{proof.directions}"

# Verify proof
puts "Proof valid: #{proof.valid?}"

Using from_elements

# Method 2: Using from_elements to automatically hash raw data
elements = ['hello', 'world', 'merkle', 'tree']

# Create tree from raw elements
tree = Merkle::BinaryTree.from_elements(
  config: config, 
  elements: elements
)

# The elements are automatically hashed before building the tree
root = tree.compute_root
puts "Root from elements: #{root}"

# With optional leaf tag for tagged hashing (e.g., Taproot)
taproot_config = Merkle::Config.taptree
tagged_tree = Merkle::AdaptiveTree.from_elements(
  config: taproot_config,
  elements: elements,
  leaf_tag: 'TapLeaf'  # Optional tag for leaf hashing
)

# Generate and verify proof
proof = tree.generate_proof(0)
puts "Proof for first element valid: #{proof.valid?}"

Adaptive Tree Example

# Create adaptive tree for better performance with frequently accessed leaves
adaptive_tree = Merkle::AdaptiveTree.new(config: config, leaves: leaves)

root = adaptive_tree.compute_root
proof = adaptive_tree.generate_proof(0)
puts "Adaptive tree proof valid: #{proof.valid?}"

Custom Tree Example

# CustomTree allows you to define your own tree structure using nested arrays
# This gives you precise control over how leaves are grouped

# Example 1: Basic usage with pre-hashed leaves
leaf_a = config.tagged_hash('A')
leaf_b = config.tagged_hash('B')
leaf_c = config.tagged_hash('C')
leaf_d = config.tagged_hash('D')

# Define structure: [[A, [B, C]], D]
nested_leaves = [[leaf_a, [leaf_b, leaf_c]], leaf_d]
custom_tree = Merkle::CustomTree.new(config: config, leaves: nested_leaves)

root = custom_tree.compute_root
puts "Custom tree root: #{root}"

# Valid structures:
# - [A, B] → Simple binary node
# - [[A, B], C] → Left subtree with right leaf
# - [A] → Single child node
# Invalid: [A, B, C] → Error (max 2 children per node)

Configuration Options

# Bitcoin-compatible configuration with double SHA256
bitcoin_config = Merkle::Config.new(hash_type: :double_sha256)

# Configuration with tagged hashing (Taproot-style)
taproot_config = Merkle::Config.taptree

# Configuration with non-sorted hashing (directions needed in proofs)
non_sorted_config = Merkle::Config.new(
  hash_type: :sha256,
  sort_hashes: false
)

Architecture

Tree Structures

  • BinaryTree: Bitcoin-compatible merkle tree that duplicates odd nodes
  • AdaptiveTree: Unbalanced tree that promotes odd nodes to higher levels for optimized access patterns
  • CustomTree: User-defined tree structure using nested arrays for precise control over leaf grouping

Proof System

The library generates compact Merkle proofs that include:

  • siblings: Array of sibling hashes needed for verification
  • directions: Array indicating left (0) or right (1) position at each level
  • root: The merkle root hash
  • leaf: The original leaf value

Verification

proof = tree.generate_proof(leaf_index)
is_valid = proof.valid? # Returns true/false