¿Cómo recupera la clave pública EC de una firma de estilo VRS en python?
Estoy tratando de configurar un cifrado entre dos partes a través de ECIES, pero primero quería obtener la clave pública a través de la recuperación de una transacción. El siguiente es un ejemplo de transacción de mi consola geth con la que he estado trabajando.
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"
De la transacción anterior, tengo la materia prima para la firma (p. ej., V, R, S) y el remitente (es decir, el campo "de") que puedo usar para verificar la dirección.
Estoy tratando de hacer esto en python.
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 :-("
El ecdsa_raw_recover nunca da como resultado el valor correcto. Abrí el archivo de claves para verificar la clave pública/privada y la siguiente línea nunca da como resultado el valor correcto.
rec_pub = bitcoin.ecdsa_raw_recover(rawhash,vrs)
¿Hay algún aspecto de esto que me falta o una mejor recomendación sobre cómo lograrlo? ¡Gracias de antemano!
¡ El rawhash
que usaste no está bien!
Lea esto: Cómo generar el rawhash en python .
Como tiene el paquete ethereum
en su código, la forma más sencilla de obtener la clave pública es:
#!/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()
Ingeniero de tecnología de la ciudad de Nueva York