decrypt static method

Tuple<List<int>, PubKeyModes> decrypt(
  1. String privKeyEnc,
  2. String passphrase
)

Decrypt a BIP38-encrypted private key with a passphrase.

This method decrypts a BIP38-encrypted private key using the provided passphrase. It returns the decrypted private key as bytes and identifies the associated public key mode (compressed or uncompressed).

  • privKeyEnc: The BIP38-encrypted private key to be decrypted.
  • passphrase: The passphrase used for decryption.
  • Returns: A tuple (pair) containing the decrypted private key bytes and the associated public key mode.

Implementation

static Tuple<List<int>, PubKeyModes> decrypt(
    String privKeyEnc, String passphrase) {
  final privKeyEncBytes = Base58Decoder.checkDecode(privKeyEnc);

  /// Check if the length of the encrypted private key is valid.
  if (privKeyEncBytes.length != Bip38EcConst.encByteLen) {
    throw ArgumentException(
        'Invalid encrypted length (${privKeyEncBytes.length})');
  }

  /// Extract various components from the encrypted private key.
  final prefix = privKeyEncBytes.sublist(0, 2);
  final flagbyte = List<int>.from([privKeyEncBytes[2]]);
  final addressHash = privKeyEncBytes.sublist(3, 7);
  final ownerEntropy = privKeyEncBytes.sublist(7, 15);
  final encryptedPart1Lower = privKeyEncBytes.sublist(15, 23);
  final encryptedPart2 = privKeyEncBytes.sublist(23);

  /// Verify the prefix of the encrypted private key.
  if (!BytesUtils.bytesEqual(prefix, Bip38EcConst.encKeyPrefix)) {
    throw ArgumentException(
        'Invalid prefix (${BytesUtils.toHexString(prefix)})');
  }

  /// Extract flag options based on the flag byte.
  final flagOptions = _getFlagbyteOptions(flagbyte);

  /// Derive the pass factor and key halves for decryption.
  final passfactor =
      Bip38EcUtils.passFactor(passphrase, ownerEntropy, flagOptions.item2);

  final derivedHalves = Bip38EcUtils.deriveKeyHalves(
      Bip38EcUtils.passPoint(passfactor), addressHash, ownerEntropy);

  /// Decrypt 'factorb' and compute the private key.
  final factorb = _decryptAndGetFactorb(encryptedPart1Lower, encryptedPart2,
      derivedHalves.item1, derivedHalves.item2);
  final privateKeyBytes = _computePrivateKey(passfactor, factorb);

  /// Create a public key from the private key and calculate address hash.
  final toPub = Secp256k1PrivateKeyEcdsa.fromBytes(privateKeyBytes);
  final addressHashGot = Bip38Addr.addressHash(
      toPub.publicKey.point.toBytes(), flagOptions.item1);

  /// Verify the extracted address hash matches the expected value.
  if (!BytesUtils.bytesEqual(addressHash, addressHashGot)) {
    throw ArgumentException(
        'Invalid address hash (expected: ${BytesUtils.toHexString(addressHash)}, got: ${BytesUtils.toHexString(addressHashGot)})');
  }

  return Tuple(privateKeyBytes, flagOptions.item1);
}