Can I somehow get the public key of an ethereum account knowing just the corresponding ethereum address (e.g. 0x54dbb737eac5007103e729e9ab7ce64a6850a310)?


You can if and only if a transaction has been sent from the account. When you send a tx, you sign the transaction and it includes these v r and s values. You parse these from the signed tx and then pass these v r and s values and the hash of the transaction back into a function and it'll spit out the public key. This is actually how you get the from address of a transaction.

You can do so yourself using a tool like ethereumjs-utils:

 * ECDSA public key recovery from signature
 * @param {Buffer} msgHash
 * @param {Number} v
 * @param {Buffer} r
 * @param {Buffer} s
 * @return {Buffer} publicKey
exports.ecrecover = function (msgHash, v, r, s) {
  var signature = Buffer.concat([exports.setLength(r, 32), exports.setLength(s, 32)], 64)
  var recovery = v - 27
  if (recovery !== 0 && recovery !== 1) {
    throw new Error('Invalid signature v value')
  var senderPubKey = secp256k1.recover(msgHash, signature, recovery)
  return secp256k1.publicKeyConvert(senderPubKey, false).slice(1)

As another real-world scenario, ethereumjs-tx uses this function to verify the signature:

* Determines if the signature is valid
* @return {Boolean}
verifySignature () {
  const msgHash = this.hash(false)
  // All transaction signatures whose s-value is greater than secp256k1n/2 are considered invalid.
  if (this._homestead && new BN(this.s).cmp(N_DIV_2) === 1) {
    return false

  try {
    let v = ethUtil.bufferToInt(this.v)
    if (this._chainId > 0) {
      v -= this._chainId * 2 + 8
    this._senderPubKey = ethUtil.ecrecover(msgHash, v, this.r, this.s)
  } catch (e) {
    return false

  return !!this._senderPubKey

For more information on v r and s:

v, r, and s are parameters that can be parsed from the signature. Here's a good example from the ethereumjs utils library:

 var sig = secp256k1.sign(msgHash, privateKey)
  var ret = {}
  ret.r = sig.signature.slice(0, 32)
  ret.s = sig.signature.slice(32, 64)
  ret.v = sig.recovery + 27

Note how you can parse each value from a given signature.


  • 2
    Very helpful. I had to look why an "extra" call secp256k1.publicKeyConvert is needed and the reason appears to be to get the decompressed public key, since secp256k1.recover returns a compressed public key.
    – eth
    Apr 4 '17 at 6:06
  • What do the values s, r, v stand for?
    – John
    Mar 22 '18 at 7:50
  • 4
    What is the msgHash? Is that the hash of the message sent as part of the transaction or the actual hash of the transaction itself? Sep 19 '18 at 12:24
  • How are you going to parse v,r and if you don't have the private key of the end user?
    – Iulian
    Sep 10 '19 at 20:44

I don't think this is possible, since you lose information when going from public key to address:

  1. Start with the public key (64 bytes)
  2. Take the Keccak-256 hash of the public key. You should now have a string that is 32 bytes. (note: SHA3-256 eventually became the standard, but Ethereum uses Keccak)
  3. Take the last 20 bytes of this public key (Keccak-256). Or, in other words, drop the first 12 bytes. These 20 bytes are the address, or 40 characters. When prefixed with 0x it becomes 42 characters long.

How are ethereum addresses generated?

  • 2
    I thought that all transactions from an ethereum address are signed using account's private key and validated on chain using account's public key. If that's the case, then public keys of all accounts should be available for all nodes in a network. Am I wrong? Mar 31 '17 at 11:50
  • 1
    @EdwardRuchevits The address in the question hasn't signed a transaction so it's not feasible to get the public key. When there's a signature, this may help crypto.stackexchange.com/questions/18105/… and stackoverflow.com/questions/19665491/… Maybe some people can also add great answers here.
    – eth
    Mar 31 '17 at 19:00
  • 6
    A nice property of addresses is that since the public key is not known until the account is used, the account is safe against quantum attacks until it is spent from Apr 4 '17 at 3:15

It is now possible to recover public key from Ethereum transaction without any coding:

  1. Open the transaction in Etherscan.io
  2. Click on vertical ellipsis in the top-right corner
  3. Click on "Get Row TxnHash" in popup menu
  4. You will see raw transaction in hex, copy it
  5. Open “Recover address” tool from ABDK Toolkit
  6. Select "Transaction" radio button
  7. Paste raw transaction into "Message" field
  8. See the public key in the text bow below
  • This works extremely well. However, I couldn't find the source code for this anywhere, even though they say this is open sourced.
    – DUO Labs
    Dec 30 '20 at 21:52
  • The best I could do is make a WARC file for offline use here.
    – DUO Labs
    Jan 1 at 20:49
  • Best method, thanks!
    – Gaia
    Apr 11 at 20:13
  • thanks! this just works
    – hack3r_0m
    Jul 19 at 10:53

Using @tayvano hint, you can do it as follows:

  1. Go to etherscan, and check if there are outgoing transactions: https://etherscan.io/address/0x54dbb737eac5007103e729e9ab7ce64a6850a310
  2. Get hash of one of them e.g. 0xa8206c5fcfb6a2527fb8540ab543b4701f4c86d1c21862ad89fa220c84bad260
  3. use ipython with web3
In [1]: import web3
w3 = web3.Web3(web3.HTTPProvider('https://geth.golem.network:55555'))
tx = w3.eth.getTransaction(0xa8206c5fcfb6a2527fb8540ab543b4701f4c86d1c21862ad89fa220c84bad260)
Out[1]: HexBytes('0xa8206c5fcfb6a2527fb8540ab543b4701f4c86d1c21862ad89fa220c84bad260')

In [2]: from eth_account.internal.signing import extract_chain_id, to_standard_v
s = w3.eth.account._keys.Signature(vrs=(

from eth_account.internal.transactions import ALLOWED_TRANSACTION_KEYS
tt = {k:tx[k] for k in ALLOWED_TRANSACTION_KEYS - {'chainId', 'data'}}

from eth_account.internal.transactions import serializable_unsigned_transaction_from_dict
ut = serializable_unsigned_transaction_from_dict(tt)
Out[2]: '0x9678ad0aa2fbd7f212239e21ed1472e84ca558fecf70a54bbf7901d89c306191c52e7f10012960085ecdbbeeb22e63a8e86b58f788990b4db53cdf4e0a55ac1e'

In [3]: s.recover_public_key_from_msg_hash(ut.hash()).to_checksum_address()
Out[3]: '0x54Dbb737EaC5007103E729E9aB7ce64a6850a310'

In [4]: t['from']
Out[4]: '0x54Dbb737EaC5007103E729E9aB7ce64a6850a310'
  • 1
    This doesn't work for contract deployment transactions.And for the latest version you have to adjust the code to from eth_account._utils.signing import extract_chain_id, to_standard_v, serializable_unsigned_transaction_from_dict from eth_account._utils.transactions import ALLOWED_TRANSACTION_KEYS
    – Chris
    Jan 10 '20 at 20:58

Solution in Java. Perhaps it can be done simpler, but it works.

Utility classes come from web3j.crypto.

    BigInteger v = new BigInteger("26", 16);
    BigInteger r = new BigInteger("5fd883bb01a10915ebc06621b925bd6d624cb6768976b73c0d468b31f657d15b", 16);
    BigInteger s = new BigInteger("121d855c539a23aadf6f06ac21165db1ad5efd261842e82a719c9863ca4ac04c", 16);
    BigInteger chainId = new BigInteger("1", 16);
    v = v.subtract(chainId.multiply(BigInteger.valueOf(2)).add(BigInteger.valueOf(8)));
    Sign.SignatureData signatureData = new Sign.SignatureData(v.toByteArray(), r.toByteArray(), s.toByteArray());
    byte[] raw = DatatypeConverter.parseHexBinary("f86b0b85250523760082520894eafaf9bb8f35235d0df61275e86fd65d9ef2c3f9870aaa0065c66b8b8026a05fd883bb01a10915ebc06621b925bd6d624cb6768976b73c0d468b31f657d15ba0121d855c539a23aadf6f06ac21165db1ad5efd261842e82a719c9863ca4ac04c");

    RawTransaction decoded = TransactionDecoder.decode(DatatypeConverter.printHexBinary(raw));
    byte[] encoded = TransactionEncoder.encode(decoded, chainId.longValue());
    byte[] rawTxHash = Hash.sha3(encoded);

    System.out.println("Raw tx hash:                    " + DatatypeConverter.printHexBinary(rawTxHash));
    System.out.println("Pub key from raw tx hash :      " + signedMessageHashToKey(rawTxHash, signatureData).toString(16));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.