github.com/dusk-network/dusk-crypto@v0.1.3/merkletree/merkletree.go (about)

     1  package merkletree
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  
     7  	"github.com/dusk-network/dusk-crypto/hash"
     8  )
     9  
    10  // Payload is data that can be stored and checked in the Merkletree.
    11  // Types implementing this interface can be items of the Merkletree
    12  type Payload interface {
    13  	CalculateHash() ([]byte, error)
    14  }
    15  
    16  // Tree struct representing the merkletree data structure.
    17  // It includes a pointer to the Root of the tree, list of pointers to the Leaves and the MerkleRoot
    18  type Tree struct {
    19  	Root       *Node
    20  	MerkleRoot []byte
    21  	Leaves     []*Node
    22  }
    23  
    24  // Node of the Merkletree which includes pointers to the Parent, the immediate Left and Right children
    25  // and whether it is a leaf or not
    26  type Node struct {
    27  	Parent *Node
    28  	Left   *Node
    29  	Right  *Node
    30  	Hash   []byte
    31  	Data   Payload
    32  	IsLeaf bool
    33  	IsDup  bool
    34  }
    35  
    36  // VerifyNode calculates the hash of each level until hitting a leaf.
    37  // It returns the Hash of Node n
    38  func VerifyNode(n *Node) ([]byte, error) {
    39  	if n.IsLeaf {
    40  		return n.Data.CalculateHash()
    41  	}
    42  
    43  	rightBytes, err := VerifyNode(n.Right)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	leftBytes, err := VerifyNode(n.Left)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	return hash.Sha3256(append(leftBytes, rightBytes...))
    54  }
    55  
    56  // CalculateNodeHash is a helper function for calculating the hash of a node
    57  func CalculateNodeHash(n *Node) ([]byte, error) {
    58  	if n.IsLeaf {
    59  		return n.Data.CalculateHash()
    60  	}
    61  
    62  	return hash.Sha3256(append(n.Left.Hash, n.Right.Hash...))
    63  }
    64  
    65  // NewTree constructs a merkletree using the Payload/Content pl
    66  func NewTree(pl []Payload) (*Tree, error) {
    67  	root, leaves, err := create(pl)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	return &Tree{
    73  		Root:       root,
    74  		MerkleRoot: root.Hash,
    75  		Leaves:     leaves,
    76  	}, nil
    77  }
    78  
    79  // create is the helper to map the Payload array recursively into a Hash tree with a root and a set of leaf nodes
    80  // returns an error if the Payload array is empty
    81  func create(pl []Payload) (*Node, []*Node, error) {
    82  	if len(pl) == 0 {
    83  		return nil, nil, errors.New("cannot construct tree with no content")
    84  	}
    85  
    86  	var leaves []*Node
    87  	for _, payload := range pl {
    88  		h, err := payload.CalculateHash()
    89  		if err != nil {
    90  			return nil, nil, err
    91  		}
    92  
    93  		leaves = append(leaves, &Node{
    94  			Data:   payload,
    95  			Hash:   h,
    96  			IsLeaf: true,
    97  		})
    98  	}
    99  
   100  	if len(leaves)%2 == 1 {
   101  		previous := leaves[len(leaves)-1]
   102  		duplicate := &Node{
   103  			Hash:   previous.Hash,
   104  			Data:   previous.Data,
   105  			IsLeaf: true,
   106  			IsDup:  true,
   107  		}
   108  		leaves = append(leaves, duplicate)
   109  	}
   110  
   111  	root, err := createIntermediate(leaves)
   112  	if err != nil {
   113  		return nil, nil, err
   114  	}
   115  	return root, leaves, nil
   116  }
   117  
   118  // createIntermediate is the helper function that for a set of leafs nodes, recursively builds the intermediate and root level of a Tree. Returns the resulting root node
   119  func createIntermediate(nl []*Node) (*Node, error) {
   120  	var nodes []*Node
   121  	for i := 0; i < len(nl); i += 2 {
   122  		var left, right int = i, i + 1
   123  		if i+1 == len(nl) {
   124  			right = i
   125  		}
   126  		payloadHash := append(nl[left].Hash, nl[right].Hash...)
   127  
   128  		h, err := hash.Sha3256(payloadHash)
   129  		if err != nil {
   130  			return nil, err
   131  		}
   132  
   133  		node := &Node{
   134  			Left:  nl[left],
   135  			Right: nl[right],
   136  			Hash:  h,
   137  		}
   138  
   139  		nodes = append(nodes, node)
   140  		nl[left].Parent = node
   141  		nl[right].Parent = node
   142  
   143  		if len(nl) == 2 {
   144  			return node, nil
   145  		}
   146  	}
   147  
   148  	return createIntermediate(nodes)
   149  }
   150  
   151  // RebuildTree is a helper method to rebuild a Tree with only the Data contained in the leafs
   152  func (t *Tree) RebuildTree() error {
   153  	var pl []Payload
   154  	for _, node := range t.Leaves {
   155  		pl = append(pl, node.Data)
   156  	}
   157  
   158  	return t.RebuildTreeUsing(pl)
   159  }
   160  
   161  // RebuildTreeUsing is a helper method to replace the Data in the Markletree and rebuild the Tree entirely
   162  // The root gets replaced but the Merkletree survives the operation
   163  // Returns an error if there is no payload
   164  func (t *Tree) RebuildTreeUsing(pl []Payload) error {
   165  	root, leaves, err := create(pl)
   166  	if err != nil {
   167  		return err
   168  	}
   169  
   170  	t.Root = root
   171  	t.Leaves = leaves
   172  	t.MerkleRoot = root.Hash
   173  	return nil
   174  }
   175  
   176  // VerifyTree Verifies each Node's hash and check if the resulted root hash is correct compared to the reported root hash of the merkle tree
   177  func VerifyTree(t *Tree) (bool, error) {
   178  	calculatedRoot, err := VerifyNode(t.Root)
   179  	if err != nil {
   180  		return false, err
   181  	}
   182  
   183  	if bytes.Compare(t.MerkleRoot, calculatedRoot) == 0 {
   184  		return true, nil
   185  	}
   186  
   187  	return false, nil
   188  }
   189  
   190  //VerifyContent verifies whether a piece of data is in the merkle tree
   191  func (t *Tree) VerifyContent(data Payload) (bool, error) {
   192  	for _, leaf := range t.Leaves {
   193  		ok, err := equals(leaf.Data, data)
   194  		if err != nil {
   195  			return false, err
   196  		}
   197  
   198  		if ok {
   199  			currentParent := leaf.Parent
   200  			for currentParent != nil {
   201  				rightBytes, err := CalculateNodeHash(currentParent.Right)
   202  				if err != nil {
   203  					return false, err
   204  				}
   205  
   206  				leftBytes, err := CalculateNodeHash(currentParent.Left)
   207  				if err != nil {
   208  					return false, err
   209  				}
   210  
   211  				h, err := hash.Sha3256(append(leftBytes, rightBytes...))
   212  
   213  				if err != nil {
   214  					return false, err
   215  				}
   216  
   217  				if bytes.Compare(h, currentParent.Hash) != 0 {
   218  					return false, nil
   219  				}
   220  
   221  				currentParent = currentParent.Parent
   222  			}
   223  
   224  			return true, nil
   225  		}
   226  	}
   227  
   228  	return false, nil
   229  }
   230  
   231  // equals returns true, if two payloads hash to the same value
   232  func equals(a, b Payload) (bool, error) {
   233  	hashA, err := a.CalculateHash()
   234  	if err != nil {
   235  		return false, err
   236  	}
   237  	hashB, err := b.CalculateHash()
   238  	if err != nil {
   239  		return false, err
   240  	}
   241  
   242  	return bytes.Equal(hashA, hashB), nil
   243  }