Golang实现默克尔树(merkle tree)
什么是默克尔树??
默克尔树是一种哈希二叉树,1979年由RalphMerkle发明。哈希树可以用来验证任何一种在计算机中和计算机之间存储、处理和传输的数据。它们可以确保在点对点网络中数据传输的速度不受影响,数据跨越自由的通过任意媒介,且没有损坏,也没有改变。
Merkle树结构简单来说,哈希树(默克尔树)中,每个节点都标有一个数据块的加密哈希值。
- 一个根节点(root)
- 一组中间节点
- 一组叶节点(leaf)组成
叶节点(leaf)包含存储数据或其哈希值,中间节点是它的两个子节点内容的哈希值,根节点也是由它的两个子节点内容的哈希值组成。所以Merkle树也称哈希树。
默克尔树 哈希树的特点任意底层数据的任何变动,都会传递到其父节点,一直到树根。因此只需要判断Hash Root是否一致,就可以判断整个数据书否一致。
因此,在区块链系统中,区块头只需要封装默克尔根(也就是Hash Root),通过对默克尔根的比对,从而验证区块交易数据是否一致。 极大的提升了数据校验的效率。
Golang实现默克尔树完整代码已发布至 https://github.com/wk331100/MerkleTree,可使用go get github.com/wk331100/MerkleTree
获取代码库。
package merkleTree
import (
"bytes"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"errors"
"hash"
"math"
)
const (
errEmptyData = "empty data"
)
// MerkleTree 默克尔树
type MerkleTree struct {
Root *Node
Leaves []*Node
hashHandler func() hash.Hash
}
// Node 节点
type Node struct {
Parent *Node
Left *Node
Right *Node
leaf bool
single bool
Hash []byte
Data []byte
}
// GetRootHash 获取默克尔树根Hash
func (m *MerkleTree) GetRootHash() []byte {
return m.Root.Hash
}
// NewMerkleTree 创建一个新的 默克尔树
func NewMerkleTree(hashType string, data [][]byte) (*MerkleTree, error) {
mk := &MerkleTree{}
mk.hashHandler = mk.buildHash(hashType)
root, leaves, err := mk.buildMerkleTreeRoot(data)
if err != nil {
return nil, err
}
mk.Root = root
mk.Leaves = leaves
return mk, nil
}
// VerifyData 验证数据是否在默克尔树中
func (m *MerkleTree) VerifyData(data []byte) (bool, error) {
dataHash := m.calHash(data)
for _, leaf := range m.Leaves {
if bytes.Compare(dataHash, leaf.Hash) == 0 {
return true, nil
}
}
return false, nil
}
// VerifyTree 验证默克尔树Hash
func (m *MerkleTree) VerifyTree() (bool, error) {
calRoot, err := m.Root.verifyNode(m)
if err != nil {
return false, err
}
if bytes.Compare(calRoot, m.Root.Hash) == 0 {
return true, nil
}
return false, err
}
// verifyNode 重新计算节点Hash
func (n *Node) verifyNode(mk *MerkleTree) ([]byte, error) {
if n.leaf {
return mk.calHash(n.Data), nil
}
leftNodeHash, err := n.Left.verifyNode(mk)
if err != nil {
return nil, err
}
rightNodeHash, err := n.Right.verifyNode(mk)
if err != nil {
return nil, err
}
return mk.calHash(append(leftNodeHash, rightNodeHash...)), nil
}
// buildMerkleTree 构建 默克尔树 节点
func (m *MerkleTree) buildMerkleTreeRoot(data [][]byte) (*Node, []*Node, error) {
if len(data) <= 0 {
return nil, nil, errors.New(errEmptyData)
}
leaf := m.buildMerkleTreeLeaf(data)
root, err := m.buildMerkleTreeNode(leaf)
return root, leaf, err
}
// buildMerkleTreeNode 构建 默克尔树 中间节点
func (m *MerkleTree) buildMerkleTreeNode(nodes []*Node) (*Node, error) {
length := int(math.Ceil(float64(len(nodes)) / 2))
var nodeSlice []*Node
var single bool
for i := 0; i < length; i++ {
leftNode := nodes[i*2]
var rightNode = new(Node)
if i*2+1 < len(nodes) {
rightNode = nodes[i*2+1]
} else {
single = true
}
node := &Node{
Parent: nil,
Left: leftNode,
Right: rightNode,
leaf: false,
single: single,
Hash: nil,
Data: nil,
}
// 将两个子节点Hash拼接后,计算自身Hash
if !single {
leftNode.Hash = append(leftNode.Hash, rightNode.Hash...)
}
node.Hash = m.calHash(leftNode.Hash)
// 将当前节点设置为 两个子节点的父节点
nodes[i*2].Parent = node
nodes[i*2+1].Parent = node
nodeSlice = append(nodeSlice, node)
}
if len(nodeSlice) > 1 {
return m.buildMerkleTreeNode(nodeSlice)
}
return nodeSlice[0], nil
}
// buildMerkleTreeLeaf 构建 默克尔树 叶节点
func (m *MerkleTree) buildMerkleTreeLeaf(data [][]byte) []*Node {
var leaf []*Node
for _, item := range data {
node := &Node{
Parent: nil,
Left: nil,
Right: nil,
leaf: true,
single: false,
Hash: m.calHash(item),
Data: item,
}
leaf = append(leaf, node)
}
return leaf
}
// buildHash 根据Hash类型,构建Hash
func (m *MerkleTree) buildHash(hashType string) func() hash.Hash {
switch hashType {
case "md5":
return md5.New
case "sha1":
return sha1.New
case "sha256":
return sha256.New
case "sha512":
return sha512.New
default:
return sha1.New
}
}
func (m *MerkleTree) calHash(data []byte) []byte {
hashHandler := m.hashHandler()
hashHandler.Write(data)
return hashHandler.Sum(nil)
}
单测及结果 package merkleTree
import (
"encoding/json"
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
var (
testData []byte
testHash []byte
)
func TestMerkleTree(t *testing.T) {
data := initData()
mk, err := NewMerkleTree("md5", data)
require.Nil(t, err)
fmt.Sprintf("%x", mk.GetRootHash())
printHash(mk)
res, _ := mk.VerifyData(testData)
require.True(t, res)
res2, _ := mk.VerifyTree()
require.True(t, res2)
}
func printHash(mk *MerkleTree) {
if mk.Root.leaf {
return
}
cyclePrint(mk.Root)
}
func cyclePrint(node *Node) {
if node.leaf {
fmt.Println(fmt.Sprintf("Leaf: hash[%x], data[%s], leaf[%v]\n", node.Hash, node.Data, node.leaf))
} else {
fmt.Println(fmt.Sprintf("Node: hash[%x], data[%s], leaf[%v]\n", node.Hash, node.Data, node.leaf))
}
if node.Left != nil {
cyclePrint(node.Left)
}
if node.Right != nil {
cyclePrint(node.Right)
}
}
func TestBuildMerkleTreeLeaf(t *testing.T) {
m := &MerkleTree{}
data := initData()
m.hashHandler = m.buildHash("sha256")
leaf := m.buildMerkleTreeLeaf(data)
fmt.Println(leaf)
}
func initData() [][]byte {
var data [][]byte
for i := 0; i < 4; i++ {
str := fmt.Sprintf("test data %d", i)
bz, _ := json.Marshal(str)
if i == 3 {
testData = bz
}
data = append(data, bz)
}
return data
}
结果
=== RUN TestMerkleTree
Node: hash[3c95e6ec5965e5c1b797709a8e649c14], data[], leaf[false]
Node: hash[e1c340b19bee346c95fe9ef64ad992e09820b47149a1893754e7557b0d7fdb13], data[], leaf[false]
Leaf: hash[56f0aade6664b4bf7ef30ab6de77ecd1481cf84fb2f19c94e04293027b39ad90], data["test data 0"], leaf[true]
Leaf: hash[481cf84fb2f19c94e04293027b39ad90], data["test data 1"], leaf[true]
Node: hash[9820b47149a1893754e7557b0d7fdb13], data[], leaf[false]
Leaf: hash[3381b0b53c7f1e8bb44d469dec35051565997690d1ade051def10b273ae49fe5], data["test data 2"], leaf[true]
Leaf: hash[65997690d1ade051def10b273ae49fe5], data["test data 3"], leaf[true]
--- PASS: TestMerkleTree (0.00s)
PASS
原文地址:https://cloud.tencent.com/developer/article/2137259
版权声明
本文仅代表作者观点,不代表xx立场。
本文系作者授权xx发表,未经许可,不得转载。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。