1.2.0: mux loss-concealment read path (P3/Edit-2, A2 NULL-TS fill)

Decrypt-verify is a RIP gate, not a MUX gate. On the mux read path an
undecryptable content unit must never abort the mux:

- DecryptingSectorSource gains tolerate_decrypt_loss(): when set, an
  undecryptable in-content unit is tallied, overwritten with valid NULL
  TS packets (PID 0x1FFF) via aacs::fill_null_ts_unit, logged loud with
  its LBA, and the read returns Ok — the stream keeps flowing. The rip
  paths keep the fail-loud DECRYPT_VERIFY_READ decorator (re-read off the
  disc); only the mux opts in.
- Wire it into both mux read paths: the file-backed highway
  (build_iso_pipeline) and the inline DiscStream.
- NULL-TS fill keeps the demuxer byte-synced on the 192-byte stride; the
  lost video/audio PID packets surface as a CC gap the TS assembler
  already drops a partial PES on (the B1 foundation). Ciphertext is never
  passed downstream either way.
- Fix stale resolve_vid_only no-cert test: default is UHD (audit #4).

Tests: conceal-as-NULL-TS, fill well-formedness, fail-loud still holds.
This commit is contained in:
Matthew Jackson
2026-06-28 22:44:19 -07:00
parent a731e7b26b
commit 9a7be7a1a5
6 changed files with 234 additions and 8 deletions
+10 -4
View File
@@ -660,10 +660,12 @@ mod tests {
assert!(st.bus_encryption, "cert bus_encryption bit must propagate");
}
/// No content cert at all but bus_encryption can't be read → version
/// defaults to 1 (encrypt.rs: `None => 1`). bus_encryption false.
/// No content cert at all → version defaults to UHD (major 2), matching
/// `read_aacs_version` so the scanned `AacsState.version` and the out-of-band
/// fetch agree on the Unit_Key_RO stride (audit #4: a wrong BD-vs-UHD guess
/// mis-parses unit keys). bus_encryption false (unreadable → off).
#[test]
fn resolve_vid_only_no_cert_defaults_version_1() {
fn resolve_vid_only_no_cert_defaults_version_uhd() {
let mut disc = MemDisc::new();
let udf = build_aacs_fs(
&mut disc,
@@ -675,7 +677,11 @@ mod tests {
}],
);
let st = Disc::resolve_vid_only(&udf, &mut disc, None).expect("state");
assert_eq!(st.version, 1, "no cert → default version 1");
assert_eq!(
st.version,
aacs::AACS_MAJOR_UHD,
"no cert → default UHD (major 2)"
);
assert!(!st.bus_encryption);
}