Mux: pure decrypt, policy at the caller (no null, no key-server storm)

decrypt_sectors is now a pure decrypt — apply the CPS unit key, leave the
plaintext, report how many bytes did not reach clean TS ("unverified"). It
never restores ciphertext, nulls, or re-fetches. "Did a key produce clean TS?"
is a key-selection / read-verify signal, not the verdict "did we decrypt?": a
correct key can decrypt a bad-encoded region, and broken TS is a muxer concern
(the demuxer drops the packet and resyncs).

Callers own the policy:
- mux (read > decrypt > mux): pass the decrypted bytes to the muxer, whatever
  they are; fail loud only on a genuine can't-decrypt (no key / misaligned).
- sweep/patch (reading from a disc): an unverified unit is a bad read — recover
  a fresh key and retry, or fail loud so disc-recovery re-reads it.

Removes three duplicated decisions — the decrypt-time ciphertext restore, the
mux NULL-TS conceal loop, and the per-unit key-server refetch — plus the dead
aacs_unit_still_ciphertext predicate. Key-fetch recovery now samples the on-disc
ciphertext explicitly (a pure decrypt leaves the buffer plaintext) and lives
only on the rip/verify path, never the mux.

Fixes the 30-90s/region mux stalls and key-server storm on bad-encoded UHD runs
that 1.4.1 left behind (it relaxed the gate but not the surrounding machinery).
This commit is contained in:
Matthew Jackson
2026-07-14 21:04:24 -07:00
parent e62ffed2b1
commit 04728d7d94
7 changed files with 284 additions and 343 deletions
+5 -4
View File
@@ -237,10 +237,11 @@ impl DiscStream {
// CSS/unencrypted content needs a decrypting wrapper to yield plaintext
// VOB bytes before the AC-3 sub-stream probe can read real `acmod`s.
// MUX path: tolerate decrypt loss — conceal an undecryptable unit (NULL TS
// fill) + tally + log rather than abort the stream (P3). DiscStream is a
// decode/mux stream (live-drive single-pass / direct), never the
// ciphertext-preserving sweep, so concealment is always correct here.
// MUX path (read > decrypt > mux): decrypt every unit in place and pass the
// bytes to the muxer; a unit that decrypts to broken TS is the muxer's
// concern, never conceal / re-fetch / count as loss (fail loud only on a
// genuine can't-decrypt). DiscStream is a decode/mux stream (live-drive
// single-pass / direct), never the ciphertext-preserving sweep.
let mut reader =
DecryptingSectorSource::new(reader, decrypt_keys.clone()).tolerate_decrypt_loss();