Lace / docs

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, secret keys, verification keys, and Marks. 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

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.

Decoding is the inverse of encoding: map each symbol to its 6-bit index, join those bits most-significant bit first, discard only the zero-filled tail bits, and emit each complete 8-bit byte in order. Implementations MUST validate canonical length and zero-filled tail bits before accepting the result:

Ordering follows decoded bytes

Canonical B64A strings compare in the same order as their decoded byte strings under unsigned bytewise lexicographic ordering. If one decoded byte string, and therefore its canonical encoding, 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, =, +, /.