Export a `generatePrivateKey` method
webmaster128 opened this issue · comments
-
I'm submitting a ...
[ ] bug report
[x] feature request
[x] question about the decisions made in the repository
[ ] question about how to use this project -
Summary
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?
- Other information (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. StackOverflow, personal fork, etc.)
@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:
- file loading – Fetch API for browser, fs.readFile for Node.js
- secure random number generation – Crypto.getRandomValues for browser, crypto.randomBytes for Node.js
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))
);
// ...
})();
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.
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.
@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.)
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.
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.