Die Beispielsignatur in BIP143 validiert nicht?

In BIP143 hat das erste Beispiel eine Zeugensignatur und es scheint nicht zu validieren/korrekt zu sein?! Ich habe ein supereinfaches Python-Programm geschrieben, um es zu demonstrieren

import ecdsa
import asn1

#Importing the 3 pieces of data from the example to byte arrays
pub = bytearray.fromhex("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357")
sighash = bytearray.fromhex("c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670")
dersigscript = bytearray.fromhex("304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee")

#deocding the DEC encoding
decoder = asn1.Decoder()
decoder.start(bytes(dersigscript))
tag, sigscript = decoder.read()

#stripping off the script  potion so we just have a signature
sig = bytearray(sigscript)[2:66]

vk = ecdsa.VerifyingKey.from_string(pub,  curve=ecdsa.SECP256k1)
vk.verify(sig, sighash)

Wenn jemand etwas Licht ins Dunkel bringen kann, was ich so dumm mache, oder eine Beispielreferenz, die es aufschlüsselt, damit es funktioniert, wäre das wirklich hilfreich. Ich habe auch versucht, die Byte-Reihenfolge bei allen 8 Kombinationen der 3 Eingänge umzukehren. Davon abgesehen habe ich den veröffentlichten privaten und öffentlichen Schlüssel verwendet, um meine eigenen Signaturen / Validierungen durchzuführen, daher bin ich ziemlich zuversichtlich, dass sie in der richtigen Reihenfolge sind, nur weniger sicher in Bezug auf die Signatur.

Danke schön!!

----EDIT-----
Ich wollte nur der Vollständigkeit halber andere Dinge auflisten, die versucht wurden

  1. Wie Pieter darauf hinwies, habe ich den privaten Schlüssel falsch entschlüsselt. S und R werden in 2 verschiedene Variablen aufgeteilt
304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caedbee
wird
3044 02 20 3609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a 02 20 573a954c4518331561406f90300e8f3358f51928d43c21
Die rohe 64-Byte-Sig ist also 609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a573a954c4518331561406f90300e8f3358f51928d43c212a8caed02c212a7caed02
das hat leider immer noch nicht funktioniert

Zusätzlich habe ich versucht, Pythons native der style ecdsa zu verwenden, was immer noch nicht erfolgreich war
aus ecdsa.util import sigencode_der, sigdecode_der
vk.verify(bytes(sig), bytes(sighash), sigdecode=sigdecode_der)
Und
vk.verify(bytes(sig), bytes(sighash), hashlib.sha256, sigdecode=sigdecode_der)
wobei sig mit 0x30 beginnt:
3044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad40107268705406b6dcfe9dc

Interessant ist, dass die Python-Bibliothek mir keine Fehler außer einer schlechten Signatur gegeben hat. Ich kann also noch keine Hinweise finden, wie dies mit einer Standardbibliothek zu tun ist. Wenn ich es herausfinde, werde ich eine Antwort posten

Antworten (2)

Verwendung dieser Bibliothek:

from cryptotools import Signature, PublicKey, hex_to_bytes

pub = PublicKey.from_hex('025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357')
sig = Signature.from_hex('304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee')
sighash = hex_to_bytes('c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670')

>>> sig.verify_hash(sighash, pub)
True
Warte, warte, Witz. Ist der Grund, warum ich dies nie mit einer Standardbibliothek sehe, weil der Bitcoin-Signaturalgorithmus nicht RFC-konform ist?!?! Von hier en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm heißt es, dass die Signatur 71-73 Bytes für die Signatur ist, was nicht korrekt ist. Das ist umwerfend
@ noone392 auf welchen RFC beziehst du dich? Afaik-Bitcoin-Signaturen folgen der DER-Codierungsspezifikation github.com/bitcoin/bips/blob/master/…
Es ist mit der DER-Codierung kompatibel, ich meine die eigentliche ECDSA-Spezifikation wie RFC 6979. Die Signatur muss genau 64 Bytes lang sein, um SECP256k1-konform zu sein. Und die bereitgestellte Signatur, obwohl sie mit dem Wiki darauf übereinstimmt, hat nicht die richtige Länge, um konform zu sein. Grundsätzlich glaube ich nicht, dass man dieses ECDSA eher als eine Bitcoin-Signatur bezeichnen kann, die Elliptische-Kurven-Mathematik verwendet.
Bitcoin verwendet ECDSA mit DER-codierten Signaturen. Es folgt genau diesen Spezifikationen. ECDSA ist ein Signaturalgorithmus, nicht die Kodierung.
@PieterWuille, auf welche Spezifikation beziehst du dich genau? weil ich es in meinem Beispiel dekodiere und verwende, was ich für den rohen 64-Byte-Schlüsselteil halte.
Ok, Ihre Konvertierung von DER in das 64-Byte-Signaturformat ist falsch. Eine DER-Signatur besteht aus einem 2-Byte-„Struct-Marker“ (der besagt, dass ein Tupel folgt), dann einem 2-Byte-„Integer-Marker“, gefolgt von der R-Ganzzahl (variable Anzahl von Bytes), dann einem weiteren 2-Byte-„Integer“. marker", gefolgt von der S-Ganzzahl (variable Anzahl von Bytes). Sie müssen die R- und S-Elemente extrahieren, sie auf jeweils 32 Bytes auffüllen (indem Sie Nullen voranstellen/entfernen) und sie dann verketten.
Sie können das wahrscheinlich mit dem asn1-Modul tun, indem Sie die "sigscript" -Variable, die Sie erhalten (nicht wirklich passend benannt, es ist nur ein Tupel von Signaturelementen, kein Skript beteiligt), erneut mit asn1 decodieren.
@PieterWuille Vielen Dank, dass Sie dieses Problem gefunden haben. Ihre Hilfe wird sehr geschätzt. Aus irgendeinem Grund erinnere ich mich, dass ecdsa sig eine einzelne Variable ist ... jedenfalls habe ich die 2 32-Byte-Stücke jetzt miteinander verbunden, da ich sie parse. Leider wird es immer noch nicht verifiziert. Ich habe auch versucht, Pythons sigdecode=sigdecode_der zu verwenden, um das codierte Format bereitzustellen, aber auch kein Glück ...
Das Problem liegt wahrscheinlich darin, dass Sie VerifyingKey.verify_digest statt .verify verwenden müssen. Letztere hasht die Nachrichten erneut, während Sie bereits eine gehashte Nachricht bereitstellen.
@PieterWuille Das hat es getan :-DI wird die Antwort posten. Danke noch einmal
Der Standard für ECDSA ist X9.62, wie in RFC6979 klar angegeben, und spezifiziert keine Codierung für die Signatur. RFC6979 in 2.4 Schritt 4 stellt richtig fest, dass es "üblich" ist, DER-codiertes ASN.1 zu verwenden, aber das ist keine Voraussetzung, und es ist absolut keine feste Länge. Der Beispielcode in A.3 macht DER, aber das ist nur ein Beispiel. Bitcoin verwendet DER für Transaktionssignaturen , aber das „einfache“ Format mit fester Länge für Nachrichtensignaturen ; siehe bitcoin.stackexchange.com/questions/12554 und bitcoin.stackexchange.com/questions/90799
@dave_thompson_085 Vielen Dank für die Klarstellung

ok Also dank PieterWuille konnte ich (wir) herausfinden, warum mein Code nicht funktionierte und wie man eine Standard-Python- oder Openssl-Bibliothek verwendet.
Dies waren die folgenden Probleme

  1. Die DER-Decodierung für die Python-Bibliothek wurde falsch verwendet. Wir mussten alle Variablen durchlaufen und die beiden Teile der Signatur (r und s) separat abrufen und neu kombinieren.
  2. Da die Standard-Signaturbibliotheken den Hash in das Signieren/Verifizieren integriert haben und Bitcoin einen doppelten Hash verwendet, müssen Sie ihn 1 Mal manuell hashen und dann der Bibliothek zur Verfügung stellen, um den zweiten Hash auszuführen, damit es mit einer Standardbibliothek funktioniert. Das bedeutet, dass wir sigHash nicht als Eingabe verwenden können, sondern den Hash preImage verwenden müssen. Im Folgenden wird über das kürzestmögliche Python-Skript berichtet, das zeigt, wie die Signaturen mit den Beispielen überprüft werden, die sowohl im Rohformat als auch im DER-codierten Format angegeben sind:
ECDSA importieren
asn1 importieren
Hashlib importieren
#verwendet für die Version
aus ecdsa.util import sigencode_der, sigdecode_der

#Importieren der 3 Daten aus dem Beispiel in Byte-Arrays
pub = bytearray.fromhex("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357")
DerEncodedSig = bytearray.fromhex("304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee")
prehashimage = bytearray.fromhex("0100000096b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd3752b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3bef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a010000001976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac0046c32300000000ffffffff863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e51100000001000000")

#Entschlüsselung der DEC-Codierung
Decoder = asn1.Decoder()
decoder.start(bytes(DerEncodedSig))
tag, sigder = decoder.read()

sig1 = sigder[2:34]
sig2 = sigder[36:68]
sig = sig1+sig2

#Jetzt brauchen wir den einzelnen sha256-Hash des Preimages
m = hashlib.sha256()
m.update (Prehash-Bild)
singlesighash = m.digest()

#Wir werden den doppelten Hash nicht für unsere Überprüfung verwenden, aber dies zeigt Ihnen, dass es derselbe ist wie sigHash in bip143
n = hashlib.sha256()
n.update (einzelnes Gash)
sigHash = n.digest

vk = ecdsa.VerifyingKey.from_string(bytes(pub), curve=ecdsa.SECP256k1)
#Wir müssen die Hash-Bibliothek bereitstellen, da der Standardwert nicht sha256 ist
result = vk.verify(bytes(sig), bytes(singlesighash), hashlib.sha256)
Drucken (Ergebnis)
#Dies ist der native Weg und erfordert nicht, dass wir die Signatur entschlüsseln, ist aber kompatibel mit openssl
result = vk.verify(bytes(DerEncodedSig), bytes(singlesighash), hashlib.sha256, sigdecode=sigdecode_der)
Drucken (Ergebnis)