arnaucube
arnaucube/go-merkletree-iden3Public Self-hosted repository
go-merkletree-iden3/node.go
node.goRaw
  1package merkletree
  2
  3import (
  4	"fmt"
  5	"math/big"
  6)
  7
  8// NodeType defines the type of node in the MT.
  9type NodeType byte
 10
 11const (
 12	// NodeTypeMiddle indicates the type of middle Node that has children.
 13	NodeTypeMiddle NodeType = 0
 14	// NodeTypeLeaf indicates the type of a leaf Node that contains a claim.
 15	NodeTypeLeaf NodeType = 1
 16	// NodeTypeEmpty indicates the type of an empty Node.
 17	NodeTypeEmpty NodeType = 2
 18
 19	// DBEntryTypeRoot indicates the type of a DB entry that indicates the current Root of a MerkleTree
 20	DBEntryTypeRoot NodeType = 3
 21)
 22
 23// Node is the struct that represents a node in the MT. The node should not be
 24// modified after creation because the cached key won't be updated.
 25type Node struct {
 26	// Type is the type of node in the tree.
 27	Type NodeType
 28	// ChildL is the left child of a middle node.
 29	ChildL *Hash
 30	// ChildR is the right child of a middle node.
 31	ChildR *Hash
 32	// Entry is the data stored in a leaf node.
 33	Entry [2]*Hash
 34	// key is a cache used to avoid recalculating key
 35	key *Hash
 36}
 37
 38// NewNodeLeaf creates a new leaf node.
 39func NewNodeLeaf(k, v *Hash) *Node {
 40	return &Node{Type: NodeTypeLeaf, Entry: [2]*Hash{k, v}}
 41}
 42
 43// NewNodeMiddle creates a new middle node.
 44func NewNodeMiddle(childL *Hash, childR *Hash) *Node {
 45	return &Node{Type: NodeTypeMiddle, ChildL: childL, ChildR: childR}
 46}
 47
 48// NewNodeEmpty creates a new empty node.
 49func NewNodeEmpty() *Node {
 50	return &Node{Type: NodeTypeEmpty}
 51}
 52
 53// NewNodeFromBytes creates a new node by parsing the input []byte.
 54func NewNodeFromBytes(b []byte) (*Node, error) {
 55	if len(b) < 1 {
 56		return nil, ErrNodeDataBadSize
 57	}
 58	n := Node{Type: NodeType(b[0])}
 59	b = b[1:]
 60	switch n.Type {
 61	case NodeTypeMiddle:
 62		if len(b) != 2*ElemBytesLen {
 63			return nil, ErrNodeDataBadSize
 64		}
 65		n.ChildL, n.ChildR = &Hash{}, &Hash{}
 66		copy(n.ChildL[:], b[:ElemBytesLen])
 67		copy(n.ChildR[:], b[ElemBytesLen:ElemBytesLen*2])
 68	case NodeTypeLeaf:
 69		if len(b) != 2*ElemBytesLen {
 70			return nil, ErrNodeDataBadSize
 71		}
 72		n.Entry = [2]*Hash{{}, {}}
 73		copy(n.Entry[0][:], b[0:32])
 74		copy(n.Entry[1][:], b[32:64])
 75	case NodeTypeEmpty:
 76		break
 77	default:
 78		return nil, ErrInvalidNodeFound
 79	}
 80	return &n, nil
 81}
 82
 83// LeafKey computes the key of a leaf node given the hIndex and hValue of the
 84// entry of the leaf.
 85func LeafKey(k, v *Hash) (*Hash, error) {
 86	return HashElemsKey(big.NewInt(1), k.BigInt(), v.BigInt())
 87}
 88
 89// Key computes the key of the node by hashing the content in a specific way
 90// for each type of node.  This key is used as the hash of the merklee tree for
 91// each node.
 92func (n *Node) Key() (*Hash, error) {
 93	if n.key == nil { // Cache the key to avoid repeated hash computations.
 94		// NOTE: We are not using the type to calculate the hash!
 95		switch n.Type {
 96		case NodeTypeMiddle: // H(ChildL || ChildR)
 97			var err error
 98			n.key, err = HashElems(n.ChildL.BigInt(), n.ChildR.BigInt())
 99			if err != nil {
100				return nil, err
101			}
102		case NodeTypeLeaf:
103			var err error
104			n.key, err = LeafKey(n.Entry[0], n.Entry[1])
105			if err != nil {
106				return nil, err
107			}
108		case NodeTypeEmpty: // Zero
109			n.key = &HashZero
110		default:
111			n.key = &HashZero
112		}
113	}
114	return n.key, nil
115}
116
117// Value returns the value of the node.  This is the content that is stored in the backend database.
118func (n *Node) Value() []byte {
119	switch n.Type {
120	case NodeTypeMiddle: // {Type || ChildL || ChildR}
121		return append([]byte{byte(n.Type)}, append(n.ChildL[:], n.ChildR[:]...)...)
122	case NodeTypeLeaf: // {Type || Data...}
123		return append([]byte{byte(n.Type)}, append(n.Entry[0][:], n.Entry[1][:]...)...)
124	case NodeTypeEmpty: // {}
125		return []byte{}
126	default:
127		return []byte{}
128	}
129}
130
131// String outputs a string representation of a node (different for each type).
132func (n *Node) String() string {
133	switch n.Type {
134	case NodeTypeMiddle: // {Type || ChildL || ChildR}
135		return fmt.Sprintf("Middle L:%s R:%s", n.ChildL, n.ChildR)
136	case NodeTypeLeaf: // {Type || Data...}
137		return fmt.Sprintf("Leaf I:%v D:%v", n.Entry[0], n.Entry[1])
138	case NodeTypeEmpty: // {}
139		return "Empty"
140	default:
141		return "Invalid Node"
142	}
143}