bitauth / libauth

An ultra-lightweight, zero-dependency TypeScript library for Bitcoin Cash, Bitcoin, and Bitauth applications.
https://libauth.org
MIT License
272 stars 50 forks source link

Export a `generatePrivateKey` method #3

Closed webmaster128 closed 4 years ago

webmaster128 commented 6 years ago

I am getting started with this library and did not find a keypair generator in the API. Is this something that can be added? Or do you expect the keypairs to come from somewhere else?

bitjson commented 6 years ago

@webmaster128 thanks for opening these issues! I'll definitely need to provide better explanation for some of this in the docs.

You're correct that there is no key generation method currently – I'm trying to avoid including environment-specific code (browser vs. Node.js) in this library. That makes things slightly more difficult since some important functionality is very environment-specific:

To safely generate a key, you'll need to use one of the above secure random number generation APIs (depending on your platform).

We can still make it simpler though – I'll work on providing a generatePrivateKey function, maybe with a signature: generatePrivateKey(secp256k1: Secp256k1, secureRandom: () => Uint8Array): Uint8Array. It would simply call the provided secureRandom function until it found a key that passes secp256k1.validatePrivateKey.

You would still need to provide the entropy source in the secureRandom function, but it's a bit more ergonomic/declarative.

So if you're in Node.js, you'd write something like:

import { randomBytes } from 'crypto';
import { generatePrivateKey, instantiateSecp256k1 } from 'bitcoin-ts';

(async () => {
  const secp256k1 = await instantiateSecp256k1();
  const key = generatePrivateKey(secp256k1, () => randomBytes(32));
  // ...
})();

And in the browser:

import { generatePrivateKey, instantiateSecp256k1 } from 'bitcoin-ts';

(async () => {
  const secp256k1 = await instantiateSecp256k1();
  const key = generatePrivateKey(secp256k1, () =>
    window.crypto.getRandomValues(new Uint8Array(32))
  );
  // ...
})();
webmaster128 commented 6 years ago

Heyho @bitjson, thanks for doing this library and your extensive replies!

I only recently realized, that key generation is as simple as taking 32 random bytes until validatePrivateKey is true, so this could as well be out of scope for the library.

A key generator might still be handy. I agree that injecting the randomness is better than having yet another library trying to cover all the cases needed to access a RNG. Most applications will have an rng wrapper anyway.

However, I'd prefer to have a deterministic key derivation based on an initial seed. I don't know how to do that without further dependencies but basically, you could use the series entropy, sha256(entropy), sha256(sha256(entropy)), sha256(sha256(sha256(entropy))) … to be able to have multiple attempts. I was also thinking of requiring 64 bytes of input data and use 32 bytes starting from position 0, 1, 2, ... But I am not entirely sure if that created some structure in the end result.

webmaster128 commented 6 years ago

Or just take 512 bytes, split it in 32 byte chunks, which gives you 16 entirely independent attempts. This is deterministic, dependency free, simple to understand and review and structure free.

bitjson commented 6 years ago

@webmaster128 thanks for opening issues!

Yes, I'd definitely like to export some clean, pure functions that make both those cases more declarative/ergonomic.

Are you familiar with BIP39? If not, you'll find it's very similar to your solution. 😄

I'm definitely planning to implement something similar to BIP 39, though with some changes to elements that bother me. (I might also implement BIP 39 itself for backwards-compatibility, not sure yet.)

webmaster128 commented 6 years ago

I am primarily familiar with the entropy->words encoding of BIP39, which is great. Today I looked into the second part of BIP39 "From mnemonic to seed". I consider this a horrible, overly complicated algorithm that does not at all match principles of the BIP39 mnemonic encoding. Why is this using strings as input, not entropy if BIP39 allows string representations in multiple languages? Why run a password based key derivation function on high entropy strings? Furthermore, it contains contradicting requirements (Although using a mnemonic not generated by the algorithm described in "Generating the mnemonic" section is possible, this is not advised vs. software must compute a checksum). I would stay away from that whenever possible.

I think the cleanest solution here is to use any standard pseudo random generator that is seeded with 256bit of entropy and produces keys until there is a valid one.

bitjson commented 6 years ago

You've identified exactly my qualms with it. 😆

It may be a little while before I get to it, but I'm definitely planning to work on this. I'll leave this issue open until then.