雖然這篇Preimage attack鄉民發文沒有被收入到精華區:在Preimage attack這個話題中,我們另外找到其它相關的精選爆讚文章
在 preimage產品中有3篇Facebook貼文,粉絲數超過3,460的網紅Taipei Ethereum Meetup,也在其Facebook貼文中提到, 📜 [專欄新文章] Tornado Cash 實例解析 ✍️ Johnson 📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium Tornado Cash 是一個使用 zk-SNARKs 建立...
同時也有10000部Youtube影片,追蹤數超過2,910的網紅コバにゃんチャンネル,也在其Youtube影片中提到,...
preimage 在 Taipei Ethereum Meetup Facebook 的最讚貼文
📜 [專欄新文章] Tornado Cash 實例解析
✍️ Johnson
📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium
Tornado Cash 是一個使用 zk-SNARKs 建立的 Dapp,它實現了匿名的代幣交易,這篇文章就用一些程式碼片段,來分享它是怎麼運作的。
本文為 Tornado Cash 研究系列的 Part 3,本系列以 tornado-core 為教材,學習開發 ZKP 的應用,另兩篇為:
Part 1:Merkle Tree in JavaScript
Part 2:ZKP 與智能合約的開發入門
Special thanks to C.C. Liang for review and enlightenment.
我們知道在以太坊上的交易紀錄都是公開的,你可以在 etherscan 上看到某個地址的所有歷史交易紀錄,當然地址是合約的話也是一樣。
也許創建一個新的錢包和地址就好了?假設一個情境是 Alice 想要匿名傳送 1 ETH 給 Bob,Alice 原本的錢包是 A,但她不想讓 A 地址傳給 Bob 的交易紀錄被看到,所以 Alice 創建另一個錢包 B,顯然 B 錢包是空的,Alice 必須把 A 錢包的 1 ETH 傳到 B 錢包,再用 B 錢包的地址傳給 Bob。
但問題就在於,只要追蹤 B 錢包的地址,就能看到 B 的歷史交易紀錄中 A 錢包曾經打幣給 B 錢包,於是到頭來交易還是被追蹤到了。
Tornado Cash 的解決方案,簡單來說,它是一份合約,當你要匿名傳送代幣時,就把一定數量的幣丟進合約裡 (Deposit),此時你會拿到一個 note,長得像這樣:
tornado-eth-0.1-5-0x3863c2e16abc85d72b64d78c68fca5936db2501832e26345226efdfb2bc45804977f167d86b711bb6b4095ddaa646ec93f0a93ac4884a66c1d881f4fc985
note 就是一串字串,擁有這字串的人,就能提領 (Withdraw) 剛剛傳入合約的代幣。握有 note 就代表擁有提款的權利,所以 note 一旦被別人知道,別人就可以把錢給提走。
其中,後面那段亂碼,本篇文章就以「秘密」來稱呼,這個秘密是由 secret 與 nullifier 組成,而這兩個都是在鏈下隨機產生的亂數。
因此 Tornado 的合約基本上會有兩個函式:
Deposit
Withdraw
有興趣的人可以先到 Dapp 上先玩一次看看,使用 Goerli 測試網,這裡可以領 Goerli 的代幣:https://goerli-faucet.slock.it/
Deposit
我們就從 Deposit 開始說起,簡單來說, Deposit 是將資料儲存到合約的 Merkle Tree 上。
剛剛提到的秘密,它是在鏈下產生,由 secret 跟 nullifier 組成,合在一起之後也稱作 preimage,因為我們要對這個 preimage 進行 hash,就會成為 commitment。
合約中 Deposit 如下:
deposit 除了傳送代幣到合約之外,需填入一個參數 _commitment。
我們對 preimage 使用 Pedersen 作為 hash function 加密後產生 commitment,以偽代碼表示如下:
const preimage = secret + nullifier;const commitment = pedersenHash(preimage);
這個 commitment 會成為 Merkle Tree 的葉子,所以合約中的 _insert(commitment) 來自 MerkleTreeWithHistory.sol 的合約,將我們的資料插入 Merkle Tree,然後回傳一個 index 給你,告訴你這個 commitment 在 Merkle Tree 上的位置,最後一起發布成公開的 Deposit 事件。
我們知道 MerkleTree 是將一大筆資料兩兩做雜湊後產生一個唯一值 root,這個 root 就是合約上所儲存的歷史資料。
root 的特性就是只要底下的資料一有更動,就會重新產生新的 root。
所以只要一有用戶 deposit ,就會插入新的葉子到 Merkle Tree 上,於是就會產生新的 root,所以在合約中有一個陣列是用來儲存所有的 root 的 roots:
bytes32[ROOT_HISTORY_SIZE] public roots;
roots 是用來紀錄每個 deposit 的歷史,每一次 deposit 都會創造新的 root,而所有 root 都會被儲存進 roots 裡,於是當你要提領的時候,就要證明你的 commitment 所算出的 root 曾經出現在 roots 裡,代表曾經有 deposit 的動作,因此才可以進行提領。
Withdraw
在 Deposit 之前 Tornado Cash 就會在鏈下產生秘密後交給使用者,擁有這個秘密的人等於擁有提款的權利。
提領的時候,秘密會在鏈下計算後產生 proof,proof 是 withdraw 需要的參數,所以只要確保這個 proof 能夠被驗證,那麼代幣的接收地址 (recipient) 就可以隨便我們填,只要不填上當初拿來 deposit 用的地址,基本上就做到匿名交易的效果了。
也就是說,產生這個 proof 並提交給合約,能夠證明此人知道秘密,但卻不告訴合約秘密本身是什麼。
function withdraw(bytes calldata _proof, bytes32 _root, bytes32 _nullifierHash, address payable _recipient, address payable _relayer, uint256 _fee, uint256 _refund) external payable nonReentrant;
我們可以清楚看到 withdraw 函式裡沒有接收有關秘密的任何資訊作為參數,也就是秘密不會與合約有所接觸,也不會暴露在 etherscan 上。
回顧 ZKP 所帶來的效果:
鏈下計算
隱藏秘密
在 Tornado Cash 的例子中,我們用秘密來產生證明,完成的鏈下計算包括:
將秘密 hash 成 commitment
算出 Merkle Tree 的 root。
以下是簡化後的 withdraw.circom:
template Withdraw(levels) { signal input root; signal input nullifierHash;
signal private input nullifier; signal private input secret; signal private input pathElements[levels]; signal private input pathIndices[levels];
component hasher = CommitmentHasher(); // Pedersen hasher.nullifier <== nullifier; hasher.secret <== secret; hasher.nullifierHash === nullifierHash;
component tree = MerkleTreeChecker(levels); // MiMC tree.leaf <== hasher.commitment; tree.root <== root; for (var i = 0; i < levels; i++) { tree.pathElements[i] <== pathElements[i]; tree.pathIndices[i] <== pathIndices[i]; }}
component main = Withdraw(20);
從上述代碼就可以看出這份 circuit 的 private 變數有:
secret
nullifier
pathElements
pathIndices
而 public 變數有:
root
nullifierHash
如同我們一開始說過的,秘密就是指 secret 與 nullifier。這裡進行的鏈下計算就是對 secret 與 nullifier 雜湊成 commitment。而使用的 hash function 叫做 Pedersen。
在進行 Merkle Tree 的計算之前,我們還檢查了 nullifier 雜湊後的 nullifierHash 跟 public 變數 nullifierHash 是不是一樣的。
hasher.nullifierHash === nullifierHash;
接下來,開始計算 Merkle Proof,用意是確認經過雜湊後的 commitment 有沒有出現在 Merkle Tree 上,所以我們的 private input 還有 pathElements 與 pathIndices(詳情參考 Part 1 Merkle Tree in JavaScript),讓它跑一趟 Merkle Proof 的計算,最後就能夠算出一個 root,再確認計算後的 root 與我們的 public 變數 root 是否一樣。
tree.root <== root;
於是我們就能產生一個 ZKP 的證明 — 證明 private 變數:secret, nullifier, pathElements, pathIndices 可以計算出 public 變數:root 與 nullifierHash。
把這個證明提交給合約,合約透過 Verifier 驗證 proof 是否正確,以及必須事先確認:
public 變數 root 有在合約的 roots 裡面。
public 變數 nullifierHash 在合約中是第一次出現。
以下附上完整的 withdraw 原始碼:
必須注意 ZKP 是向合約證明使用者填入的 secret 和 nullifier 可以計算出某個 root,但無法保證這個 root 曾經在合約的 roots 歷史上。
所以合約的 withdraw 中,除了 verifyProof 之外,還要事先檢查 ZKP 算出來的 root 是不是真的在歷史上發生過,所以需要 isKnownRoot 的檢查:
function isKnownRoot(bytes32 _root) public view returns(bool)
必須先檢查 isKnownRoot 後才能進行 verifyProof。
經過 verifyProof 驗證成功後,合約就開始進行提款的動作,也就會將代幣傳到 recipient 的地址,最後拋出 Withdrawal 的事件。
nullifier 與 nullifierHash
為什麼我們的秘密不是只有 secret 還要額外加一個 nullifier?
簡單來說,這是為了防止已經提領過的 note 又再提領一次,也就是所謂的 double spend。
require(!nullifierHashes[_nullifierHash], "The note has been already spent");
可以看到 withdraw 需要填入參數 nullifierHash,跟 isKnownRoot 一樣的狀況,我們需要對電路的 public 變數先經過一層檢查之後,才能帶入到 verifyProof 裡面。
nullifierHash 可以理解為這個 note 的 id,但它不會連結到 deposit,因此可以用來紀錄這個 note 是否已經被提領過。
所以當 verifyProof 驗證成功之後,我們要紀錄 nullifierHash 已完成提領:
nullifierHashes[_nullifierHash] = true;
有關為什麼需要事先檢查 public 變數後,才能帶入 verifyProof ,可以參考 Part 2:ZKP 與智能合約的開發入門 提到的 publicSignals 的部分。
附上 Tornado Cash 的架構圖:
簡化版的 tornado-core
tornado-core 的程式碼很簡潔漂亮,所以我模仿該專案自己實作一遍:
simple-tornado:https://github.com/chnejohnson/simple-tornado
這份專案只完成了 tornado-core 的核心部分,不一樣的是我的開發環境使用 hardhat 與 ethers 寫成,而 circom 與 snarkjs 使用官方當前的版本,合約用 0.7.0,測試使用 Typescript 。
比起兩年前的 tornado-core ,simple-tornado 使用的技術更新,可能更適合初學者理解這份專案,但是它有 bug…我在 issues 的地方有紀錄說明。
在開發的過程中,我的順序是先從最小單位的 MiMC hash function 開始玩,發現必須 javascript 算一次 hash、solidity 算一次、circom 再算一次,確保這三個語言對同一個值算出同樣的 hash 之後,才能放心去做更複雜的 Merkle Tree。
總結
我們可以看到 Tornado Cash 簡單的兩個函式:Deposit 與 Withdraw,透過將代幣送入合約後再提領到另一個地址的流程,應用 ZKP 達成匿名的交易。
除了斷開 Deposit 與 Withdraw 的地址關聯性之外,Tornado Cash 還有做了一層「藏樹於林」的隱私防護,這部份的解釋就請參考 ZKP 讀書會 Tornado Cash。
網路上很多關於 ZKP 的文章或專案都是在 2019 年後出產的,經過許多人對這項技術的嘗試,讓我們對 ZKP 有了更清晰的理解,如今兩年後,開發工具也變得更加成熟,期待未來在 web 隱私議題上能看到更多 ZKP 大放異彩的應用。
原始碼
tornado-core
simple-tornado
參考資料
ZKP 讀書會 Tornado Cash
Tornado Privacy Solution Cryptographic Review
Tornado Cash 實例解析 was originally published in Taipei Ethereum Meetup on Medium, where people are continuing the conversation by highlighting and responding to this story.
👏 歡迎轉載分享鼓掌
preimage 在 Taipei Ethereum Meetup Facebook 的精選貼文
📜 [專欄新文章] [ZKP 讀書會] Tornado Cash
✍️ Jerry Ho
📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium
Disclaimer: 本人與Tornade Cash專案及其員工無任何利益往來。
Tornado Cash是一個Ethereum上的原生隱私轉帳解決方案,使用zk-SNARK+Merkle Tree的路徑證明作為其核心隱私保護機制。
你知我知,Ethereum上的交易記錄是公開的,這使得任何一個人只要知道你的address,便可以在https://etherscan.io/ 之類的網站上查出有多少人和這個位置進行過交易,你做過什麼消費行為或是交易行為等。
或許這聽來不像是個問題,而想要隱藏自己的交易記錄甚至聽起來反而像是不法分子的銷贓行為。
但試想下開情境:因為我曾經使用ethereum捐款給一個政治不正確的專案/組織,而我在接受dd/kyc/reference check的時候因為我的ethereum address就寫在自己的blog上而被查了個底朝天,因而被拒絕入職/拒絕開戶/拒絕服務。
這並不是一個很遙遠的情境…
Tl;dr
解決交易隱私問題分為兩個層次,Assuming你的目的是讓自己的金錢流向無法被追蹤。
層次一:我的錢「丟進了」Tornado Cash的contract,我要如何在不使用與轉入時同一個address的情況下— 若是同一個address就沒有隱私可言了 — 取出我的錢?contract如何知道我存過錢,餘額還夠,所以現在我來領錢了他讓我領?
層次二:就算層次一成立,我的隱私如何達成?到底有多隱私?到底有多不隱私?
技術上來說(細節下文詳談),層次一使用zero-knowledge的set-membership proof來證明,透過預先在Merkle Tree中「登記」一個自己的entry/leaf,tornado cash稱為note,爾後在提款時提出該leaf之zk proof,來解決這個提款時的認證問題。
層次二則是所謂的藏樹於林。既然轉出和轉入無法被連結在一起,那麼只要使用Tornado Cash的人數夠多,總轉出和總轉入的交易總筆數就會太多,以致無法輕易重新關聯轉入與轉出地址背後的真人。
使用界面
https://tornado.cash/
當然你也可以直接和合約地址互動啦
上圖左方紅框為存入幣種與金額大小,右方紅框為該額度對應之帳戶內有多少顆「樹」。
記得藏樹於林嗎?右方的 Anonymity set 就是告訴你現在森林的規模有多大。數量一大,跑資料分析試圖重新關聯某筆特定存款到某筆特定提款就變得更為困難。
提款界面如上。
值得注意的是,提款時的以上兩個選項(Wallet/Relayer),是在目前Account Abstraction尚未實現時的一個折衷方案。
這裡有個死循環:既然我提款的時候需要支付gas,那麼我的gas從哪裡來?是不是勢必得從交易所或是其他帳號來?簡言之,若是無法直接新建立一個地址然後直接將其作為Tornado Cash提款用,達到的隱私強度就大打折扣。
Relayer就是針對這個問題所設計的。透過付出一些手續費來提供社群架設relayer node的誘因,提款時該筆轉帳的gas費用,便可以讓relayer node來負責先出。relayer node收到使用者的zk proof後將其轉交給tornado cash的合約,合約就會會將應有的relayer手續費與扣除手續費+gas後的款項分別轉給relayer與使用者。
社群治理
Tornado Cash天生是一個比較沒有銅臭味的專案 — 社群治理和funded的味道相當強烈。
透過預先設計好的proxy contract與staking/locking機制,任何一個Tornado Cash的使用者都能夠提出對合約實行的改動建議,並交由社群來投票決定是否要執行該改動。
技術細節可以參照此篇,同時Tornado Cash的第一輪社群治理提案也剛投票過關,回顧可參考此處之討論。
誘因設計
本文作者比較任性不在意錢,請移駕此處閱讀官方如何設計Anonymity Mining來確保以下兩點:
機制能讓使用者願意加入存錢,提供流動性同時也讓樹林變大,增加隱私程度。
產生TORN(ERC20 token)與領取TORN的機制,透過在原本的tornado cash上面再加一層,來避免TORN激勵層錯誤的設計導致下一層之隱私洩漏(激勵層出事不影響核心隱私之意)。
技術細節
首先本文不打算解釋何為zero-knowledge proof,請接受以下描述:
若有一NP statement分類上是satisfiability problem(例:merkle tree中的hash chaining H(H(H(a,b),c),d) ),則我們可以設計出一個arithmetic circuit來確保能夠有效率的產生proof, 有效率的驗證, 無法產生假的且能說服人的proof…且其電路驗證的statement是我們想要的,像是此例中的merkle tree opening.
存款
存款者透過送出C = H(k, r) 以及存入之數額給tornado cash的合約來進行存款的動作。其中k在之後會成為存款者領錢的憑證,稱為nullifier,r則是增加randomness而已,此二值需要記下。此時合約端會將這個C(commitment)丟入Merkle Tree上其中一個空的leaf,並更新root hash。存款者還需要記下自己的C對應之leaf index。
產生proof,用此proof作為提款憑證
用一段話來概括,若是我
知道Merkle Tree上某個leaf的commitment的preimage, 代表我能在電路中證明我知道H(k, r) 中的 k, r, 同時不洩漏k, r到底是多少(zk特性, magic)。
我知道該leaf至root的路徑上會經過哪些點,我也提供了一個可以讓電路驗證root hash的hash chaining過程,代表我知道他是從哪個leaf開始走的。因而,這證明了我提出的1.中的commitment確實屬於某顆公開的、大家都知道的merkle tree中的特定leaf(就是我之前存款對應到的leaf)。
就可以在不需要提供像是原本存款地址的簽章之類的驗證機制情況下,透過zk proof,亦能正確做permission control讓unlinkable的提款能夠成真。
另,讀者可以看到在proof中已然預設了relayer的存在。這使得上開所提到之「使用者提款, 拜託relayer執行=>relayer預付gas發起transaction,將內容送給tornado cash合約=>合約處理proof並將款項拆成兩份給relayer與使用者」這個行為得以成立,且relayer無法得知或假造proof內容。
提款流程
基本上在上方的產生證明都講過一次了,這邊就是pseudo code順過一次提款流程而已,大家自己看啊。
值得一提的是,使用者除了需要提出上一部分提到的證明之外,還需要將k的部分額外拿出來再做一次H(k),將值一併傳給contract。
這裡的設計哲學,簡單來講是這樣的:zero-knowledge太強了,強到就算證明了我知道H(k, r)的k跟r, 收到的驗證者並沒有辦法知道H(k)是什麼東西。為了讓同一筆款項不會被提領兩次,在提款流程中合約會將「每一筆成功提款中的H(k)」記錄下來,另外開個表存著。爾後若是其他提款交易中的H(k)與表中的重複了,這就代表有人試圖想要騙合約重複提款,自然該提款嘗試就不會成立。
洗錢失敗例
工程師都知道使用者從來不看說明書,看了可能也不會懂。
Koh Wei Jie分析了Kucoin的駭客事件。Kucoin的駭客使用Tornado Cash來洗錢,但忽略了Tornado Cash官方一直三令五申的使用需知,因而讓款項在進入Tornado Cash跑了一輪之後還是能夠被追蹤,哈哈UCCU。
簡單來說,hacker為了節省多次使用relayer的手續費,而將大多數的提領過程都變成直接提領到wallet。雖然該wallet的位置是全新產生的沒有gas,但是透過只讓第一次的提款使用relayer,hacker便能從第一次提款中取得手續費並分發給其他全新產生的wallet address。
那問題在哪?還要問?
要達到隱私需要保持藏樹於林原則,同時使用者不應自己破壞tornado cash幫你達成的address unlinkability。這位hacker因為愛省手續費,所以違背了後者;同時他因為太心急又愛省手續費,太快、分太少次提領、每次提領的數額又太大了,所以side-channel去給他做簡單的traffic analysis就能夠用虛無假設推出:「綜觀歷史上所有的存款位置與數額,扣掉駭客存錢的那些位址之後,我們還需要14個unique address/user共謀,才能有能力一次提這麼多錢。」
這看起來可能嗎?自然是不可能的。
所以這位駭客就是錯誤的沒有遵守藏樹於林的原則,才導致自己的金流重新被和帳號聯繫在一起。
提供一些延伸閱讀,圈子內的”名人”對這種不看說明書的使用者的看法:
tornado * Gavin Andresen
如何避免洗錢失敗
我自己的投影片,我自己翻譯:
打開你的VPN 打開你的TOR 打開你的無痕瀏覽器分頁 用上你全新的VM PC VPS instance 最好連data-link layer安全都顧到 產生全新的地址不要懶惰 自己跑一個fullnode 乖乖用relayer付手續費提款 領錢之後記得把C(k,r)的記錄刪掉 不要急一次存或提領大額 時間拉長數目減少…..
簡而言之:要設計相對安全但又讓使用者可以直覺上手的安全系統真的很他媽難 - 使用者永遠會想辦法抄近路,然後系統的security assumption就爆炸了。
結論上來講,你想要多安全取決於你在臺大水源校區的腳踏車平常都上幾個大鎖=想付出多少成本。只要不要學Kucoin Hacker那樣連鎖都不鎖車還是新的,大部分時間都沒啥問題 lol。
參考資料與文中出現過的連結,不按先後順序:
https://tornado.cash/Tornado.cash_whitepaper_v1.4.pdf
https://tornado.cash/audits/TornadoCash_cryptographic_review_ABDK.pdf
https://tornado.cash/audits/TornadoCash_circuit_audit_ABDK.pdf
https://torn.community/t/whats-next-for-tornado-cash-governance/250
https://weijiek.medium.com/deanonymising-the-kucoin-hacker-418fa5e9911d
https://tornado-cash.medium.com/tornado-cash-governance-proposal-a55c5c7d0703#2084
https://eips.ethereum.org/EIPS/eip-2938
http://gavinandresen.ninja/private-thoughts
[ZKP 讀書會] Tornado Cash was originally published in Taipei Ethereum Meetup on Medium, where people are continuing the conversation by highlighting and responding to this story.
👏 歡迎轉載分享鼓掌
preimage 在 Taipei Ethereum Meetup Facebook 的最佳解答
📜 [專欄新文章] Boomerang: 在支付通道網路中利用冗餘改進Latency以及Throughput
✍️ Brian Po-han Chen
📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium
上個月去參加Stanford Blockchain Conference 2020,聽到了許多我覺得很有趣的新題目,有時間再一一分享
我一直對區塊鏈的Scalability很有興趣,如果你不是非常熟悉閃電網路,我建議可以看一下陳品在Coscup19的演講.
前幾年許多人在討論Atomic Multi-Path Payments (AMP),原因是當支付通道的金額越高,Client需要在通道中存越高的金額,並且整個網路越難找到適合的支付路徑,Liquidity也會降低.所以Idea就是把大筆的金額分成多個小筆的金額透過不同的路徑付給收取人,但是問題是在網路中這筆應付款項可能會部分成功、部分失敗;所以同時讓所有的微支付交易可以做到Atomic就是這一個題目的挑戰.
AMP 也很常因為部分路徑上的交易延遲或者失敗,而使得完成交易的時間變得很長(long time-to-completion)、減緩已成功的微支付交易的Liquidity、最後使得整個網路的Throughput變差.
舉例:Alice 要轉帳給Bob 4塊錢,透過4個不同的路徑各自轉1塊錢
在上述例子中,AMP整體消耗的Liquidity是$4 * 4 = $16 sec
假設一下如果Alice可以分成8個路徑(增加額外4個冗餘路徑)各自付1塊錢,使得只要其中的4個路徑完成並且Bob不會偷額外的金額,AMP就算完成
在上述例子中,AMP整體消耗變成$1*6 + $2*4 = $14 sec
上面兩個例子都還是假設每個路徑會成功的情況,若是有中間節點crash或者是delay超久,冗餘路徑可以大幅的改進這筆交易的Latency以及整個網路的Throughput跟Liquidity
不過要怎麼保證Bob不會拿額外冗餘路徑上的錢呢?
先講一個這篇文章使用到的重要密碼學工具,利用區塊鏈橢圓曲線上的循環群特性可得到以下的同態特性
Boomerang利用同態特性以及Publicly Verifiable Secret Sharing (有關secret sharing可以參考Kimi的文章)所構成的preimages 和 preimages challenges使得當Bob overdraws款項時,Alice會得到Bob設定的秘密 alpha_0,而Boomerang contract做了一個HTLC-type的限制,當Alice得到alpha_0,則Alice可以revert這筆微支付.
首先,Alice跟Bob同意了將一筆價值v的交易切成v個1塊錢的微支付交易,另外利用額外的u個冗餘路徑來增加效率(BTW 可以不止u個,理論上無限個也可以),所以全部的路徑為v+u
Bob設定一個degree為v的多項式P(x),係數為alpha_0, alpha_1,…,alpha_v
接著Bob 將H(alpha_0), H(alpha_1),…,H(alpha_v)交給Alice來commit 這組P(x),因此Alice可以算出
對於第i-th路徑的微支付交易(HTLC-type)來說,Bob只要揭露preimage P(i)便可以redeem這筆微交易,Bob只要揭露在v個路徑上對應的每一個P(i)就可以得到總額v的交易.而當Bob揭露了v+1個P(i)時,Alice就可以利用插值法將係數算出來取得alpha_0並且revert全部的微交易.
大致上的架構是這樣,有一些實作的細節像是微交易的手續費、設定的延遲時間、合約的script可以去參考paper或者跟我討論,感謝
Reference:
Boomerang: Redundancy Improves Latency and Throughput in Payment-Channel Network
Boomerang: 在支付通道網路中利用冗餘改進Latency以及Throughput was originally published in Taipei Ethereum Meetup on Medium, where people are continuing the conversation by highlighting and responding to this story.
👏 歡迎轉載分享鼓掌