aacs: remove the mod.rs facade — module paths are the public API

Delete the pub-use re-export facade; consumers now import from the owning
module (aacs::content::decrypt_unit, aacs::mkb::MkbType, aacs::derive::derive_vuk,
aacs::boil::mk_from_dk, aacs::resolve::resolve_keys_v2, ...). Internal callers
repointed accordingly. Path-only change; logic hash identical (95fb9924); 2210
tests green.
This commit is contained in:
Matthew Jackson
2026-07-04 14:19:40 -07:00
parent 84aaceceb7
commit 5ff04649ba
12 changed files with 223 additions and 250 deletions
+2 -2
View File
@@ -10,8 +10,8 @@
pub fn collect_host_certs(
opts: &crate::disc::ScanOptions,
mkb: Option<u32>,
) -> Vec<crate::aacs::HostCert> {
let mut host_certs: Vec<crate::aacs::HostCert> = Vec::new();
) -> Vec<crate::aacs::types::HostCert> {
let mut host_certs: Vec<crate::aacs::types::HostCert> = Vec::new();
if let Some(c) = &opts.credentials {
host_certs.extend(c.host_certs.iter().cloned());
}
+15 -57
View File
@@ -50,62 +50,21 @@ pub const PATH_MKB_RW: &str = "/AACS/MKB_RW.inf";
pub const PATH_CONTENT_CERT: &str = "/AACS/Content000.cer";
pub const PATH_CONTENT_CERT_ALT: &str = "/AACS/Content001.cer";
// Boil-down derivation primitives (thin newtypes + wrappers over the crypto).
pub use boil::{
KeyCandidate, MediaKey, ProcessingKey, ResolvedChain, UnitKey, Vid, Vuk, mk_from_dk,
mk_from_pk, resolve_candidate, uk_from_vuk, vuk_from_mk,
};
// Structured, English-free resolution trace.
pub use trace::{KeyNode, KeyOutcome, KeyStep, ResolutionTrace, UnlockOutcome, UnlockStep};
// Explicit re-exports — only items needed by external consumers and sibling crate modules.
// AES primitives (aes_ecb_encrypt, aes_ecb_decrypt, aes_cbc_decrypt) are pub(crate) in decrypt.rs.
pub use content::{
ALIGNED_UNIT_LEN, ALIGNED_UNIT_SECTORS, UnitKeyResult, aacs_unit_encrypted,
aacs_unit_needs_decrypt, aacs_unit_still_ciphertext, decrypt_bus, decrypt_unit,
decrypt_unit_checked, decrypt_unit_full, decrypt_unit_try_keys, fill_null_ts_unit,
is_unit_aligned, ts_packet_total, ts_sync_count, ts_sync_destroyed, unit_is_clean_ps,
unit_is_clean_ts, unit_key_validates,
};
// `probe` is a reproduction-harness helper (see keys.rs), not part of the
// documented 1.0 surface; keep it reachable but off the rendered docs so we
// don't commit semver stability to test primitives.
#[doc(hidden)]
pub use derive::probe;
pub use derive::{decrypt_unit_key, derive_vuk};
pub use derive::{
derive_media_key_and_pk_from_dk, derive_media_key_from_dk, derive_media_key_from_pk,
recover_dk_position,
};
pub use inf::{
ContentCert, UnitKeyFile, disc_hash, disc_hash_hex, parse_content_cert, parse_unit_key_ro,
read_mkb_from_drive,
};
pub use mkb::{
AACS_MAJOR_BD, AACS_MAJOR_UHD, AacsVersion, MKB_20_CATEGORY_C, MKB_21_CATEGORY_C,
MKB_TYPE_3_RECORDABLE, MKB_TYPE_4_PRERECORDED, MKB_TYPE_10_CLASS_II, MkbRecord, MkbType,
mkb_content_len, mkb_is_uhd, mkb_type, mkb_type_raw, mkb_version, trim_mkb, walk_mkb,
};
pub use provider::KeyProvider;
pub use resolve::{
ResolveContext, ResolveFailure, ResolvedKeys, resolve_keys_v1, resolve_keys_v2,
resolve_keys_v21, resolve_keys_with_reason,
};
pub use types::{DeviceKey, DiscEntry, HostCert};
pub use variant::{
KEY_CORRECTION_DATA_PLACEHOLDER, MediaKeyVariantError, ProcessingKeyMatch,
derive_media_key_variant, is_variant_mkb, variant_nonce, walk_processing_key,
};
// No facade: the module structure IS the public API. Consumers import from the
// owning module directly — e.g. `aacs::content::decrypt_unit`, `aacs::mkb::MkbType`,
// `aacs::derive::derive_vuk`, `aacs::boil::mk_from_dk`, `aacs::resolve::resolve_keys_v2`.
// The `derive::probe` reproduction harness stays reachable via its module path.
#[cfg(test)]
mod tests {
//! Re-export surface guards. The module's public API is the set of
//! `pub use` items above. A regression that drops or renames an export
//! (the class of bug that shipped in 0.31.0 by silently changing a
//! surface) breaks compilation of these references, so they act as a
//! compile-time contract for the crate's AACS surface.
//! Surface guards. The public API is the module tree itself (no facade).
//! Touching one representative item per module keeps these as a
//! compile-time contract that the module paths stay stable.
use super::*;
use super::content::{ALIGNED_UNIT_LEN, ts_sync_destroyed};
use super::inf::{disc_hash, disc_hash_hex};
use super::mkb::{AacsVersion, mkb_content_len, walk_mkb};
use super::variant::{KEY_CORRECTION_DATA_PLACEHOLDER, is_variant_mkb};
#[test]
fn aligned_unit_len_is_three_2048_byte_sectors() {
@@ -134,14 +93,13 @@ mod tests {
}
#[test]
fn public_helpers_are_callable_through_the_facade() {
// Touch a representative function from each re-export group so a
// dropped/renamed export fails to compile. These are smoke calls, not
// behavioural assertions (behaviour is covered in each module).
fn public_helpers_are_callable_by_module_path() {
// Touch a representative function from each module so a dropped/renamed
// item fails to compile. Smoke calls, not behavioural assertions.
let _ = ts_sync_destroyed(&[0u8; ALIGNED_UNIT_LEN]);
let _ = mkb_content_len(&[]);
let _ = is_variant_mkb(&walk_mkb(&[]));
let _ = disc_hash_hex(&disc_hash(b"x"));
let _ = mk_from_pk(&[[0u8; 16]], &[]);
let _ = super::boil::mk_from_pk(&[[0u8; 16]], &[]);
}
}
+15 -15
View File
@@ -1068,7 +1068,7 @@ mod tests {
disc_entry: None,
};
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,
@@ -1111,7 +1111,7 @@ mod tests {
};
let vid = [0u8; 16];
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,
@@ -1153,7 +1153,7 @@ mod tests {
};
let vid = [0u8; 16];
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,
@@ -1193,7 +1193,7 @@ mod tests {
};
let vid = [0u8; 16];
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,
@@ -1240,7 +1240,7 @@ mod tests {
media_keys: vec![km],
disc_entry: None,
};
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,
@@ -1627,7 +1627,7 @@ mod tests {
mkb.extend_from_slice(&[0x2f, 0x00, 0x00, 0x14]);
mkb.extend_from_slice(&[0x55; 16]);
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,
@@ -1663,7 +1663,7 @@ mod tests {
}),
};
let mkb = vec![0x10, 0x00, 0x00, 0x08, 0, 0, 0, 1];
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,
@@ -1697,7 +1697,7 @@ mod tests {
let mut cc = vec![0u8; 20];
cc[0] = 0x10;
cc[1] = 0x80;
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: Some(&cc),
@@ -1731,7 +1731,7 @@ mod tests {
unit_keys: Vec::new(),
}),
};
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &data,
content_cert: None,
@@ -1769,7 +1769,7 @@ mod tests {
unit_keys: Vec::new(),
}),
};
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,
@@ -1786,7 +1786,7 @@ mod tests {
fn resolve_keys_returns_none_when_no_provider_has_anything() {
// Empty provider array + VID present + no MKB → all paths miss → None.
let uk_ro = minimal_unit_key_ro();
let providers: &[&dyn super::super::KeyProvider] = &[];
let providers: &[&dyn super::super::provider::KeyProvider] = &[];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,
@@ -1969,7 +1969,7 @@ mod tests {
#[test]
fn classify_processing_keys_zero_vid_is_vid_unavailable() {
let prov = material_provider(Vec::new(), vec![[0u8; 16]]);
let providers: &[&dyn super::super::KeyProvider] = &[&prov];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&prov];
let uk_ro = minimal_unit_key_ro();
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
@@ -1994,7 +1994,7 @@ mod tests {
#[test]
fn classify_vid_present_with_material_is_no_material_not_vid() {
let prov = material_provider(vec![one_device_key()], vec![[0u8; 16]]);
let providers: &[&dyn super::super::KeyProvider] = &[&prov];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&prov];
let uk_ro = minimal_unit_key_ro();
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
@@ -2017,7 +2017,7 @@ mod tests {
#[test]
fn classify_vid_present_no_material_is_no_material() {
let prov = material_provider(Vec::new(), Vec::new());
let providers: &[&dyn super::super::KeyProvider] = &[&prov];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&prov];
let uk_ro = minimal_unit_key_ro();
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
@@ -2055,7 +2055,7 @@ mod tests {
unit_keys: Vec::new(),
}),
};
let providers: &[&dyn super::super::KeyProvider] = &[&keydb];
let providers: &[&dyn super::super::provider::KeyProvider] = &[&keydb];
let ctx = ResolveContext {
unit_key_ro: &uk_ro,
content_cert: None,