iT邦幫忙

0

Proof of Work 工作量證明

前言

在區塊鏈中每條鏈或多或少都各自發展出自己不同的共識機制,例如 Proof of Work、Proof of Stake、Proof of blah blah blah 等等之類,其概念基本上是讓使用者付出代價,讓使用成本升高從而確保安全性,其中比較著名的就是比特幣使用的 Proof of Work(POW) 工作量證明,也是此篇文章的主旨。

介紹

某些網站在你登入或註冊前會要你做一些煩人的益智題目,例如:選腳踏車、路燈或是移動拼圖等等,這些題目拖慢了使用者註冊和登入,看似破壞了使用者體驗且沒甚麼好處。但事實上是,對於一個願意花時間做這些驗證的人,我們姑且就相信他是一個"真人"使用者,因為他做了一些題目提出了證明。

同樣的概念用在比特幣區塊鏈上,工作量證明就是讓挖礦者花時間算數學題目,目前算一個區塊需要 10~15 分鐘的時間,對於願意花時間來算題目的節點,我們就認證他是一個合格的節點。此外,由於工作證明是基於同樣資料會得出同樣結果的雜湊函式,所以其他的節點也能去驗證新區塊的正確性。藉由工作證明增加寫入的困難度增進網路的安全性,若惡意節點想要竄改資料,他必須花上全節點加總 51% 以上的算力才有可能成功。其他的應用如最初是 Hashcash 運用工作證明的方式來防止大量的垃圾信件,其中工作量證明的演算法也叫做 Hashcash 演算法。

原理

工作量證明證明的數學題概念上很簡單,給定一個固定的資料型態,並且去調整一個可變的隨機數 nonce,使得雜湊出來的符合難度的結果。

https://ithelp.ithome.com.tw/upload/images/20210418/20123459N9XGy3Tpcu.png

然而何謂難度?以比特幣系統來說,就是雜湊完的結果前綴有幾個'0'字符,而由於雜湊出來結果是用 HEX 編碼(16 位元) 的方式去轉回字串所以每晉升一個難度會是前一個難度的 16 倍,範例如下:

// 難度1 可能性 1/16
"0treca8b5e0361a0c063db6ad77dc4b23369b9f5de85e4842539c381c333e99d"
// 難度2 可能性 1/256
"00reca8b5e0361a0c063db6ad77dc4b23369b9f5de85e4842539c381c333e99d"
// 難度3 可能性 1/4096
"000eca8b5e0361a0c063db6ad77dc4b23369b9f5de85e4842539c381c333e99d"

難度越高則所花費的時間越久,筆者單機手動測試難度為 5 大概花 0.57 秒,而難度為 6 則需要花費 8.71 秒。
目前的比特幣難度是 20 以上,可知道為何人人說比特幣是很耗資源的東西。

而在驗證工作證明的方式也極其簡單,就是把固定的資料和隨機數做一次雜湊,去比對難度是否符合需求就可以。

實現

這裡做出一個假設案例,目前我們希望做一個應用在註冊帳號的工作量證明防止他人大量製造帳號:

package main

import (
	"crypto/sha256"
	"fmt"
)

// 註冊資料格式
type Registraction struct {
	username  string
	password  string
	timestamp int64
}

// 回傳給伺服器的結果
type Data struct {
	registraction Registraction
	nonce         uint // 計算工作證明的隨機數
}

func main() {
    // 註冊資料
	register := Registraction{
		username:  "test",
		password:  "test123",
		timestamp: time.Now().UnixNano(),
	}

    // 難度
	difficulty := 6
	data := Data{register, 0}
	s := fmt.Sprintf("%v", data)
	
    // 主要的 hash 函式
    result := sha256.Sum256([]byte(s))

    for !isValid(difficulty, fmt.Sprintf("%x", result)) {
		data.nonce++
        s = fmt.Sprintf("%v", data)
		result = sha256.Sum256([]byte(s))
	}
	fmt.Printf("hash result: %x\n", result)
	fmt.Printf("Data result: %v\n", data)
}

// 檢測結果是否符合標準
func isValid(difficulty int, signature string) bool {
	for i := 0; i < difficulty; i++ {
		if signature[i] != '0' {
			return false
		}
	}
	return true
}

結論

工作證明可以防範大量請求,從無延遲請求到設定所需時間的工作證明來驗證使用者來達成目的。以上面範例來說,使原本創大量假帳號的效率可能從每秒 1 萬個降低成每分鐘只能創建 1 個的程度,大大加大惡意使用者的成本的簡單機制。

參考

Hashcash Wiki:
https://en.wikipedia.org/wiki/Hashcash

比特幣白皮書:
https://bitcoin.org/bitcoin.pdf

How do miners validate transactions:
https://medium.com/@blairlmarshall/how-do-miners-validate-transactions-c01b05f36231

如果有錯誤或其他意見歡迎提出


尚未有邦友留言

立即登入留言