tendermint/crypto/merkle/simple_tree.go

79 lines
1.7 KiB
Go
Raw Normal View History

2018-06-20 15:30:44 -07:00
package merkle
import (
2018-08-16 08:52:59 -07:00
"math/bits"
"github.com/tendermint/tendermint/crypto/tmhash"
2018-06-20 15:30:44 -07:00
)
// SimpleHashFromTwoHashes is the basic operation of the Merkle tree: Hash(left | right).
func SimpleHashFromTwoHashes(left, right []byte) []byte {
var hasher = tmhash.New()
_, err := hasher.Write(InnerHashPrefix)
2018-08-16 08:52:59 -07:00
if err != nil {
panic(err)
}
_, err = hasher.Write(left)
2018-06-20 15:30:44 -07:00
if err != nil {
panic(err)
}
2018-08-16 08:52:59 -07:00
_, err = hasher.Write(right)
2018-06-20 15:30:44 -07:00
if err != nil {
panic(err)
}
2018-06-20 15:30:44 -07:00
return hasher.Sum(nil)
}
2018-08-16 08:52:59 -07:00
// SimpleHashFromByteSlices computes a Merkle tree from items that are byte slices.
func SimpleHashFromByteSlices(items [][]byte) []byte {
2018-06-20 15:30:44 -07:00
hashes := make([][]byte, len(items))
for i, item := range items {
2018-08-16 08:52:59 -07:00
hash := tmhash.Sum(append([]byte{0}, item...))
2018-06-20 15:30:44 -07:00
hashes[i] = hash
}
return simpleHashFromHashes(hashes)
}
// SimpleHashFromMap computes a Merkle tree from sorted map.
// Like calling SimpleHashFromHashers with
// `item = []byte(Hash(key) | Hash(value))`,
// sorted by `item`.
func SimpleHashFromMap(m map[string]Hasher) []byte {
sm := newSimpleMap()
for k, v := range m {
sm.Set(k, v)
}
return sm.Hash()
}
//----------------------------------------------------------------
// Expects hashes!
func simpleHashFromHashes(hashes [][]byte) []byte {
// Recursive impl.
switch len(hashes) {
case 0:
return nil
case 1:
return hashes[0]
default:
2018-08-16 08:52:59 -07:00
k := getSplitPoint(len(hashes))
left := simpleHashFromHashes(hashes[:k])
right := simpleHashFromHashes(hashes[k:])
2018-06-20 15:30:44 -07:00
return SimpleHashFromTwoHashes(left, right)
}
}
2018-08-16 08:52:59 -07:00
func getSplitPoint(length int) int {
if length < 1 {
panic("Trying to split a tree with size < 1")
}
uLength := uint(length)
bitlen := bits.Len(uLength)
k := 1 << uint(bitlen-1)
if k == length {
k >>= 1
}
return k
}