github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/merkle/compact_merkle_tree.go (about) 1 // Copyright 2016 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package merkle 16 17 import ( 18 "bytes" 19 "encoding/base64" 20 "encoding/hex" 21 "fmt" 22 "math/bits" 23 24 log "github.com/golang/glog" 25 "github.com/google/trillian/merkle/hashers" 26 ) 27 28 // RootHashMismatchError indicates a unexpected root hash value. 29 type RootHashMismatchError struct { 30 ExpectedHash []byte 31 ActualHash []byte 32 } 33 34 func (r RootHashMismatchError) Error() string { 35 return fmt.Sprintf("root hash mismatch got: %v expected: %v", r.ActualHash, r.ExpectedHash) 36 } 37 38 // CompactMerkleTree is a compact Merkle tree representation. 39 // Uses log(n) nodes to represent the current on-disk tree. 40 type CompactMerkleTree struct { 41 hasher hashers.LogHasher 42 root []byte 43 // the list of "dangling" left-hand nodes, NOTE: index 0 is the leaf, not the root. 44 nodes [][]byte 45 size int64 46 } 47 48 func isPerfectTree(x int64) bool { 49 return x != 0 && (x&(x-1) == 0) 50 } 51 52 // GetNodeFunc is a function prototype which can look up particular nodes within a non-compact Merkle tree. 53 // Used by the CompactMerkleTree to populate itself with correct state when starting up with a non-empty tree. 54 type GetNodeFunc func(depth int, index int64) ([]byte, error) 55 56 // NewCompactMerkleTreeWithState creates a new CompactMerkleTree for the passed in |size|. 57 // This can fail if the nodes required to recreate the tree state cannot be fetched or the calculated 58 // root hash after population does not match the value we expect. 59 // |f| will be called a number of times with the co-ordinates of internal MerkleTree nodes whose hash values are 60 // required to initialize the internal state of the CompactMerkleTree. |expectedRoot| is the known-good tree root 61 // of the tree at |size|, and is used to verify the correct initial state of the CompactMerkleTree after initialisation. 62 func NewCompactMerkleTreeWithState(hasher hashers.LogHasher, size int64, f GetNodeFunc, expectedRoot []byte) (*CompactMerkleTree, error) { 63 sizeBits := bits.Len64(uint64(size)) 64 65 r := CompactMerkleTree{ 66 hasher: hasher, 67 nodes: make([][]byte, sizeBits), 68 root: hasher.EmptyRoot(), 69 size: size, 70 } 71 72 if isPerfectTree(size) { 73 log.V(1).Info("Is perfect tree.") 74 r.root = append(make([]byte, 0, len(expectedRoot)), expectedRoot...) 75 r.nodes[sizeBits-1] = r.root 76 } else { 77 // Pull in the nodes we need to repopulate our compact tree and verify the root 78 for depth := 0; depth < sizeBits; depth++ { 79 if size&1 == 1 { 80 index := size - 1 81 log.V(1).Infof("fetching d: %d i: %d, leaving size %d", depth, index, size) 82 h, err := f(depth, index) 83 if err != nil { 84 log.Warningf("Failed to fetch node depth %d index %d: %s", depth, index, err) 85 return nil, err 86 } 87 r.nodes[depth] = h 88 } 89 size >>= 1 90 } 91 r.recalculateRoot(func(depth int, index int64, hash []byte) error { 92 return nil 93 }) 94 } 95 if !bytes.Equal(r.root, expectedRoot) { 96 log.Warningf("Corrupt state, expected root %s, got %s", hex.EncodeToString(expectedRoot[:]), hex.EncodeToString(r.root[:])) 97 return nil, RootHashMismatchError{ActualHash: r.root, ExpectedHash: expectedRoot} 98 } 99 log.V(1).Infof("Resuming at size %d, with root: %s", r.size, base64.StdEncoding.EncodeToString(r.root[:])) 100 return &r, nil 101 } 102 103 // NewCompactMerkleTree creates a new CompactMerkleTree with size zero. This always succeeds. 104 func NewCompactMerkleTree(hasher hashers.LogHasher) *CompactMerkleTree { 105 r := CompactMerkleTree{ 106 hasher: hasher, 107 root: hasher.EmptyRoot(), 108 nodes: make([][]byte, 0), 109 size: 0, 110 } 111 return &r 112 } 113 114 // CurrentRoot returns the current root hash. 115 func (c CompactMerkleTree) CurrentRoot() []byte { 116 return c.root 117 } 118 119 // DumpNodes logs the internal state of the CompactMerkleTree, and is used for debugging. 120 func (c CompactMerkleTree) DumpNodes() { 121 log.Infof("Tree Nodes @ %d", c.size) 122 mask := int64(1) 123 numBits := bits.Len64(uint64(c.size)) 124 for bit := 0; bit < numBits; bit++ { 125 if c.size&mask != 0 { 126 log.Infof("%d: %s", bit, base64.StdEncoding.EncodeToString(c.nodes[bit][:])) 127 } else { 128 log.Infof("%d: -", bit) 129 } 130 mask <<= 1 131 } 132 } 133 134 type setNodeFunc func(depth int, index int64, hash []byte) error 135 136 func (c *CompactMerkleTree) recalculateRoot(f setNodeFunc) error { 137 if c.size == 0 { 138 return nil 139 } 140 141 index := c.size 142 143 var newRoot []byte 144 first := true 145 mask := int64(1) 146 numBits := bits.Len64(uint64(c.size)) 147 for bit := 0; bit < numBits; bit++ { 148 index >>= 1 149 if c.size&mask != 0 { 150 if first { 151 newRoot = c.nodes[bit] 152 first = false 153 } else { 154 newRoot = c.hasher.HashChildren(c.nodes[bit], newRoot) 155 if err := f(bit+1, index, newRoot); err != nil { 156 return err 157 } 158 } 159 } 160 mask <<= 1 161 } 162 c.root = newRoot 163 return nil 164 } 165 166 // AddLeaf calculates the leafhash of |data| and appends it to the tree. 167 // |f| is a callback which will be called multiple times with the full MerkleTree coordinates of nodes whose hash should be updated. 168 func (c *CompactMerkleTree) AddLeaf(data []byte, f setNodeFunc) (int64, []byte, error) { 169 h, err := c.hasher.HashLeaf(data) 170 if err != nil { 171 return 0, nil, err 172 } 173 seq, err := c.AddLeafHash(h, f) 174 if err != nil { 175 return 0, nil, err 176 } 177 return seq, h, err 178 } 179 180 // AddLeafHash adds the specified |leafHash| to the tree. 181 // |f| is a callback which will be called multiple times with the full MerkleTree coordinates of nodes whose hash should be updated. 182 func (c *CompactMerkleTree) AddLeafHash(leafHash []byte, f setNodeFunc) (int64, error) { 183 defer func() { 184 c.size++ 185 // TODO(al): do this lazily 186 c.recalculateRoot(f) 187 }() 188 189 assignedSeq := c.size 190 index := assignedSeq 191 192 if err := f(0, index, leafHash); err != nil { 193 return 0, err 194 } 195 196 if c.size == 0 { 197 // new tree 198 c.nodes = append(c.nodes, leafHash) 199 return assignedSeq, nil 200 } 201 202 // Initialize our running hash value to the leaf hash 203 hash := leafHash 204 bit := 0 205 // Iterate over the bits in our tree size 206 for t := c.size; t > 0; t >>= 1 { 207 index >>= 1 208 if t&1 == 0 { 209 // Just store the running hash here; we're done. 210 c.nodes[bit] = hash 211 // Don't re-write the leaf hash node (we've done it above already) 212 if bit > 0 { 213 // Store the leaf hash node 214 if err := f(bit, index, hash); err != nil { 215 return 0, err 216 } 217 } 218 return assignedSeq, nil 219 } 220 // The bit is set so we have a node at that position in the nodes list so hash it with our running hash: 221 hash = c.hasher.HashChildren(c.nodes[bit], hash) 222 // Store the resulting parent hash. 223 if err := f(bit+1, index, hash); err != nil { 224 return 0, err 225 } 226 // Now, clear this position in the nodes list as the hash it formerly contained will be propagated upwards. 227 c.nodes[bit] = nil 228 // Figure out if we're done: 229 if bit+1 >= len(c.nodes) { 230 // If we're extending the node list then add a new entry with our 231 // running hash, and we're done. 232 c.nodes = append(c.nodes, hash) 233 return assignedSeq, nil 234 } else if t&0x02 == 0 { 235 // If the node above us is unused at this tree size, then store our 236 // running hash there, and we're done. 237 c.nodes[bit+1] = hash 238 return assignedSeq, nil 239 } 240 // Otherwise, go around again. 241 bit++ 242 } 243 // We should never get here, because that'd mean we had a running hash which 244 // we've not stored somewhere. 245 return 0, fmt.Errorf("AddLeaf failed running hash not cleared: h: %v seq: %d", leafHash, assignedSeq) 246 } 247 248 // Size returns the current size of the tree, that is, the number of leaves ever added to the tree. 249 func (c CompactMerkleTree) Size() int64 { 250 return c.size 251 } 252 253 // Hashes returns a copy of the set of node hashes that comprise the compact representation of the tree. 254 func (c CompactMerkleTree) Hashes() [][]byte { 255 if isPerfectTree(c.size) { 256 return nil 257 } 258 n := make([][]byte, len(c.nodes)) 259 copy(n, c.nodes) 260 return n 261 } 262 263 // Depth returns the number of levels in the tree. 264 func (c CompactMerkleTree) Depth() int { 265 if c.size == 0 { 266 return 0 267 } 268 return bits.Len64(uint64(c.size - 1)) 269 }