1. 程式人生 > >區塊鏈工作量證明及哈希算法

區塊鏈工作量證明及哈希算法

!= 得獎 逆向 Coding sent 努力 恢復 core red

什麽是工作量證明:
1、工作的結果作為數據加入區塊鏈成為一個區塊
2、完成這個工作的人會獲得獎勵(這也就是通過挖礦獲得比特幣)
3、整個“努力工作並進行證明”的機制,就叫工作量證明

為什麽采用哈希算法:
1、不可逆:無法從一個哈希值恢復原始數據,哈希並不是加密
2、唯一性:對於特定的數據,只能有一個哈希值,並且這個哈希值是唯一的
3、防篡改:改變輸入數據中的一個字節,導致輸出一個完全不同的哈希

哈希算法特征:
1、正向快速:給定明文和hash算法,在有限時間和有限資源內能計算出hash值
2、逆向困難:給定hash值,在有限時間內很難逆推出明文
3、輸入敏感:原始輸入信息修改一點信息,產生的hash值會有很大的不同

4、沖突避免:很難找到兩段內容不同的明文,使得他們的hash值一致(發生沖突)

main.go

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

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

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

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

區塊鏈工作量證明及哈希算法