base64-ng 2.0.0

no_std-first Base64 encoding and decoding with strict APIs and a security-heavy release process
Documentation
# 2.0 Public API Migration Ledger

This ledger freezes the disposition of the complete `v1.3.9` public API before
2.0 implementation begins. The machine inventory under
[`api-snapshots/v1.3.9`](../api-snapshots/v1.3.9) is authoritative for what
existed. This document is authoritative for what happens to it.

## Disposition Rules

Every snapshot line has a disposition. A line inherits the disposition of its
most specific row below. Implementations, derived trait methods, associated
types, fields, and variants inherit the disposition of their owning item unless
a row overrides them. Therefore an item omitted from a method-by-method table
is not undecided.

- **Retain**: preserve the concept and source compatibility unless a later
  explicitly listed signature refinement is required.
- **Rename**: provide the named canonical 2.0 replacement; the 1.x spelling is
  removed unless this ledger says it remains an alias.
- **Replace**: preserve the capability through a deliberately different 2.0
  type or contract.
- **Move**: provide the capability in the named companion or namespace.
- **Remove**: intentionally unavailable in 2.0.

The exact signatures are implemented and tested by their numbered commits in
the release plan. This ledger freezes direction; it does not expose unfinished
2.0 APIs from the 1.3.9 development baseline.

Commit 5 implements the owned validated-alphabet representation internally.
Commit 6 integrates it with sealed strict specifications and a validated
runtime-codec builder. Both remain private so the frozen 1.3.9 public snapshot
cannot accidentally acquire a partial 2.0 surface; the complete canonical API
is exposed only at its later planned checkpoint.

Commit 7 adds the private validated wrapping value. Its width is stored as
`NonZeroUsize`, runtime construction is fallible, and MIME/PEM constants name
body layout only. The 1.x wrapping constructors and public fields remain
unchanged until the complete 2.0 surface replaces them.

Commit 8 adds the private error, progress, source-position, lifecycle, and
reporting contract model. It makes output exhaustion retryable, malformed
input and backend faults absorbing, repeated successful finish idempotent, and
source-position overflow checked before processing. The complete destination
atomicity and leakage matrix is frozen in
[`2.0_OPERATION_CONTRACTS.md`](2.0_OPERATION_CONTRACTS.md). The 1.x public
errors and state machines remain unchanged until their complete 2.0
replacements are exposed.

Commit 9 implements the private heapless ordinary encoder state over the
Commit 6 codec settings and Commit 8 lifecycle. It supports arbitrary input
and one-byte output chunks, exact retry progress, and canonical padded or
unpadded finalization without allocation or `Drop`. Its frozen contract and
evidence are recorded in
[`2.0_INCREMENTAL_ENCODER.md`](2.0_INCREMENTAL_ENCODER.md). Public 1.x encode
methods continue to use their existing implementation until Commit 12.

Commit 10 implements the private heapless strict padded decoder with exact
source indexes, absorbing malformed-input failures, canonical padding and
trailing-bit validation, terminal-data rejection, and retryable one-byte
output draining. Its contract and locked RFC 4648 requirement trace are in
[`2.0_INCREMENTAL_PADDED_DECODER.md`](2.0_INCREMENTAL_PADDED_DECODER.md).
Explicitly unpadded finalization was reserved for Commit 11, and public 1.x
decode methods remain unchanged until Commit 12.

Commit 11 completes private strict unpadded decoding and finalization. Two- and
three-symbol canonical tails finalize through the same bounded output retry
state; one-symbol tails return `InvalidLength`, and every `=` is rejected as
`InvalidPadding` at its absolute source index. Padded truncation remains
distinct. The contract and exhaustive tail evidence are in
[`2.0_INCREMENTAL_DECODER_FINALIZATION.md`](2.0_INCREMENTAL_DECODER_FINALIZATION.md).
Public 1.x decode methods remain unchanged until Commit 12.

Commit 12 publishes `Base64<Spec>`, the sealed `Codec` consumer trait,
validated alphabets/builders, explicit strict presets, heapless incremental
states, and the canonical `encode_into`, `decode_into`, `validate`, checked
length, and allocating one-shot methods. The complete v1.3.9 snapshot remains
an unchanged compatibility subset during development. Intentional 2.0
additions are frozen under `api-snapshots/v2.0.0`.

The release-owner-approved pre-seal usability reopening extends that ordinary
surface with `Base64String<S>` and `base64_ng::prelude`. The string owner keeps
the exact codec that encoded or validated its immutable text and remains
ordinary, printable, and non-wiping. The focused prelude excludes secret,
compatibility, protocol, and historical APIs. Neither addition replaces a
1.3.9 item or permits implicit secret-owner conversion.

Commit 13 adds typed exact-output const transforms for built-in and validated
runtime codecs and ordinary `EncodedArray` and `DecodedArray` storage without
drop-time cleanup. Commit 18 moves the non-Clone, full-capacity-wiping
`SecretArray` to the capability-gated `secret` namespace. Const malformed-input
and sizing failures remain typed unless a caller deliberately promotes them to
const-evaluation panics.

Commit 14 adds finite-buffer reverse encode and forward decode under one typed
`InPlaceError` contract. Ordinary preflight is non-destructive. Secret-bearing
decode is available only through byte-disjoint private staging, fixed-work
symbol processing, an opaque result gate, and explicit staging or dual-buffer
cleanup according to the failure class.

Commit 15 adds allocation-free lazy display, formatter and exact counted-sink
encoding, synthesized encoded-chunk iteration, and allocating append methods.
Formatter output is prefix-committing with only fully successful calls
confirmed. Controlled `String` and `Vec<u8>` append restores entry length and
prefix on returned crate errors and unwinding panics.

Commit 16 adds the exact WHATWG forgiving Base64 algorithm under
`web::FORGIVING`, with opaque content errors, transactional one-shot methods,
and a heapless incremental decoder. Separately named `compat` constants expose
the accepted padding-indifferent and noncanonical-trailing-bit combinations
without changing strict RFC 4648 defaults or any secret eligibility rule.

Commit 17 replaces ambiguous future profile names with `BodyCodec` body-layout
composition, explicitly named alphabet-level codecs, and the sole
`legacy::ASCII_WHITESPACE` compatibility decoder. Full MIME, PEM, password,
BinHex, and modified-UTF-7 protocol semantics remain assigned to their later
companion commits.

Commit 18 activates `base64_ng::secret` as the canonical storage and exposure
boundary. `SecretInput`, `SecretOutput`, `SecretArray`, and `SecretVec` are
non-Clone redacted owners or classifications without implicit slice coercions.
Only explicitly exposed or declassified views implement ordinary
interoperability traits. Commit 19 adds bounded `SecretArrayFrame`,
`SecretFrame`, and `SecretVecFrame` decoding through `SecretDecoderState`.
These frames retain plaintext privately until an opaque final validity gate;
Commit 20 adds bounded `SecretArrayEncoder`, `SecretEncoder`, and
`SecretVecEncoder` owners plus one-shot methods. Built-in secret alphabets use
private arithmetic mapping, custom alphabets use a fixed 64-entry scan, and
encoded output remains secret until explicit exposure or declassification.

Commit 21 separates the secret cleanup capability from ordinary portability.
Commit 22 adds `base64_ng::assurance`, generation-bound non-copyable tokens,
allocation-specific `ProtectedSecret<_, State, Level>` typestates, an unsafe
provider/attestation extension boundary, and the finite volatile
`BestEffortProvider`. Assured operations require both a token and one protected
allocation; they do not accept ordinary mutable slices. No persistent provider
or restart-recovery API is included in base 2.0.

Commit 23 replaces the ambiguous active-backend report with independent
`encode_backend`, `strict_decode_backend`, and `secret_decode_backend` values.
Token snapshots carry separate context generations without claiming protected
memory. Allocation and teardown snapshots report physical protection only for
the exact participating `ProtectedSecret` and keep wipe, accounting,
lifecycle, pending teardown, and address-free allocation presence independent.

Commit 24 adds direct per-backend known-answer tests, process-local health
states and generations, permanent ordinary backend quarantine, explicit
startup initialization, checked scalar/SIMD comparison, and a thread-bound
static `no_std` backend token. Backend faults remain separate from malformed
input and secret operations remain scalar and outside ordinary quarantine.

Commit 25 adds `StaticBackendToken::encode_standard` and
`StaticBackendToken::encode_url_safe`. They expose only ordinary Standard and
URL-safe encode through the exact healthy SSSE3/SSE4.1 or AVX2 token; stale
tokens and architecture kernels awaiting later checkpoints remain scalar.

Commits 27 and 28 add `StaticBackendToken::decode_standard` and
`StaticBackendToken::decode_url_safe`. They expose ordinary strict Standard and
URL-safe decode through exact healthy SSSE3/SSE4.1, AVX2, or AVX-512 VBMI
tokens. Detailed errors, canonicality, destination atomicity, padding, and
tails remain scalar-defined. Stale tokens, non-x86 backends awaiting their own
checkpoints, and all secret operations remain scalar.

Caller-slice one-shot operations are transactional: validation and exact
sizing finish before mutation, and every returned error leaves the destination
unchanged. Allocating methods use `try_reserve_exact`, expose explicit output
limits, and do not introduce an allocating secret surface.

## Canonical Names

| 2.0 name | 1.x migration source | Decision |
|---|---|---|
| `encode_into` | `encode_slice` | Rename; transactional ordinary destination contract |
| `decode_into` | `decode_slice` / `decode_slice_clear_tail` | Rename and replace with one documented atomicity contract |
| `encode_to_string` | `encode_string` | Rename |
| `decode_to_vec` | `decode_vec` | Rename |
| `encode_in_place` | `encode_in_place` | Retain name; replace progress/error contract |
| `decode_in_place` | `decode_in_place` | Retain name; replace progress/error contract |
| `encoder` | `encoder_reader` / `encoder_writer` | Replace direction-specific constructor names with state/sink-specific overloads or constructors |
| `decoder` | `decoder_reader` / `decoder_writer` | Replace direction-specific constructor names with state/source-specific overloads or constructors |
| `encode_redacted` | `encode_secret` | Move to `secret::*`; constant-time-oriented scalar computation only |
| `decode_redacted` | `decode_secret` | Move to `secret::*`; constant-time-oriented scalar computation only |

`secret::*` is reserved exclusively for constant-time-oriented computation,
redacted secret storage, and its explicit declassification boundary. Ordinary
SIMD wrapped in a redacted container is not a secret API.

## Core Types And Modules

| 1.x surface | 2.0 disposition |
|---|---|
| `Engine<A, PAD>` and its owned impls | Replace with `Base64<Spec>` and the sealed codec/specification model |
| `Profile<A, PAD>` and its owned impls | Replace with validated specs/presets; protocol grammar moves to companions |
| `Alphabet` and `define_alphabet!` | Replace with validated compile-time and runtime alphabets; retain a checked custom-alphabet construction path |
| `Standard`, `UrlSafe`, `Bcrypt`, `Crypt` | Retain alphabet concepts under validated 2.0 names |
| `AlphabetError`, `validate_alphabet`, `decode_alphabet_byte` | Replace with validation/construction APIs; low-level scan helper is not a stable 2.0 consumer API |
| `EncodedBuffer`, `DecodedBuffer`, exposed array wrappers | Replace with ordinary bounded buffers whose initialized length remains private and checked |
| `SecretBuffer`, `ExposedSecretVec`, `ExposedSecretString` | Move to `secret::*` and replace with explicit exposure/declassification types |
| `ct` module, `CtEngine`, and CT constants | Replace with `secret::*` codecs/states; no `ct` compatibility module in 2.0 |
| `stream` module and four synchronous adapter types | Rebuilt in Commit 35 over canonical incremental `encoder`/`decoder` states; compatibility names remain during development freeze |
| `LineEnding`, `LineWrap` | Replace with validated wrap policy types; protocol-specific line grammar moves to companions |
| length helpers | Retain capability with checked specification-bound results |
| `EncodeError`, `DecodeError`, `DecodeErrorKind` | Replace with non-exhaustive 2.0 errors carrying explicit progress/atomicity/backend classification |
| `runtime::*` | Replaced in Commit 23 with per-operation reports, opaque stable backend identifiers, Wasm artifact posture, assurance generations, quarantine state, and policy tokens |
| `secure_wipe`, `clear_bytes` | Move to `secret::*` cleanup policy; remove duplicate public spellings |
| `constant_time_eq`, `constant_time_eq_fixed_width` | Move to `secret::*`; reviewed companion integrations remain available |
| root `encode`, `decode` | Retain as strict Standard allocating conveniences forwarding to canonical methods |
| root `encode_infallible` | Rename to `encode_to_string_infallible`; the name keeps allocation-abort behavior explicit |
| root engine/profile constants | Replace with explicit strict RFC 4648 presets and named compatibility/protocol specs |
| legacy whitespace-tolerant decode | Use `legacy::ASCII_WHITESPACE` only for the documented four-byte transport set; use exact `web::FORGIVING` only for web strings |

All trait implementations, constructors, accessors, formatting behavior,
conversion traits, and owned methods in the core snapshot inherit the row for
their owning type.

## Engine And Profile Method Families

| 1.x family | 2.0 disposition |
|---|---|
| `encode_slice*` | Rename to `encode_into`; clear-tail becomes an explicit destination policy rather than a parallel alias |
| `decode_slice*` | Rename to `decode_into`; strict ordinary errors are non-mutating unless a progress API explicitly says otherwise |
| `encode_string*`, `encode_vec*` | Rename to `encode_to_string` and an explicit byte-vector helper; infallible aliases follow the final allocation contract |
| `decode_vec*` | Rename to `decode_to_vec` |
| `encode_buffer`, `decode_buffer` | Replace with bounded ordinary buffer APIs |
| `encode_secret*`, `decode_secret*` | Move to `secret::encode_redacted` / `secret::decode_redacted` and secret state methods |
| `encode_in_place*`, `decode_in_place*` | Retain canonical names; remove clear-tail aliases in favor of one explicit post-error contract |
| `*_legacy*` | Replace with an explicitly named compatibility policy; never part of `secret::*` |
| `*_wrapped*` | Replace with validated wrapping policy; MIME/PEM grammar moves to companions |
| `validate*`, `decoded_len*`, `encoded_len*` | Retain capabilities on the owning 2.0 specification |
| `encoder_reader`, `encoder_writer` | Commit 35 delegates both compatibility adapters to the canonical `encoder` state and retains only external I/O queues |
| `decoder_reader`, `decoder_writer` | Commit 35 delegates both compatibility adapters to the canonical `decoder` state and retains only framing and external I/O queues |
| `new`, `is_padded`, `engine`, `wrap`, `checked_new` | Replace with validated immutable spec construction and accessors |

No 1.x clear-tail alias survives merely as a second spelling. Where cleanup or
rollback differs materially, 2.0 expresses it through an ordinary, secret,
in-place, or progress-bearing type contract.

## Constants And Profiles

| 1.x constant | 2.0 disposition |
|---|---|
| `STANDARD`, `STANDARD_NO_PAD`, `URL_SAFE`, `URL_SAFE_NO_PAD` | Replace with explicitly named strict RFC 4648 presets; retain top-level convenience access |
| `BCRYPT_NO_PAD`, `CRYPT_NO_PAD` | Replace with `BCRYPT_ALPHABET_NO_PAD` / `CRYPT_ALPHABET_NO_PAD`; password-record transforms live in `base64-ng-password` |
| `MIME`, `PEM`, `PEM_CRLF` | Replace body use with `MIME_BODY_STRICT`, `PEM_BODY_LF`, `PEM_BODY_CRLF`; full protocol behavior moves to companions |
| profile `BCRYPT`, `CRYPT` | Replace with accurately named alphabet-level codec values; protocol record semantics are not implied |
| `ct::{STANDARD, STANDARD_NO_PAD, URL_SAFE, URL_SAFE_NO_PAD}` | Replace with `secret::*` strict presets |

## Cargo Features

| 1.x feature | 2.0 disposition |
|---|---|
| `default`, `alloc`, `std`, `simd`, `stream` | Retain with exact edges `std -> alloc`, `stream -> std` |
| `secrets` | New dependency-free capability; storage/exposure in Commit 18, secret computation in Commits 19-21, and assured tokens/protected providers in Commit 22, with no implicit `alloc` edge |
| `checked-backend` | New active ordinary integrity capability; exact edge `checked-backend -> simd`; bounded stack staging, scalar comparison, quarantine, and scalar retry from Commit 24 |
| `allow-wasm32-best-effort-wipe` | No-op for ordinary builds; explicit best-effort acknowledgement only when `secrets` is enabled on WASM |
| `allow-compiler-fence-only-wipe` | No-op for ordinary builds; explicit best-effort acknowledgement only for secret builds on unsupported native targets |
| inert `tokio` | Remove; use `base64-ng-tokio` |
| inert `kani`, `fuzzing` | Remove from published capability API; verification remains repository tooling |

Commit 2 reserves `secrets` and `checked-backend` so feature-unification and ABI
checks precede behavior. Commit 18 activates only `secrets` storage and
explicit exposure; Commit 24 activates `checked-backend`. Neither is a
functional API in the published 1.3.9 baseline.

## Companion Packages

Every public item in a companion snapshot inherits its package row unless an
explicit later commit replaces it.

| 1.x package/surface | 2.0 disposition |
|---|---|
| `base64-ng-derive` / `Base64Secret` | Retain package; replace expansion with 2.0 secret types and sealed traits |
| `base64-ng-sanitization` | Retained; Commit 40 adds 2.0 `Base64<S>` protected two-allocation fill, removes degraded compatibility defaults, bounds dynamic compatibility decode with fallible allocation, caps stack staging at 1,024 bytes, and keeps core `decode_assured` as the provider-quarantined no-copy route |
| `base64-ng-serde` modules and wrappers | Retain package; replace engine bounds and add bounded/secret policy separation |
| `base64-ng-bytes` errors and `EngineBytesExt` | Retain package; replace extension target with sealed 2.0 codec and progress contracts |
| `base64-ng-subtle` comparison helpers | Retain reviewed integration; move secret implementations to 2.0 secret storage types |
| `base64-ng-tokio` helpers/readers/writers | Retain package; replace engine bounds and align async progress, cancellation, and limits with the new states |

New MIME, PEM, multibase, IMAP, password-format, OpenPGP, and WASM-loader
companions are additions, not migrations from an independently versioned 1.x
package.

Commit 47 adds `base64-ng-password` for exact Passlib PBKDF2 and SHA-crypt
field/record transforms. Existing PBKDF2 and crypt alphabet values remain
alphabet-level codecs and do not imply record parsing, SHA-crypt digest
permutations, hashing, or password verification.

Commit 48 adds `base64-ng-openpgp` for complete ordinary RFC 9580 ASCII armor
framing. It validates exact registered boundaries, headers, blank separation,
Base64 body, optional CRC-24 state, matching tails, and finite document limits.
The default policy follows RFC 9580's checksum non-rejection rule; strict
CRC-24 enforcement is separately named. Packet parsing and the cleartext
signature framework remain outside the package.

Commit 49 adds no runtime API. It freezes every specialized companion claim
and all named core configuration constants in `protocol-registry/v1`, binds
them to immutable source/errata/requirement/API hashes, and executes retained
positive and negative cases through independent models and public production
surfaces. Any future public protocol/configuration name changes this evidence
boundary and must update the registry in the same reviewed commit.

Commit 50 adds no runtime API. It adds Kani-only proof helpers and modules,
classifies every harness in `kani/harnesses.tsv`, and bounds normal, advanced,
and exploratory verification. The ordinary in-place overlap helper is exposed
only under `cfg(kani)`; published API and runtime behavior are unchanged.

Commit 51 adds no published API. It expands only the isolated fuzz workspace,
test-only property and panic-injection code, campaign scripts, and evidence
documentation. Root and companion runtime behavior remain unchanged.

Commit 52 adds no published API. It expands timing classes, target-aware
release/LTO assembly evidence, source-pattern gates, cleanup evidence revision
binding, and documentation. `WIPE_PRIMITIVE_REVISION` remains crate-private;
operation-specific runtime wipe generations continue to come from assurance
reports and tokens.

Commit 53 adds no callable API. It confirms the existing private provider-state
cleanup owner wipes provider-owned quarantined storage when a volatile
`BestEffortProvider` instance is dropped. The commit adds test-only secret
allocation identity evidence, cross-crate corpus coverage, dynamic sanitizer
campaigns, resource accounting, and the native hardware release boundary.
QEMU and compile evidence remain explicitly non-admitting.

Commit 43 adds `base64-ng-mime` as the bounded RFC 2045 Section 6.8
content-transfer body companion. Its canonical and compatible body policies
do not imply complete message, header, media-type, or multipart parsing.

Commit 44 adds `base64-ng-pem` as the complete RFC 7468 textual encoding
boundary. Existing `PEM_BODY_LF` and `PEM_BODY_CRLF` remain body-layout values;
callers needing labels, boundaries, adjacent text, multiple blocks, or
expected-label secret release migrate to the companion.

Commit 45 adds `base64-ng-multibase` for the four registered Base64-family
prefixes only. The package owns exact prefix selection, strict canonical
payload validation, bounded one-shot operations, and heapless incremental
states; it does not claim the complete open-world multibase registry.

Commit 46 adds `base64-ng-imap` for the obsolete RFC 3501 Section 5.1.3
modified-Base64 payload transform. It consumes and returns already-converted
UTF-16BE bytes, enforces strict unpadded canonical payloads and finite limits,
and deliberately excludes Unicode conversion, direct-character selection,
shift delimiters, and complete mailbox grammar.

Commit 42 completes the `base64-ng-derive` replacement. `Base64Secret`
requires one private `SecretArray<N>` field and mandatory sealed alphabet,
padding, exact-length, and exposure policy. Its staged decode and wiping encode
delegate to the final secret frame types; 1.x raw-array constructors, ordinary
string conversions, generated equality, and implicit exposure are removed.

Commit 36 completes the `base64-ng-bytes` replacement. `Base64BytesExt`
targets `Base64<S: Codec>`; `BytesEncoder` and `BytesDecoder` expose exact
transform/output progress for arbitrary `BufMut`, while owned `Bytes`
transforms remain transactional and do not coalesce fragmented input.

Commit 37 replaces the Tokio read-all and `AsyncRead` codec boundary with
`Base64<S: Codec>`, `EncoderState`, and `DecoderState`. EOF-mode readers and
exact-length readers have separate contracts; exact readers do not consume an
overflow lookahead byte.

Commit 38 replaces the Tokio `AsyncWrite` codec boundary with
`Base64<S: Codec>`, `EncoderState`, and `DecoderState`. Writers expose exact
adapter-accepted and downstream-committed progress, retain bounded output
across retryable I/O failures and cancellation, and provide checked inner
recovery that rejects retained input or output.

Commit 41 replaces the 1.x `base64-ng-subtle` ordinary-buffer extension with
the sealed `SubtleSecretEq` trait over final 2.0 secret owners and views. The
method name exposes public-length behavior, returns `Choice`, and provides no
boolean convenience method. Raw public-length and fixed-width array helpers
remain explicitly named free functions.

Commit 39 migrates every retained Serde field module and wrapper to the 2.0
specification constants. Compatibility modules retain exactly sized `Vec`
output; `bounded::*` adds fixed-capacity ordinary output and `secret::*` adds
fixed-work, opaque-error, wiping output. Human-readable formats use strings,
binary formats use byte strings containing Base64 text, and wrapped body
decode avoids a compacted encoded-input allocation.

## Migration Evidence

`scripts/check-2.0-migration-smoke.sh` compiles the canonical naming map
against the current 1.x implementation. It is a signature and example bridge,
not an assertion that the 2.0 contracts already exist. Each implementation
commit replaces its bridge with direct public API tests.

`scripts/check-api-snapshots.sh` rejects any removal or signature mutation in
the frozen 1.3.9 inventory and any unreviewed drift from the current 2.0
development snapshot. Intended additions update this ledger and the
development snapshot; they never rewrite the `v1.3.9` baseline.