Python-ECDSA-Public-Key-Wiederherstellung

Wie stellen Sie den öffentlichen EC-Schlüssel aus einer Signatur im VRS-Stil in Python wieder her?

Ich versuche, eine Verschlüsselung zwischen zwei Parteien über ECIES einzurichten, aber ich wollte zuerst den öffentlichen Schlüssel durch Wiederherstellung aus einer Transaktion erhalten. Das Folgende ist eine Beispieltransaktion von meiner Geth-Konsole, mit der ich gearbeitet habe.

eth.getTransaction("0x912b33e09311a72b988af66918abcd53f43831688c7acb6b44870c491f073dab")
{
  blockHash: "0xfdc5a1c9e1a0dcdfb2b9884919b79157a04eb15b0b58c91131e957f2803f8195",
  blockNumber: 100449,
  from: "0xc6f4f527587ea4a03aa85e0322783592367c1b9a",
  gas: 100000,
  gasPrice: 18000000000,
  hash: "0x912b33e09311a72b988af66918abcd53f43831688c7acb6b44870c491f073dab",
  input: "0x",
  nonce: 21,
  r: "0xab90122dc4e4bbdbb14ef22ad3ae21aecc19a1c90a9c8989c68b26cc782ff303",
  s: "0x36e5f275147049d3afd5d33b735cc9313d2c1aad3ab401aefdce678128e2f1d0",
  to: "0xa593094cebb06bf34df7311845c2a34996b52324",
  transactionIndex: 0,
  v: "0x1c",
  value: 1000000000000
}
web3.sha3(eth.getRawTransaction("0x912b33e09311a72b988af66918abcd53f43831688c7acb6b44870c491f073dab"),{encoding:'hex'})
"0x912b33e09311a72b988af66918abcd53f43831688c7acb6b44870c491f073dab"

Aus der obigen Transaktion habe ich das Rohmaterial für die Signatur (z. B. V, R, S) und den Absender (dh das "Von"-Feld), mit dem ich die Adresse überprüfen kann.

Ich versuche, dies in Python zu tun.

sender = "0xc6f4f527587ea4a03aa85e0322783592367c1b9a"
hash = "0x912b33e09311a72b988af66918abcd53f43831688c7acb6b44870c491f073dab"
r = "0xab90122dc4e4bbdbb14ef22ad3ae21aecc19a1c90a9c8989c68b26cc782ff303"
s ="0x36e5f275147049d3afd5d33b735cc9313d2c1aad3ab401aefdce678128e2f1d0"
v = "0x1c"
import bitcoin
import ethereum.keys #for a good sha3 implementation
from rlp.utils import decode_hex, encode_hex
rawhash = decode_hex(hash[2:]) # omit the 0x
vrs = (int(v[2:],16),int(r[2:],16),int(s[2:],16)) # omit the 0x and convert to integers based on base16 (hex)
rec_pub = bitcoin.ecdsa_raw_recover(rawhash,vrs) ## Trouble line!
enc_rec_pub = bitcoin.encode_pubkey(rec_pub,"bin")
rec_address = encode_hex(ethereum.keys.sha3(enc_rec_pub[1:]))[24:]
if rec_address == sender[2:]:
    print "[+++] The address was recovered from the public key! :-)"
else:
    print "[-] This address is not the same :-("

Das ecdsa_raw_recover ergibt nie den richtigen Wert. Ich habe die Schlüsseldatei geöffnet, um den öffentlichen/privaten Schlüssel zu überprüfen, und die folgende Zeile ergibt nie den richtigen Wert.

rec_pub = bitcoin.ecdsa_raw_recover(rawhash,vrs)

Gibt es einen Aspekt, den ich vermisse, oder eine bessere Empfehlung, wie dies zu erreichen ist? Vielen Dank im Voraus!

Antworten (1)

Die rawhashvon Ihnen verwendete ist nicht richtig!

Lesen Sie dies: So generieren Sie den Rohhash in Python .

Da Sie das Paket ethereumin Ihrem Code haben, ist der einfachste Weg, den öffentlichen Schlüssel zu erhalten:

#!/usr/bin/env python

import rlp
import ethereum
import ethereum.transactions


class MyTransaction(ethereum.transactions.Transaction):

    _publickey = None

    @property
    def publickey(self):
        secpk1n = ethereum.transactions.secpk1n
        if not self._publickey:
            if self.v in (27, 28):
                vee = self.v
                rlpdata = rlp.encode(
                    self, ethereum.transactions.UnsignedTransaction)
            elif self.v >= 37:
                vee = self.v - self.network_id * 2 - 8
                assert vee in (27, 28)
                rlpdata = rlp.encode(
                    rlp.infer_sedes(self).serialize(self)[:-3] \
                    + [self.network_id, '', ''])
            else:
                return None  # Invalid V value
            if self.r >= secpk1n or self.s >= secpk1n or self.r == 0 \
                    or self.s == 0:
                return None  # Invalid signature values!
            sighash = ethereum.utils.sha3(rlpdata)
            pub = ethereum.utils.ecrecover_to_pub(sighash, vee, self.r, self.s)
            if pub == b'\x00' * 64:
                return None  # Invalid signature (zero privkey cannot sign)
            self._publickey = pub
        return self._publickey

    @publickey.setter
    def publickey(self, value):
        self._publickey = value


def main():
    nonce = 21
    gasprice = 18000000000
    startgas = 100000
    to = '0xa593094cebb06bf34df7311845c2a34996b52324'
    value = 1000000000000
    data = ''
    sender = "0xc6f4f527587ea4a03aa85e0322783592367c1b9a"
    r = "0xab90122dc4e4bbdbb14ef22ad3ae21aecc19a1c90a9c8989c68b26cc782ff303"
    s ="0x36e5f275147049d3afd5d33b735cc9313d2c1aad3ab401aefdce678128e2f1d0"
    v = "0x1c"
    r = int(r, 16)
    s = int(s, 16)
    v = int(v, 16)
    tx = MyTransaction(nonce, gasprice, startgas, to, value, data, v, r, s)
    assert sender[2:] == ethereum.utils.sha3(tx.publickey)[-20:].hex()

if __name__ == '__main__':
    main()
Was ist, wenn Sie nur die Signatur und die v-, r-, s-Werte haben?