Merkle树

Merkle Tree,通常也被称作Hash Tree,顾名思义,就是存储hash值的一棵树。Merkle树是一种数据结构,Merkle树的叶子是数据块(例如,文件或者文件的集合)的hash值。非叶节点是其对应子节点串联字符串的hash。


image

对于网站中的交易: https://www.blockchain.com/btc/block/000000000001741120135274584b2a0da45b39c8cc78322a14f9004ae766a8e0

第一笔hash:
16f0eb42cb4d9c2374b2cb1de4008162c06fdd8f1c18357f0c849eb423672f5f
大小端转换为:
5f2f6723b49e840c7f35181c8fdd6fc0628100e41dcbb274239c4dcb42ebf016

第二笔hash:
cce2f95fc282b3f2bc956f61d6924f73d658a1fdbc71027dd40b06c15822e061
大小端转换为:
61e02258c1060bd47d0271bcfda158d6734f92d6616f95bcf2b382c25ff9e2cc

将两个拼接在一起:
5f2f6723b49e840c7f35181c8fdd6fc0628100e41dcbb274239c4dcb42ebf01661e02258c1060bd47d0271bcfda158d6734f92d6616f95bcf2b382c25ff9e2cc

将上面拼接的字符串进行两次hash如下:

第一次hash结果:
9b2ec096d49fee8b310752082d63d8fe198386ae2172d90533d9186bb28df63d

将上面计算出的hash值再次进行hash:
525894ddd0891b36c5ff8658e2a978d615b35ce6dedb5cb83f2420dbcd40a0c7

大小端转换即为结果:
c7a040cddb20243fb85cdbdee65cb315d678a9e25886ffc5361b89d0dd945852
package main

import (
    "encoding/hex"
    "crypto/sha256"
    "fmt"
)




func ReverseBytes2(data []byte){
    for i,j :=0,len(data) - 1;i<j;i,j = i+1,j - 1{
        data[i],data[j] = data[j],data[i]
    }
}

func main(){


    //字符串hash转换为字节
    hash1,_:=  hex.DecodeString("16f0eb42cb4d9c2374b2cb1de4008162c06fdd8f1c18357f0c849eb423672f5f")

    hash2,_:=  hex.DecodeString("cce2f95fc282b3f2bc956f61d6924f73d658a1fdbc71027dd40b06c15822e061")

    //大小端的转换
    ReverseBytes2(hash1)

    ReverseBytes2(hash2)

    //拼接在一起
    rawdata:=append(hash1,hash2...)
    //double hash256
    firsthash:=sha256.Sum256(rawdata)
    secondhash:= sha256.Sum256(firsthash[:])
    merkroot := secondhash[:]

    //反转,与浏览器当中的数据对比
    ReverseBytes2(merkroot)

    fmt.Printf("%x",merkroot)


}

merkle树实战

func min(a int,b int) int{

    if(a>b){
        return b
    }
    return a
}


//默克尔树节点
type MerkleTree struct{
    RootNode *MerkleNode
}

//默克尔根节点
type MerkleNode struct{
    Left *MerkleNode
    Right *MerkleNode
    Data []byte
}
//生成默克尔树中的节点,如果是叶子节点,则Left,right为nil ,如果为非叶子节点,根据Left,right生成当前节点的hash
func NewMerkleNode(left,right *MerkleNode,data []byte) *MerkleNode{
    mnode := MerkleNode{}

    if left ==nil && right==nil{
        mnode.Data = data
    }else{
        prevhashes := append(left.Data,right.Data...)
        firsthash:= sha256.Sum256(prevhashes)
        hash:=sha256.Sum256(firsthash[:])
        mnode.Data = hash[:]
    }

    mnode.Left = left
    mnode.Right = right

    return &mnode
}

//构建默克尔树
func NewMerkleTree(data [][]byte) *MerkleTree{
    var nodes []MerkleNode
    //构建叶子节点。
    for _,datum := range data{
        node:= NewMerkleNode(nil,nil,datum)
        nodes =  append(nodes,*node)
    }
    //j代表的是某一层的第一个元素
    j:=0
    //第一层循环代表 nSize代表某一层的个数,每循环一次减半
    for nSize :=len(data);nSize >1;nSize = (nSize+1)/2{
        //第二条循环i+=2代表两两拼接。 i2是为了当个数是基数的时候,拷贝最后的元素。
            for i:=0 ; i<nSize ;i+=2{
                i2 := min(i+1,nSize-1)

                node := NewMerkleNode(&nodes[j+i],&nodes[j+i2],nil)
                nodes = append(nodes,*node)
            }
        //j代表的是某一层的第一个元素
            j+=nSize

    }

    mTree := MerkleTree{&(nodes[len(nodes)-1])}
    return &mTree
}


全部代码

package main

import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"
)


func min(a int,b int) int{

    if(a>b){
        return b
    }
    return a
}


//默克尔树节点
type MerkleTree struct{
    RootNode *MerkleNode
}

//默克尔根节点
type MerkleNode struct{
    Left *MerkleNode
    Right *MerkleNode
    Data []byte
}
//生成默克尔树中的节点,如果是叶子节点,则Left,right为nil ,如果为非叶子节点,根据Left,right生成当前节点的hash
func NewMerkleNode(left,right *MerkleNode,data []byte) *MerkleNode{
    mnode := MerkleNode{}

    if left ==nil && right==nil{
        mnode.Data = data
    }else{
        prevhashes := append(left.Data,right.Data...)
        firsthash:= sha256.Sum256(prevhashes)
        hash:=sha256.Sum256(firsthash[:])
        mnode.Data = hash[:]
    }

    mnode.Left = left
    mnode.Right = right

    return &mnode
}

//构建默克尔树
func NewMerkleTree(data [][]byte) *MerkleTree{
    var nodes []MerkleNode
    //构建叶子节点。
    for _,datum := range data{
        node:= NewMerkleNode(nil,nil,datum)
        nodes =  append(nodes,*node)
    }
    //j代表的是某一层的第一个元素
    j:=0
    //第一层循环代表 nSize代表某一层的个数,每循环一次减半
    for nSize :=len(data);nSize >1;nSize = (nSize+1)/2{
        //第二条循环i+=2代表两两拼接。 i2是为了当个数是基数的时候,拷贝最后的元素。
            for i:=0 ; i<nSize ;i+=2{
                i2 := min(i+1,nSize-1)

                node := NewMerkleNode(&nodes[j+i],&nodes[j+i2],nil)
                nodes = append(nodes,*node)
            }
        //j代表的是某一层的第一个元素
            j+=nSize

    }

    mTree := MerkleTree{&(nodes[len(nodes)-1])}
    return &mTree
}


func ReverseBytes3(data []byte){
    for i,j :=0,len(data) - 1;i<j;i,j = i+1,j - 1{
        data[i],data[j] = data[j],data[i]
    }
}

func main(){
    //测试网站下的5个hash是否能够生成merkleRoot
    //https://www.blockchain.com/btc/block/00000000000090ff2791fe41d80509af6ffbd6c5b10294e29cdf1b603acab92c
    //传递hash
    data1,_:=hex.DecodeString("6b6a4236fb06fead0f1bd7fc4f4de123796eb51675fb55dc18c33fe12e33169d")
    data2,_:=hex.DecodeString("2af6b6f6bc6e613049637e32b1809dd767c72f912fef2b978992c6408483d77e")
    data3,_:=hex.DecodeString("6d76d15213c11fcbf4cc7e880f34c35dae43f8081ef30c6901f513ce41374583")
    data4,_:=hex.DecodeString("08c3b50053b010542dca85594af182f8fcf2f0d2bfe8a806e9494e4792222ad2")
    data5,_:=hex.DecodeString("612d035670b7b9dad50f987dfa000a5324ecb3e08745cfefa10a4cefc5544553")

    //大小段转换
    ReverseBytes3(data1)
    ReverseBytes3(data2)
    ReverseBytes3(data3)
    ReverseBytes3(data4)
    ReverseBytes3(data5)

    hehe := [][]byte{
        data1,
        data2,
        data3,
        data4,
        data5,
    }
    //生成默克尔树
    merleroot:= NewMerkleTree(hehe)
    //反转
    ReverseBytes3(merleroot.RootNode.Data)
    fmt.Printf("%x",merleroot.RootNode.Data)

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352