How It Works

Glossia encodes data by embedding words from a payload wordlist into natural-looking sentences generated by a context-free grammar. The encoding process maps data bits to word indices in the wordlist, which is why wordlists must be append-only.

Encoding Process

  1. Payload tokens: BIP39 words (or words from your custom payload wordlist) are tagged with allowed POS categories (Noun, Verb, Adjective, etc.)

  2. Grammar expansion: The CFG generates a stream of POS slots (e.g., Det N V NP Dot)

  3. Slot filling: Payload tokens are embedded when they fit a slot's POS, otherwise cover words are used

  4. Decoding: Extract payload words by filtering the output against the payload wordlist

Wordlist Encoding

When encoding binary data (like ASCII text or API keys), Glossia uses bit-packing:

  • Each word in the wordlist represents a unique index (0, 1, 2, ...)
  • The number of bits per word is determined by the wordlist size: bits_per_word = log2(word_count)
  • For example, a 2048-word list uses 11 bits per word
  • Data bytes are packed into these bits, with multiple bytes potentially spanning across words

Frequency ordering for payload wordlists: When creating custom payload wordlists (not BIP39, which is frozen in alphabetical order), ordering words by frequency (most frequent first) provides encoding efficiency benefits. Common words appear at lower indices and are more likely to be selected during encoding, making the generated text more natural while maintaining the same information density. This is the same principle used for cover wordlists in Merkle mode.

Example

If your wordlist has 2048 words:

  • Each word represents 11 bits of data
  • The word at index 0 represents bits 00000000000
  • The word at index 2047 represents bits 11111111111
  • When encoding ASCII text, bytes are packed into these 11-bit chunks

BIP39 seed phrase example:

A 12-word BIP39 seed phrase contains 11 × 12 = 132 bits total:

  • 128 bits of entropy + 4 bits of checksum = 132 bits
  • Each of the 12 words encodes 11 bits of information
  • This provides 128 bits of cryptographic entropy (sufficient for 128-bit security)

Density vs. steganography

This information density is what distinguishes Glossia from steganography, and the distinction is deliberate. A steganographic scheme hides the existence of data, and pays for that concealment by spending almost all of its capacity on cover — typically well under 1 bit per symbol. Glossia hides nothing: the payload is meant to be decoded, so every payload word carries its full log2(word_count) bits — 11 for BIP39, up to ~15 for larger lists. The goal is a readable encoding, not a hidden one — making machine data human-friendly without sacrificing too much security.

Encoding and Decoding via Wordlist

When encoding or decoding a payload, Glossia determines the effective wordlist size based on the actual words used in that payload.

Effective Wordlist Size

For a given series of payload words, the effective size of the wordlist is:

effective_size = max_index + 1

Where max_index is the highest index of any word actually used in the payload.

Why This Matters

This approach provides two key benefits:

  1. Unambiguous decoding for existing payloads: When decoding a message, you only need to consider the words that were actually used. The effective wordlist size is determined by the maximum index present, ensuring that decoding is unambiguous even if the wordlist has grown since the message was encoded.

  2. Future payloads access more entropy: As the wordlist grows (via appending new words), future payloads can use a larger vocabulary. This means they can encode more information per word:

    • A 1024-word list (10 bits per word) can encode 10 bits per word
    • A 2048-word list (11 bits per word) can encode 11 bits per word
    • A 4096-word list (12 bits per word) can encode 12 bits per word

Entropy Growth Example

Example: Expanding the English BIP39 wordlist

The English BIP39 wordlist has 2048 words, which provides 11 bits of information per word (since 2^11 = 2048).

If developers decide to increase the wordlist by appending 2048 new English lemmas:

  • Initial wordlist: 2048 words (11 bits per word)

    • Each word encodes 11 bits of information
    • Maximum entropy: 11 bits per word
    • A 12-word seed phrase contains 11 × 12 = 132 bits
  • After expansion: 4096 words (12 bits per word)

    • Each word now encodes 12 bits of information
    • Maximum entropy: 12 bits per word
    • Gain: +1 bit per word for all payloads written after the expansion
    • The same 132 bits can now be represented with 11 words instead of 12 (since 132 ÷ 12 = 11)

This means that as you expand your wordlist by appending new words, you're not just adding vocabulary—you're also increasing the information density of future encodings. Payloads encoded before the expansion continue to decode correctly using the smaller effective size (11 bits), while new payloads can take advantage of the increased entropy (12 bits) and be more compact.

Example: Glossia's Latin vocabulary

Glossia's Latin vocabulary has 2^16 = 65,536 words, providing 16 bits of information per word. This means:

  • A 12-word BIP39 seed phrase contains 132 bits (11 × 12)
  • The same 132 bits can be represented with just 9 Latin Glossia words (since 132 ÷ 16 = 8.25, requiring 9 words to encode 132 bits)
  • This demonstrates how larger wordlists enable more compact encodings of the same information

Practical Example

Consider a wordlist that starts with 1000 words and grows to 2000 words:

  • Payload A (encoded when wordlist had 1000 words):

    • Uses words with indices 0-999
    • Effective size: 1000 words (10 bits per word)
    • Decodes correctly even after wordlist grows to 2000 words
  • Payload B (encoded after wordlist grew to 2000 words):

    • Can use words with indices 0-1999
    • Effective size: 2000 words (11 bits per word)
    • Encodes 1 more bit per word than Payload A

This demonstrates how the append-only constraint enables both backward compatibility and forward compatibility with increased entropy.

Glossia Translation

This is where Glossia's flexibility really shines: any Glossia-expressed bit stream can be converted to any other Glossia language in two simple steps:

  1. Decode from original language to binary: Extract payload words from the source text and convert them to their binary representation using the source language's wordlist
  2. Encode binary to target language: Convert the binary data to payload words using the target language's wordlist, then embed them in natural-looking sentences using the target language's grammar

How It Works

Since Glossia encodes data by mapping words to their indices in the wordlist, and those indices represent binary data, the translation process is straightforward:

Source Language Text
    ↓ (decode)
Binary Data (bits)
    ↓ (encode)
Target Language Text

The binary representation is language-agnostic—it's just bits. As long as both languages have wordlists that can represent the required bit range, translation is lossless and unambiguous.

Bijectivity

This translation results in no information loss, meaning that for a given bitstream all Glossia languages are bijective.

In mathematical terms, this means there exists a one-to-one correspondence (bijection) between any two Glossia languages for the same bitstream:

  • Each unique bitstream maps to exactly one word sequence in each language
  • All statements made in a language with the same order-preserving payload words will map back to exactly one bitstream
  • Translation between languages preserves this one-to-one mapping

Furthermore, deterministic grammars ensure that every bitstream will map to one canonical representation for a given language.

This bijective property ensures that:

  • No information is lost during translation
  • No ambiguity exists—each bitstream has a unique word sequence in each language
  • Round-trip translation (Language A → Language B → Language A) recovers the original exactly
  • Commutative translation (Language A → Language B → Language C) yields the same result as (Language A → Language C)

Benefits

  • Language independence: Encode once, translate to any supported language
  • Lossless conversion: The binary representation preserves all information
  • Flexible deployment: Choose the best language for your use case (compactness, readability, etc.)
  • Future-proof: As new languages are added, existing encodings can be translated to them

Example Use Cases

  • Compact encoding: Translate from English BIP39 (11 bits/word) to Latin Glossia (16 bits/word) for more compact representation
  • Readability: Translate to a language with better grammar or more natural sentence structures
  • Localization: Convert messages to languages appropriate for different regions or contexts
  • Migration: Move existing encodings to newer, larger wordlists as they become available

The verb is authoritative: encode vs. transcode

The verb you use in a meta instruction decides how the input is interpreted, so intent is declared, not guessed:

  • encode into <language> — the input is raw data to encode. Glossia never inspects it for "is this secretly a seed or existing prose?" — that guessing is exactly what could silently corrupt ordinary text whose words happen to be payload words. So a bare list of payload words (even a full BIP39 mnemonic) given to encode into … is encoded as text and round-trips verbatim.

  • transcode into <language> (or translate) — the input is an existing Glossia encoding. Glossia detects its source dialect and re-encodes. This is what compacts a seed into a denser language (a 12-word seed → ~9 Latin words). If no source encoding is detected, it errors and asks you to name the source with from <source> rather than guessing.

echo "<12-word seed>" | glossia --meta "encode into english"      # → encoded as text, round-trips
echo "<12-word seed>" | glossia --meta "transcode into latin"     # → detected as a seed, compacted to Latin
glossia --meta "transcode from latin into english"                # explicit source, always works

The same input behaves differently under encode vs. transcode, but each is an explicit instruction — there is no content-based heuristic that can misfire.

Two things bypass the verb, by design:

  • Naming the source explicitly (transcode from <source> into <target>) always wins — useful when auto-detection would be ambiguous.
  • Structured crypto formats (a bc1… bech32 address, an npub…, etc.) are always recognized so they encode via their native alphabet. That is unambiguous format recognition, not seed/prose guessing.

When the target is a Format (the decode direction, e.g. decode into hex), Glossia always detects which language the input prose is in — there, identifying the source is the whole job.

Glossia Transmission

While direct-to-direct transmission is lossless, noise may be introduced while in-transit. For this reason, Glossia-encoded messages should always utilize checksums, error correction, and any additional information necessary for delivery.

Error Handling and Payload Integrity

However, note that because the decoding process is lossless, all corrections to the bitstream are included in the payload, not outside it. In other words:

  • Checksums and error correction codes are encoded as part of the payload bitstream itself
  • Delivery metadata (addresses, routing information, etc.) is also encoded within the payload
  • The language is agnostic to the information carried—it only presents the data with an aesthetic wrapper that is effectively ignored

What This Means

Glossia's role is to encode bits into natural language and decode them back to bits. It doesn't care what those bits represent:

  • The bits could be raw data, checksums, error correction codes, or metadata
  • All of these are treated equally as part of the payload bitstream
  • The language layer is purely an aesthetic wrapper—converting bits to readable text and back, effectively ignored during decoding

Practical Implications

  • Design your protocol: Include checksums, error correction, and metadata as part of the data you encode
  • Glossia handles encoding/decoding: The language layer ensures the bits can be represented as natural text
  • Your protocol handles integrity: Checksums and error correction verify and correct the decoded bits
  • Separation of concerns: Glossia is transport-agnostic; your application layer handles semantics and integrity

This design ensures that Glossia remains a pure encoding layer—it faithfully represents whatever bits you give it, without making assumptions about what those bits mean or how they should be validated.

Why Wordlists Must Be Append-Only

Critical constraint: Both payload and cover wordlists are append-only.

What This Means

  • You can add new words to the end of wordlists
  • You cannot replace existing words
  • You cannot reorder words in the wordlist

Why This Constraint Exists

Glossia encodes data by mapping words to their position (index) in the wordlist. When you encode a message:

  1. Data bits are converted to word indices
  2. Those indices are used to select words from the wordlist
  3. The selected words are embedded in generated sentences

When decoding:

  1. Payload words are extracted from the text
  2. Each word is looked up in the wordlist to find its index
  3. Those indices are converted back to data bits

If you change the wordlist order or replace words:

  • Previously encoded messages would decode incorrectly
  • The same index would point to a different word
  • The decoded data would be corrupted

By keeping wordlists append-only:

  • All existing indices remain valid
  • Previously encoded messages can still be decoded correctly
  • New words can be added without breaking backward compatibility
  • The information contained in bits written before new words were added is preserved

Practical Implications

  • When creating a wordlist, plan carefully - you can't fix mistakes by reordering
  • If you need to add words, append them to the end
  • If you need to remove a word, you can mark it as deprecated but shouldn't remove it (or you'll break backward compatibility)
  • Wordlist versioning can help track when words were added, but the core list must remain stable

Merkle Mode

Glossia supports a Merkle mode (--merkle) that wraps payload words in a Merkle proof structure. This expands N payload words into 2N-1 total words (N payload words + N-1 Merkle nodes).

How Merkle Mode Works

  1. Tree Construction: Payload words become leaves of a binary Merkle tree
  2. Cover Word Assignment: The first N-1 cover words from the cover wordlist are used as internal nodes (Merkle nodes)
  3. Pre-order Traversal: The tree is traversed in pre-order to generate the final sequence
  4. Root Position: The most frequent cover word (typically "the") becomes the Merkle root and appears first in the sequence

Why Frequency Ordering Matters

Critical requirement: Cover words must be ordered by frequency (most frequent first) in the cover wordlist.

When Merkle mode is enabled:

  • The first N-1 cover words are selected as Merkle tree internal nodes
  • These words appear in the generated text as Merkle proof nodes
  • The first cover word (most frequent) becomes the Merkle root and appears at the start of the sequence

By ordering cover words by frequency:

  • Common words like "the", "a", "is" appear as Merkle roots and internal nodes
  • This makes the generated text look more natural
  • The Merkle proof structure is hidden within common, everyday words

Example: If "the" is the first word in your cover wordlist (most frequent), it will appear as the Merkle root when using --merkle mode, making the output look like natural prose starting with "The ..."

Decoding Merkle Mode

To decode a Merkle-encoded message:

  1. Use --demerkle mode to parse the sequence
  2. The parser extracts payload words by identifying which words are leaves (payload) vs internal nodes (cover words)
  3. The original payload sequence is recovered in order

The Merkle structure provides cryptographic proof that the payload words are authentic and in the correct order, while maintaining the natural appearance of the generated text.