什么是 Merkle Tree
- Merkle(默克尔)树通常又被叫做 Hash 树,该树的名字来源于他的专利作者Ralph Merkle。
- 它是一个非线性的二叉树。
- 该树可用于对大量数据中的内容进行有效且安全的一致性验证,而无需访问整个数据集。
如何构建树
叶子节点:
该叶子节点对应数据的 Hash值。没有固定的hash算法,例如 SHA-256 或者 Keccak 以及 SHA3-256。
非叶子节点:
该节点的所有子节点的 Hash。例如 C 有 A,B两个子节点,那么 C = hash(AB)。
如果某一回合计算出现了奇数个节点,那么将最后一个节点复制一份并与它自己做 Hash.
示例
下面是一个简单的计算 默克尔树根的示例。
package main
import (
"encoding/hex"
"fmt"
"golang.org/x/crypto/sha3"
"math"
)
// HashLength is expected length of hash.
const HashLength = 32
// Hash represents 32 byte SHA3-256 hash of arbitrary data.
type Hash [HashLength]byte
// Bytes gets the byte representation of h.
func (h Hash) Bytes() []byte {
return h[:]
}
// Hex returns the hex representation of h, prefixed with '0x'.
func (h Hash) Hex() string {
enc := make([]byte, len(h)*2+2)
copy(enc, "0x")
hex.Encode(enc[2:], h[:])
return string(enc)
}
// SetBytes sets the h to the value of b.
// if b is larger than len(h), b will be cropped from the left.
func (h *Hash) SetBytes(b []byte) {
if len(b) > len(h) {
b = b[len(b)-HashLength:]
}
copy(h[HashLength-len(b):], b)
}
// sha3-256
func sha3256(h1 Hash, h2 *Hash) (h Hash) {
fn := sha3.New256()
fn.Write(h1[:])
if h2 == nil {
fn.Write(h1[:])
} else {
fn.Write(h2[:])
}
h.SetBytes(fn.Sum(nil))
return
}
// ComputeMerkleRoot computes merkle root of given hashes.
// This will modify the input array, the result at index 0.
func ComputeMerkleRoot(hashes []Hash) {
var i, j, z, l = 0, 0, 0, len(hashes)
arr := hashes
for l > 1 {
for ; i < l; i++ {
var right *Hash
z = i + 1
if z < l {
right = &(arr[z])
}
arr[j] = sha3256(arr[i], right)
fmt.Println(arr[j].Hex())
j++
i = z
}
fmt.Println("---------------------------------------------------------------")
l = int(math.Ceil(float64(l)/2))
i, j = 0, 0
}
}
// newSha3256Hash creates a Hash object with sha3-256(str)
func newSha3256Hash(str string) Hash {
var h Hash
b := sha3.Sum256([]byte(str))
h.SetBytes(b[:])
return h
}
func main() {
hashes := make([]Hash, 5)
hashes[0] = newSha3256Hash("Hello")
hashes[1] = newSha3256Hash("World")
hashes[2] = newSha3256Hash("Merkle")
hashes[3] = newSha3256Hash("Tree")
hashes[4] = newSha3256Hash("Joel")
ComputeMerkleRoot(hashes)
fmt.Println(hashes[0].Hex())
}