3

Been learning about generating wallets in Ethereum and things have been smooth until the point where I turn a public key into an actual address.

Multiple sources say to use Keccak to hash the public key (sans first byte), then take the last 20 bytes of the resulting hash as the address.

The public key I'm using (generated from a tool that I hope does this correctly), is: 0x025f37d20e5b18909361e0ead7ed17c69b417bee70746c9e9c2bcb1394d921d4ae And the resulting address is supposed to be: 0xd09D3103CcABfb769eDc3e9B01500Ca7241D470A

But none of the various implementations of Keccak (yes, even the ones that are really Keccak and not SHA3) are giving me something that resembles that address.

The hash I'm getting is 83453a8e57a0a2bb1277baea830983bd264e23140ef2cadd74b1e68c5c12f98f which means the address would be the last 20 bytes, or 0x830983bd264e23140ef2cadd74b1e68c5c12f98f

What am I doing wrong here?

4

This program computes your address given a public key. In your case it returns "0xd09d3103ccabfb769edc3e9b01500ca7241d470a" as address

const assert = require('assert');
const EC = require('elliptic').ec;
const keccak256 = require('js-sha3').keccak256;

async function main() {
  try {
    const ec = new EC('secp256k1');

    // Decode public key
    const key = ec.keyFromPublic('025f37d20e5b18909361e0ead7ed17c69b417bee70746c9e9c2bcb1394d921d4ae', 'hex');

    // Convert to uncompressed format
    const publicKey = key.getPublic().encode('hex').slice(2);

    // Now apply keccak
    const address = keccak256(Buffer.from(publicKey, 'hex')).slice(64 - 40);

    console.log(`Public Key: 0x${publicKey}`);
    console.log(`Address: 0x${address.toString()}`);
  } catch (err) {
    console.log(err);
  }
}

main();

If you have the private key you can replace ec.keyFromPublic('025f...', 'hex') with ec.keyFromPrivate('4444...', 'hex') and should output the same address.

  • Thanks Ismael - there's lots of code out there that does the right thing. I'm more concerned with what what I'm not understanding about the process that's causing me to get the wrong hash. – Nick Oct 29 '17 at 3:07
  • Your public key is in uncompressed format (indicated by the '02' in front). You have to convert to uncompressed format, and hash the uncompressed value. – Ismael Oct 29 '17 at 4:21
  • Awesome, that seems like a good direction to go in. If a key is made up of X and Y values (two very large ints), how does one construct an uncompressed key format from that? – Nick Oct 29 '17 at 19:38
  • In my example I've used the elliptic library to calculate the uncompressed format. If you want to implement your own you have tu use the elliptic curve formulas, ethereum like bitcoin uses secp256k1 en.bitcoin.it/wiki/Secp256k1, also safecurves.cr.yp.to/equation.html. You can look at elliptic implementation. – Ismael Oct 29 '17 at 20:24
  • 1
    @EvilJordan You are correct '02' is compressed format, unfortunatelly comments cannot be modified after some time. – Ismael Feb 18 '18 at 16:56

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.