"'Curve' object has no attribute 'p'" in recover_public_keys()
opacey opened this issue · 4 comments
When calling:
generatorPoint = ecdsa.ellipticcurve.PointJacobi(SECP256k1, secp256k1_generator_x, secp256k1_generator_y, 1, secp256k1_group_order, True)
sig = ecdsa.ecdsa.Signature(r, s)
pubkey1, pubkey2 = sig.recover_public_keys(message, generatorPoint)
I get the error:
Traceback (most recent call last):
File "sig2pubkey.py", line 100, in <module>
pubkey1, pubkey2 = sig.recover_public_keys(message, generatorPoint)
File "~/.local/lib/python3.10/site-packages/ecdsa/ecdsa.py", line 113, in recover_public_keys
pow(x, 3, curve.p()) + (curve.a() * x) + curve.b()
AttributeError: 'Curve' object has no attribute 'p'
Indeed the Curve object does not have a p attribute, but it does contain an ecdsa/ellipticcurve/CurveFp() object (named curve_secp256k1 in my case) which has a p attribute.
Could this be a bug? If not I'd be v grateful for any tips on how to fix my own code!
Why you're constructing those objects manually?
VerifyingKey has two APIs to create them from signatures:
python-ecdsa/src/ecdsa/keys.py
Line 415 in 2457dc7
and
python-ecdsa/src/ecdsa/keys.py
Line 467 in 2457dc7
What you're trying to do doesn't work because PointJacobi doesn't expect Curve objects, it expects the low level CurveFp objects, as specified in documentation:
python-ecdsa/src/ecdsa/ellipticcurve.py
Line 509 in 2457dc7
I have the hash of a signed message, and the signature itself. I wish to recover the pubkey from that sig. I am not trying to verify the sig which is why it didn't occur to me to try that route. Thanks for the tips, though, is VerifyingKey the correct way to approach the solution?
Edit: I am using your suggested method, and the code now looks like this, but I am getting an error which I was getting with a version of my prior approach too:
sig = "3045022100a6cbf37057ed3eef9a99ec1c50e23b0478d305e60f045a1ea03fc5ae058692eb02202a3da3e03d61cc0c3a5f9f6e54465bc80602646b451f15ac90d924260798b0f80103228ed3c02d8d54b2f326c87864f2a7328d908f71b94829edf3cfc355c1b785d7"
message = "cb3bc36e531ce92c1b59e13884622fc8622d369a52b758722a3a6a20e9865d71"
pubkey = ecdsa.keys.VerifyingKey.from_public_key_recovery_with_digest(
sig.encode('utf-8'),
message.encode('utf-8'),
ecdsa.SECP256k1,
sha256,
ecdsa.util.sigdecode_der,
False
)
print("pubkey raw = %s" % (pubkey.to_string(raw)))
Traceback (most recent call last):
File "sig2pubkey.py", line XX, in <module>
pubkey = ecdsa.keys.VerifyingKey.from_public_key_recovery_with_digest(
File "~/.local/lib/python3.10/site-packages/ecdsa/keys.py", line 509, in from_public_key_recovery_with_digest
r, s = sigdecode(signature, generator.order())
File "~/.local/lib/python3.10/site-packages/ecdsa/util.py", line 422, in sigdecode_der
rs_strings, empty = der.remove_sequence(sig_der)
File "~/.local/lib/python3.10/site-packages/ecdsa/der.py", line 150, in remove_sequence
raise UnexpectedDER("wanted type 'sequence' (0x30), got 0x%02x" % n)
ecdsa.der.UnexpectedDER: wanted type 'sequence' (0x30), got 0x33
Should I be asking this on a forum? Apologies if this is an inappropriate venue, but any help appreciated. N.B, the sig is from a bitcoin transaction's witness, and the digest is the relevant txid - I just grabbed them from a recent block.
both message and sig are hex encoded, while you're passing them as-is; you need to convert the hex characters to bytes
THANK YOU. I thought I'd done that already so gave myself a blind spot. Really appreciate the help. I now have the code I need.