javascriptcryptographybitcoinprivate-keywebcrypto-api

What is a reliable way to generate bitcoin private key in browser?


Is there a way to generate truly random bitcoin private key without relying on 3rd party libraries like ECPair nor tiny-secp256k1?

As a recommended approach to generate secure random key is to use something like this:

import ECPairFactory from 'ecpair'
import * as ecc from 'tiny-secp256k1'

const ECPair = ECPairFactory(ecc)

export function generatePrivateKey() {
  const keyPair = ECPair.makeRandom()
  return keyPair.privateKey.toString('hex')
}

Can the same be done by just using browser native Web Crypto API window.crypto.getRandomValues only?

function generatePrivateKey() {
  const privateKeyBytes = new Uint8Array(32); // 256 bits for a Bitcoin private key
  window.crypto.getRandomValues(privateKeyBytes)
  
  const privateKeyHex = 
     Array.from(privateKeyBytes)
    .map(byte => byte.toString(16).padStart(2, '0'))
    .join('')
  
  return privateKeyHex
}

Solution

  • Yes, that would work practically speaking. The private key is a number in the range [1, n). However, since the chance of generating a number that is either 0 or n-or-higher is negligible, you can safely disregard that ever happening.

    For reference, the order of secp256k1 is:

    FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
    

    using big endian, static sized byte array (in hexadecimals) to represent the value. The private key has the same format. From this you can see that the chance of creating a bad private key is about 1 in 2^128.

    Of course this does assume that the cryptographically secure random number generator is working as advertised. Beware as well that the calculation of the public key point (W) requires EC point multiplication - that's actually the hard part. So don't ask to do that without a library - as it would basically entail to write a new one from scratch.