gomerkle

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 27, 2018 License: MIT Imports: 6 Imported by: 0

README

gomerkle

GoDoc Build Status Go Report Card

An implementation of a Merkle Tree data structure in Golang using the SHA256 cryptographic hashing algorithm with builtin defense against second-preimage attacks.

A Merkle tree allows for efficient and secure verification of the contents of large data structures. This implementation provides APIs to perform the fundamental operations on Merkle trees such as providing a Merkle root, generating proofs and verifying them.

API

The MerkleTree operates on a Block which is just a byte slice and typically represents chunks of a larger data structure such as a file. It can be instantiated with a list of blocks and inserted after initialization. Note, that order of insertion is important and correlates to the Merkle root. If the supplied list of blocks is not a power of two, the last block is duplicated which results in a complete binary Merkle tree.

To initialize and insert chunks of raw data (blocks):

import (
  "github.com/alexanderbez/gomerkle"
)

blocks := []gomerkle.Block{
  gomerkle.Block("chunk1"),
  gomerkle.Block("chunk2"),
  gomerkle.Block("chunk3"),
  // ...
  gomerkle.Block("chunkn"),
}

mt := gomerkle.NewMerkleTree(blocks...)

Or create an empty Merkle tree and insert chunks:

mt := gomerkle.NewMerkleTree()

err := mt.Insert(gomerkle.Block("chunk1"))
if err != nil {
  // handle error...
}

Once all chunks have been inserted, a Merkle tree needs to 'finalized' to provide a Merkle root, proofs, and proof verification:

err := mt.Finalize()
if err != nil {
  // handle error...
}

To obtain the Merkle root:

root, err := mt.RootHash()
if err != nil {
  // handle error...
}

To generate a Merkle proof for a chunk of data (block):

proof, err := mt.Proof(gomerkle.Block("chunk1"))
if err != nil {
  // handle error...
}

To verify a generated Merkle proof:

err := mt.Verify(gomerkle.Block("chunk1"), proof)
if err != nil {
  // handle error...
}

Tests

$ go test -v ./...

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b feature/my-new-feature)
  3. Commit your changes (git commit -m 'Add some feature')
  4. Push to the branch (git push origin feature/my-new-feature)
  5. Create a new Pull Request

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrDirtyMerkleTree    = errors.New("merkle tree has not been finalized")
	ErrNotDirtyMerkleTree = errors.New("merkle tree has been finalized")
	ErrEmptyMerkleTree    = errors.New("merkle tree has no data blocks")
	ErrNilBlock           = errors.New("block cannot be nil")
)

Errors reflecting invalid operations on a Merkle tree.

Functions

This section is empty.

Types

type Block

type Block []byte

Block reflects a block of data to be stored in the tree.

func (Block) Bytes

func (b Block) Bytes() []byte

Bytes returns the raw bytes of a Block.

type MerkleTree

type MerkleTree struct {
	// contains filtered or unexported fields
}

MerkleTree implements a binary complete Merkle tree data structure such that every node is cryptographically hashed and is composed of the hashes of it's children. If a node has no child, it is the cryptographic hash of a data block. A Merkle tree allows for efficient and secure verification of the existence of data blocks that lead up to a secure root hash. A data block is any arbitrary data structure that can be interpreted as a byte slice such as chunks of a file.

Data blocks can be inserted into the Merkle tree in a given order where the order is critical as it corelates to the construction of the root hash. When the Merkle tree is ready to be constructed, it is "finalized" such that the root hash is computed and proofs may be granted along with verification of said proofs.

func NewMerkleTree

func NewMerkleTree(blocks ...Block) *MerkleTree

NewMerkleTree returns a reference to a new initialized Merkle tree with a given set of initial data blocks.

func (*MerkleTree) Finalize

func (mt *MerkleTree) Finalize() error

Finalize builds a SHA256 cryptographically hashed Merkle tree from a list of data blocks. If no blocks exist in the tree, an error is returned. The following invariants will be enforced:

All leaf nodes and root node will be encoded with a 0x00 byte prefix and all internal nodes will be encoded with a 0x01 byte prefix to prevent second pre-image attacks.

If there are an odd number of leaf nodes, the last data block will be duplicated to create an even set.

func (*MerkleTree) Insert

func (mt *MerkleTree) Insert(b Block) error

Insert inserts a new data block into the Merkle tree. This operations marks the tree as dirty and thus Finalize will need to be invoked to recreate the root hash. An error is returned if the given block is nil.

func (MerkleTree) Proof

func (mt MerkleTree) Proof(block Block) ([]Node, error)

Proof returns a cryptographic Merkle proof for the existence of some block. If the Merkle tree has not been finalized or if the block does not exist, an error is returned. Otherwise, a proof consisting of Nodes is returned following the given procedure:

for any given node (starting at the provided block), add it's sibling to the proof and then set the current node to the current node's parent, repeating until the root is reached.

func (*MerkleTree) RootHash

func (mt *MerkleTree) RootHash() ([]byte, error)

RootHash returns the root hash of a finalized Merkle tree. An error is returned if the tree has not been finalized yet.

func (*MerkleTree) String

func (mt *MerkleTree) String() (s string)

String implements the Stringer interface. It returns the string-encoded root hash with a '0x' prefix.

func (MerkleTree) Verify

func (mt MerkleTree) Verify(block Block, proof []Node) error

Verify performs a cryptographic Merkle tree verification for a given block and proof. If the given proof can be constructed up to the Merkle root correctly, the proof is valid. Otherwise, an error is returned.

type Node

type Node []byte

Node reflects a unique and uniformly distributed hash of a node in the tree.

func (Node) Bytes

func (h Node) Bytes() []byte

Bytes returns the raw bytes of a Node.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL