If you want convert private key to public key and not address, then I would recommend using eth-keys library. It is in the dependencies of eth-account library, which is in the dependencies of web3py.
Private key, used for account generation, consists of 64 hexadecimal characters (32 bytes total). So, if you have 32-bytes private key, then public key can be acquired with the following code:
>>> from eth_keys import keys
>>> pk = keys.PrivateKey(your_32bytes_private_key)
>>> print(pk.public_key)
If your private key is a string of 64 characters, then it can be converted to 32-bytes private key with the following code:
>>> import codecs
>>> decoder = codecs.getdecoder("hex_codec")
>>> private_key_bytes = decoder(private_key_str)
Since you mentioned in comments that you're open to using web3.py v5, here is the v5 approach to sign a message:
from eth_account import Account, messages
msg_hash_hex = "058c3b4c8e5dc4632b5c6b861b2c1861d53e426dc673c907ddf2651942b0f230"
private_key_hex = "b25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364"
#// This part prepares "version E" messages, using the EIP-191 standard
message = messages.encode_defunct(hexstr=msg_hash_hex)
#// This part signs any EIP-191-valid message
signed_message = Account.sign_message(message, private_key=private_key_hex)
print("signature =", signed_message.signature.hex())
If you'd like to know more about EIP-191, check out the original EIP-191 writeup. It's short and readable.
That snippet is equivalent to the javascript:
msgHash = "0x058c3b4c8e5dc4632b5c6b861b2c1861d53e426dc673c907ddf2651942b0f230"
privateKeyUser = "b25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364"
// web3.js sign() *only* supports "version E" EIP-191 signing
// so it adds the preamble for you.
let signature = await web3.eth.accounts.sign(msgHash, '0x' + privateKeyUser);
console.log('signature ='+signature.signature);
Note that the javascript sign()
method "signs arbitrary data" rather than a message hash. So although you appear to be hashing it first, you could sign the original message instead.
In the python version, prepare the original message for signing with: encode_defunct(text=original_message)
.
Best Answer
If you don't mind importing another library, Brownie's Wei class makes it very simple to get from
gwei
towei
: