flutter 如何在dart中使用secp256k1将助记符转换为AsymmetricKeyPair

kqlmhetl  于 2023-08-07  发布在  Flutter
关注(0)|答案(2)|浏览(213)

我使用bip39.generateMnemonic();生成助记符。我需要用secp256k1将此助记符转换为AsymmetricKeyPair。

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;
  }

字符串
未处理异常:无效参数:福图纳PRNG只能使用256位密钥。
最后我可以生成AsymmetricKeyPair如下。但我不确定我是否以正确的方式做了它。如果我错了请纠正我。

/// 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);
  }


由于FortunaRandom不是强大的,你能建议其他的吗?

4ktjp1zp

4ktjp1zp1#

如果我查看代码,那么BIPS 39的mnemonicToSeed将生成512位输出(PBKDF 2的输出大小,更多信息here)。你可以只使用最左边的位/字节,取256位。Ye old福图纳在计数器模式下使用块密码,并且可能初始种子大小必须与(或)密钥大小相同。
请注意,我不知道你想做什么。如果我尝试确定性地生成另一个密钥对,我不会使用您的代码,因为它依赖于实现。如果generateKeyPair中有任何变化,例如如果使用不同的方法来提取随机字节,那么它将中断,而API将保持不变。对于具有secp256k1的椭圆曲线,这种可能性并不高,因为密钥对生成在很大程度上也是确定性的,但是突然生成错误的私钥肯定会产生可怕的后果。

trnvg8h3

trnvg8h32#

为了避免使用PRNG(例如FortunaRandom),您可以应用以下方法:
在导出原始32字节私钥(通过getMnemonic()mnemonicToSeed())后,可以直接使用ECPrivateKey()导入。
原始公钥通过与生成点相乘并随后导入ECPublicKey()得到:

import 'package:bip39/bip39.dart' as bip39;
import 'package:bip32/bip32.dart' as bip32; // if BIP32 is applied
import 'package:pointycastle/export.dart';
import 'package:nanodart/nanodart.dart';
import 'package:basic_utils/basic_utils.dart'; // if PEM conversion required

...

// get seed
// var mnemonic = getMnemonic();
var mnemonic = "viable rhythm total tissue muscle forget culture strong lobster drama swim wasp"; // apply a static mnemonic for testing
var seed = bip39.mnemonicToSeed(mnemonic);

// derive private key
var privateKeyBytes = bip32.BIP32.fromSeed(seed).privateKey!; // apply BIP32 and use the "extended private key" 
// var privateKeyBytes = seed.sublist(0, 32);                 // alternatively, do not apply BIP32 and generate a key of the required size from the seed (e.g. the SHA256 hash or the first 32 bytes of the seed)

// create ECPrivateKey/ECPublicKey instances (this is what you asked for in the comment)
var privateKey = NanoHelpers.byteToBigInt(privateKeyBytes);
var domain = ECDomainParameters('secp256k1');
var ecPrivateKey = ECPrivateKey(privateKey, domain);
var g = ecPrivateKey.parameters?.G;
var ecPublicKey = ECPublicKey(g! * privateKey, domain);

// output the raw keys...
print('mnemonicToSeed=========: $seed');
print('privateKey=========: $privateKeyBytes');
var uncompressed = ecPublicKey.Q?.getEncoded(false);
print('publicKey=========: $uncompressed');

// ...or export as PEM
var sec1Pem = CryptoUtils.encodeEcPrivateKeyToPem(ecPrivateKey);
var spkiPem = CryptoUtils.encodeEcPublicKeyToPem(ecPublicKey);
print('private as sec1=========: $sec1Pem');
print('public as x.509/SPKI=========: $spkiPem');

字符串

相关问题