工作量证明及哈希算法
什么是工作量证明:
1、工作的结果作为数据加入区块链成为一个区块
2、完成这个工作的人会获得奖励(这也就是通过挖矿获得比特币)
3、整个“努力工作并进行证明”的机制,就叫工作量证明
为什么采用哈希算法:
1、不可逆:无法从一个哈希值恢复原始数据,哈希并不是加密
2、唯一性:对于特定的数据,只能有一个哈希值,并且这个哈希值是唯一的
3、防篡改:改变输入数据中的一个字节,导致输出一个完全不同的哈希
哈希算法特征:
1、正向快速:给定明文和hash算法,在有限时间和有限资源内能计算出hash值
2、逆向困难:给定hash值,在有限时间内很难逆推出明文
3、输入敏感:原始输入信息修改一点信息,产生的hash值会有很大的不同
4、冲突避免:很难找到两段内容不同的明文,使得他们的hash值一致(发生冲突)
main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package main import ( "core" "fmt" "strconv" ) func main() { bc := core.NewBlockChain() bc.AddBlock( "Send 1 BC to Ivan" ) bc.AddBlock( "Send more BC to Ivan" ) for _,block := range bc.Blocks { fmt.Printf( "Prev hash: %x\n" , block.PrevBlockHash) fmt.Printf( "Data: %s\n" , block.Data) fmt.Printf( "Hash: %x\n" , block.Hash) //创建工作量证明 pow := core.NewProofOfWork(block) //验证工作量证明 fmt.Printf( "Pow: %s\n" , strconv.FormatBool(pow.Validate())) fmt.Println() } } |
block.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | package core import ( "time" "strconv" "bytes" "crypto/sha256" ) //Block keeps block header type Block struct { Timestamp int64 //区块创建的时间 Data []byte //区块包含的数据 PrevBlockHash []byte //前一个区块的哈希值 Hash []byte //区块自身的哈希值,用于校验区块数据有效 Nonce int //记录工作量证明用到的数字 } //NewBlock create and returns Block func NewBlock(data string, prevBlockHash []byte) *Block { block := &Block{ Timestamp:time.Now().Unix(), Data: []byte(data), PrevBlockHash: prevBlockHash, Hash: []byte{}, } pow := NewProofOfWork(block) //新建工作量证明 nonce,hash := pow.Run() //执行工作量证明(挖矿) block.Hash = hash block.Nonce = nonce return block } func (b *Block) SetHash() { timestamp := []byte(strconv.FormatInt(b.Timestamp, 10)) headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp},[]byte{}) hash := sha256.Sum256(headers) b.Hash = hash[:] } //NewGenesisBlock create and returns genesis Block func NewGenesisBlock() *Block { return NewBlock( "Genesis Block" , []byte{}) } |
proofofwork.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | package core import ( "math" "math/big" "fmt" "crypto/sha256" "bytes" ) var ( maxNonce = math.MaxInt64 ) const targetBits = 20 //ProofOfWork represents a proof-of-work type ProofOfWork struct { block *Block target *big.Int } //NewProofOfWork builds and returns a ProofOfWork func NewProofOfWork(b *Block) *ProofOfWork { target := big.NewInt(1) target.Lsh(target,uint(256-targetBits)) pow := &ProofOfWork{b, target} return pow } func (pow *ProofOfWork) prepareData(nonce int) []byte { data := bytes.Join( [][]byte{ pow.block.PrevBlockHash, pow.block.Data, IntToHex(int64(pow.block.Timestamp)), IntToHex(int64(nonce)), }, []byte{}, ) return data } func (pow *ProofOfWork) Run() (int, []byte) { var hashInt big.Int var hash [32]byte nonce := 0 fmt.Printf( "Mining the block containing \"%s\"\n" , pow.block.Data) for nonce < maxNonce { data := pow.prepareData(nonce) hash = sha256.Sum256(data) fmt.Printf( "\r%x" , hash) hashInt.SetBytes(hash[:]) if hashInt.Cmp(pow.target) == -1 { break } else { nonce++ } } fmt.Print( "\n\n" ) return nonce,hash[:] } func (pow *ProofOfWork) Validate() bool { var hashInt big.Int data := pow.prepareData(pow.block.Nonce) hash := sha256.Sum256(data) hashInt.SetBytes(hash[:]) isValid := hashInt.Cmp(pow.target) == -1 return isValid } |
utils.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package core import ( "bytes" "encoding/binary" "log" ) func IntToHex(num int64) []byte { buff := new(bytes.Buffer) err := binary.Write(buff, binary.BigEndian, num) if err != nil { log.Panic(err) } return buff.Bytes() } |
打印结果:
Mining the block containing "Genesis Block"
00000965faabec60c056cc30d9e6e45a0db7cfa84cb5897d8d5bdaa96971bd5f
Mining the block containing "Send 1 BC to Ivan"
000006910ca6331d7c640787defe1189fb158bc3d624949bc61b68a3f0031efc
Mining the block containing "Send more BC to Ivan"
00000a9e4f7f891bf6dd7323a1a5b698d5ba88c9363c8f5c9676fd075d526796
Prev hash:
Data: Genesis Block
Hash: 00000965faabec60c056cc30d9e6e45a0db7cfa84cb5897d8d5bdaa96971bd5f
Pow: true
Prev hash: 00000965faabec60c056cc30d9e6e45a0db7cfa84cb5897d8d5bdaa96971bd5f
Data: Send 1 BC to Ivan
Hash: 000006910ca6331d7c640787defe1189fb158bc3d624949bc61b68a3f0031efc
Pow: true
Prev hash: 000006910ca6331d7c640787defe1189fb158bc3d624949bc61b68a3f0031efc
Data: Send more BC to Ivan
Hash: 00000a9e4f7f891bf6dd7323a1a5b698d5ba88c9363c8f5c9676fd075d526796
Pow: true
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步