iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0
Modern Web

web3 短篇集系列 第 25

Commit-Reveal Scheme

  • 分享至 

  • xImage
  •  

Commit-Reveal Scheme 設法達到以下兩個特性:

  • Hiding: commitment 要隱藏一個值。
  • Binding: commitment 只能隱藏一個值。假設你隱藏 x,揭開 (reveal) 時就不能是 y。

假設你知道某支股票下個月會漲的消息,但基於法律問題你不能告訴你的朋友,但你又想向朋友證明你知道會漲(傲慢作祟)。那你可以將「某股下個月會漲」這串字進行雜湊 (commit),將亂碼交給你的朋友,一個月後,股票真的漲了,再將原字串告訴你的朋友(reveal),你的朋友用同樣的雜湊函數得到的結果跟一個月前給的亂碼一樣,你朋友相信你是真的知道股票會漲。

上面例子出自 Real-World Cryptography by David Wong (p.32 - 2.4.1)

Blind Auction

Solidity 文件的範例二介紹如何實作彌封拍賣(sealed-bid auction),它的原理就是使用 commitment scheme。彌封拍賣是指競標者彼此不知道別人的出價下競標。

首先合約至少要區分 commit phase 和 reveal phase 兩個階段。commit 階段用戶要在鏈下對一筆資料進行雜湊:keccak256(abi.encodePacked(value, fake, secret)),會得到 32-bytes hash (or digest),然後呼叫 bid(),就是將你的 commitment 放上鏈。

function bid(bytes32 blindedBid) external payable onlyBefore(biddingEnd) {
    bids[msg.sender].push(Bid({blindedBid: blindedBid, deposit: msg.value}));
}

等到 reveal 階段,每個參與者要公佈當初雜湊的 input (or pre-image),呼叫 reveal 後會在鏈上進行雜湊,確認符合之前的 commitment,然後將當前最高價格儲存起來,之後每個人 reveal 都會比對並更新最高價格。

function reveal(uint256[] calldata values, bool[] calldata fakes, bytes32[] calldata secrets) external onlyAfter(biddingEnd) onlyBefore(revealEnd)

雜湊的資料由三個元素組成:

  • value: 你的真實競價,bid() 的同時你要投入大於等於 value 的值。
  • fake: 為了混淆視聽的假競價,因為鏈上看得到你投入多少 ETH 給合約,會被發現那是你的競價,因此要投入比真實競價要高的 ETH 才不會被猜到。reveal() 要設計退款機制。
  • secret: 為了確保雜湊結果不重複,否則跟別人同樣 value 和 fake 會產生一樣的 hash。

競標者會不會有動機出價後不 reveal?因為出價時必須投入 ETH 到合約,如果你不 reveal,合約可以藉此沒收你的 ETH 作為懲罰。

原始碼範例

剪刀石頭布

要設計剪刀石頭布的遊戲也需要 Commit-Reveal Scheme。

為了避免某個人先呼叫合約就把自己要出的拳公開在鏈上,我們要先對出拳進行 commit,把 commitment 存在合約,等到 reveal 階段時,第二個玩家揭露後就能跟第一個玩家比較,然後分出勝負。

玩家有沒有動機不 reveal?當玩家 A 看到玩家 B reveal 剪刀,玩家 A 知道自己輸定了,決定不 reveal,於是合約只能宣判玩家 A 棄賽,但只要玩家 A 不 reveal,除了 A 之外沒人真的知道是誰輸誰贏(儘管我們心理都知道)。解決辦法是強迫兩個玩家 commit 之前先抵押一定額度的 ETH,reveal 後才能領回,作為鼓勵 reveal 的誘因。

ethereum-rockpaperscissors

PS: zk 剪都石頭布

  1. player 1 commits their valid move with a secret
  2. player 2 plays their move in the clear
  3. player 1 reveals their move by providing the same secret

匿名投票

如果投票要求結果出爐也必須保護投票者匿名,那就不能用 commitment scheme,因為最後需要 reveal。

如果只需要在投票階段匿名,reveal 時公佈各自投得票,那面臨不 reveal 的狀況怎麼辦?要看表決的決策對投票者的影響有多大,如果票數對決策有重大影響,就算多數決仍輸,不 reveal 反而比較好的話,可能就算抵押了代幣,寧願損失抵押品也不願 reveal。

MACI 是一個匿名且防買票的投票系統,它防買票的設計建立在投票者無法向別人證明他投給誰。但 MACI 的缺點是中心化的計票者,計票者記得票一定正確,但計票者可以知道別人的票投給誰,買票者可以賄賂計票者而得知別人的票。因此計票者必須是可以被所有人信任的人。(目前的理解是這樣,若有錯請不吝糾正。)

後記

最後附上有趣影片,主要是片頭前五分鐘表演次價拍賣中不 reveal 的搞笑情境:

https://www.youtube.com/watch?v=amUP8EZ8Z0w

影片中只有兩個人在玩次價拍賣,次價拍賣是出價最高者獲勝,但只需要付第二高價來獲得商品。兩個人都 commit 以後,第一個人 reveal,第二個人看到別人的出價決定不 reveal,於是整場拍賣沒有第二高價,唯一出價的人要用最高價買下商品 XD


上一篇
可升級合約的初始化
下一篇
部署合約 (create & create2)
系列文
web3 短篇集30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言