[ZKP 讀書會] MACI

Kimi Wu
Taipei Ethereum Meetup
4 min readNov 29, 2020
Photo by Jesus Kiteque on Unsplash

預計這將是一系列介紹ZKP應用的文章,認識目前ZKP的應用,包含L1, L2和其他比較難分類的應用,當中也穿插著常用的ZKP演算法。而目前的規劃的主題有

  • MACI
  • ZKopuru
  • ZKSync
  • Trust Token
  • ZCash
  • Groth16
  • PLONK
  • ZKZK Rollup

首次的讀書會介紹了

本篇文章先介紹MACI,ZKopru會由 NIC Lin在撰文介紹。

MACI

MACI 是 Minimal Anti-Collusion Infrastructure的縮寫, Vitalik 在2019年5月於ethreaser.ch所提出,為了讓用應用程式在區塊鏈上可以有抵抗共謀的一個機制(主要是想達到正確地執行你的想法跟抗審查(censorship resistance))。而最實際的應用就是投票,若在區塊鏈上投票能做到他人無法查驗你的票,這樣行賄者就無法知道你是否有乖乖投票,如此一來就能減低行賄的誘因。

(關於共謀的概念可以參考 Williams Lai 翻譯 Vitalik的論共謀

基本流程大致為

  • 欲投票者需要註冊期間內,以公鑰(EdDSA)向合約注冊身份
  • 註冊期結束
  • 投票開始,投票者將自己的票加密送到合約
  • 投票結束,協調者(coordinator)從合約上抓下所有的票, 計算結果,並產生zk證明到合約,更新票數(注1)

MACI中最關鍵的機制在於,投票結束前,投票者都可以向合約發出更換公鑰的指令,然後再使用新的公私鑰去投票。當協調者計票時,會去合約上找註冊者的公鑰,若發現此身份有更換過公鑰,則舊公鑰所投的票就會被認定為無效票。程序大約為

  • Alice 註冊身份為 公鑰A
  • 行賄者利誘或威脅 Alice 投贊成票,而 Alice 也照行賄者的意思投給了贊成票
  • 在投票結束前,Alice 隨時可以向合約更改身份為公鑰B
  • 更改完公鑰後,Alice 可再用私鑰B簽章投反對票
  • 當協調者計票時,會發現用公鑰A已經被改為公鑰B,所以私鑰A所簽的贊成票,將記為無效票

再深入一點細節 . . .

  • 使用者註冊先產生一組EdDSA的私鑰對(注2),再是透過合約的 signUp() 註冊公鑰,而合約中有一 merkle tree 記載著帳號相關的資訊
  • 接著使用者產生一組臨時的 (ECDSA)私鑰對 prvE/pubE(每次投票就產生一組)
  • 利用這組臨時的私鑰 prvE 協調者的公鑰 pubC 產生加密的鑰匙 EncKey,使用密鑰 EncKey 加密投票指令(command)(注3)
  • 再將臨時的公鑰 pubE 與加密過的指令,透過合約的 publishMessage()上鏈
  • 協調者透過 ECDH 交換秘密的方式可以得到 EncKey,當投票結束時協調者再使用這把密鑰把訊息(注3)解密,接著更新票數。

而更換公鑰的指令也是透過 publishMessage()上鏈,因為上鏈的指令都是加密過的,也只有協調者能解密,因此行賄者無法得知受賄者是否有更換過身份。

在MACI中,所有訊息都是上鏈的,因此不怕協調者不打包特定資料。不過所有資料協調者都可以解密,行賄者可以直接與協調者串通,去得知受賄者們是否有乖乖投票,如何防範不在 MACI 原本的提案內,有興趣的人可以去 MACI Github 上了解實作細節。

注1:對!MACI系統中協調者必須是誠實的
注2:在 snarks 的應用中通常使用EdDSA做簽章,而非以太的ECDSA,因為EdDSA在 zk circuit 的實作上複雜度比較低。
注3:在 MACI 中投票, 更換公鑰等動作都稱作指令(command),而加密後的指令稱作訊息(message)

Reference:

--

--