概要
Proof of PIN(PoP)是 MetaID 中的一個有趣概念,我們參考了比特幣的挖礦原理制定了 PoP 機制。PoP 值反映的是用戶在 MetaID 世界的“工作量”證明。在 MetaID 世界中,用戶最小的“工作量”是發送一條 PIN,因此每條 PIN 都有一個哈希值,並且該將用戶的 PIN 與其所在的區塊難度結合。PoP 值反映了如下兩個維度:
用戶創建 MetaID 數據的數量概況:創建 MetaID PIN 越多,獲得高難度的 PoP 值的概率越高。
用戶創建 MetaID 數據的算力消耗:PoP 值和 MetaID 數據所在區塊鏈算力情況掛鉤,算力越高越容易獲得難度高的 PoP 值。
PIN 如同 SHA256 算力,PoP 如同難度哈希,算力越高則越大概率獲得高難度的哈希值。
通過驗證用戶相關的 PoP 值,我們可以快速評價一個用戶在 MetaID 世界的貢獻度,也讓 PIN 有了等級和稀有度的概念。
計算方法
PoP 是通過區塊的 MerkleRoot
和 PINID
用 SHA256 聯合哈希,然後再與 BlockHash
相乘,從而生成一個新的值。具體公式為:
PoP = hash(PIN_ID + Merkle_Root) * Block_Hash
得出的原始哈希值然後進行 8 進制轉換,轉換後的結果即為 PoP。
以下是計算 PoP 的代碼:
package pop
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"math/big"
"strconv"
)
func CalculateHash(pinid string, merkleRoot string) string {
h := sha256.New()
h.Write([]byte(pinid + merkleRoot))
return hex.EncodeToString(h.Sum(nil))
}
func CalculateProductToHexStr(blockhash string, pinHash string) string {
blockhashByte, _ := hex.DecodeString(blockhash)
blockhashInt, _ := new(big.Int).SetString(blockhash, 16)
pinHashByte, _ := hex.DecodeString(pinHash)
pinHashInt, _ := new(big.Int).SetString(pinHash, 16)
popByte := new(big.Int).Mul(blockhashInt, pinHashInt).Bytes()
// 計算總位數:32+32=64
totalLen := len(blockhashByte) + len(pinHashByte)
// 需要補 0 的位數
remainingLen := totalLen - len(popByte)
for i := 0; i < remainingLen; i++ {
popByte = append([]byte{0}, popByte...)
}
return hex.EncodeToString(popByte)
}
func ConvertToOctalHex(productHex string) (string, int64) {
productByte, _ := hex.DecodeString(productHex)
// 轉二進制
bList := make([]string, 0)
for _, b := range productByte {
binaryB := fmt.Sprintf("%b", b)
bList = append(bList, fmt.Sprintf("%08s", binaryB))
}
productBinaryStr := ""
for _, b := range bList {
productBinaryStr += b
}
productBinaryStr = productBinaryStr[:510]
bCount := int64(0)
for _, b := range productBinaryStr {
if b == '0' {
bCount++
} else {
break
}
}
// 二進制 str 轉 8 進制 str
octal := ""
for i := 0; i < len(productBinaryStr); i += 3 {
binaryStr := productBinaryStr[i : i+3]
num, err := strconv.ParseInt(binaryStr, 2, 64)
if err != nil {
fmt.Println("ParseInt error:", err)
return "", 0
}
octal += strconv.FormatInt(num, 8)
}
return octal, bCount
}
func GenPop(pinid, merkleRoot, blockHash string) (string, int64) {
// 計算 pinHash
pinHash := CalculateHash(pinid, merkleRoot)
// blockhash * pinHash
productHexStr := CalculateProductToHexStr(blockHash, pinHash)
// 轉 8 進制
octal, bCount := ConvertToOctalHex(productHexStr)
return octal, bCount
}
PoP 計算的測試用例:
func Test_pop(t *testing.T) {
pinid := "77aac2ae323748dee3b8b1ae6b7c33c1c4466f568c572ea488f584f041f0de4ei0" // 64 char hash
merkleRoot := "e56011a241cb196fc4efbeafef051ca901761ffb569a43146582f9133bfd41d2" // 64 char hash
blockhash := "000000000000000004c2db0441a47fd3574992d508b8d9d866a789d371aa5060" // real block hash
pop, bCountZero := GenPop(mockPinId, merkleRoot, blockHash)
fmt.Println("POP:", octal)
fmt.Println("POP-0:", bCountZero)
}
PoP Level(難度等級)
在MetaID系統中,PoP值的難度等級是依據類似區塊雜湊的前綴「0」位數來定義。具體而言,PoP值前綴中「0」的數量越多,其對應的難度等級(PoP Level)就越高。系統規定,任何有效的PoP值至少需包含21位前綴「0」,作為最低標準。
為了高效評估與表達PoP的稀有性與難度,MetaID提出了PoP Level的設定。PoP Level為整數,目前體系中共有1至13級,主要應用於PIN稀有度的快速判定、MRC20等場景的資產鑄造等。於不同的主鏈環境下,PoP Level的起始標準有所不同,例如MVC常以1級為初始門檻,BTC則通常從6級起步。
具體難度劃分為:PoP Level為1時,需滿足PoP值前綴有22個「0」;PoP Level為2時,需要有23個「0」;此後每提升一級,「0」的數量相應增加1位。前綴「0」的數量越多,代表PoP值的稀有性及運算挑戰難度越高。
此外,PoP Level等級之間屬指數級增長,即每提升一個等級,PoP值挖掘難度為前一級的8倍,極大提升了高等級PoP的安全性與稀缺性。
PoP Score(PoP分數)
PoP Score 的定義與應用場景
PoP Score 是為了比 PoP Level 更加精細地評估 PIN 稀有度而設立的數值指標。尤其是在如 MetaSo 系統下的 PEV 值、MDV 值等需要細緻區分 PoP 難度的場景中,PoP Score 能為每一條 PIN 精確地打分及排序。每一條 PIN 都會對應一個 PoP Score,並記錄於 MetaID 系統中。
PoP Score 的計算方法
a. 確定 PoP Level 整數部分
以某一 PIN 對應的 PoP 值為例:
0000000000000000000000215206653161113226643512614250403542335511435340330664252463510373257440244542222437344512355773452022004517474440724217350505346711227665150775715
首先統計前綴連續「0」的數量。假設如上例有 22 個「0」,則對應的 PoP Level 為 1,因此整數部分為 1。
b. 計算 PoP Sub Octal
將前綴「0」全部去除後,取其後非 0 部分的前4位數字,作為小數點後的部分。例如,例子中的這4位是「2152」,將其記錄為 PoP Sub Octal。所以此步得到 PoPSubOctal = 0.2152。
需注意,PoP Sub Octal 是特殊的 8 進制小數。
c. 8進制均勻化轉換
為使數值分佈更均勻,將 8 進制小數 PoPSubOctal 轉換為 [0,1] 範圍內均勻分佈的 10 進制小數。此步驟使用 Octal Fraction To Uniform Decimal 方法進行轉換。
d. 求取 PoP Sub Decimal
將最終均勻化後的小數記作 PoP Sub Decimal,並採用以下公式修正:
PoPSubDecimal = 1 - octalFractionToUniformDecimal(PoPSubOctal)
如此可保證小數值越接近0,對應的 PoP Level Decimal 越大,契合難度設計的初衷。
e. 計算 PoP Level Decimal
將整數等級與小數等級相加:
PoP Level Decimal = PoP Level + PoP Sub Decimal
如本例算得 PoP Level Decimal 約為 1.72。
f. 求取 PoP Score
以 8 為底數,取 PoP Level Decimal 為指數,得到最終 PoP Score 值:
PoP Score = 8 ^ PoP Level Decimal
舉例來說,8 的 1.72 次方約等於 35.7531(取小數點後 4 位)。
計算結果
根據上述計算步驟,在本例中:
0000000000000000000000215206653161113226643512614250403542335511435340330664252463510373257440244542222437344512355773452022004517474440724217350505346711227665150775715
其 PoP Level 為:Lv.1
其 PoP Score 為:35.7531