Creación de un creador de direcciones sin conexión para Ethereum

Encontré esta billetera de papel Bitcoin: https://bitcoinpaperwallet.com/bitcoinpaperwallet/generate-wallet.html

Me gustaría agregarlo Ethereum solo por diversión.

En esta pregunta , muestran cómo crear una dirección sin conexión.

Intenté usar la misma biblioteca EllipticCurve que están usando, puede verificarlo aquí , supongo que Elliptic Curve es igual en todas partes, ¿no?

Basado en eso, creé el script que se muestra a continuación. Obtengo una clave privada, una clave pública y una dirección pero... Si trato de generar una dirección a partir de una clave privada usando web3, obtengo una diferente.

Cualquier idea será muy apreciada.

<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");
            console.log(input);
            if (!input) {
                var n = ecparams.getN();
                console.log("getN");

                this.priv = ECDSA.getBigRandom(n);
                console.log();
                console.log("this.priv");
                console.log(this.priv);
                console.log("====");
            }
        }

        ECKey.prototype.getEthereumAddress = function () {

            console.log("getEthereumAddress");
            var hash = this.getPubKeyHash();
            console.log("hashEther");
            console.log(hash);
            var ola =  Crypto.util.bytesToHex(hash).toString().toUpperCase();
            console.log("ola");
            console.log(ola);

            //var sourceAddress = keccak256(hash);



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

            console.log("AAAAAA");
            console.log(address);
            return address.toString();
        };

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

            console.log("getPub");
                if (this.pubUncomp) return this.pubUncomp;
                return this.pubUncomp = this.getPubPoint().getEncoded(0);

        };

        ECKey.prototype.getPubKeyHash = function () {
            console.log("getPubKeyHashx");
            console.log(this.getPub());
            console.log("====");
            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();
            console.log("getBitcoinHexFormat");
            console.log(ola);
            return ola;
        };

        ECKey.prototype.getEthereumAddressHexFormat = function () {
            var ola =  Crypto.util.bytesToHex(this.getEthereumPrivateKeyByteArray()).toString().toUpperCase();
            console.log("getBitcoinHexFormat");
            console.log(ola);
            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 () {
            console.log("getEthereumPrivateKey");
            var bytes = this.getEthereumPrivateKeyByteArray();
            return Crypto.util.bytesToHex(bytes).toString().toUpperCase();
        };


        return ECKey;
    })();


    </script>

Respuestas (1)

Este código es mayormente correcto, pero hay dos pequeños problemas:

  1. Antes de codificar la clave pública, debe eliminar el primer byte. El primer byte suele indicar si la clave está comprimida o no. En Ethereum, el valor siempre debe estar sin comprimir, y no incluye el prefijo al realizar el hash.
  2. buffer2Hexparece estar roto.

Aquí hay una versión fija de getEthereumAddress:

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

(Si keccak256.arrayno existe para usted, tal vez esté usando una biblioteca diferente a la que usé. Usé js-sha3 ).

¡¡¡Gracias!!! ese fue mi error ¿Puedes darme tu correo electrónico o twitter o linkedin? ¡¡eres un salvavidas!!
smarx@smarx.com, @smarx
Gracias @smarx. Tal vez puedas ayudarme con este: ethereum.stackexchange.com/questions/36036/…
una pregunta más, si el usuario ingresa una cadena aleatoria, como semilla para generar una dirección, ¿sería esto válido? var bytes = Crypto.charenc.UTF8.stringToBytes(suppliedKey)); this.priv = new BigInteger(bytes); Si un usuario ingresa una cadena de clave privada, ¿sería válida? var bytes = Crypto.util.hexToBytes(privStr); this.priv = new BigInteger(bytes);
¡Soy nuevo en esto y obtuve una combinación entre todas las monedas! :D