Public-Key
密鑰恢復的簽名驗證是否應該忽略壓縮狀態?
該
bitcoinj
庫的 API 提供了該類的signMessage
方法,該方法ECKey
將簽名(r,s)
作為 65 字節編碼為 Base64 字元串返回。編碼的關鍵在於允許密鑰恢復的附加前導字節((r,s)
僅 64 個字節不足以實現該目的)。特別地,編碼的前導字節包括關於簽名密鑰的壓縮狀態的資訊。現在我假設實現這種特定的簽名編碼是有充分理由的,我懷疑這是因為它是一種標準編碼,存在於許多其他比特幣庫和核心中。
現在通過密鑰恢復驗證簽名時,該
verifyMessage
方法忽略了恢復密鑰的壓縮狀態,只保證對應的橢圓曲線點匹配。當然,這是一個很好的檢查,但是如果我們以後要忽略它,為什麼還要費心編碼簽名密鑰的壓縮狀態呢?這是其他已知庫採用的語義,還是核心?我附上一個小片段來說明:import org.bitcoinj.core.ECKey; import java.security.SignatureException; public class Test { public static void main(String[] args) { String message = "some arbitrary message"; ECKey k1 = new ECKey(); // random , compressed ECKey k2 = k1.decompress(); // Signature (r,s) encoded as 65 bytes, with leading byte // allowing key recovery (including compression status) String sig1 = k1.signMessage(message); String sig2 = k2.signMessage(message); // compression status is encoded in signature => differing leading byte System.out.println(sig1); // INgDhkt98Mme9m9AQ+nqtjyvjj ... System.out.println(sig2); // HNgDhkt98Mme9m9AQ+nqtjyvjj ... // signatures are verified succesfully try { k1.verifyMessage(message, sig1); // compressed case } catch(SignatureException e) { System.out.println("it should not happen"); } try { k2.verifyMessage(message, sig2); // uncompressed case } catch(SignatureException e) { System.out.println("it should not happen"); } // in fact, compression status is ignored ... try { k1.verifyMessage(message, sig2); // should it throw ? } catch(SignatureException e) { System.out.println("it does not happen"); } } }
里程可能因此答案而異。使用 libbitcoin 時,簡短的回答可能是否定的。
理由:一年多前,當我嘗試使用簽名交易將資金發送到未壓縮地址時,相應的壓縮密鑰無法用於花費相同的資金,反之亦然。平衡取決於密鑰的壓縮。使用未壓縮地址接收資金時,僅使用關聯的未壓縮私鑰進行支出。同理,收款時使用壓縮地址收款時,只能使用相關的壓縮私鑰進行消費。