decryptFile method

Future<PqStreamingHeader> decryptFile({
  1. required Uint8List recipientSecretKey,
  2. required File input,
  3. required File output,
  4. Uint8List? recipientKexSecretKey,
  5. String? recipientKeyId,
  6. Uint8List? signerPublicKey,
  7. Uint8List? aadResolver(
    1. PqStreamingHeader header
    )?,
  8. void onProgress(
    1. int bytesProcessed,
    2. int? totalBytes
    )?,
})

Streams a .pqfs input back to plaintext at output in bounded memory.

aadResolver builds the expected AAD from the (now header-bound) metadata, mirroring the recipe binding of the one-shot path. On any failure — a bad signature, AAD mismatch, tampered/reordered/truncated frame — the partial output is removed before the error propagates.

Implementation

Future<PqStreamingHeader> decryptFile({
  required Uint8List recipientSecretKey,
  required File input,
  required File output,
  Uint8List? recipientKexSecretKey,
  String? recipientKeyId,
  Uint8List? signerPublicKey,
  Uint8List? Function(PqStreamingHeader header)? aadResolver,
  void Function(int bytesProcessed, int? totalBytes)? onProgress,
}) async {
  await output.parent.create(recursive: true);
  final sink = await output.open(mode: FileMode.write);
  PqStreamingHeader? header;
  var success = false;
  try {
    final frames = decryptStream(
      recipientSecretKey: recipientSecretKey,
      recipientKexSecretKey: recipientKexSecretKey,
      recipientKeyId: recipientKeyId,
      input: input,
      signerPublicKey: signerPublicKey,
      aadResolver: aadResolver,
      onHeader: (h) => header = h,
    );
    var processed = 0;
    await for (final plaintext in frames) {
      if (plaintext.isNotEmpty) await sink.writeFrom(plaintext);
      processed += plaintext.length;
      onProgress?.call(processed, _contentLengthOf(header));
    }
    await sink.flush();
    success = true;
    return header!;
  } finally {
    await sink.close();
    if (!success) await _deleteQuietly(output);
  }
}