讓我跟你說說我偶然遇到的一個怪異的談判問題
想像一下:一家企業能源買家需要確認一間氫氣供應商擁有至少3,000 MWh的認證綠色信用證,他們才會簽署採購合約。這很合理。供應商確實有這些信用證。他們想要這筆交易。所以他們分享了實際的庫存數字
而就在他們這麼做時,房間裡的情勢發生了變化。
因為現在買家知道供應商手上有8,500 MWh。突然間買家對供應商的絕境有了非常清晰的認識 不。談判的優勢已經轉移。供應商的交易條件即將惡化,而他們無能為力,因為他們已經暴露了自己的底牌。
我一直在思考這個問題。然後我意識到它並不是一個談判問題。它是一個資訊架構問題。供應商需要一種方法來說「是的,我符合資格」,而不需要說「這裡就是我確切有多少」。
那就是我用H2Ledger所建立的。:一個去中心化的綠色氫氣信用市場,供應商可以在這裡向智能合約證明actualAmount >= threshold,並且完全保證加密安全性,實際數字從未出現在任何地方。不在鏈上。不在證明中。不在傳輸中。無處可尋。
實現這一點的工具被稱為零知識證明. 讓我向你展示它是如何運作的,程式碼看起來是什麼樣子,以及誠實地說,我後來希望我做了不同的選擇.
在我們深入之前:零知識證明到底是什麼?
我保證這沒有聽起來那麼可怕。
這樣想吧。想像你的朋友鼓勵你證明你知道一個保險箱的密碼,但你拒絕將數字大聲說出來。零知識證明基本上是一個數學協議,讓你贏得那個挑戰。你讓另一方相信一個陳述是真的,但又不透露其背後的秘密。
更精確地說,必須滿足三件事:
- 完整性: 如果你說的是真實的,而且你擁有正確的密鑰,你總是可以產生一個有效的證明.
- 調性: 如果你撒謊,你無法偽造一個有效的證明。數學讓作弊在計算上不可行.
- 零知識: 檢查證明的人學習僅僅僅 這個陳述是否為真或假。沒有其他泄露。
在 H2Ledger 中,這個陳述是 actualAmount >= threshold。密鑰(稱為「見證」)是 actualAmount。而檢查證明的當事人不是人;它是一個 Solidity 智能合約,位於一個與 EVM 兼容的區塊鏈上。
不需要信任。不需要中介。只需要數學。
真實問題:綠色氫氣信用市場相當於一場災難
好吧,“災難”這詞用得比較嚴重。但目前的狀況確實非常脆弱。
目前,氫氣信用市場處理的是:
- 紙基認證鏈 沒有鏈上錨點的。同樣的認證信用可以悄悄地呈現給不同談判的多個買家。沒有人有一個共享帳本來抓到它。
- 分離的登記處 在不相容的監管框架下運行,沒有互操作性。一個德國的買家和一個智利供應商可能正在使用完全不同的認證標準,沒有辦法來驗證跨越這個差距。
- 在透明度與不透明度之間被迫做出選擇. 將您的信用餘額放在公共區塊鏈上,每個競爭對手都能實時看到您的庫存。保持鏈下運作,就沒有無信任的清算機制。您必須選擇您的苦難.
零知識證明讓您可以完全擺脫那個跷跷板。您獲得一個共享賬本進行清算 和 保障底層數據的隱私。同時進行。
H2Ledger 的實際運作方式:三層圖像
在高層次上,系統有三層之間互相溝通:
[ Supplier (off-chain) ]
|
| Private: actualAmount (stays here, never transmitted)
v
[ Circom Circuit + Groth16 Prover ]
|
| Outputs: proof.json (256 bytes) + public.json (threshold only)
v
[ GreenHydrogenMarketplace.sol ]
|
| Delegates the heavy cryptographic check to:
v
[ Verifier.sol ] --> true / false
供應商的實際庫存數字從不離開他們的機器。上鏈的是一個 256 字節的證明和公共閾值。智能合約檢查證明,確認其有效,並將訂單狀態切換為已完成。這就是整個結算流程.
ZK 環路:魔法變得無聊(但這是好事)
環路是 ZK 證明系統評估的程序。我寫的是我的。Circom 2.0,本質上是一種特定領域語言,用於表達計算為算術約束系統。這裡是核心模板:
template ThresholdVerification(n) {
signal input actualAmount; // Private: never leaves the prover's machine
signal input threshold; // Public: the buyer's stated minimum
signal output isValid; // 1 if actualAmount >= threshold, else 0
// Uses LessThan from circomlib to prove:
// NOT (actualAmount < threshold) = (actualAmount >= threshold)
}
當你編譯這個時,它產生128 R1CS 約束在193條線路上。這裡是那些約束實際上做了什麼:
- 64 個會將
actualAmount和threshold都分解成他們的 64 位二進位表示法。 - 另外有 64 個則實作了逐位比較器,用來判斷哪個數字較大。
關於 64 位元的選擇:企業市場中的氫氣容量是以百萬 MWh 為單位計算的。一個 64 位元的欄位可容納最高達 2^64 的值,這提供了大約 2^40 的額外空間,遠超過你將來可能交易的所有數值。沒有實際的上限擔憂.
Groth16 證明器接收這個電路、證明者以及來自設定典禮的證明金鑰,並在 BN254 上輸出三個椭圆曲線群元素:
π_a, π_b, π_c
這三個元素就是證據。序列化後,它們總是精確等於256 字節,無論見證內容為何。這個固定大小在實際中確實很有用:燃料成本是可預測的,ABI 編碼是乾淨的,而存儲則不是問題。
在一般筆記型電腦上,證明生成約需1到2秒,而且這一切都發生在鏈下。區塊鏈從未看到計算;它只看到輸出。
智能合約:真正有意義的訪問控制
onlyOwner 陷阱
這裡是我一開始就想避免的模式。
許多合約系統默認為單一onlyOwner 修飾子適用於每一個特權操作。它很簡單。它有效。而在單一演員系統中,它可能很好。
但 H2Ledger 有三種不同的演員類型,具有完全不同的信任假設:生產者(持有信用的供應商),買家(發布採購訂單的公司),和 驗證代理。 (憑證當事人,在鏈下證明基礎認證的合法性)。將三者通過單一擁有者地址導入,會創造出一個單方面控制點,這與整個系統無需信任的基礎前提根本矛盾。
所以我建立了一個基於角色的訪問層。每個地址會被分配一種四種狀態中的一种:NONE,PRODUCER,VERIFIER_AGENT,或BUYER 每個敏感功能會在進行任何其他操作之前檢查呼叫者的角色。
pragma solidity ^0.8.0;
import "./Verifier.sol";
contract GreenHydrogenMarketplace {
Verifier verifier;
enum Role { NONE, PRODUCER, VERIFIER_AGENT, BUYER }
mapping(address => Role) private roles;
address public admin;
modifier onlyRole(Role _required) {
require(roles[msg.sender] == _required, "Access denied: insufficient role");
_;
}
modifier onlyAdmin() {
require(msg.sender == admin, "Access denied: not admin");
_;
}
constructor(address _verifier) {
verifier = Verifier(_verifier);
admin = msg.sender;
}
function assignRole(address _account, Role _role) external onlyAdmin {
roles[_account] = _role;
}
}
結果是:沒有地址可以身兼兩職。買家無法提交證明。製造商無法建立訂單。角色分配本身受到管理員密鑰的保護,這是我將在下方學習部分誠實處理的剩餘中心化點。onlyRole修飾子是可組合的,所以擴展到新的函數類型只需要一行。
建立訂單
僅僅BUYER地址可以建立採購訂單。一旦訂單建立,門檻便不可變更。我想強調最後這部分,因為它比看似的更重要。
若供應商已產生他們的證明後,買家能夠降低門檻,他們可以追溯性地取消合規達到原來標準的供應商。在創建時鎖定門檻可完全防止這種操縱。
struct ProcurementOrder {
address buyer;
address supplier;
uint256 threshold;
bool fulfilled;
}
mapping(uint256 => ProcurementOrder) public orders;
uint256 public nextOrderId;
function createOrder(address _supplier, uint256 _threshold)
external
onlyRole(Role.BUYER)
returns (uint256 orderId)
{
orderId = nextOrderId++;
orders[orderId] = ProcurementOrder({
buyer: msg.sender,
supplier: _supplier,
threshold: _threshold,
fulfilled: false
});
}
證明提交通過:先做便宜檢查,後做昂貴檢查
這裡才是 ZK 驗證實際發生的地方。當供應商提交他們的證明時,合約會按預設順序執行五次檢查,從最便宜到最貴:
- 角色檢查: 呼叫者是不是已註冊的 PRODUCER?(修飾器,~200 gas)
- 供應商身分: 這是不是與這訂單綁定的特定供應商?(SLOAD,~2,100 gas)
- 防止重放: 這個訂單已經完成履行了嗎?(SLOAD, ~2,100 gas)
- 閾值綁定: 公開信號是否符合儲存的閾值?(比較, ~200 gas)
- 配對檢查: ZK 證明是否具有加密有效性?(~285,000 gas)
昂貴的配對計算最後才執行。每個較便宜的防禦機制若在此之前失敗,就能讓呼叫者免於在注定失敗的交易上消耗285k gas。
function submitThresholdProof(
uint256 orderId,
uint[2] calldata _pA,
uint[2][2] calldata _pB,
uint[2] calldata _pC,
uint[1] calldata _pubSignals
) external onlyRole(Role.PRODUCER) {
ProcurementOrder storage order = orders[orderId];
require(msg.sender == order.supplier, "Caller is not the designated supplier");
require(!order.fulfilled, "Order already fulfilled");
require(_pubSignals[0] == order.threshold, "Public signal does not match order threshold");
require(
verifier.verifyProof(_pA, _pB, _pC, _pubSignals),
"ZK proof verification failed"
);
order.fulfilled = true;
// Downstream: emit event, trigger escrow release, etc.
}
這裡有一項檢查值得額外注意:_pubSignals[0] == order.threshold。這看起來可能是重複的,但它正在做重要的工作。沒有它,供應商可能會提交一個對應於不同的閾值(例如,1,000 MWh,他們輕易達成),並搭配一個需要 3,000 MWh 的訂單。證明本身會通過搭配檢查,因為它 是 一個有效的 1,000 MWh 證明。只有這個綁定檢查才能捕捉到替換並拒絕它.
性能數據:這實際上花費多少?
| 指標 | 價值 |
|---|---|
| 證明大小 | 256 字節(固定) |
| 證明生成時間 | 1 到 2 秒(鏈下) |
| 驗證者部署 Gas | ~2,850,000(一次性) |
| 每個證明的驗證 Gas | ~289,096 |
| 在 30 Gwei 下以太坊 L1 的成本 | ~$0.87 每個證明 |
| 在 Arbitrum 或 Optimism 上的成本 | ~每證明$0.01 |
對於企業採購合約,若個別合約價值達數百萬美元,L1上的每項驗證$0.87完全合理。若接近更高頻率,L2是明顯的途徑
我做對了什麼,以及我在哪裡會做不同的事
好的部份
分開Verifier.sol 來自 GreenHydrogenMarketplace.sol 是正確的建築選擇。驗證器是一種無狀態的加密原語,沒有業務邏輯。保持其隔離意味著你可以獨立於其他所有事物進行審計。更小的表面,更清晰的審計範圍.
從便宜到昂貴的排序在submitThresholdProof 在測試中也獲得了回報。當輸入無效時的失敗提交始終比先運行配對檢查時的成本要低。
誠實的遺憾
受信任的設定是我的最大未解決負債。 Groth16 需要一個一次性 MPC 典禮來生成證明和驗證金鑰。PoC 使用模擬典禮,對研究環境來說是沒問題的。但在生產環境中,如果典禮中的任何單一參與者保留了他們的「有毒廢物」(來自他們貢獻的隱密隨機性),他們可以無限期地為虛假聲明製造有效證明。生產部署需要一個大型、公證的 MPC 典禮,具有可審計的記錄,或者遷移到像 PLONK 或 Halo2 這樣的透明設定證明系統,這些系統根本不需要任何可信設定。
管理員金鑰是一個信任瓶頸,我沒有完全解決。 目前,單一地址控制著整個市場的角色分配。這是一個有意義的中央化風險。在下一個版本中,管理員角色應該在第一天轉移到 Gnosis Safe 多簽名,並對角色分配操作設置時間鎖,以便參與者能夠提前得知任何變更。
Gas 可以更低。 在 Verifier.sol 中的 BN254 配對操作顯著受益於以太坊上的 EIP-197 預編譯。如果生成的驗證器能夠通過它而不是在 EVM 解釋器中計算,驗證成本會降低 30% 到 40%。在生產部署之前應仔細測量。
這個電路只證明了一件事。 真正的採購合約不僅關心數量。純度等級、認證日期、原產國;這些都重要。將電路擴展到複合檢查 (volume >= min_vol AND purity >= min_purity AND date >= cutoff) 增加了大約 256 項額外限制,並可能將證明生成時間加倍。這兩者都在實際限制範圍內,並會使系統有意義地更加實用.
運行它自己
若想編輯程式碼:
git clone <your-repo-url>
cd h2ledger-poc
npm install
npm run verify
# Expected: OK
# (verifies the included proof where actualAmount=5000 >= threshold=3000)
而要直接查看電路統計資訊:
snarkjs r1cs info circuits/credit_proof.r1cs
# Curve: bn-128
# Constraints: 128
# Wires: 193
# Private Inputs: 1
# Public Inputs: 1
這種模式在氫氣之外的意義為何
在我開發這個過程中,我反覆思考的一件事是:H2Ledger 並非真正是一個氫氣項目。它是一個通用模式的展示。
任何市場,如果有人需要證明一個數字達到某個門檻,但揭露這個數字會產生成本,這就適用於這種架構。信用評分。保險核保。供應鏈供應商資格審查。工資合規審計。電路會變化;模式不變。
零知證明常以抽象概念討論。我想要展示的是,使用 Circom、SnarkJS 和幾百行 Solidity,你可以在幾週內用這些工具建立實際東西。這些工具真的很有用。數學不必是魔法;它只需要正確地連接在一起。
如果你以類似的方法建立某個東西,或者如果你發現有什麼我應該修正的,我真心希望能聽到關於它的信息。
H2Ledger 是一個研究上的概念證明 (v0.1.0)。證明系統:Groth16 (BN254)。電路:128 個約束,193 個線路。問題或合作:nioomeee@gmail.com













