Public-Key

密鑰恢復的簽名驗證是否應該忽略壓縮狀態?

  • September 30, 2016

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 時,簡短的回答可能是否定的。

理由:一年多前,當我嘗試使用簽名交易將資金發送到未壓縮地址時,相應的壓縮密鑰無法用於花費相同的資金,反之亦然。平衡取決於密鑰的壓縮。使用未壓縮地址接收資金時,僅使用關聯的未壓縮私鑰進行支出。同理,收款時使用壓縮地址收款時,只能使用相關的壓縮私鑰進行消費。

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