I have generated mnemonic using bip39.generateMnemonic();
. I need to convert this mnemonic to AsymmetricKeyPair with secp256k1.
AsymmetricKeyPair<PublicKey, PrivateKey> secp256k1KeyPair() {
var keyParams = ECKeyGeneratorParameters(ECCurve_secp256k1());
var mnemonic = getMnemonic();
var seed = bip39.mnemonicToSeed(mnemonic);
print('mnemonicToSeed=========$seed');
var random = FortunaRandom();
random.seed(KeyParameter(seed));
var generator = ECKeyGenerator();
generator.init(ParametersWithRandom(keyParams,random));
return generator.generateKeyPair();
}
getMnemonic() {
var mnemonic = bip39.generateMnemonic();
print('mnemonic=========$mnemonic');
return mnemonic;
}
Unhandled Exception: Invalid argument(s): Fortuna PRNG can only be used with 256 bits keys.
Finally I’m able to generate the AsymmetricKeyPair as follows.but I’m not sure whether I did it in a correct way.Please correct me if I’m wrong.
/// generates dynamic mnemonic
String getMnemonic() {
var mnemonic = bip39.generateMnemonic();
print('mnemonic=========$mnemonic');
return mnemonic;
}
AsymmetricKeyPair<PublicKey, PrivateKey> secp256k1KeyPair() {
var keyParams = ECKeyGeneratorParameters(ECCurve_secp256k1());
var mnemonic = getMnemonic();
var seed = bip39.mnemonicToSeed(mnemonic);
final digest = sha256.convert(seed); // 32 bytes
print('mnemonicToSeed=========$seed');
var random = FortunaRandom();
random.seed(KeyParameter(_seed(digest.bytes)));
var generator = ECKeyGenerator();
generator.init(ParametersWithRandom(keyParams,random));
return generator.generateKeyPair();
}
Uint8List _seed(List<int> digest) {
var seed = List<int>.generate(digest.length, (_) => digest[_]);
return Uint8List.fromList(seed);
}
As FortunaRandom is not robust ,Could you please suggest anything else.
2
Answers
If I’m looking at the code then
mnemonicToSeed
for BIPS39 will generate a 512 bit output (the output size of PBKDF2, more information here). You can just use the leftmost bits/bytes of that and take 256 bits. Ye old Fortuna uses a block cipher in counter mode and likely the initial seed size must be identical to the (or a) key size.Note that I’ve got no idea what you are trying to do. If I’d try to generate another key pair deterministically, I’d not use your code as it is implementation dependent. If anything changes in
generateKeyPair
, e.g. if a different method is used to extract random bytes then it would break, while the API would remain the same. The chance of that is not that high for Elliptic Curve withsecp256k1
as key pair generation is largely deterministic as well but suddenly generating a the wrong private key can certainly have terrible consequences.To avoid using a PRNG (e.g.
FortunaRandom
), you could apply the following approach:After derivation of a raw 32 bytes private key (via
getMnemonic()
andmnemonicToSeed()
) this can be imported directly withECPrivateKey()
.The raw public key results by a multiplication with the generator point and subsequent import with
ECPublicKey()
: