Blockchain-Prüfsignatur fehlgeschlagen

Ich versuche, ein Prüfsignal von einer Transaktion in der Live-Blockchain zu verifizieren. es schlägt auf meinem Debian-Jessie-PC mit fehl openssl 1.0.1k, schlägt auf meiner virtuellen Ubuntu 12.04-Maschine mit fehl openssl 1.0.1und validiert korrekt auf meinem Debian Wheezy-PC mit openssl 1.0.1e. beide verwenden den gleichen Code . die Transaktion ist die erste Instanz eines SIGHASH_NONE in der Live-Blockchain . ich berechne den "message" (tx) hash wie folgt:

hex: 2c7ecdcb2381e657228284398f2f66b2d7d9cf6aa1bd8e39a7300d0b3c8cfa5a
same thing in base58: 3zh5uvKWoRjFgKMSLRVqEWXB6YVLsuDKo97yCsCJZ2wB

die signatur ist:

hex: 30440220bb4fbc495aa23babb2c2be4e3fb4a5dffefe20c8eff5940f135649c3ea96444a022004afcda966c807bb97622d3eefea828f623af306ef2b756782ee6f8a22a959a2
same thing in base58: 381yXZvFc5V2dx81gRNNpj7ResKUgWA92mkTefemM9gM2kW37b3DGkV5v2BsFq94pSuH1E4jHq9ScHcp6T7Mfg41a7rbZCnd
note that this signature does not have the 02 hashcode appended to it

und der pubkey ist:

hex: 04f1939ae6b01e849bf05d0ed51fd5b92b79a0e313e3f389c726f11fa3e144d9227b07e8a87c0ee36372e967e090d11b777707aa73efacabffffa285c00b3622d6
same thing in base58: SJa4B8CrqDs6St5KaXMm4KCCksaT7RDcCaRDyKSD6Mbu1WzSwokEq3JwGtfZRz7by6jYD5QmuVhgqsPYc6wTijQq
converts to bitcoin address: 145YPBBWRj4aquewvx59SAWNrSZFT5rvxr

könnte mir jemand sagen, ob diese parameter die ecdsa-überprüfung bestehen oder nicht? Auch wenn jemand einen Online-Validator kennt, der hilfreich wäre.


Ich versuche, dies mit dem jsonrpc-Client zu überprüfen, aber es funktioniert auf keinem Computer, den ich habe:

#!/usr/bin/env python2.7                                                        

from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
rpcuser = 1
rpcpassword = 1
rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:8332" % (rpcuser, rpcpassword))
message = "3zh5uvKWoRjFgKMSLRVqEWXB6YVLsuDKo97yCsCJZ2wB"                        
sig = "381yXZvFc5V2dx81gRNNpj7ResKUgWA92mkTefemM9gM2kW37b3DGkV5v2BsFq94pSuH1E4jHq9ScHcp6T7Mfg41a7rbZCnd"
addr = "145YPBBWRj4aquewvx59SAWNrSZFT5rvxr"                                     
res = rpc_connection.verifymessage(addr, sig, message)                          
print res

Ausgang:

False

Vielleicht codiere ich die Nachricht oder Signatur für den RPC-Client falsch? Ich habe versucht, binär codierte Daten an ihn weiterzugeben, aber das hat ihm nicht gefallen:

File "/usr/local/lib/python2.7/dist-packages/bitcoinrpc/authproxy.py", line 125, in __call__
    json.dumps(args, default=EncodeDecimal)))
  File "/usr/lib/python2.7/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 200, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 263, in iterencode
    return _iterencode(o, 0)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xcd in position 2: invalid continuation byte

Die Verifizierung mit pybitcointools funktioniert auf allen Rechnern:

from bitcoin import *
import binascii

msg = "2c7ecdcb2381e657228284398f2f66b2d7d9cf6aa1bd8e39a7300d0b3c8cfa5a"
# make sure to include the 02 hashcode on the end of the signature here!!
sig = "30440220bb4fbc495aa23babb2c2be4e3fb4a5dffefe20c8eff5940f135649c3ea96444a022004afcda966c807bb97622d3eefea828f623af306ef2b756782ee6f8a22a959a202"
pub = "04f1939ae6b01e849bf05d0ed51fd5b92b79a0e313e3f389c726f11fa3e144d9227b07e8a87c0ee36372e967e090d11b777707aa73efacabffffa285c00b3622d6"
msg = binascii.unhexlify(msg)
print ecdsa_raw_verify(msg, der_decode_sig(sig), pub)

Ausgang:

True

Antworten (2)

Ja, Sie haben den Digest 2c7ecdcb2381e657228284398f2f66b2d7d9cf6aa1bd8e39a7300d0b3c8cfa5a richtig berechnet.

Hier ist mein Stück schmutziger Code:

static void xxtest ( )
{
  const QByteArray t ( MyByteArray ( )
      .putInt32 ( TX_VERSION ) // 01000000
      .putInt8 ( 1 )           // 01 : one input
      .putArray ( QByteArray::fromHex ( "5f386c8a3842c9a9dcfa9b78be785a40a7bda08b64646be3654301eaccfc8d5e" ) )
      .putInt32 ( 1 )          // 01000000 : index
      .putPrefixed ( MyByteArray ( )
         .putInt8 ( OP_DUP )
         .putInt8 ( OP_HASH160 )
         .putPrefixed ( QByteArray::fromHex ( "21c43ce400901312a603e4207aadfd742be8e7da" ) )
         .putInt8 ( OP_EQUALVERIFY )
         .putInt8 ( OP_CHECKSIG ) )
       .putInt32 ( TX_SEQUENCE )
       .putInt8 ( 0 )          // no outputs
       .putInt32 ( TX_LOCK )
       .putInt32 ( SIGHASH_NONE ) );
  _trace ( QString ( t.toHex ( ).constData ( ) ) );
  const MyKey32 digest ( t.constData ( ), t.size ( ) );
  _trace ( QString ( "digest = %1" ).arg ( digest.toStringRev ( ) ) );
  const QByteArray pubkey ( QByteArray::fromHex ( "04f1939ae6b01e849bf05d0ed51fd5b92b79a0e313e3f389c726f11fa3e144d9227b07e8a87c0ee36372e967e090d11b777707aa73efacabffffa285c00b3622d6" ) );
  const QByteArray signature ( QByteArray::fromHex ( "30440220bb4fbc495aa23babb2c2be4e3fb4a5dffefe20c8eff5940f135649c3ea96444a022004afcda966c807bb97622d3eefea828f623af306ef2b756782ee6f8a22a959a2" ) );
  _trace ( QString ( "verify=%1 (expected value=1)" ).arg ( digest.verify ( pubkey, signature ) ) );
  // now test the same with wrong digest
  const MyKey32 temp ( "temp", 4 );
  _trace ( QString ( "verify=%1 (expected value=0)" ).arg ( temp.verify ( pubkey, signature ) ) );
}
//--------------------------------------------------------------
bool MyKey32::verify ( const QByteArray& pub, const QByteArray& sig ) const
{
  return 0 < ECDSA_verify ( 0, constPtr ( ), 32, (const quint8*)sig.constData ( ), sig.size ( ), EC_KEY_pub_key ( pub ) );
}

die ausgabe ist:

"01000000015f386c8a3842c9a9dcfa9b78be785a40a7bda08b64646be3654301eaccfc8d5e010000001976a91421c43ce400901312a603e4207aadfd742be8e7da88acffffffff000000000002000000"
"digest = 2c7ecdcb2381e657228284398f2f66b2d7d9cf6aa1bd8e39a7300d0b3c8cfa5a"
"verify=1 (expected value=1)"
"verify=0 (expected value=0)"

Update: Hier ist ein kleines Programm zum Überprüfen von Signaturen mit Abhängigkeit nur für die OpenSSL-Bibliothek:

#include <QByteArray>
#include <QDebug>

#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/ecdsa.h>
#include <openssl/sha.h>

static EC_KEY* EC_KEY_pub_key ( const QByteArray& pub )
{
  static EC_KEY* eckey = EC_KEY_new_by_curve_name ( NID_secp256k1 );
  const quint8* ppub = (const quint8*)pub.constData ( );
  o2i_ECPublicKey ( &eckey, &ppub, pub.size ( ) );
  return eckey;
}
//--------------------------------------------------------------
int main(int argc, char *argv[])
{
  const QByteArray data ( QByteArray::fromHex ( argv [1] ) );
  const QByteArray sign ( QByteArray::fromHex ( argv [2] ) );
  const QByteArray pubk ( QByteArray::fromHex ( argv [3] ) );

  quint8 tmp [32];
  ::SHA256 ( (const quint8*)data.constData ( ), data.size ( ), tmp );
  quint8 digest [32];
  ::SHA256 ( tmp, 32, digest );
  qDebug ( ) << "data=" << QString ( data.toHex ( ) );
  qDebug ( ) << "sign=" << QString ( sign.toHex ( ) );
  qDebug ( ) << "pubk=" << QString ( pubk.toHex ( ) );

  qDebug ( ) << "digest=" << QString ( QByteArray ( (const char*)digest, 32 ).toHex ( ) );

  const bool v ( ::ECDSA_verify ( 0, digest, 32, (const quint8*)sign.constData ( ), sign.size ( ), EC_KEY_pub_key ( pubk ) ) );
  qDebug ( ) << "result=" << v;

  return 0;
}
großartig, danke. Es ist sehr seltsam, dass es auf zwei meiner PCs nicht überprüft werden kann! ich werde es mit dem rpc-client und auch mit pybitcointools testen. Wenn der RPC-Client fehlschlägt, muss es ein Problem mit einer bestimmten Version / Konfiguration von openssl geben ...
Oh ja! Die Signatur hat eine nicht standardmäßige Der-Codierung! Schauen Sie einfach auf den Anfang: 30440220bb ... - die richtige Codierung ist 3044022100bb ... weil der R-Teil nicht negativ sein kann und mit "bb" beginnt. Einige OpenSSL-Versionen erlauben dies, andere nicht. Siehe bitcoin.stackexchange.com/questions/2376/…
um richtig zu sein 3045022100bb...
kein Glück mit dem RPC-Client - siehe meine aktualisierte op :p
Ich habe rpc nie zum Überprüfen von Transaktionssignaturen verwendet. Mir scheint, dass dieser Anruf für etwas anderes bestimmt ist. Schreiben Sie mir eine Mail an alistermaclin@mail.ru und ich schicke Ihnen Qt/C++-Code, um solche Dinge zu überprüfen
Ja, OpenSSL-Versionen seit Jan. 2015 prüfen korrekten DER in Signaturen (DSA und RSA sowie ECDSA); das sind 0.9.8zd+ 1.0.0p+ 1.0.1k+ und 1.0.2*. bitcoin.stackexchange.com/questions/35841/… ist das gleiche Problem.
Ich bin beim Googeln auf bip66 gestoßen und dies behebt das Problem.

Die Tatsache, dass pybitcointools(eine reine Python-Implementierung von ecdsa) in der Lage ist, die Nachricht anhand des Pubkeys und der Signatur zu verifizieren, weist darauf hin, dass es sich um ein Problem mit opensslund nicht um die Daten selbst handelt, die falsch sind.

Gemäß den Kommentaren von amaclin unter seiner Antwort ist die Codierung für diese Signatur nicht standardmäßig:

30440220bb4fbc495aa23babb2c2be4e3fb4a5dffefe20c8eff5940f135649c3ea96444a022004afcda966c807bb97622d3eefea828f623af306ef2b756782ee6f8a22a959a2

dies wird dekodiert als:

0x30 # constant placeholder
0x44 # total length = 68 bytes
0x02 # constant placeholder
0x20 # r-length = 32 bytes
0xbb4fbc495aa23babb2c2be4e3fb4a5dffefe20c8eff5940f135649c3ea96444a # r
0x02 # constant placeholder
0x20 # s-length = 32 bytes
0x04afcda966c807bb97622d3eefea828f623af306ef2b756782ee6f8a22a959a2 # s

Beachten Sie, dass der rWert hier mit beginnt 0xbb = 1011 1011- da das höchstwertige Bit ( 0x80) gesetzt ist, ist dies eine negative Zahl. Dies würde die IsValidSignatureEncodingPrüfung nicht bestehen und seit bip66 abgelehnt werden . Insbesondere diese Zeile würde den Fehler verursachen:

// Negative numbers are not allowed for R.
if (sig[4] & 0x80) return false;

Hier sig[4]ist das erste (ganz linke) Byte des rWerts.

dies erklärt also, warum einige Versionen von openssl diese Prüfsignatur nicht bestehen und andere sie bestehen - es handelt sich um eine Nicht-Standard-Kodierung, die nur mit bestimmten Versionen von openssl kompatibel ist.