I found this Bitcoin Paper Wallet: https://bitcoinpaperwallet.com/bitcoinpaperwallet/generate-wallet.html

I would like to add it Ethereum just for fun.

On this question, they show how to create address offline.

I have tried to use the same EllipticCurve library they are using, you can check it here, I guess Elliptic Curve is the same everywhere right?

Based on that I created the script shown below. I get private key, public key and address but... If I try to generate address from private key using web3, I get a different one.

Any ideas will be greatly appreciated.

<script type="text/javascript">
    //Ethereum - January 2018
    Ethereum.ECDSA = Bitcoin.ECDSA;

    Ethereum.ECKey = (function() {

        var ECDSA = Ethereum.ECDSA;
        var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
        var rng = new SecureRandom();

        var ECKey = function (input) {
            console.log("ethereum input");
            if (!input) {
                var n = ecparams.getN();

                this.priv = ECDSA.getBigRandom(n);

        ECKey.prototype.getEthereumAddress = function () {

            var hash = this.getPubKeyHash();
            var ola =  Crypto.util.bytesToHex(hash).toString().toUpperCase();

            //var sourceAddress = keccak256(hash);

            var sourceBuffer = keccak256.buffer(hash).slice(-20);
            address = this.buffer2Hex(sourceBuffer);

            return address.toString();

         * Return public key as a byte array in DER encoding
        ECKey.prototype.getPub = function () {

                if (this.pubUncomp) return this.pubUncomp;
                return this.pubUncomp = this.getPubPoint().getEncoded(0);


        ECKey.prototype.getPubKeyHash = function () {
            if (this.pubKeyHashUncomp) return this.pubKeyHashUncomp;
            return this.pubKeyHashUncomp = this.getPub();


         * Return public point as ECPoint object.
        ECKey.prototype.getPubPoint = function () {
            if (!this.pubPoint) {
                this.pubPoint = ecparams.getG().multiply(this.priv);
                this.pubPoint.compressed = this.compressed;
            return this.pubPoint;

        ECKey.prototype.buffer2Hex = function(buffer) { // buffer is an ArrayBuffer
            return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16))).join('');

         * Set whether the public key should be returned compressed or not.
        ECKey.prototype.setCompressed = function (v) {
            this.compressed = !!v;
            if (this.pubPoint) this.pubPoint.compressed = this.compressed;
            return this;

        // Private Key Hex Format
        ECKey.prototype.getEthereumPrivateKeyHexFormat = function () {
            var ola =  Crypto.util.bytesToHex(this.getEthereumPrivateKeyByteArray()).toString().toUpperCase();
            return ola;

        ECKey.prototype.getEthereumAddressHexFormat = function () {
            var ola =  Crypto.util.bytesToHex(this.getEthereumPrivateKeyByteArray()).toString().toUpperCase();
            return ola;

        ECKey.prototype.getEthereumPrivateKeyByteArray = function () {
            // Get a copy of private key as a byte array
            var bytes = this.priv.toByteArrayUnsigned();
            // zero pad if private key is less than 32 bytes
            while (bytes.length < 32) bytes.unshift(0x00);
            return bytes;

        // Sipa Private Key Wallet Import Format
        ECKey.prototype.getEthereumPrivateKey = function () {
            var bytes = this.getEthereumPrivateKeyByteArray();
            return Crypto.util.bytesToHex(bytes).toString().toUpperCase();

        return ECKey;


1 Answer 1


This code is mostly correct, but there are two small issues:

  1. Before hashing the public key, you need to drop the first byte. The first byte often indicates whether the key is compressed or not. In Ethereum, the value must always be uncompressed, and you don't include the prefix when hashing.
  2. buffer2Hex appears to be broken.

Here's a fixed version of getEthereumAddress:

ECKey.prototype.getEthereumAddress = function () {
  return Crypto.util.bytesToHex(
      this.getPub().slice(1) // drop the 1-byte prefix
    ).slice(-20));           // take the last 20 bytes

(If keccak256.array doesn't exist for you, maybe you're using a different library than I did. I used js-sha3.)

  • Thanks!!! that was my error. Can you give me your email or twitter or linkedin? you are a life saver!!
    – Eduardo
    Commented Jan 9, 2018 at 14:13
  • [email protected], @smarx
    – user19510
    Commented Jan 9, 2018 at 14:28
  • Thank you @smarx. Maybe you can help me with this one: ethereum.stackexchange.com/questions/36036/…
    – Eduardo
    Commented Jan 12, 2018 at 16:08
  • one more question, If user enters a Random string, as seed to generate an address, would this be valid? var bytes = Crypto.charenc.UTF8.stringToBytes(suppliedKey)); this.priv = new BigInteger(bytes); If a user enters a Private key string, would this be valid? var bytes = Crypto.util.hexToBytes(privStr); this.priv = new BigInteger(bytes);
    – Eduardo
    Commented Jan 12, 2018 at 19:24
  • I am new to this, and I got a mix among all coins! :D
    – Eduardo
    Commented Jan 12, 2018 at 19:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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