為什麼在簽名中使用雜湊見證腳本而不是公鑰腳本?
當一個 segwit 輸入被簽名時,簽名將送出給見證腳本(或者在 p2wpkh 的情況下是一個類似 p2pkh 的腳本)。這是在BIP143中指定的:
- 對於
P2WPKH
見證程序,scriptCode
是0x1976a914{20-byte-pubkey-hash}88ac
.- 對於
P2WSH
見證程序,+ 如果
witnessScript
不包含任何OP_CODESEPARATOR
,則scriptCode
被witnessScript
序列化為裡面的腳本CTxOut
。 + 如果witnessScript
包含任何OP_CODESEPARATOR
,則scriptCode
是witnessScript
但刪除所有內容,包括在執行OP_CODESEPARATOR
簽名檢查操作碼之前執行的最後一次執行,序列化為內部的腳本CTxOut
。(下面的範例展示了確切的語義)這背後的原因是什麼?為什麼雜湊不像在傳統(p2pkh 和 p2sh)支付中那樣送出到 pubkey 腳本?這種差異使簽名/驗證程式碼有點複雜,所以我想一定有一些很好的理由。
也許我的問題應該是:為什麼散列送出到任何腳本來進行隔離見證輸入?在遺留簽名中,將 scriptPubkey 放在 scriptSig 中以用於目前輸入是一種(複雜的,見下文)避免輸入之間的簽名重用的方法。但在 segwit 中,這是通過
outpoint
散列算法的一部分來完成的。所以我們不能跳過這一scriptCode
部分嗎?在我看來,為什麼我們散列用於遺留簽名的 scriptPubkey 和用於 segwit 簽名的見證腳本還有另一個原因,因為有更簡單的方法可以避免簽名重用:
- 舊版:我們可以在目前輸入的某處添加一個虛擬字節
- Segwit:目前輸入的outpoint已經解決了問題。
我只是在猜測,但是通過將事務送出到 scriptCode,我們確保簽名者知道他們正在簽署的腳本。例如,硬體錢包只能確定 outpoint 1234…cdef:0 支付特定腳本,如果我們給它創建該 outpoint 的交易(以便它可以散列該交易,驗證 txid,提取 scriptPubKey ,並將其與提供的見證腳本進行比較)。因為一筆交易(沒有見證數據)的大小可能高達近 1 兆字節,而一筆支出交易可以參考數千筆以前的交易,我們創造了這樣一種情況,即硬體錢包等資源匱乏的設備很難驗證它們的內容。重新簽名。
相比之下,使用 BIP143,我們只需要告訴錢包它應該簽名的每個 scriptCode。BIP141 允許這些最大為 10,000 字節,這只是事務最大大小的 1/100。錢包可以檢查這些 scriptCode,確保它們與錢包的期望一致,並在其簽名中承諾它們,因為知道如果向他們發送 scriptCode 的人對實際的 scriptCode 撒謊,則簽名將無效。
這與 BIP143 簽名格式承諾每個輸入的值的原因相同。在它必須處理以前的交易以獲得它們的輸出量之前;現在它只接受它收到的任何數據並對其進行簽名,知道如果有人在金額上撒謊,簽名將無效。