Class: Merkle::CustomTree
- Inherits:
-
AbstractTree
- Object
- AbstractTree
- Merkle::CustomTree
- Defined in:
- lib/merkle/custom_tree.rb
Overview
Custom Merkle tree implementation that allows specifying the tree structure Example: [leaf_A, [leaf_B, leaf_C], [leaf_D, leaf_E], leaf_F]
Constant Summary
Constants included from Util
Util::HASH_SIZE, Util::MAX_DEPTH
Instance Attribute Summary
Attributes inherited from AbstractTree
Class Method Summary collapse
-
.from_elements(config:, elements:) ⇒ Object
Create tree from elements with custom structure The tag used for the leaf hash comes from
config.leaf_tag.
Instance Method Summary collapse
-
#compute_root ⇒ String
Compute merkle root using custom structure.
-
#generate_proof(leaf_index) ⇒ Object
Override generate_proof to work with nested structure.
-
#initialize(config:, leaves:) ⇒ CustomTree
constructor
Constructor.
Methods included from Util
#bin_to_hex, #combine_sorted, #decode_hash, #hex_string?, #node_hash?, #normalize_hash
Constructor Details
#initialize(config:, leaves:) ⇒ CustomTree
Constructor
10 11 12 |
# File 'lib/merkle/custom_tree.rb', line 10 def initialize(config:, leaves:) super(config: config, leaves: leaves) end |
Class Method Details
.from_elements(config:, elements:) ⇒ Object
Create tree from elements with custom structure
The tag used for the leaf hash comes from config.leaf_tag.
18 19 20 21 22 23 24 25 26 27 |
# File 'lib/merkle/custom_tree.rb', line 18 def self.from_elements(config:, elements:) raise ArgumentError, 'config must be Merkle::Config' unless config.is_a?(Merkle::Config) raise ArgumentError, 'elements must be Array' unless elements.is_a?(Array) # Convert elements to hashes while preserving structure. This walks the input before the # constructor gets to check it, so it has to enforce the depth limit itself. hashed_structure = convert_elements_to_hashes(elements, config) self.new(config: config, leaves: hashed_structure) end |
Instance Method Details
#compute_root ⇒ String
Compute merkle root using custom structure
31 32 33 34 35 36 37 38 39 |
# File 'lib/merkle/custom_tree.rb', line 31 def compute_root # Re-check here rather than trusting the constructor. +leaves+ is readable and its arrays # are mutable, so a structure that was rejected at construction can be assembled afterwards. validate_leaves! all_leaves = extract_leaves(@leaves) raise Error, 'leaves is empty' if all_leaves.empty? result = compute_node_hash(@leaves) result.unpack1('H*') end |
#generate_proof(leaf_index) ⇒ Object
Override generate_proof to work with nested structure
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/merkle/custom_tree.rb', line 85 def generate_proof(leaf_index) # Walking the structure before checking it would hit the recursion limit on a structure # assembled after construction, and SystemStackError escapes the caller's rescue. validate_leaves! all_leaves = extract_leaves(@leaves) raise ArgumentError, 'leaf_index must be Integer' unless leaf_index.is_a?(Integer) raise ArgumentError, 'leaf_index out of range' if leaf_index < 0 || all_leaves.length <= leaf_index siblings, directions = siblings_with_directions(leaf_index) siblings = siblings.map { |sibling| bin_to_hex(sibling) } directions = [] if config.sort_hashes Proof.new( config: config, root: compute_root, leaf: all_leaves[leaf_index], siblings: siblings, directions: directions ) end |