https://github.com/pmarreck/pgpwords
LuaJIT CLI for translating hexadecimal bytes to and from the PGP word list
https://github.com/pmarreck/pgpwords
Last synced: 3 days ago
JSON representation
LuaJIT CLI for translating hexadecimal bytes to and from the PGP word list
- Host: GitHub
- URL: https://github.com/pmarreck/pgpwords
- Owner: pmarreck
- License: mit
- Created: 2026-06-01T10:49:55.000Z (18 days ago)
- Default Branch: yolo
- Last Pushed: 2026-06-01T14:47:17.000Z (18 days ago)
- Last Synced: 2026-06-01T16:26:44.634Z (18 days ago)
- Language: Lua
- Size: 23.4 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# pgpwords
`pgpwords` translates hexadecimal bytes to and from the PGP word list.
The stock PGP word list maps each byte to one of two 256-word tables. Bytes are rendered left-to-right. Byte offset 0 uses the even table, byte offset 1 uses the odd table, and the tables alternate from there. This catches common spoken-word mistakes such as adjacent transpositions, insertions, and deletions when they disturb the expected even/odd sequence.
## Usage
```sh
pgpwords --encode E582
# topmost Istanbul
pgpwords --decode 'topmost Istanbul'
# E582
printf '82e5' | pgpwords --encode -
# miser travesty
```
Hex input is case-insensitive and may contain spaces, colons, hyphens, or underscores as separators. PGP words are case-insensitive.
## Streaming
Explicit stdin modes stream. `pgpwords --encode -` emits each word as soon as a complete byte is available, and `pgpwords --decode -` emits each hex byte as soon as a complete word is available. `--endian=auto` keeps only the bounded prefix needed to decide whether an endian marker or escape is present.
When no `--encode` or `--decode` mode is provided for stdin, `pgpwords` buffers stdin so it can preserve auto-detection between hex and word input.
## Endian Extension
By default, `pgpwords` follows the stock PGP wordlist behavior exactly: no endian marker is emitted or interpreted.
The optional endian extension is for byte streams that represent fingerprints or binary values where byte-order confusion would be costly.
```sh
pgpwords --encode --endian=big E582
# skydive travesty miser
pgpwords --decode --endian=auto 'skydive travesty miser'
# E582
```
`--endian=big` is valid while encoding. It prefixes byte `BE` before the input bytes, with the assumption that the input is already in big-endian order. The marker intentionally shifts every following payload word to the opposite even/odd table.
`--endian=auto` is valid while decoding. It interprets a leading `BE` byte as an extension marker and strips it from the returned hex bytes. Literal payloads that collide with marker prefixes use repeated `00 00` escapes:
The endian marker is width-agnostic metadata only. `pgpwords` does not reorder bytes and does not infer whether the payload represents 16-bit, 32-bit, 64-bit, or larger values. Any byte-order conversion has to happen before encoding; the marker records the intended interpretation of the byte stream.
```text
BE ... marker; return ...
00 00 BE BE ... escaped literal; return BE ...
00 00 00 00 BE 00 00 BE ... escaped literal; return 00 00 BE ...
```
Malformed escaped prefixes are rejected instead of silently dropping bytes.
## Development
```sh
nix develop
./test
./build
nix flake check
```
The executable lives at `bin/pgpwords` and uses `#!/usr/bin/env luajit` so it can be picked up directly by PATH setups that include this repository's `bin/` directory.
## References
- https://philzimmermann.com/docs/PGP_word_list.pdf
- https://web.mit.edu/network/pgpfone/manual/