dvb-csa 0.2.0

DVB Common Scrambling Algorithm (CSA2) — pure-Rust, with an optional bitsliced 64-payload batch fast path, validated against libdvbcsa known-answer vectors.
Documentation
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.2.0] - 2026-08-11

### Changed
- `ts::ts_payload_mut` now decodes `adaptation_field_control` via
  `mpeg_ts::ts::TsHeader::parse` (a new dependency on `mpeg-ts`) instead of
  hand-rolling the same AFC bit decode — a duplication-audit finding.
  Magic-number `188`/`0x3f`/`0x80` replaced with named,
  spec-cited constants (`mpeg_ts::ts::TS_PACKET_SIZE`/`SCRAMBLING_MASK` plus
  a local `TSC_EVEN_KEY`). The payload byte-offset computation and the
  `&mut` slicing itself stay hand-rolled, with a comment explaining why:
  `mpeg_ts::ts::TsPacket` only exposes an immutable `payload: &[u8]`, and
  CSA (de)scrambling needs to write back into the caller's own buffer.
  Identical behaviour; no public API change.
- MSRV raised to **1.95.0** (issue #949). This removes the workspace's MSRV
  split: `webrtc-runtime`'s optional `media` feature needed rustc 1.88 (via
  `rcgen`), which had grown a dedicated CI job, six `--exclude` lanes and a
  guard script to contain. Adopting let-chains and `is_multiple_of` where the
  1.95 lints require them; no functional or API change.

## [0.1.2] - 2026-08-08

`0.1.1` was never separately published (no such version exists on crates.io,
no `dvb-csa-v0.1.1` tag) — its doc-accuracy fix is folded into this release
below, alongside the new bitsliced feature.

### Fixed
- **Documentation corrected — the published 0.1.0 advertised two things that
  do not exist.** No code or behaviour change; the cipher is unaffected.
  - The crates.io `description` claimed "a bitsliced fast path", and the
    crate-root docs described a `bitsliced` feature "differentially tested
    against the scalar reference". There is no such feature and no such code.
    Both claims removed; the docs now say a bitsliced path is unimplemented.
  - The crate-root docs listed a **TSDuck** scrambled-capture oracle as part
    of "the gate". The fixture is committed but the control word it was
    scrambled with was never recorded, so it cannot be decrypted and no test
    references it. The claim is removed and the situation is now recorded in
    `tests/fixtures/PROVENANCE.md`, including how to make it a real oracle.
  - The remaining oracle — byte-exact known-answer vectors from libdvbcsa
    1.1.0, in `tests/golden_vectors.rs` — is genuine and unchanged.

### Added
- **`bitsliced` feature — a real bitsliced fast path**, restoring (and now
  earning) the claim the documentation fix above had to strip. Off by
  default; purely additive, so no existing API changes and nothing breaks.
  - `dvb_csa::bitsliced::{scramble_batch, descramble_batch, LANES}` process up
    to `LANES` (64) **independent payloads** per pass, transposing the data and
    evaluating the cipher as a branch-free boolean circuit so every gate acts
    on all 64 lanes at once.
  - **The unit of parallelism is the payload, not the block** — deliberately.
    Scrambling's block cipher is a reverse CBC (`C[i] = E(P[i] ^ C[i+1])`) and
    the stream cipher is a chained LFSR; both are strictly sequential within
    one payload. Only descrambling's block half (`P[i] = D(C[i]) ^ C[i+1]`) is
    independent per block, and the stream cipher — the sequential part — is
    ~2/3 of the work. So there is no bitsliced single-payload entry point: for
    one payload there is nothing worth slicing.
  - Measured on an Apple M2 Ultra (rustc 1.86.0), 64 x 184-byte TS payloads:
    scramble **15.7 -> 91.3 MiB/s (5.8x)**, descramble **15.1 -> 99.8 MiB/s
    (6.6x)**. `benches/throughput.rs` now runs both paths over the same batch.
  - `no_std`: the fast path allocates nothing and uses no `std`.
  - Circuits are generated by `tools/gen_circuits.py` from `src/tables.rs`    the tables stay the single source of truth. The generator synthesises each
    table as the cheaper of a shared ROBDD or an algebraic normal form (block
    S-box 402 gates, the seven stream S-boxes 153, `STREAM_CDEF` 58), and
    proves the linear tables linear rather than assuming it: `PERM` is a bit
    permutation and so costs nothing bitsliced, and the S-box index selection,
    `csa_stream_b_sel` and `STREAM_OUT` reduce to XOR trees.
  - Three independent correctness gates: every generated circuit is checked
    against its source table over its **entire** input domain
    (`src/bitsliced/circuit_tests.rs`); `tests/bitsliced_differential.rs`
    requires byte-identical agreement with the scalar path over randomised
    payloads, batch sizes straddling `LANES`, and lengths covering the
    pass-through (<8 B), single-block, non-multiple-of-8 and long cases, in
    both directions; and `tests/golden_vectors.rs` now drives the libdvbcsa
    known-answer vectors through the batch path too — each planted in a
    different lane of a batch of unrelated decoys — so the fast path answers
    to the external oracle, not merely to our own scalar code.

## [0.1.0] - 2026-08-07

### Added
- Initial `dvb-csa` crate: pure-Rust DVB Common Scrambling Algorithm (CSA2).
- 56-round block cipher (SPN on 8-byte blocks) with key-permutation schedule.
- LFSR stream cipher with dual 40-bit shift registers and S-box feedback.
- CBC-like chaining combining block + stream ciphers.
- `scramble()` / `descramble()` operating on raw payload bytes.
- `ControlWord` key type with `expand_block()` and `expand_stream()` derivations.
- `ts` module for TS-packet-level scramble/descramble (payload extraction).
- Oracle validation against libdvbcsa 1.1.0: 11 golden vectors (184-byte
  payloads) + 4 inline multi-size vectors (8B, 16B, 32B, 64B).
- Criterion benchmarks for 184-byte scramble/descramble throughput.
- CLI examples: `scramble_file`, `descramble_file`.
- `no_std` support (default); optional `std` feature.