generatePrivateKey static method

String generatePrivateKey(
  1. String intPassphrase,
  2. PubKeyModes pubKeyMode
)

Generate a BIP38-encrypted private key from an intermediate passphrase.

  • intPassphrase: The intermediate passphrase.
  • pubKeyMode: The public key mode specifying the address type.

Implementation

static String generatePrivateKey(
  String intPassphrase,
  PubKeyModes pubKeyMode,
) {
  /// Decode the intermediate passphrase into bytes.
  final intPassphraseBytes = Base58Decoder.checkDecode(intPassphrase);

  /// Ensure the length of the intermediate code is valid.
  if (intPassphraseBytes.length != Bip38EcConst.intPassEncByteLen) {
    throw ArgumentException.invalidOperationArguments(
      "generatePrivateKey",
      name: "intPassphrase",
      reason: "Invalid intermediate code length",
    );
  }

  /// Extract magic, owner entropy, and passpoint from the intermediate code.
  final magic = intPassphraseBytes.sublist(0, 8);
  final ownerEntropy = intPassphraseBytes.sublist(8, 16);
  final passpoint = Secp256k1PublicKey.fromBytes(
    intPassphraseBytes.sublist(16),
  );

  /// Check if the magic number is valid.
  if (!BytesUtils.bytesEqual(magic, Bip38EcConst.intPassMagicNoLotSeq) &&
      !BytesUtils.bytesEqual(magic, Bip38EcConst.intPassMagicWithLotSeq)) {
    throw ArgumentException.invalidOperationArguments(
      "generatePrivateKey",
      name: "intPassphrase",
      reason: "Invalid magic",
    );
  }

  /// Generate a random seed for seedb and derive a new point.
  final seedb = QuickCrypto.generateRandom(Bip38EcConst.seedBByteLen);
  final factorb = QuickCrypto.sha256DoubleHash(seedb);
  final newPoint = passpoint.point * BigintUtils.fromBytes(factorb);

  /// Calculate the address hash.
  final addressHash = Bip38Addr.addressHash(newPoint.toBytes(), pubKeyMode);

  /// Derive key halves using Scrypt.
  final derivedHalves = Bip38EcUtils.deriveKeyHalves(
    passpoint.compressed,
    addressHash,
    ownerEntropy,
  );

  /// Encrypt seedb and create the BIP38-encrypted private key.
  final encryptedParts = _encryptSeedb(
    seedb,
    derivedHalves.$1,
    derivedHalves.$2,
  );
  final flagbyte = _setFlagbyteBits(magic, pubKeyMode);
  final encKeyBytes = [
    ...Bip38EcConst.encKeyPrefix,
    ...flagbyte,
    ...addressHash,
    ...ownerEntropy,
    ...encryptedParts.$1.sublist(0, 8),
    ...encryptedParts.$2,
  ];

  return Base58Encoder.checkEncode(encKeyBytes);
}