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 }