零知識證明編程——用Circom、Groth16構建證明及驗證

發表於 2024-09-04 09:32 作者: 登鏈社區

來源:登鏈社區

爲工作程序員提供的 ZKP 教程介紹。

你知道爲什么斑馬有條紋嗎?一種理論是這是一種僞裝。當斑馬聚集在一起時,這使得獅子更難以區分它們的獵物。獅子必須將獵物從群體中隔離出來才能追捕它[^1]。

人類也喜歡在人群中隱藏。一個具體的例子是,當多個人在一個集體名稱下作爲一個整體行動時。《聯邦黨人文集》就是這樣創作的[^2]。 另一個例子是 Bourbaki,這是 1930 年代一群法國數學家的集體筆名。這導致了現代數學大部分內容的徹底重寫,重點在於嚴謹性和公理化方法[^3]。

Bourbaki Congress

在數字時代,假設你在一個群聊中,想要發送一條有爭議的信息。你想證明你是其中的一員,而不透露是哪一位。我們如何在數字領域使用密碼學來做到這一點?我們可以使用一種叫做 群籤名 的東西。

從傳統上講,群籤名在數學上相當復雜且難以實現。然而,使用零知識證明(ZKP),這個數學問題變成了一個簡單的編程任務。在本文結束時,你將能夠自己編寫群籤名。

介紹

這篇文章將向你展示如何從零开始編寫基本的零知識證明(ZKP)。

在學習新的技術棧時,我們希望盡快掌握編輯-構建-運行的循環。只有這樣,我們才能开始從自己的經驗中學習。

我們將首先讓你設置環境,編寫一個簡單的程序,執行所謂的可信設置,然後盡快生成和驗證證明。之後,我們將識別一些改進我們程序的方法,實施這些改進並進行測試。在此過程中,我們將建立一個更好的心理模型,以便在實踐中編程 ZKP。最後,你將熟悉(某種方式)從零开始編寫 ZKP。

我們將逐步構建一個簡單的籤名方案,你可以證明你發送了特定的消息。你將能夠理解這段代碼的作用及其原因:

    # 克隆倉庫並運行准備腳本
    git clone git@github.com:oskarth/zkintro-tutorial.git
    cd zkintro-tutorial
    
    # 在執行之前瀏覽此文件的內容
    less ./scripts/prepare.sh
    ./scripts/prepare.sh

我們建議你瀏覽 ./scripts/prepare.sh 的內容,以查看這將安裝什么,或者如果你更喜歡手動安裝。執行後,你應該看到 Installation complete 並且沒有錯誤。

如果你遇到問題,請查看最新的官方文檔 這裏[7]。完成後,你應該安裝以下版本(或更高版本):

    pragma circom 2.0.0;
    
    template Multiplier2 () {
      signal input a;
      signal input b;
      signal output c;
      c <== a * b;
    }
    
    component main = Multiplier2();

這就是我們的特殊程序或 _電路_。 [^6] 按行分析:

  • pragma circom 2.0.0; - 定義所使用的 Circom 版本

  • template Multiplier() - 模板是大多數編程語言中對象的等價物,是一種常見的抽象形式

  • signal input a; - 我們的第一個輸入,a;輸入默認是私有的

  • signal input b; - 我們的第二個輸入,b;同樣默認是私有的

  • signal output b; - 我們的輸出,c;輸出始終是公共的

  • c <== a * b; - 這做了兩件事:將信號 c 賦值 約束 c 等於 ab 的乘積

  • component main = Multiplier2() - 實例化我們的主組件

最重要的行是 c <== a * b;。這是我們實際聲明約束的地方。這個表達式實際上是兩個的組合:<--(賦值)和 ===(等式約束)。 [^7] Circom 中的約束只能使用涉及常量、加法或乘法的操作。它強制要求方程的兩邊必須相等。 [^8]

關於約束

約束是如何工作的?在類似數獨的上下文中,我們可能會說一個約束是“一個介於 1 和 9 之間的數字”。然而,在 Circom 的上下文中,這不是一個單一的約束,而是我們必須使用一組更簡單的等式約束(===)來表達的東西。 [^9]

爲什么會這樣?這與底層的數學原理有關。從根本上講,大多數 ZKP 使用 _算術電路_,它表示對 多項式 的計算。在處理多項式時,你可以輕松引入常量,將它們相加、相乘並檢查它們是否相等。 [^10] 其他操作必須用這些基本操作來表達。你不必詳細了解這一點才能編寫 ZKP,但了解底層發生的事情可能會很有用。 [^11]

我們可以將電路可視化如下:

構建我們的電路

供你參考,最終文件可以在 example1-solution.circom 中找到。有關語法的更多詳細信息,請參見 官方文檔[9]

我們可以通過運行以下命令來編譯我們的電路:

這是調用 circom 創建 example1.r1csexample1.wasm 文件的一個簡單包裝。你應該會看到類似以下內容:

    {
      "pi_a": ["15932[...]3948", "66284[...]7222", "1"],
      "pi_b": [
        ["17667[...]0525", "13094[...]1600"],
        ["12020[...]5738", "10182[...]7650"],
        ["1", "0"]
      ],
      "pi_c": ["18501[...]3969", "13175[...]3552", "1"],
      "protocol": "groth16",
      "curve": "bn128"
    }

這以一些數學對象(三個橢圓曲线元素)pi_api_bpi_c 的形式指定了證明。[^20] 它還包括有關協議(groth16)和使用的 _curve_(bn128,我們暫時忽略的數學實現細節)的元數據。這使得驗證者知道如何處理此證明以正確驗證。

請注意,證明是多么簡短;無論我們的特殊程序多么復雜,它的大小都只有這個。這展示了我們在 _友好的零知識證明介紹_[10] 中討論的 ZKP 的 succinctness 屬性。上述命令還輸出了我們的 _公共輸出_:

這是與我們的見證和電路對應的所有公共輸出的列表。在這種情況下,有一個公共輸出對應於 c:33。[^21]

我們證明了什么?我們知道兩個祕密值 ab,它們的乘積是 33。這展示了我們在上一篇文章中討論的 隱私 屬性。

請注意,證明在孤立狀態下沒有用,它需要隨之而來的公共輸出。

驗證證明

接下來,讓我們驗證這個證明。運行:

just verify_proof example1

這需要驗證密鑰、公共輸出和證明。通過這些,我們能夠驗證證明。它應該打印“證明已驗證”。請注意,驗證者從未接觸到任何私有輸入。

如果我們更改輸出會發生什么?打开 example1/target/public.json,將 33 更改爲 34,然後再次運行上述命令。

你會注意到證明不再被驗證。這是因爲我們的證明並沒有證明我們有兩個數字,其乘積是 34。

恭喜你,你現在已經編寫了你的第一個 ZKP 程序,進行了可信設置,生成了證明並最終驗證了它!

練習

  1. ZKP 的兩個關鍵屬性是什么,它們意味着什么?

  2. 證明者的角色是什么,她需要什么輸入?驗證者呢?

  3. 解釋 c <== a * b; 這一行的作用。

  4. 爲什么我們需要進行可信設置?我們如何使用其產物?

  5. 代碼:完成 example1,直到你生成並驗證了一個證明。

第二次迭代

通過上述電路,我們證明了我們知道兩個(祕密)數字的乘積。這與 質因數分解 問題密切相關,這是許多密碼學的基礎。[^22] 這個想法是,如果你有一個非常大的數字,找到兩個質數使其乘積等於這個大數字是很困難的。相反,檢查兩個數字的乘積是否等於另一個數字是非常簡單的。[^23]

然而,我們的電路存在一個大問題。你能看到嗎?

我們可以輕松地將輸入更改爲“1”和“33”。也就是說,一個數字 c 始終是 1 和 c 的乘積。這一點並不令人印象深刻,對吧?

我們想要做的是添加另一個 _約束_,使得 ab 不能等於 1。這樣,我們就被迫進行適當的整數因式分解。

我們如何添加這個約束,需要做哪些更改?

更新我們的電路

我們將爲這些更改使用 example2 文件夾。不幸的是,我們不能僅僅寫 a !== 1,因爲這不是一個有效的約束。[^24] 它不是由常量、加法、乘法和等式檢查組成的。我們如何表達“某物不是”?

這並不是立即直觀的,這種類型的問題是編寫電路的藝術所在。發展這種技能需要時間,並超出了本初始教程的範圍;幸運的是,有許多好的資源可以參考。[^25]

不過,有一些常見的習語。基本的想法是使用 IsZero() 模板來檢查一個表達式是否等於零。它對真值輸出 1,對假值輸出 0。

使用真值表[^26] 來顯示可能的值通常是有幫助的。以下是 IsZero() 的真值表:

這是一個如此有用的構建塊,以至於它被包含在 Circom 的庫 circomlib 中。在 circomlib 中還有許多其他有用的組件。[^27]

我們可以通過創建一個 npm 項目(JavaScript)並將其作爲依賴項添加來包含它。在 example2 文件夾中,我們已經爲你完成了這一步。要導入相關模塊,我們在 example2.circom 的頂部添加以下行:

include "circomlib/circuits/comparators.circom";

使用 IsZero(),我們可以檢查 ab 是否等於 1。修改 example2.circom 文件,使其包含以下行:

    just generate_proof example2
    just verify_proof example2

它仍然按預期生成和驗證證明。

如果我們將 example2/input.json 的輸入更改爲 133 並嘗試運行上述命令,我們將看到一個斷言錯誤。也就是說,Circom 甚至不會讓我們生成證明,因爲輸入違反了我們的約束。

完整流程圖

現在我們已經經歷了整個流程兩次,讓我們退後一步,看看所有部分是如何結合在一起的。

希望事情开始變得有些明朗。接下來,讓我們提升一下,讓我們的電路更有用。

練習

  1. 爲什么我們必須運行 example2 的第 2 階段,而不是第 1 階段?

  2. 上一個例子的主要問題是什么,我們是如何解決的?

  3. 代碼:完成 example2,直到你無法生成證明。

第三次迭代

通過上述電路,我們已經證明了我們知道兩個祕密值的乘積。單靠這一點並不是很有用。在現實世界中,有用的是 _數字籤名方案_。通過它,你可以向其他人證明你寫了特定的消息。我們如何使用 ZKP 來實現這一點?要實現這一點,我們必須首先涵蓋一些基本概念。

現在是短暫休息的好時機,去喝一杯你最喜歡的飲料。

數字籤名

數字籤名已經存在,並且在我們的數字時代無處不在。現代互聯網沒有它們是無法運作的。通常,這些是使用 公鑰密碼學 實現的。在公鑰密碼學中,你有一個私鑰和一個公鑰。私鑰僅供你自己使用,而公鑰是公开共享的,代表你的身份。

數字籤名方案由以下部分組成:

  • 密鑰生成:生成一個私鑰和相應的公鑰

  • 籤名:使用私鑰和消息創建籤名

  • 籤名驗證:驗證消息是否由相應的公鑰籤名

雖然具體細節看起來不同,但我們編寫的程序和上述密鑰生成算法共享一個共同元素:它們都使用 _單向函數_,更具體地說是 _陷門函數_。陷門是容易掉進去但難以爬出來的東西(除非你能找到一把隱藏的梯子) [^30]。

對於公鑰密碼學,從私鑰構造公鑰是容易的,但反過來卻非常困難。我們的前一個程序也是如此。如果這兩個祕密數字是非常大的質數,那么將該乘積轉回原始值是非常困難的。現代公鑰密碼學通常在底層使用 _橢圓曲线密碼學_。

傳統上,創建像這些數字籤名方案這樣的密碼協議需要大量的工作,並需要提出一個涉及一些巧妙數學的特定協議。我們不想這樣做。相反,我們想使用 ZKP 編寫一個程序,以實現相同的結果。

而不是這樣:[^31]

我們只想編寫一個程序,生成我們想要的證明,然後驗證這個證明。

哈希函數和承諾

我們將使用兩個更簡單的工具:_哈希函數_ 和 _承諾_,而不是使用橢圓曲线密碼學。

哈希函數也是一種單向函數。例如,在命令行中,我們可以這樣使用 SHA-256 哈希函數:

    commitment = hash(some_secret)
    signature = hash(some_secret, message)

此時你可能有一些問題。讓我們解決一些你腦海中可能存在的問題。

首先,爲什么這有效,我們爲什么需要 ZKP?當有人驗證證明時,他們只能訪問承諾、消息和籤名。沒有直接的方法可以驗證承諾是否對應於祕密,而不揭示祕密。在這種情況下,我們只是在生成證明時“揭示”祕密,因此我們的祕密保持安全。

其次,爲什么在 ZKP 內部使用這些哈希函數和承諾,而不是公鑰密碼學?你絕對可以在 ZKP 內部使用公鑰密碼學,並且這樣做是有合理理由的。就約束而言,它的實現成本遠高於上述方案。這使得它比上述更慢,更復雜。正如我們將在下一節中看到的,哈希函數的選擇非常重要。

最後,爲什么在我們已經擁有公鑰密碼學的情況下還要使用 ZKP?在這個簡單的例子中,沒有必要使用 ZKP。然而,它作爲更有趣的應用的構建塊,例如本文开頭提到的群籤名示例。畢竟,我們想要 _編程密碼學_。

這真是太多了!幸運的是,我們已經過了難關。讓我們开始編碼吧。如果你一开始沒有完全理解上述內容,也不用擔心。習慣這種推理方式需要一些時間。

回到代碼

我們將從 example3 目錄开始工作。

要實現數字籤名,我們需要做的第一件事是生成我們的密鑰。這些對應於公鑰密碼學中的私鑰和公鑰。由於密鑰對應於一個身份(你,證明者),我們將分別稱其爲 identity_secretidentity_commitment。它們共同形成一個身份對。

這些將作爲電路的輸入,與我們要籤名的消息一起使用。作爲公共輸出,我們將擁有籤名、承諾和消息。這將允許某人驗證籤名確實是正確的。

由於我們需要身份對作爲電路的輸入,因此我們將單獨生成這些:just generate_identity

這會產生類似於以下內容:

    include "circomlib/circuits/poseidon.circom";

Poseidon 哈希模板的使用如下:

    component main {public [identity_commitment, message]} = SignMessage();

默認情況下,我們電路的所有輸入都是私有的。通過這個,我們明確標記 identity_commitmentmessage 爲公共。這意味着它們將成爲公共輸出的一部分。

有了這些信息,你應該有足夠的知識來完成 example3.circom 電路。如果你仍然卡住,可以參考 example3-solution.circom 獲取完整代碼。

像之前一樣,我們必須構建電路並運行受信任設置的第 2 階段:

    {
      "identity_secret": "21879[...]1709",
      "identity_commitment": "48269[...]7915",
      "message": "42"
    }

隨意將身份對更改爲你自己使用 just generate_identity 生成的身份對。畢竟,你想把身份祕密保留給自己!

你可能會注意到消息只是一個作爲字符串引用的數字 ("42")。不幸的是,由於約束在數學上的工作方式(使用线性代數和 _算術電路_),我們只能使用數字而不能使用字符串。電路內部支持的唯一操作是基本的算術操作,如加法和乘法。[^37]

我們現在可以生成和驗證一個證明:

    ["48968[...]5499", "48269[...]7915", "42"]

這分別對應於籤名、承諾和消息。

讓我們看看如果我們不小心,事情可能會出錯。 [^38]

首先,如果我們將身份承諾更改爲 input.json 中的隨機內容,會發生什么?你會注意到我們無法再生成證明。這是因爲我們還在電路內部檢查身份承諾。保持身份祕密和承諾之間的關系至關重要。

其次,如果我們不將消息包含在輸出中,會發生什么?我們確實得到了一個證明,並且它得到了驗證。但消息可以是 _任何東西_,因此它實際上並不能證明你發送了特定的消息。類似地,如果我們不將身份承諾包含在公共輸出中,會發生什么?這意味着身份承諾可以是任何東西,因此我們實際上不知道 籤署了消息。

作爲思考練習,想想如果我們省略這兩個關鍵約束中的任何一個會發生什么:

  • identity_commitment === identityHasher.out

  • signature <== signatureHasher.out

恭喜你,現在你知道如何編程加密了![^39]

練習

  1. 數字籤名方案的三個組成部分是什么?

  2. 使用像 Poseidon 這樣的 "ZK-Friendly hash function" 的目的是什么?

  3. 什么是承諾?我們如何將它們用於數字籤名方案?

  4. 爲什么我們將身份承諾和消息標記爲公共?

  5. 爲什么我們需要身份承諾和籤名約束?

  6. 代碼:完成 example3,直到你生成並驗證了一個證明。

下一步

通過上述數字籤名方案,以及我們在文章中看到的一些技巧,你擁有了實現文章开頭提到的 群籤名方案 的所有工具。[^40]

example4 中存在骨架代碼。你只需要 5-10 行代碼。唯一的新語法是 for 循環,它的工作方式與大多數其他語言相同。[^41]。

這個電路將允許你:

  • 籤署一條消息

  • 證明你是三個人之一(身份承諾)

  • 但不透露是哪一個

你可以把它看作一個謎題。關鍵的見解基本上歸結爲一個算術表達式。如果可以的話,嘗試在紙上解決它。如果你卡住了,可以像之前一樣查看解決方案。

最後,如果你想要一些額外的挑战,這裏有一些擴展的方法:

  1. 允許組內任意多的人

  2. 實現一個新的電路 reveal,證明你籤署了特定的消息

  3. 實現一個新的電路 deny,證明你沒有籤署特定的消息

使用經典工具創建這樣的加密協議將是一項巨大的任務,需要大量的專業知識。[^42] 使用 ZKP,你可以在一個下午變得高效和危險,將這些問題視爲編程任務。這只是我們可以做的冰山一角。

練習

  1. 群籤名與普通籤名有什么不同?它們可以如何使用?

問題

這些問題是可選的,需要更多的努力。

  1. 找出 IsZero() 是如何實現的。

  2. 代碼:完成上述群籤名方案(見 example4)。

  3. 代碼:擴展上述群籤名示例:允許更多人並實現 reveal 和/或 deny 電路。

  4. 你將如何設計一個 "ZK 身份" 系統來證明你已滿 18 歲?你可能想證明的其他屬性是什么?從高層次來看,你將如何實現它,以及你看到的挑战是什么?研究現有解決方案以更好地理解它們是如何實現的。

  5. 對於像以太坊這樣的公共區塊鏈,有時會使用 Layer 2 (L2) 來允許更快、更便宜和更多的交易。從高層次來看,你將如何使用 ZKP 設計一個 L2?解釋你看到的一些挑战。研究現有解決方案以更好地理解它們是如何實現的。## 結論

在本教程介紹中,我們熟悉了如何從頭开始編寫和修改基本的零知識證明(ZKPs)。我們設置了編程環境並編寫了一個基本電路。然後我們進行了可信設置,創建並驗證了證明。我們識別了一些問題並改進了電路,確保測試我們的更改。之後,我們使用哈希函數和承諾實現了一個基本的數字籤名方案。

我們還學習了足夠的技能和工具,以便能夠實現群體籤名,這在沒有零知識證明的情況下是很難實現的。

我希望你對編寫零知識證明所涉及的內容有了更好的心理模型,並對實際中的編輯-運行-調試周期有了更好的理解。這將爲你將來可能編寫的任何其他零知識證明程序打下良好的基礎,無論你最終使用什么技術棧。

致謝

感謝 Hanno Cornelius、Marc Köhlbrugge、Michelle Lai、lenilsonjr 和 Chih-Cheng Liang 閱讀草稿並提供反饋。

圖片

  • Bourbaki Congress 1938 - 未知,公有領域,通過 Wikimedia[11]

  • Hartmann's Zebras - J. Huber,CC BY-SA 2.0,通過 Wikimedia[12]

  • Trapdoor Spider - P.S. Foresman,公有領域,通過 [Wikimedia](https://commons.wikimedia.org/wiki/File:Trapdoor_(PSF\ "Wikimedia").png)

  • Kingsley Lockbox - P.S. Foresman,公有領域,通過 Wikimedia[13]

參考資料

[1] AI翻譯官: https://learnblockchain.cn/people/19584

[2] 翻譯小組: https://learnblockchain.cn/people/412

[3] learnblockchain.cn/article…: https://learnblockchain.cn/article/9178

[4] 零知識的友好介紹: https://learnblockchain.cn/article/6184

[5] git 倉庫: https://github.com/oskarth/zkintro-tutorial

[6]git 倉庫: https://github.com/oskarth/zkintro-tutorial

[7]這裏: https://docs.circom.io/getting-started/installation/

[8]zkrepl.dev: https://zkrepl.dev/

[9]官方文檔: https://docs.circom.io/circom-language/signals/

[10]友好的零知識證明介紹: https://learnblockchain.cn/article/6184

[11]Wikimedia: https://commons.wikimedia.org/wiki/File:Bourbaki_congress1938.png

[12]Wikimedia: https://commons.wikimedia.org/wiki/File:Hartmann_zebras_hobatereS.jpg

[13]Wikimedia: https://commons.wikimedia.org/wiki/File:Kingsley_lockbox.jpg

[14]AI 翻譯官: https://learnblockchain.cn/people/19584

[15]這裏: https://github.com/lbc-team/Pioneer/blob/master/translations/9178.md

[16]^2]:  參見 [聯邦黨人文集(維基百科): https://en.wikipedia.org/wiki/The_Federalist_Papers#Authorship

[17]^3]:  參見 [Bourbaki(維基百科): https://en.wikipedia.org/wiki/Nicolas_Bourbaki#Membership

[18]^8]:  這使得編寫約束相當具有挑战性,正如你可以想象的那樣。有關 Circom 中約束的更多詳細信息,請參見 [https://docs.circom.io/circom-language/constraint-generation/: https://docs.circom.io/circom-language/constraint-generation/

[19]^12]:  线性約束意味着它可以僅通過加法表示爲线性組合。這相當於使用常數進行乘法。需要注意的主要是线性約束比非线性約束更簡單。有關更多詳細信息,請參見 [約束生成: https://docs.circom.io/circom-language/constraint-generation/

[20]算術電路: https://docs.circom.io/background/background/#arithmetic-circuits

[21]^13]:  從數學上講,我們所做的是確保方程 Az * Bz = Cz 成立,其中 Z=(W,x,1)ABC 是矩陣,W 是見證(私有輸入),x 是公共輸入/輸出。雖然知道這一點很有用,但編寫電路時並不需要理解這一點。有關更多詳細信息,請參見 [Rank-1 約束系統: https://docs.circom.io/background/background/#rank-1-constraint-system

[22]^15]:  正如在 友好的介紹 文章中提到的那樣,2016 年 Zcash 舉辦的儀式有一個很好的外行播客,你可以在 [這裏: https://radiolab.org/podcast/ceremony

[23]^17]:  我們稱之爲 1-out-of N 信任模型。還有許多其他信任模型;你最熟悉的可能是多數規則,即你信任大多數人做出正確的決定。這基本上就是民主和大多數投票的運作方式。 [↩: #user-content-fnref-17

[24]^22]:  也稱爲 _密碼學難度假設_。請參見 [計算難度假設 (維基百科): https://en.wikipedia.org/wiki/Computational_hardness_assumption#Common_cryptographic_hardness_assumptions

[25]^23]:  有關更多信息,請參見 [https://en.wikipedia.org/wiki/Integer_factorization: https://en.wikipedia.org/wiki/Integer_factorization

[26]^24]:  雖然我們可以添加 _asserts_,但這些實際上不是約束,僅用於清理輸入。有關其工作原理,請參見 [https://docs.circom.io/circom-language/code-quality/code-assertion/: https://docs.circom.io/circom-language/code-quality/code-assertion/

[27]https://www.chainsecurity.com/blog/circom-assertions-misconceptions-and-deceptions: https://www.chainsecurity.com/blog/circom-assertions-misconceptions-and-deceptions

[28]^25]:  這份由 0xPARC 提供的資源非常出色,如果你想深入了解編寫 (Circom) 電路的藝術: [https://learn.0xparc.org/materials/circom/learning-group-1/circom-1/: https://learn.0xparc.org/materials/circom/learning-group-1/circom-1/

[29]^26]:  由於編寫約束的性質,這種情況經常出現。請參見 [https://en.wikipedia.org/wiki/Truth_table: https://en.wikipedia.org/wiki/Truth_table

[30]^27]:  有關 circomlib 的更多信息,請參見 [https://github.com/iden3/circomlib: https://github.com/iden3/circomlib

[31]^28]:  請參見 [https://github.com/iden3/circomlib/blob/master/circuits/comparators.circom: https://github.com/iden3/circomlib/blob/master/circuits/comparators.circom

[32]^29]:  人們通常在項目之間共享這些 ptau 文件以提高安全性。有關詳細信息,請參見 [https://github.com/privacy-scaling-explorations/perpetualpowersoftau: https://github.com/privacy-scaling-explorations/perpetualpowersoftau

[33]https://github.com/iden3/snarkjs: https://github.com/iden3/snarkjs

[34]^30]:  這裏的梯子代表某種值,使我們能夠以相反的“困難”方式進行。另一種思考方式是將其視爲一個掛鎖。你可以輕松鎖定它,但很難解鎖,除非你有鑰匙。陷門函數也有更正式的定義,請參見 [https://en.wikipedia.org/wiki/Trapdoor_function: https://en.wikipedia.org/wiki/Trapdoor_function

[35]^31]:  來自維基百科的截圖。請參見 [ECDSA (維基百科): https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_verification_algorithm

[36]^38]:  在現實世界的數字籤名方案中,當多個消息交換時,我們可能還希望引入一個加密隨機數。這是爲了避免重放攻擊,即某人可以在稍後時間重用相同的籤名。請參見 [https://en.wikipedia.org/wiki/Replay_attack: https://en.wikipedia.org/wiki/Replay_attack

[37]^40]:  在 ZKP 中實現群籤名的靈感來自 0xPARC,請參見 [https://0xparc.org/blog/zk-group-sigs: https://0xparc.org/blog/zk-group-sigs

[38]^41]:  請參見 [https://docs.circom.io/circom-language/control-flow/: https://docs.circom.io/circom-language/control-flow/

[39]^42]:  相比之下,實施群籤名的論文如 [https://eprint.iacr.org/2015/043.pdf: https://eprint.iacr.org/2015/043.pdf

標題:零知識證明編程——用Circom、Groth16構建證明及驗證

地址:https://www.coinsdeep.com/article/158344.html

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播信息之目的,不構成任何投資建議,如有侵權行為,請第一時間聯絡我們修改或刪除,多謝。

你可能還喜歡
熱門資訊