Script

什麼是 P2TR 中的腳本組裝和執行花費(來自 Taproot 的花費)

  • December 25, 2021

所以我發現並從根本上理解了 P2PKH 如何從輸入和輸出中組裝起來,以創建一個類似比特幣的腳本來執行。

我查看了 SegWit BIP範例部分,發現它們也很容易理解。

但是看看Taproot BIP,我可能已經達到了我的極限。寫的真好,就是看不懂。

任何人都可以看看我最近的測試網P2TR 支出原始 JSON),並告訴我如何使用witnessDatascriptPubKeysigScript數據來建構一個類似比特幣的腳本來執行和驗證嗎?我只對單簽名 Taproot 感興趣。在我掌握了這一點之後,也許我可以擴展到 multisig-taproot。我知道 BIP 中提供了 python 範例,但老實說,仍然不明白。

順便說一句 .. 如果需要,我可以提供 testnet 私鑰,但我可能需要重建 TXN。

如果您缺乏足夠的 SE 業力來發表評論,我已經在 reddit 上發布了 XPosted 。

在我們開始之前

我意識到您的問題僅與單簽名方案有關,並且您想要一個專注於驗證如何工作的答案。我將解決這些問題,但我認為我需要詳細說明如何創建 P2TR 輸出,以及腳本如何首先適應,因為我擔心否則會更加混亂。

在下文中,我將進行簡化:我將描述一種變體,其中 P2TR 輸出只能用於一個腳本,而不是一個腳本樹,而不是描述實際的 BIP341 主根規則。可變大小。這不會影響您的問題的答案,但避免了解釋會分散注意力的樹結構的需要。

建構主根輸出

在這個簡化版的 taproot 中,每個輸出都可以通過使用密鑰(稱為P)簽名或滿足腳本(稱為S)來使用。密鑰P可以是(可證明)沒有人知道私鑰的密鑰,以防您想要一個只能由腳本使用的主根輸出。如果您想要一個只能由鍵使用的主根輸出(就像“單信號”主根的情況一樣),該腳本S可以是左右。OP_FALSE但在任何情況下,兩者PS都是一些東西

在主要範例中,我將假設P是一個有人知道私鑰的公鑰d。我還將假設腳本Sequals <P1> OP_CHECKSIGVERIFY <P2> OP_CHECKSIG,這是一個腳本,它使用鍵P1and強制執行 2-of-2 策略P2,並使用堆棧中的兩個簽名(一個 byP1和一個 by P2)。換句話說,我們的主根輸出將有一個對應於P or (P1 and P2). 在花費時間,花費者可以使用“關鍵路徑”(P)或“腳本路徑”(P1 and P2)。這樣做的方式將非常不同。

然而,第一步是創建主根輸出。為此,接收者首先計算所謂的“tweaked pubkey” Q。這是使用調整功能完成的:Q = tweak(P,S) = P + hash(P || S)*G. 它有兩個重要的屬性:

  • 如果有人知道 的私鑰dP並且他們知道,他們可以計算出(即)S的私鑰。Q``d + hash(P || S)
  • 給定Q或 給定PS,沒有人能找到另一個P’ 和 S’ Q = tweak(P',S')

Q在某種程度上仍然是一個公鑰,但它也以某種方式“送出”到腳本S,因為只有一個P並且S可以為它揭示。交易輸出中的 scriptPubKey 將完全是OP_1 <Q>,因此它在Q沒有任何散列的情況下儲存。OP_1表示它是具有 32 字節推送(又名 P2TR)的版本 1 見證輸出。在實踐中,這是通過將接收方編碼QBIP350 (bech32m) 地址並將其提供給發送方來完成的。然後,發送者的錢包知道如何使用預期的 scriptPubKey 建構交易輸出。這意味著發件人知道Q,但他們不知道(或關心)Pand S

支出和驗證支出

主根支出規則現在規定,任何與模板匹配的交易輸出OP_1 <32 bytes>都將被視為主根輸出,32 字節推送將被解釋為(調整後的)公鑰Q。它可以通過兩種方式花費:

  • 密鑰路徑:交易輸入的見證棧只包含一個元素,它被解釋為公鑰的 BIP340 簽名Q
  • 腳本路徑:交易輸入的見證棧由兩個或多個元素組成。最後一個被解釋為“未調整的”公鑰P,倒數第二個被解釋為腳本S,之前的所有元素都被解釋為 script 的腳本參數S。為了有效,必須是這樣的情況Q = tweak(P,S)(從而表明已Q送出到腳本S,表明它被允許使用),並且S使用提供的腳本參數執行腳本必須返回 true。

因此,在密鑰路徑支出的情況下,(調整後的)公鑰Q僅被視為公鑰,使用它進行支出實際上只需要一個有效的簽名。驗證碼不知道或不關心Q在這種情況下實際調整了什麼,但錢包當然知道:它不使用其普通私鑰簽名d(因為那是 的私鑰P),而是使用調整後的私鑰d + hash(P || s)(的私鑰Q)。所以在這種情況下,見證堆棧正好是[sig(Q)]. 請注意,我的意思是“用私鑰sig(Q)簽名”。Q

在腳本路徑花費的情況下,簽名錢包基本上建構了一個證人,證明“你看到了公鑰Q,但猜猜看!事實上那不是公鑰,它是一個S-tweaked 版本P,這意味著我” m 也允許通過滿足腳本來花費它S!”。在我們的範例中,這意味著見證堆棧將是[sig(P2),sig(P1),S,P]; 最後兩個元素證明Q允許的支出S,前兩個是S提供所需簽名的腳本參數。那時,驗證只是通過執行 script S= <P1> OP_CHECKSIGVERIFY <P2> OP_CHECKSIGwith inputs來進行[sig(P2),sig(P1)]

為什麼這很有用?

你現在可能會想……好吧,這可以工作,但是這一切有什麼意義呢?

這個想法是,我們已經發現了各種方案,使單個公鑰實際上可以做很多事情,包括從一組其他密鑰中計算“聚合”公鑰的可能性,這樣所有單獨的私鑰都是需要為聚合簽名(例如MuSig2)。

這樣,“內部”未調整的公鑰P也可能是一個聚合。在比單一簽名(例如閃電網路)更複雜的支出政策中,可以將P雙方的公鑰聚合在一起,而“合作”支出的情況將只是鏈上的單個簽名,即非常便宜。此外,只要可以遵循此密鑰路徑,整個構造就與普通的單個 sig 沒有區別:在這兩種情況下,scriptPubKey 都是OP_1 <Q>for some Q,而witness stack 是 just [sig(Q)]

一些最後的筆記

如果您想要公鑰的單簽名主根輸出P,實際上完全可以Q=P直接使用,並直接使用其未調整的私鑰進行簽名d。由於驗證程式碼不知道或不關心關鍵路徑花費中的調整方面,這是完全合法的。BIP341 建議不要這樣做,並建議仍然使用等效的無效腳本進行調整S,以處理有人謊稱他們的公鑰秘密地是某個其他密鑰的已調整版本的情況。使用無效腳本調整您要使用的任何鍵可確保根本無法使用它建構有效的腳本路徑支出。

在真正的 BIP341S中,不是單個腳本,而是腳本樹的 Merkle 根,其中每個葉子都可以是不同的葉子。樹可以是空的(僅關鍵路徑),由單個腳本組成(如這裡),或者是具有許多不同葉子的巨樹。這些葉子腳本也有自己的內部版本號,這將允許引入與目前主根腳本PubKeys 沒有區別的新腳本功能,只要這些腳本實際上不需要使用。真實 BIP341 中的最後一個見證堆棧元素不僅僅是未調整的公鑰P,但它還包括所選腳本的內部版本號,以及 Merkle 路徑,以證明揭示的腳本與 Merkle 根的關係(以及由此產生的版本+密鑰+路徑結構稱為控制塊)。腳本語言(在 BIP342 中記錄)、簽名散列(參見 BIP341)以及稱為附件的附加擴展機制還有各種其他更改,目前尚未使用。這些在這裡都不是特別重要,但我想提及它們以與實際規范建立聯繫。

好的,我想我也沒有真正回答你解釋腳本翻譯成什麼的問題。那是因為沒有真正的腳本更改。主根支出規則並沒有真正改變腳本的工作方式(除了 BIP342)。相反,他們在交易驗證和腳本驗證之間引入了一層支出邏輯。在關鍵路徑花費的情況下,根本沒有腳本可言,而只有一個簽名。在腳本路徑花費的情況下,規則改變瞭如何確定使用哪個腳本,以及如何確定它是正確的腳本,但那個腳本只不過是直接聲明的腳本。

引用自:https://bitcoin.stackexchange.com/questions/111098