Sollte die Signaturüberprüfung durch Schlüsselwiederherstellung den Komprimierungsstatus ignorieren?

Die bitcoinjAPI der Bibliothek bietet eine signMessageMethode der ECKeyKlasse, die eine Signatur (r,s)als 65 Byte codiert als Base64-String zurückgibt. Der Knackpunkt der Kodierung liegt im zusätzlichen führenden Byte, das eine Schlüsselwiederherstellung ermöglicht (die 64 Bytes allein (r,s)reichen dafür nicht aus). Insbesondere enthält das führende Byte der Codierung Informationen über den Komprimierungsstatus des Signaturschlüssels.

Nun gehe ich davon aus, dass diese spezifische Signaturcodierung aus einem sehr guten Grund implementiert wurde, und ich vermute, dass es sich um eine Standardcodierung handelt, die in vielen anderen Bitcoin-Bibliotheken und im Kern vorhanden ist.

Wenn nun eine Signatur durch Schlüsselwiederherstellung verifiziert wird, verifyMessageignoriert das Verfahren den Komprimierungsstatus des wiederhergestellten Schlüssels und stellt einfach sicher, dass die entsprechenden elliptischen Kurvenpunkte übereinstimmen. Sicher, das ist eine ziemlich gute Prüfung, aber warum machen wir uns die Mühe, den Komprimierungsstatus eines Signaturschlüssels zu codieren, wenn wir ihn später ignorieren werden? Ist dies die Semantik, die andere bekannte Bibliotheken übernommen haben, oder tatsächlich der Kern? Zur Veranschaulichung hänge ich einen kleinen Ausschnitt an:

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");
    }

  }
}

Antworten (1)

Der Kilometerstand kann mit dieser Antwort variieren. Die kurze Antwort lautet wahrscheinlich nein, wenn Sie libbitcoin verwenden.

Begründung: Als ich vor über einem Jahr damit experimentierte, Gelder an eine unkomprimierte Adresse mit einer signierten Transaktion zu senden, konnten die entsprechenden komprimierten Schlüssel nicht verwendet werden, um dieselben Gelder auszugeben, das Gegenteil war auch der Fall. Das Gleichgewicht war abhängig von der Kompression einer Taste. Verwenden Sie beim Empfangen von Geldern mit einer unkomprimierten Adresse nur den zugehörigen unkomprimierten privaten Schlüssel zum Ausgeben. In ähnlicher Weise verwenden Sie beim Empfangen von Geldern mit einer komprimierten Adresse nur den zugehörigen komprimierten privaten Schlüssel zum Ausgeben.

Danke schön! Ich hoffe sehr bald mit libbitcoin spielen zu können. Ich bin etwas unruhig bei dem Ausdruck "unkomprimierter/komprimierter privater Schlüssel", aber ich verstehe, was du meinst :)
Sie sprechen von Transaktionen. Die ursprüngliche Frage bezieht sich auf signierte Nachrichten.