零知識證明程式設計-用Circom、Groth16建構證明及驗證

來源:登鏈社區

為工作程式設計師提供的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 等於a 和b 的乘積

  • component main = Multiplier2() – 實例化我們的主元件

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

關於約束

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

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

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

建構我們的電路

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

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

這是呼叫circom 建立example1.r1cs 和example1.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_a、pi_b 和pi_c 的形式指定了證明。[^20] 它還包括有關協議(groth16)和使用的_curve_(bn128,我們暫時忽略的數學實作細節)的元資料。這使得驗證者知道如何處理此證明以正確驗證。

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

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

我們證明了什麼?我們知道兩個秘密值a 和b,它們的乘積是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 的乘積。這一點並不令人印象深刻,對吧?

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

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

更新我們的電路

我們將為這些變更使用example2 資料夾。不幸的是,我們不能只是寫a !== 1,因為這不是有效的限制。[^24] 它不是由常數、加法、乘法和等式檢查組成的。我們如何表達「某物不是」?

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

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

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

zAskFsVTE2hHYgsVNDGRh4saCBLWOIQXYHWuXIpW.jpeg

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

我們可以透過建立一個npm 專案(JavaScript)並將其作為依賴項新增來包含它。在example2 資料夾中,我們已經為你完成了這一步。若要匯入相關模組,我們在example2.circom 的頂部新增以下行:

include “circomlib/circuits/comparators.circom”;

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

just generate_proof example2
just verify_proof example2

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

如果我們將example2/input.json 的輸入更改為1 和33 並嘗試執行上述命令,我們將看到一個斷言錯誤。也就是說,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_secret 和identity_commitment。它們共同形成一個身分對。

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

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

這會產生類似以下內容:

include “circomlib/circuits/poseidon.circom”;

Poseidon 哈希模板的使用如下:

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

預設情況下,我們電路的所有輸入都是私有的。透過這個,我們明確標記identity_commitment 和message 為公共。這意味著它們將成為公共輸出的一部分。

有了這些訊息,你應該有足夠的知識來完成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 – PS Foresman,公有領域,透過 [Wikimedia](https://commons.wikimedia.org/wiki/File:Trapdoor_(PSF\ “Wikimedia”).png)

  • Kingsley Lockbox – PS 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)。 A、B 和C 是矩陣,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://eprintiacrorg/2015/043pdf:https://eprintiacrorg/2015/043pdf[https://eprintiacrorg/2015/043pdf:https://eprintiacrorg/2015/043pdf

Total
0
Shares
Related Posts