3

I'm trying to generate eth address on PHP. Having issue with keccak256.

I'm using this class: https://github.com/kornrunner/php-keccak

It works good, I checked many times on https://emn178.github.io/online-tools/keccak_256.html

Priv/pub keys are generated right, checked many times, but there is something with keccak256, and I get different address from myetherwallet and other tools.

Where is a mistake?

Here is my code:

include('./keccak.php');
use BitWasp\BitcoinLib\BitcoinLib;
require_once(__DIR__. '/vendor/autoload.php');
$priv = '17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55';
echo 'priv key: '.$priv;
echo "\r\n";
$pub=substr(BitcoinLib::private_key_to_public_key($priv),2); // deleting '04' padding from left side
echo 'pub key: '.$pub;
echo "\r\n";
$adr = \nmsps\Keccak::hash($pub, 256);
echo 'keccak256: '.$adr;
echo "\r\n";
echo 'ETH address:'.substr($adr,-40); // last 40
exit;

output:

priv key: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55

pub key: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124

keccak256: c39d3fed9ca154a48cad5238a063d2fa1937d32fec5166ce0a27c6e6f94c95c8

ETH address: a063d2fa1937d32fec5166ce0a27c6e6f94c95c8 // should be 0x26d1eC50B4e62c1d1a40D16E7cacc6A6580757d5

3

The correct Keccak256 Hash for your public key should be

de77577a693274e6d5e229c326d1ec50b4e62c1d1a40d16e7cacc6a6580757d5

The reason it being c39d3fed9ca154a48cad5238a063d2fa1937d32fec5166ce0a27c6e6f94c95c8 is because the public key is treated as a string, instead of a byte array.

To illustrate this, it's best to compare the results between treating '689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124' as

  • a string
  • a byte array

I am not sure how to feed a byte array into the website in the question. So I am using python3 instead.

As string

python3
from Crypto.Hash import keccak
keccak_hash = keccak.new(digest_bits=256)
s='689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
pub=bytearray()
pub.extend(map(ord, s))
keccak_hash.update(bytes(pub))
print(keccak_hash.hexdigest())

The output is

c39d3fed9ca154a48cad5238a063d2fa1937d32fec5166ce0a27c6e6f94c95c8

which matches your result

As byte array

python3
from Crypto.Hash import keccak
keccak_hash = keccak.new(digest_bits=256)
pub=bytearray.fromhex('689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124')
keccak_hash.update(bytes(pub))
print(keccak_hash.hexdigest())

This outputs

de77577a693274e6d5e229c326d1ec50b4e62c1d1a40d16e7cacc6a6580757d5

Verifying the 'As byte array' output

To verify the hash, we calculate the Ethereum address from this output.

echo de77577a693274e6d5e229c326d1ec50b4e62c1d1a40d16e7cacc6a6580757d5 | cut -c 25-

This outputs 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5

Now we import the private key using geth, which will print out the address according to its own calculation

cd $(mktemp -d)
echo 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55 > key.txt
geth --datadir . account import key.txt

Geth will ask for setting a password. Afterwards, it should output

Address: {26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5}

which matches our calculation, thus proving the 'As byte array' approach is correct.

1
  • 1
    Yeah ) you're absolutely right. I've just tried the same and now it works properly. Thanks! For php users, you have to add: $pub = pack("H*", $pub); and it'll work.
    – toptrader
    Apr 19 '18 at 16:05

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.