# Lace-006 · Base64-Ascend
Tags: record, encoding

## Purpose

Lace needs binary protocol values to be safe in paths, stable in text, and
sortable without decoding. Base64-Ascend, abbreviated B64A, is the canonical text
encoding for Lace hashes, verifiers, signing secrets, and signatures. Its
alphabet is ASCII-sorted so equal-length encoded strings sort in decoded byte
order.

This document is for record and crypto implementors. After reading it, an
implementor should be able to encode canonical B64A text, reject non-canonical
forms, and rely on text ordering for equal-length decoded values.

## Defines

Alphabet, encoding, decoding, ordering, and test vectors.

## B64A uses a path-safe sorted alphabet

```text
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~
```

Symbol indexes are assigned left to right: `0..9`, `A..Z`, `_`, `a..z`, then
`~`.

## Encoding maps bytes to canonical text

Implementations MUST encode bytes as follows:

1. Read input bits most-significant bit first.
2. Split the bit stream into 6-bit groups.
3. Zero-fill the final partial group when input length is not a multiple of 3
   bytes.
4. Emit one alphabet symbol for each 6-bit group.
5. Omit padding.

The encoded length is `ceil(8*N/6)` for `N` input bytes.

## Decoding rejects non-canonical text

Implementations MUST reject text that contains bytes outside the B64A alphabet
or contains padding.

After decoding, implementations MUST validate canonical length and zero-filled
tail bits:

- encoded length modulo 4 must not be 1;
- if encoded length modulo 4 is 2, the low 4 bits of the final symbol must be
  zero;
- if encoded length modulo 4 is 3, the low 2 bits of the final symbol must be
  zero.

## Ordering follows decoded bytes

Equal-length canonical B64A strings compare in the same order as their decoded
bytes. If one canonical string is a strict prefix of another, the shorter string
sorts first.

## Test vectors

| Hex | B64A |
|---|---|
| empty | empty |
| `00` | `00` |
| `0000` | `000` |
| `000000` | `0000` |
| `FF` | `~l` |
| `FF00` | `~l0` |
| `000102` | `0042` |

Reject examples: `01`, `001`, `~m`, `~l1`, `=`, `+`, `/`.
