merkle

package module
v0.0.0-...-34ffbce Latest Latest
Warning

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

Go to latest
Published: Mar 28, 2018 License: BSD-3-Clause Imports: 10 Imported by: 3

README

Merkle Tree Storage

This may be replaced later. The merkle package stores data in Merkle trees. The leaves are stored as files in a directory, and the branches are stored in a Bolt database.

The logic is that this provides a few useful features. The data is more secure at rest. Each forest (Merkle trees in a directory) has a key, the data cannot be read without that key. Further, it is difficult to even gather meta-data because the file names are the encrypted hashes and the data in the Bolt DB are also encrypted. Any leaves that are smaller than a full block are padded to length, to prevent IDing a file by it's size.

Storing the files this way also makes it easy to fulfill requests for segments of a file. A leaf can be retrieved along with the validation chain necessary to prove that the leaf belongs to the tree.

GoDoc

To-do

  • Delete test data: if a test fails, the next round of tests will fail because they are reading the old database.

Someday

  • pass a slice into readleaf, that could be way more efficient
  • get many blocks and uncles
  • timestamp on tree
    • ttl : erase tree after a certain point
    • accessed : erase oldest trees to clear space
  • err handling

Maybe store data is less than 4096 bytes (after encryption) in a separate bucket. It would need to be padded to certain lengths, but it could help with efficient storage.

Partial Trees

Read and ReadAll will simply not work on an incomplete tree.

Directed Encrypted Access

Just the fragment of a thought, but a Forrest could be stored remotely (and distributed). Or at least any generic blob storage could be used to store leaves. A user could securely store data on an untrusted location and leak very little meta data.

Documentation

Overview

Package merkle stores resources as Merkle Trees. It should provide security for data at rest, protecting both the data and the meta-data while storing the information in a way that makes it easy to fulfil request for partial resources with validation.

Index

Constants

View Source
const BlockSize = 8112

BlockSize is the size of each leaf. The encryption adds about 40 bytes. Most disks have a physical sector size of 4096. The block size is designed to use 2 sectors per leaf, a compromize between current effiency and future- proofing. There's also 40 bytes extra (double the encryption overhead) to ensure that it doesn't go over and require a 3rd sector.

View Source
const ErrBadWhence = errors.String("Bad whence value")

ErrBadWhence is returned if the whence value given to Seek is unknown

View Source
const ErrBucketDoesNotExist = errors.String("Bucket does not exist")

ErrBucketDoesNotExist is returned when trying to read from a bucket that does not exist.

View Source
const ErrIncomplete = errors.String("Tree is incomplete")

ErrIncomplete is returned when trying to perform an operation limited to a complete Tree (Read or ReadAll). Check if the Tree is complete with Tree.Complete()

View Source
const ErrNegativeOffset = errors.String("Attempting to Seek to negative offset")

ErrNegativeOffset is returned if the result of a seek would set the tree offset position to a negative value.

Variables

This section is empty.

Functions

This section is empty.

Types

type Forest

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

Forest is a directory used to store Merkle Trees. A Forest has a symmetric encryption key that is used to secure the data. It also has a Bolt DB file to store structural information (branches and roots).

func Open

func Open(dirStr string, key *crypto.Symmetric) (*Forest, error)

Open will either open or creates a new Forest

func (*Forest) BuildTree

func (f *Forest) BuildTree(r io.Reader) (*Tree, error)

BuildTree takes a reader and saves the data read from it to a Merkle tree in the Forest.

func (*Forest) Close

func (f *Forest) Close()

Close will close a Forest, specifically, it will close the Bolt DB and directory.

func (*Forest) First

func (f *Forest) First(bucket []byte) ([]byte, []byte, error)

First returns the first key/value pair in the bucket

func (*Forest) GetTree

func (f *Forest) GetTree(d *crypto.Digest) *Tree

GetTree will return a Tree from a Forest. It is only a reference to the Tree, not the data in the tree. If the tree is not found, it will return nil.

func (*Forest) GetValue

func (f *Forest) GetValue(bucket, key []byte) ([]byte, error)

GetValue returns a single value from the Bolt Database stored with SetValue. It does not use the Merkle tree structure, but provides a simple method to store secure information in the same container as the trees

func (*Forest) MakeBuckets

func (f *Forest) MakeBuckets(bkts ...[]byte) error

MakeBuckets takes a list of buckets and calls CreateBucketIfNotExists on each of them.

func (*Forest) New

func (f *Forest) New(d *crypto.Digest, l uint32) *Tree

New returns a new Tree

func (*Forest) Next

func (f *Forest) Next(bucket, searchKey []byte) ([]byte, []byte, error)

Next takes a searchKey and returns the next key/value after it

func (*Forest) SetValue

func (f *Forest) SetValue(bucket, key, value []byte) error

SetValue saves a single value to the Bolt Database. It does not use the Merkle tree structure, but provides a simple method to store secure information in the same container as the trees

type Tree

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

Tree is how a resource is stored. It represents the top level digest of a Merkle tree.

func (*Tree) AddLeaf

func (t *Tree) AddLeaf(vc ValidationChain, leaf []byte, lIdx int)

AddLeaf will add a validated leaf to a Sapling.

func (*Tree) Complete

func (t *Tree) Complete() bool

Complete returns true if the tree has all it's leaves.

func (*Tree) Digest

func (t *Tree) Digest() *crypto.Digest

Digest gives the Digest that identifies the tree. This can be used to request the tree from a forest.

func (*Tree) GetLeaf

func (t *Tree) GetLeaf(lIdx int) (ValidationChain, []byte, error)

GetLeaf returns the ValidationChain and Leaf for a tree.

func (*Tree) Len

func (t *Tree) Len() int

Len returns the byte size of the tree

func (*Tree) Read

func (t *Tree) Read(p []byte) (int, error)

Read implements the io.Reader interface to allow a tree to be read into a byte slice

func (*Tree) ReadAll

func (t *Tree) ReadAll() ([]byte, error)

ReadAll reads the contents of a tree into a byte slice

func (*Tree) Seek

func (t *Tree) Seek(offset int64, whence int) (int64, error)

Seek implements io.Seeker

func (*Tree) ValidateLeaf

func (t *Tree) ValidateLeaf(vc ValidationChain, leaf []byte, lIdx int) bool

ValidateLeaf uses a ValidationChain to confirm that a leaf belongs to a tree

type ValidationChain

type ValidationChain []*crypto.Digest

ValidationChain is used to validate that a leaf belongs to a tree. It includes all the Uncle digests.

Jump to

Keyboard shortcuts

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