base64-ng 2.0.0

no_std-first Base64 encoding and decoding with strict APIs and a security-heavy release process
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
# Public API Audit

This document records the public API audit that prepared the `v1.0` candidate
series. The goal is a small, explicit, security-reviewed public surface. The
audit favors removing or documenting ambiguous APIs over adding convenience.

## Audit Rules

- Keep strict, canonical decoding as the default.
- Keep legacy, wrapped, profile-specific, and constant-time-oriented behavior
  explicit in names or modules.
- Do not add broad conversion traits that hide alphabet, padding, wrapping,
  allocation, or secret-handling policy.
- Do not admit optional ecosystem dependencies without a written dependency
  admission record.
- Do not admit active SIMD dispatch through an API audit; SIMD remains governed
  by the dedicated SIMD admission manifest.
- Treat any API that exposes owned bytes or backing arrays as a security
  boundary that must be documented.
- Prefer caller-owned output APIs and recoverable errors for untrusted input.

## Status Legend

- `candidate stable`: the current API shape is accepted for the `v1.0`
  candidate, pending final CI and pentest evidence.
- `documented boundary`: the API is acceptable only because its security or
  ownership boundary is explicit in docs and examples.
- `review pending`: the API still needs audit before a stable release; stable
  releases fail the local gate if any row remains in this state.
- `deferred`: the API area is intentionally not admitted in this release
  series.

## Public Surface Under Review

| Area | Status | Notes |
| --- | --- | --- |
| Engine constants and `Engine<A, PAD>` | candidate stable | Strict/default semantics are explicit; constructor naming and stream convenience methods are accepted for the `v1.0` candidate. |
| `Profile<A, PAD>` and named profiles | candidate stable | MIME, PEM, bcrypt-style, `crypt(3)`-style, wrapping, and padding behavior are explicit and covered by policy tests. |
| Length helpers | candidate stable | Public helpers are recoverable and checked; keep examples focused on untrusted-size handling. |
| Slice encode/decode APIs | candidate stable | Caller-owned output, checked lengths, and clear-tail variants are the preferred stable surface. |
| In-place APIs | candidate stable | Encode-to-back and decode-to-front contracts are explicit, checked, and paired with clear-tail variants. |
| Validation-only APIs | candidate stable | Strict, legacy, wrapped, and ct validation APIs are documented as decode-equivalent policy checks. |
| Stack-backed buffers | documented boundary | `EncodedBuffer` and `DecodedBuffer` are retained with explicit visible-length, cleanup, comparison, and exposed-array boundaries. |
| `SecretBuffer` | documented boundary | Redaction, cleanup limits, comparison semantics, and owned escape hatches are explicit adoption boundaries. |
| `ct` module | documented boundary | Keep non-claim wording and opaque error behavior explicit unless verification evidence changes. |
| `stream` module | documented boundary | Fail-closed decode, retry semantics, state helpers, recovery helpers, and framed-reader behavior are explicit. |
| Runtime backend reporting | candidate stable | Scalar-only posture and stable log identifiers are documented and release-gated. |
| Feature flags | documented boundary | Ordinary codecs remain portable under feature unification. `secrets` enables separate secret owners and scalar processing. Its two cleanup-limit acknowledgement features are no-ops for ordinary builds and do not imply high assurance. AArch64 CSDB attestation and the high-assurance eligibility policy use custom cfgs so `--all-features` cannot assert either one. |
| Error types | candidate stable | Encode, decode, and alphabet errors are recoverable and diagnostic without committing ct errors to localized detail. |
| Macros and custom alphabets | documented boundary | Compile-time validation and conservative fixed-scan performance/security tradeoffs are explicit. |

## `v1.0` Admission Questions

- Is the API name explicit about strict, legacy, wrapped, profile, or
  constant-time-oriented behavior?
- Can the caller size memory before using the API?
- Does the API have a caller-owned buffer form when it can allocate?
- Does the API expose a clear cleanup boundary for sensitive data?
- Does the API keep malformed input recoverable instead of panicking?
- Does the API commit to behavior that future SIMD backends can reproduce
  exactly?
- Does the API require dependency admission or feature-policy documentation?

## Audit Decisions

### Profiles

`Profile<A, PAD>` and the named `MIME`, `PEM`, `PEM_CRLF`, `BCRYPT`, and
`CRYPT` profiles are candidates for the `v1.0` stable surface.

Decision rationale:

- A profile is an explicit policy bundle: alphabet, padding mode, and optional
  line wrapping remain visible through type parameters, constructor arguments,
  and policy accessors.
- `Profile::checked_new` rejects invalid wrapping policy instead of silently
  accepting an unusable profile.
- MIME and PEM wrapping policy is strict: non-final encoded lines must match
  the configured width and line ending.
- Bcrypt-style and `crypt(3)`-style profiles expose alphabet and no-padding
  interoperability only; they do not claim password-hash parsing or
  verification.
- Profiles forward to the same scalar engine, validation, in-place, clear-tail,
  stack-buffer, and secret-buffer APIs rather than introducing a separate
  decoding contract.

Stable boundary:

- Keep profile behavior strict and deterministic.
- Do not add permissive profile constructors without a new audit entry.
- Do not broaden bcrypt-style or `crypt(3)`-style profiles into full password
  hash parsers.
- Do not hide profile policy behind broad conversion traits.

### Validation-Only APIs

Strict, legacy, wrapped, and constant-time-oriented validation APIs are
candidates for the `v1.0` stable surface.

Decision rationale:

- Validation-only APIs use the same alphabet, padding, canonical-bit, and line
  wrapping checks as the corresponding decode APIs.
- Boolean helpers are convenience wrappers over `Result`-returning helpers,
  preserving recoverable diagnostics for callers that need them.
- Legacy validation is opt-in and only skips ASCII transport whitespace; it
  keeps alphabet, padding, terminal-data, and canonical-bit checks strict.
- Wrapped validation is stricter than legacy whitespace handling and accepts
  only the configured wrapping policy.
- Constant-time-oriented validation follows the `ct` module's documented
  opaque malformed-input policy.

Stable boundary:

- Keep validation/decode agreement release-tested.
- Keep strict validation canonical by default.
- Keep legacy and wrapped validation explicit in method names.
- Keep ct validation errors opaque unless formal side-channel evidence changes
  the documented contract.

### Stack-Backed Buffers

`EncodedBuffer<CAP>` and `DecodedBuffer<CAP>` are retained as documented
boundaries for `v1.0`.

Decision rationale:

- Stack-backed buffers give no-alloc callers an owned output shape without
  hiding capacity or visible length.
- Accessors expose borrowed bytes or fallible UTF-8 views rather than
  implicitly allocating or assuming decoded text.
- `Debug` is redacted for decoded buffers; encoded buffers remain printable as
  Base64 text through explicit display/text APIs.
- Drop-time cleanup is best-effort and scoped to the buffer's current backing
  array, not historical stack-frame copies.
- `EncodedBuffer<CAP>` and `DecodedBuffer<CAP>` rely on Rust auto traits for
  `Send` and `Sync`; no explicit `unsafe impl` is used. If a future internal
  field is not thread-safe, auto-trait derivation should fail instead of being
  overridden by a stale manual implementation.
- `into_exposed_array` is intentionally named as an ownership escape hatch and
  returns `ExposedEncodedArray` or `ExposedDecodedArray`, preserving redaction
  and drop-time cleanup after ownership transfer. The raw-array escape hatch is
  deliberately loud:
  `into_exposed_unprotected_array_caller_must_zeroize`.
- Equality is intentionally not exposed through `PartialEq`/`==`. Callers must
  opt into the explicit `constant_time_eq_public_len` helper, whose equal-length
  scan is best-effort and whose length mismatch remains public.

Stable boundary:

- Keep capacity and visible length explicit.
- Keep ownership escape hatches explicit in names.
- Do not add implicit text conversions for decoded bytes.
- Do not describe drop-time cleanup as formal zeroization.

### Secret Buffer

`SecretBuffer` is retained as a documented security boundary for `v1.0`.

Decision rationale:

- Formatting is redacted by default through `Debug` and `Display`.
- Secret exposure requires explicitly named borrowed or owned escape hatches.
- `SecretBuffer::into_exposed_vec` returns `ExposedSecretVec`, which keeps
  redacted formatting and drop-time cleanup. The raw-vector escape hatch is the
  deliberately loud
  `ExposedSecretVec::into_exposed_unprotected_vec_caller_must_zeroize`.
- `SecretBuffer::try_into_exposed_string` returns `ExposedSecretString`, which
  keeps redacted formatting and drop-time cleanup. The raw-string escape hatch
  is the deliberately loud
  `ExposedSecretString::into_exposed_unprotected_string_caller_must_zeroize`.
- Drop-time cleanup uses the crate's volatile best-effort wipe helper for
  initialized bytes and vector spare capacity.
- `SecretBuffer` does not lock allocations into physical memory. OS paging,
  hibernation, and crash-dump controls remain deployment responsibilities.
- `SecretBuffer` intentionally does not implement `Clone`; callers that need a
  second copy must spell that out through `from_slice`, making secret
  duplication visible at the call site.
- `SecretBuffer` relies on Rust auto traits for `Send` and `Sync`; no explicit
  `unsafe impl` is used. This is deliberate because a future non-thread-safe
  field should remove those auto traits automatically.
- Equality is intentionally not exposed through `PartialEq`/`==`. Callers must
  opt into the explicit `constant_time_eq_public_len` helper, whose equal-length
  scan is best-effort and whose length mismatch remains public.
- Strict standard padded `TryFrom` and `FromStr` implementations are kept only
  for native Rust ergonomics; non-standard profiles remain on explicit
  engine/profile methods.

Stable boundary:

- Keep redaction as the default formatting behavior.
- Keep `expose_secret`, `into_exposed_vec`,
  `into_exposed_unprotected_vec_caller_must_zeroize`, and
  `try_into_exposed_string`,
  `into_exposed_unprotected_string_caller_must_zeroize` explicit.
- Do not claim formal zeroization or allocator-wide cleanup.
- Do not add broad conversions that hide profile, alphabet, padding, or
  wrapping policy.

### In-Place APIs

In-place encode and decode APIs are candidates for the `v1.0` stable surface.

Decision rationale:

- In-place encode validates the caller-provided input length and required
  encoded length before writing.
- In-place encode writes from the back of the output region toward the front,
  so unread input bytes are not overwritten.
- In-place decode writes decoded output to the front of the same buffer, which
  is valid because Base64 decoded output is never larger than accepted encoded
  input.
- Legacy and wrapped in-place decode validate and compact input according to
  their explicit policies before decoding.
- Clear-tail variants exist for strict, legacy, wrapped, and
  constant-time-oriented in-place decode when the caller wants best-effort
  cleanup on success and failure.

Stable boundary:

- Keep all in-place APIs recoverable through `Result`.
- Keep strict, legacy, wrapped, and ct in-place behavior separated by method or
  module name.
- Keep clear-tail variants explicit rather than making cleanup an implicit
  default for all in-place APIs.
- Keep the removed non-clear-tail `ct::CtEngine::decode_slice` and
  `ct::CtEngine::decode_in_place` APIs out of the stable surface. They could
  leave decoded plaintext in caller-owned buffers on malformed input errors.
  Direct reusable secret buffers to `ct::CtEngine::decode_slice_clear_tail`,
  `ct::CtEngine::decode_buffer`, or
  `ct::CtEngine::decode_in_place_clear_tail`.
- Do not add unchecked in-place APIs to the public surface.

### Custom Alphabets

`validate_alphabet`, `decode_alphabet_byte`, and `define_alphabet!` are retained
as documented boundaries for `v1.0`.

Decision rationale:

- Custom alphabets must contain exactly 64 unique visible ASCII bytes and must
  not contain the padding byte.
- `define_alphabet!` validates the alphabet at compile time, so invalid
  literals fail the build.
- The generated `decode` method delegates to the same validated table
  semantics as runtime custom alphabet helpers.
- The default `Alphabet::encode` implementation performs a fixed 64-entry scan
  for every emitted byte. This preserves the conservative no secret-indexed
  lookup posture, but it is slower than the arithmetic mappers used by built-in
  alphabets.
- `Alphabet::ENCODE` is the authoritative encode and decode table. Runtime and
  const `Engine` APIs read that table through crate-owned mappers and never
  invoke hand-written `Alphabet::encode` or `Alphabet::decode` overrides. The
  methods remain available as low-level direct-call helpers for API
  compatibility, but cannot alter `Engine` output. Standard-family mapper
  classification is an associated compile-time constant.
- Manual `Alphabet` implementations can override `encode` or `decode`. An
  `encode` or `decode` override affects only direct calls to that low-level
  helper. Ordinary scalar, SIMD, and `ct` engine paths derive mappings from
  `Alphabet::ENCODE` and do not depend on executable custom methods.
- Strict SIMD decode is eligible only for admitted Standard-family tables. Its
  mapping is identical to scalar strict decode by construction rather than by a
  check-then-use scan of overridable code.

Stable boundary:

- Keep compile-time validation in the macro.
- Keep custom-alphabet performance tradeoffs documented.
- Keep the custom-alphabet timing contract documented on the `Alphabet` trait
  and in the macro docs.
- Do not add a faster custom-alphabet path unless it has its own audit record.
- Do not accept non-visible ASCII or padding bytes in Base64 alphabets.

### Stream Module

The `stream` module is retained as a documented boundary for `v1.0`.

Decision rationale:

- Streaming remains behind the explicit `stream` feature and depends only on
  `std::io`.
- Writer adapters expose `try_finish` for finalization without consuming the
  adapter, and `finish` for finalization plus wrapped object recovery.
- Writer adapters buffer accepted output and allow failed wrapped writes to be
  retried without re-encoding or re-decoding already accepted input.
- Direct `Write::write` calls follow normal `std::io::Write` partial-progress
  semantics; examples and migration docs recommend `write_all` when the whole
  slice must be consumed.
- Decoder adapters fail closed after malformed Base64 input and expose
  `is_failed` for diagnostics.
- `can_into_inner` and `try_into_inner` provide checked recovery paths that
  refuse to silently discard pending input or buffered output.
- Padded `DecoderReader` stops after terminal padding and leaves adjacent
  framed payload bytes unread in the wrapped reader.
- Debug output redacts wrapped I/O values and pending payload bytes while still
  exposing non-sensitive state useful for diagnostics.
- Internal pending and output queues are wiped on consumption and drop as
  best-effort retention reduction.

Stable boundary:

- Keep `std::io` streaming under the explicit `stream` feature.
- Keep async/Tokio out unless the async admission policy is satisfied.
- Keep decoder failure fail-closed.
- Keep recovery helpers explicit; do not make unchecked `into_inner` the
  recommended safe recovery path.
- Keep reader terminal-padding behavior documented for framed protocols.

### Error Types

`EncodeError`, `DecodeError`, and `AlphabetError` are candidates for the
`v1.0` stable surface.

Decision rationale:

- Public runtime errors are recoverable through `Result` and avoid panic-based
  failure for malformed input, size errors, and invalid policies.
- `EncodeError` separates length overflow, invalid line wrapping, input length,
  output capacity failures, invalid alphabet output, and accelerated-backend
  scalar mismatch failures.
- `DecodeError` separates invalid length, invalid bytes, invalid padding,
  invalid line wrapping, output capacity, and deliberately opaque malformed
  input.
- Strict, legacy, wrapped, and in-place decode paths preserve absolute input
  indexes where localized diagnostics are part of the public contract.
- `ct` APIs intentionally report malformed content as `InvalidInput` so the
  constant-time-oriented path does not promise localized error detail.
- `AlphabetError` identifies invalid, padding, and duplicate alphabet bytes
  during custom alphabet validation.

Stable boundary:

- Keep existing variants unless a later release-candidate audit finds a
  correctness reason to change them during the `v1.0` candidate review.
- Keep localized indexes for non-ct scalar diagnostics.
- Keep ct malformed-content errors opaque.
- Do not add panicking convenience APIs for error cases already represented by
  public error variants.

## Initial `v0.10` Direction

- Keep async/Tokio, serde, bytes, zeroize, subtle, property-test, and
  Criterion-style integrations out unless a concrete admission record is
  written.
- Keep `ct` documented as constant-time-oriented rather than formally
  cryptographic unless verification evidence improves during the `v0.10` to
  `v0.12` candidate series.
- Keep active dispatch scalar-only until SIMD admission evidence is complete.
- Focus implementation work on audit findings, documentation gaps, tests, and
  evidence rather than new feature breadth.

## `v1.0` Candidate Outcome

- No public API area remains marked `review pending`.
- Deferred ecosystem integrations remain outside the stable contract until
  they pass dependency admission.
- The `ct` module remains constant-time-oriented and does not claim formal
  cryptographic constant-time behavior.
- Active backend dispatch remained scalar-only at the `v1.0` boundary; later
  admitted SIMD backends remain governed by the SIMD admission policy and the
  trust dashboard.
- A future secure-decode marker trait or wrapper type remains a post-`v1.0`
  candidate. It should be designed only after the stable `ct` contract is
  exercised by downstream users, so the `v1.0` boundary relies on explicit
  `ct` constants, `Engine::ct_decoder()`, and prominent default-decoder
  warnings rather than a late broad API addition.

## Current Post-`1.3.3` Outcome

- Public encode and normal strict decode have admitted SIMD acceleration only
  for the Standard and URL-safe alphabet families under the runtime profiles
  documented in `docs/SIMD_ADMISSION.md`.
- The narrow wasm `simd128` profile is admitted only for binaries compiled with
  `target-feature=+simd128`, `simd`, and
  `allow-wasm32-best-effort-wipe`, backed by the runtime smoke evidence named
  in `docs/WASM_SIMD128_RUNTIME_REVIEW.md`.
- Non-standard surfaces remain intentionally scalar unless a later admission
  package covers them: custom alphabets, bcrypt-style and `crypt(3)` profiles,
  `ct` secret decode, broader wasm/browser claims, big-endian AArch64, and
  `no_std` dispatch. Wrapped, legacy, and strict in-place decode are admitted
  only after scalar validation and staging; line-profile validation,
  line-ending compaction, and legacy-whitespace compaction remain scalar.

## 2.0 Commit 22 Assurance Surface

- `base64_ng::assurance` is available only with `secrets`.
- `AssuranceToken` is context-borrowing, non-`Copy`, non-`Clone`, and split
  into `BestEffort` and unsafe-evidence-backed `Attested` levels.
- Assured encode/decode accepts only an allocation-specific
  `ProtectedSecret<Uninitialized, Level>` and returns `Validated`; ordinary
  mutable slices cannot enter this API.
- Typestate fields and transitions are private. Explicit exposure remains
  redacted and borrows the validated owner.
- `ProtectedMemoryProvider` and `PlatformAttestation` are unsafe extension
  protocols. Cross-thread movement requires the crate-sealed
  `ThreadMovableProvider` proof; protected owners are never `Sync`.
- `try_close` and `Drop` share one ordered teardown implementation with bounded
  provider quarantine. Reports are redacted and separate wipe, physical,
  accounting, lifecycle, retry, and health posture.
- `BestEffortProvider` is finite, volatile, and in-process only. No persistent
  provider or restart-recovery API is part of base 2.0.

## 2.0 Commit 23 Reporting Surface

- `BackendReport` names ordinary encode, ordinary strict decode, and secret
  decode independently. Secret decode is always reported as
  `scalar-constant-time-oriented`.
- `BackendIdentifier` is privately constructed and exposes only a stable
  logging string. Wasm reports artifact selection rather than native runtime
  CPU probing.
- `AssuranceToken::report` includes separate ordinary-backend,
  secret-algorithm, wipe-barrier, and speculation generations but makes no
  protected-allocation claim.
- `ProtectedSecret::operation_report` requires the matching token and reports
  physical posture only for its exact provider handle. Stale generations fail
  closed.
- Cleanup snapshots report wipe, physical protection, accounting, lifecycle,
  pending stage/substage, provider health, and allocation presence separately.
  Tombstones retain no address and say presence is unknown.

## 2.0 Commit 24 Backend Health Surface

- `initialize_backends` performs direct, non-recursive known-answer tests for
  every accelerated ordinary encode and strict-decode backend available to the
  process. First-use admission uses the same KAT boundary.
- Each operation/backend pair owns a monotonic process-local generation and a
  `NeverRun`, `Testing`, `Healthy`, or permanently `Quarantined` state.
  Backend integrity faults remain distinct from malformed caller input.
- `ScalarExecutionOnly` accepts only terminal scalar health states; temporary
  fallback during `NeverRun` or `Testing` is not treated as durable policy
  evidence.
- `checked-backend` redundantly evaluates bounded accelerated and scalar
  chunks, validates reported lengths before slicing, commits only matching
  bytes, and quarantines plus retries scalar on disagreement.
- `StaticBackendToken` represents compile-time-proven or unsafely
  deployment-attested `no_std` SIMD capability. It is thread-bound,
  generation-bound, and cannot bypass KAT or quarantine.
- Secret operations remain outside ordinary SIMD health and checked mode.

## 2.0 Commit 25 Static Encode Surface

- `StaticBackendToken::encode_standard` and
  `StaticBackendToken::encode_url_safe` expose padded or unpadded ordinary
  encoding without `std` runtime probing.
- SSSE3/SSE4.1 and AVX2 tokens enter the exact rewritten kernels only while
  their generation remains healthy. Invalidated tokens and architecture
  backends awaiting later checkpoints execute scalar code.
- The methods preserve ordinary `EncodeError`, output-capacity, tail, and
  padding behavior. They do not authorize secret SIMD processing.

## 2.0 Commits 27-28 Static Strict-Decode Surface

- `StaticBackendToken::decode_standard` and
  `StaticBackendToken::decode_url_safe` expose padded or unpadded ordinary
  strict decode without `std` runtime probing.
- SSSE3/SSE4.1, AVX2, and AVX-512 VBMI tokens enter the direct Commit 27-28
  kernels only while their generation remains healthy. Invalidated tokens and
  non-x86 token backends awaiting their own checkpoints execute scalar code.
- The methods preserve ordinary detailed `DecodeError`, canonicality,
  output-capacity, tail, padding, and no-write-on-error behavior. They do not
  authorize constant-time-oriented secret SIMD processing.

## 2.0 Pre-Seal Usability Surface

- The release owner explicitly reopened the pre-seal API freeze for two narrow
  ordinary usability additions before the final full-range pentest.
- `Base64String<S>` retains the exact sealed codec value that encoded or
  validated its immutable owned text. It is `alloc`-only, visibly printable,
  conditionally cloneable, and non-wiping; it cannot accept `SecretInput`
  without explicit exposure.
- `base64_ng::prelude` contains only the four strict presets, the ordinary
  `Base64`, `Codec`, and `OneShotError` types, plus `Base64String` under
  `alloc`. It excludes compatibility, secret, constant-time-oriented,
  protocol, and historical APIs.
- No untyped `Base64String` default, implicit policy inference, mutable text
  access, secret coercion, or panicking convenience constructor is admitted.