base64-ng 2.0.0

no_std-first Base64 encoding and decoding with strict APIs and a security-heavy release process
Documentation
# 2.0 In-Place Operations

Status: implemented in Commit 14 for the `2.0.0` candidate.

## Finite Buffer Only

`Base64::encode_in_place(buffer, input_len)` and
`Base64::decode_in_place(buffer, input_len)` transform only the declared prefix
of one finite caller-owned buffer. They do not permit arbitrary overlapping
input/output slices and are not streaming APIs.

Encoding expands from the end toward the beginning. Every source group is
copied into local scalar values before its destination group is written. The
reverse cursor therefore cannot overwrite unread input. Decoding validates the
complete prefix first, then compacts forward with `write <= read` after every
quantum.

Preflight checks the declared input prefix, checked output length, complete
buffer capacity, strict input validity, and backend readiness before the first
write. Every ordinary returned error leaves the complete buffer byte-for-byte
unchanged. Once mutation begins, the scalar mutation kernel is infallible. On
success the returned length identifies the initialized output prefix; bytes
after that prefix are ordinary residual storage and are not wiped.

## Staged Secret Decode

`Base64::decode_in_place_staged(buffer, input_len, private_staging)` is the only
secret-bearing in-place operation in this slice. The selected codec must use
strict canonical trailing bits and either canonical required padding or
forbidden padding. Compatibility policies are rejected before processing.

Callers obtain the public-length staging requirement from
`secret_decode_staging_len`. The calculation reserves three candidate bytes
for every complete or partial four-byte input block. It does not inspect input
validity or padding.

Preflight executes in this order:

1. Check `input_len <= buffer.len()`.
2. Check that the codec policy permits secret processing.
3. Calculate staging capacity with checked arithmetic.
4. Check the complete staging capacity.
5. Check the complete byte ranges for address overflow and overlap.

Every preflight error leaves both ranges byte-for-byte unchanged and performs
no alphabet scan, backend call, fault accounting, or quarantine transition.
Safe Rust normally prevents overlapping mutable slices, but the explicit
byte-disjoint range check also binds future unsafe protected-memory providers
and foreign adapter boundaries.

An unsafe caller must check raw address descriptors before constructing Rust
references. Creating overlapping `&mut [u8]` values is already undefined
behavior, so the in-function check is defense in depth and cannot repair
references that were invalid before entry. Future providers must reuse the
checked range preflight before they form either reference.

After preflight, every valid and invalid input performs four fixed 64-entry
alphabet scans for every public four-byte block, including a partial final
block. Candidate plaintext is written only to private staging while validity,
padding, and canonical trailing-bit failures accumulate opaquely.

At the result gate:

- valid input copies the completed staged plaintext into the original buffer,
  then wipes the complete staging range;
- invalid input leaves the original encoded buffer unchanged, returns only
  `InPlaceError::InvalidSecretInput`, and wipes the complete staging range;
- an internal integrity fault wipes both complete ranges and returns a backend
  fault.

Private staging is held by an RAII wipe guard after preflight. Normal return,
typed error, and panic unwinding all wipe the complete staging range. Dropping
partially progressed owned or borrowed secret states is the synchronous
cancellation boundary and follows the same cleanup rule. Abort, process
termination, and deliberate destructor suppression remain outside that rule.

The fixed-work claim ends at the result gate. Final validity and successful
plaintext release are public. The success-only declassification copy is not
claimed to have the same whole-call timing as the invalid-input path. Commit 19
owns the decoder's optimizer/assembly evidence and timing boundary; Commit 20
adds an independently reviewed secret encoder rather than changing this gate.

## Overlap And Protected Pages

Two non-empty byte ranges overlap when each begins before the other ends. End
addresses use checked `usize` arithmetic. Exact adjacency and empty ranges are
accepted; partial overlap, complete overlap, and overflowing address ranges are
typed preflight errors.

Byte-disjoint ranges may currently occupy the same effective memory page. That
does not grant a protected-memory provider permission to lock, unlock, wipe, or
quarantine one page independently of another live range. Commit 40 owns page
identity, reference accounting, and teardown coordination. Until then, a
provider must preserve byte disjointness and may not claim independent page
ownership.

## Resource And Migration Notes

These methods allocate no heap memory. Stack use is constant apart from the
caller-provided buffers. Secret staging is caller-owned and scales as three
bytes per public four-byte block, rounded up to a complete candidate block.

The 1.3.9 `Engine::encode_in_place` and `Engine::decode_in_place` compatibility
methods remain available during development. New code targeting 2.0 should
pass an explicit input prefix length and handle `InPlaceError`; secret-bearing
decode must use the staged method rather than ordinary forward compaction.

Evidence is maintained by:

- `src/v2/in_place_tests.rs`
- `src/v2/secret_in_place_tests.rs`
- `scripts/check-2.0-in-place.sh`
- `scripts/check-2.0-in-place-sanitizers.sh`
- `scripts/check_miri.sh`
- bounded Kani cursor proofs in `src/kani_in_place_proofs.rs`
- shared cursor-length helpers used directly by both production kernels and
  Kani, with exhaustive deterministic tests over every padding/tail decision