Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Labwords

Version 1.0

Overview

LabWords is a method and a set of word lists for deterministically assigning a two-word mnemonic to an integer ID so that people can easily verify it visually or verbally. LabWords serves as redundant verification information for an ID and helps prevent number mix-ups and transcription errors.

It was proposed for the KamLAND experiment to ensure that photomultiplier tube wiring could be performed reliably inside a dark detector where sound echoes and speech is difficult to hear clearly. For example, verbally reporting that PMT-0171 was connected to Cable-0177 can lead to mishearing or mix-ups. LabWords generates non-duplicating mnemonics within a namespace.

namespace=PMT
serial, LabWords
1, SWEET RICH
2, STOOD FISH
3, CLIMB WHEY
..., ...
171, LEMON MENU
..., ...

namespace=Cable
..., ...
171, CURVE DRIP
..., ...
177, JUMBO SOUL
..., ...

Using LabWords, one can report that PMT - LEMON MENU was connected to Cable - JUMBO SOUL, helping prevent errors. Words that would be startling or alarming to hear in such an environment have been excluded in advance.

Design

Design goals

LabWords has the following goals.

  • Always generate the same mnemonic from the same input
  • Never duplicate a mnemonic within the same scheme and namespace
  • Arrange outputs for consecutive serials irregularly
  • Avoid words with similar spelling, appearance, or pronunciation within each dictionary as much as possible
    • The beginning and ending letters (for four-letter words), and the beginning, middle, and ending letters (for five-letter words), are unique within each dictionary
  • Be relatively easy to pronounce for non-native English speakers
    • The assumption of Japanese speakers as the non-native English speakers is an unavoidable bias
  • Use five letters plus four letters so that word order can be determined reliably
  • Prioritize human readability over machine readability
  • Produce the same result independently of the programming-language implementation

Format

The canonical mnemonic consists of two uppercase ASCII words joined by exactly one ASCII space.

<LEFT5> <RIGHT4>
^[A-Z]{5} [A-Z]{4}$

It contains a five-character left word, a one-character separator, and a four-character right word, for a total of ten characters. Examples:

AMBER AXLE
SOLAR MINT
QUIET LAVA
BRISK TENT

Word selection criteria

Dictionary words are selected according to the following general criteria.

  • Consist only of ASCII letters
  • Are not duplicated within a dictionary
  • Are easy to pronounce
  • Differ sufficiently in spelling, appearance, and pronunciation from other words in the dictionary
  • Are generally neutral and abstract
  • Are generally common English words
  • Are generally not proper nouns
  • Are unlikely to be mistaken for equipment names or safety instructions in experimental facilities involving physics, chemistry, or underground environments
    • Words such as ALARM, ERROR, ACID, and FIRE are not included
  • Do not have offensive, discriminatory, or unpleasant meanings
  • Do not have major regional differences in pronunciation
  • Are not extremely rare
  • Loanwords are acceptable when they are generally recognized
  • Company names and trademarks may be included if they also function as common words; otherwise they are excluded
  • Numbers are not included because they are easily confused

The left dictionary additionally favors colors, natural states, and nouns that do not sound unnatural when used as modifiers. The right dictionary refers to Bytewords and favors words that sound natural as nouns.

Lists

512 Left words

ABOUT ACTOR ADAPT ADMIN ADULT AGAIN AGENT AGING
AGREE AHEAD ALBUM ALIEN ALIVE ALLEY ALLOW ALONE
AMBER AMONG ANGEL ANNEX ANTSY APPLE AREAS ARENA
ARGUE ARMOR AROMA ARRAY ARROW ASHES ASKEW ASSET
AUDIO AUDIT AVOID AWAKE AWARD AXIOM AZURE BACON
BADGE BAKED BASIL BEGIN BEIGE BELOW BENCH BINGO
BIRDS BIRTH BLAND BLOCK BLUES BLURB BONUS BOOKS
BOOST BOSSY BOXER BRASS BRAVO BRICK BROAD BROWN
BRUSH BUDDY BUILT BUSES BUYER CABIN CACHE CAMPS
CANAL CANDY CARGO CAUSE CELLO CHAIR CHARM CHEAP
CHECK CHEWY CHIEF CHILD CHOSE CIDER CIVIL CLASS
CLEAR CLIMB CLOAK CLOTH CLOUD CLUBS COACH COBRA
COCOA COMBO COMET COMFY CORAL COSTS COULD COUNT
COVER CRAFT CRISP CUBIC CURED CURVE CUSHY DAILY
DANCE DATES DEBUT DECOR DENIM DEPTH DIARY DISCO
DODGE DOING DONUT DRAMA DREAM DRESS DRINK DRIVE
EAGER EAGLE EARLY EARTH EATEN EBONY EDGED EDICT
ELBOW ELDER ENDED ENJOY ENTRY EPOCH EQUAL ESSAY
ETHOS EVENT EXACT EXILE FACET FAMED FANCY FEEDS
FENCE FERRY FETCH FIBER FIELD FIERY FILMS FINAL
FLAGS FLOOR FLUKE FOLIO FORGE FORUM FOUND FRESH
FRIED FROST FRUIT FUZZY GAINS GAUGE GECKO GHOST
GIANT GIFTS GIVEN GIZMO GLORY GLOVE GLUED GOALS
GRAPH GRAVY GREAT GRILL GRIND GROUP GROWS GUARD
GUESS GUIDE HABIT HAPPY HATCH HAWKS HAZEL HEART
HEAVY HEDGE HELPS HENNA HERBS HINGE HOLLY HONOR
HOPED HORSE HOTEL HOURS HUMAN HUMOR HUSKY IDEAL
IDIOM IMAGE IMPLY INDEX INNER ITEMS IVORY JADED
JEANS JELLY JEWEL JOINT JOKER JUDGE JUICY JUMBO
KHAKI KINGS KITTY KNEES KNOCK KNOWN KOALA LABOR
LARGE LATTE LAUGH LAYER LEAFY LEARN LEFTY LEGAL
LEMON LEVEL LIKED LILAC LIMIT LIONS LOBBY LOGIC
LOOSE LORDS LOVED LOYAL LUCKY LUNAR LUNCH LYRIC
MADAM MAGIC MAGMA MAJOR MAKER MANGO MAPLE MASON
MATTE MAYBE MEANT MEDIA MERIT METAL MILES MIMIC
MINOR MISSY MIXED MOCHA MODEL MOIST MONEY MOTIF
MOUSE MOVIE MULCH MUSIC NAIVE NEVER NIGHT NINJA
NOBLE NODES NOMAD NORTH NOVEL NYLON OASIS OCCUR
OCEAN OFFER OLDEN ONION OPENS OPERA OPTIC ORBIT
OUTER OVERT OWNED PAIRS PANDA PAPER PASTA PEACE
PERKY PHONE PHOTO PIANO PILOT PINTO PITCH PIXEL
PIZZA PLAIN PLANK PLAZA POETS POLAR POLKA POPPY
PORCH PRIME PRIOR PRISM PROOF PROXY PURSE QUAIL
QUEEN QUEST QUICK QUIET QUOTE RACER RADIO RAISE
RANGE REACH RECAP RELAX RELIC RENEW REPLY RESIN
RETRO RIDGE RIGID RISKS RIVER ROBOT ROOMY ROUGE
RUGBY RULES RURAL RUSTY SAINT SALES SALON SAMBA
SAUCE SAUNA SAVED SCARF SCENE SCRUB SENSE SEWED
SHADY SHARP SHELF SHINY SHOPS SILKY SIZES SKILL
SLEEP SMALL SMART SMITH SNACK SNEAK SNOWY SOCKS
SOLID SOLVE SONIC SOUTH SPACE SPEED SPIRE SPLIT
SPOON SPORT SQUAT STAND STOCK STOOD STORM STRAW
STUDY STUFF STUMP STYLE SUGAR SUITS SUNNY SUPER
SURGE SUSHI SWEAR SWEET SWING SYRUP TACIT TAKEN
TASTY TAWNY TEARS TEMPO TEPID TEXTS THANK THESE
THICK THING THUMB TIARA TIGER TITLE TODAY TOOTH
TOPIC TOUGH TOWER TRADE TRAIL TREND TRIPS TROUT
TRULY TRUST TUNED TURNS TUTOR TWICE TWIST TYPES
ULTRA UNCLE UNDER UNITY UNTIL UPPER URBAN URGED
USAGE USERS USUAL VALUE VAPOR VAULT VENUE VIDEO
VIEWS VIGOR VILLA VINYL VISIT VISTA VOCAL VOGUE
VOICE VOTED WAGES WAGON WALLS WATER WEEKS WHARF
WHEEL WHITE WHOLE WHOOP WIDTH WINDY WIVES WOMEN
WOODS WORLD YEAST YOUNG YOUTH YUMMY ZEBRA ZONES

256 Right words

ALSO APEX ARCH AREA ARID ARMY ATOM AUNT
AXIS AXLE BACK BEAN BEAR BEEF BELL BETA
BIAS BIKE BIRD BLOG BOAT BODY BREW BUMP
BUZZ CAFE CALL CALM CAMP CARD CASH CATS
CHAT CHEF CITY CLAW CLUB COIN COLA CORK
DASH DATA DAWN DELI DESK DIAL DICE DIET
DOGS DOOR DRAW DRIP DRUM DUTY EASY ECHO
EDGE EPIC EVEN EXAM EYES FACT FAIR FANS
FEEL FILE FILM FISH FIZZ FLAP FLOW FLUX
FOOD FOXY FROG FUNK GAME GEAR GIFT GIRL
GOLD GOLF GRAB GREW GREY GRIP GUYS GYRO
HAIR HALF HARP HAWK HEAD HERB HERO HIGH
HILL HINT HITS HOME HORN ICED IDEA IDOL
INFO IRIS IRON ITEM JAZZ JOBS JOIN JOKE
JUDO JUMP JURY JUST KEEP KICK KIDS KIND
KING KIWI KNEE KNOT KNOW LADY LAMP LAVA
LEAF LENS LIME LION LIST LOGO LOUD LUCK
LUNG MAKE MAMA MANY MARK MEMO MENU MILD
MINI MINT MOON MOSS MYTH NAIL NAVY NECK
NEED NEON NEST NEWS NOIR NOTE NOVA OBOE
OMIT ONYX OPAL OVEN OVER OWNS PAGE PAIR
PAPA PARK PATH PLAN PLUG POEM POLO POND
PONY POOL POST PUFF PULP PUTS QUIZ RAIN
REAL RIBS RICH RING ROAD ROCK ROOF ROOM
ROSE RUBY RUST SAND SEES SIGN SILK SITE
SNOW SODA SONG SOUL SPOT STAR STEP SURF
SWIM TAPE TAXI TEAM TENT THRU TIED TOIL
TOOK TOPS TOUR TOWN TRAY TRIO TUBA TURF
UNTO URGE USES VAST VERY VIBE VIEW VITA
VOID VOWS WALL WARM WAYS WEAR WERE WHAT
WHEN WHEY WIKI WINK WISH WOLF WORD YANK
YARD YEAR YOGA YOYO ZINC ZIPS ZONE ZOOM

Verifying the dictionary files

The following two files are the canonical dictionaries.

wordlists/left5.txt
wordlists/right4.txt

Each file is ASCII, contains one word per line, uses LF line endings, and includes an LF after the final line. The SHA-256 hashes of the complete byte sequences are:

336c887c1dc9c4ecd4591bf7d00a55aa4cb1d4c10fdae97faa04b5a38bf205f7  left5.txt
308847b4daf19f8bf3909a540a109cf4e721f060c97c50939dec557045b4e726  right4.txt

The same values are stored in wordlists/SHA256SUMS. They can be verified from a shell with either of the following commands.

(cd wordlists && sha256sum -c SHA256SUMS)        # Linux
(cd wordlists && shasum -a 256 -c SHA256SUMS)    # macOS

In addition to the hashes, the Python implementation's verification command checks the word counts, word lengths, uppercase ASCII form, duplicates, and final LF.

(cd python && uv run labwords check-wordlists)

Usage

Generation and use

Every namespace uses the same left and right dictionary vocabularies. A namespace separates the permutation from serials to word pairs. Any byte sequence can be used as a namespace. An implementation that accepts a string converts it to bytes using UTF-8. All of the following are valid namespace names.

'' (empty byte sequence)
PMT
Cable#
Server-
https://labwords.mzks.dev?id=

Do not use part of a simple hash as the index. Instead, use a keyed permutation over the 17-bit space so that duplicates do not occur.

namespace=PMT
0, LYRIC LAMP
1, SWEET RICH
...
131071, DISCO GIRL

Thus, within the same namespace, different serials in the valid range are guaranteed to have different mnemonics. The same mnemonic may occur in different namespaces.

Reverse mapping

If the namespace is unknown, the original namespace and serial cannot be uniquely recovered from the mnemonic alone. Candidates can be listed by applying the inverse transformation for each possible namespace.

mnemonic=LYRIC LAMP
PMT,    0
Cable,  61214
PMT-,   86219

Basic operations

An implementation provides at least the following operations. Here, start and count are integers satisfying 0 <= start <= start + count <= 131072.

generate(namespace, serial) -> mnemonic
generate_many(namespace, start, count) -> mnemonics
decode(namespace, mnemonic) -> serial

The result of generate_many(namespace, start, count) is identical to the following sequence.

generate(namespace, start)
generate(namespace, start + 1)
...
generate(namespace, start + count - 1)

The result for count = 0 is an empty sequence.

Permutation

The LabWords permutation is an eight-round, 17-bit arithmetic unbalanced Feistel permutation that uses a 128-bit permutation key derived from the namespace. It is not intended for encryption; its purposes are uniqueness within a namespace and irregular placement of consecutive serials.

The process has two stages.

  1. Convert an arbitrary namespace into a 16-byte permutation key
  2. Use the permutation key to map a 17-bit serial to a 17-bit word index

The conversion from namespace to permutation key is needed only once per namespace. In an environment without SHA-256, stage 2 can be implemented by supplying a 16-byte key derived in another environment.

Deriving the permutation key

The canonical form of a namespace is an arbitrary byte sequence. An implementation that accepts strings converts them to bytes using UTF-8.

digest = SHA-256(namespace_bytes)
key = digest[0:16]

The canonical form of a permutation key is a 16-byte byte sequence. When hex is used for display or transport, it is represented by 32 hexadecimal digits.

From a shell, the following one-liner reads the namespace byte sequence from standard input and generates the hexadecimal permutation key.

printf %s 'PMT' | openssl dgst -sha256 -binary | head -c 16 | xxd -p -c 16

Arithmetic round function

All values are treated as non-negative integers. & is bitwise AND, ^ is bitwise XOR, and >> is logical right shift.

MASK17 = (1 << 17) - 1

F(right, round_key, round_number, output_bits):
    output_mask = (1 << output_bits) - 1

    x = (right + round_key + 0x9E37 * (round_number + 1)) & MASK17
    x ^= x >> 7
    x = (x * 0x1B3D) & MASK17
    x ^= x >> 5
    x = (x * 0x15A7) & MASK17
    x ^= x >> 8

    return x & output_mask

Each intermediate value is limited to 17 bits after multiplication. The largest value before multiplication is 131071, and the largest multiplication result is 131071 * 0x1B3D = 913958083.

Forward transformation

Split the serial into an upper eight-bit L and a lower nine-bit R. In even-numbered rounds, F produces eight bits; in odd-numbered rounds, it produces nine bits. After an even number of rounds, L is again eight bits and R is nine bits.

L = serial >> 9
R = serial & 0x1FF

for r = 0 to 7:
    round_key = U16BE(key[2*r : 2*r+2])
    width = 8 if r is even else 9
    L, R = R, L ^ F(R, round_key, r, width)

index = (L << 9) | R

Map the index to words.

left_word  = LEFT_WORDS[index >> 8]
right_word = RIGHT_WORDS[index & 0xFF]
mnemonic   = left_word + " " + right_word

Inverse transformation

Map the mnemonic's left and right words back to their dictionary positions and reconstruct the index.

left_index  = index of left_word in LEFT_WORDS
right_index = index of right_word in RIGHT_WORDS
index = (left_index << 8) | right_index

L = index >> 9
R = index & 0x1FF

for r = 7 down to 0:
    round_key = U16BE(key[2*r : 2*r+2])
    width = 8 if r is even else 9
    L, R = R ^ F(L, round_key, r, width), L

serial = (L << 9) | R

Because this is a Feistel structure, the complete permutation is always bijective even if the round function output has collisions. Therefore, all 131072 serials in the same namespace map to distinct mnemonics, and the following always holds.

decode(namespace, generate(namespace, serial)) == serial

Test vectors

namespace  serial  mnemonic
""         0       HUSKY BETA
""         1       GHOST OVER
""         131071  HEDGE OWNS
"PMT"      0       LYRIC LAMP
"PMT"      1       SWEET RICH
"PMT"      131071  DISCO GIRL
"labwords" 0       DREAM ITEM
"labwords" 1       SEWED DESK
"labwords" 131071  SYRUP JURY

The permutation keys for the empty namespace and namespace="PMT" are:

namespace=""     e3b0c44298fc1c149afbf4c8996fb924
namespace="PMT"  e1873c093bf22185bbd6959d28cc21fb

Implementations

Python

Install from PyPI as follows.

uv add labwords

To install only the CLI as a standalone tool:

uv tool install labwords

The following API is provided.

import labwords

labwords.generate(0, namespace="PMT")
labwords.generate_many(100, namespace="PMT")
labwords.decode("LYRIC LAMP", namespace="PMT")

To let developers distinguish the method implementation from helper scripts, the package itself is divided into the following two files.

  • python/src/labwords/__init__.py
    • Left and right dictionaries embedded in the source
    • Hash verification of the embedded dictionaries actually in use
    • Permutation-key derivation
    • 17-bit Feistel permutation and inverse transformation
    • Conversion between indexes and mnemonics
    • Namespace API, key API, and bulk generation
  • python/src/labwords/scripts.py
    • Displaying permutation keys
    • Command-line interface for dictionary verification

Run the tests from python/.

uv sync
uv run python -m unittest discover -s tests -v

The CLI can generate permutation keys and verify the dictionaries.

uv run labwords key PMT
uv run labwords check-wordlists

C++

This is a C++17 header-only library. The dictionary, 17-bit Feistel implementation, and SHA-256 used to derive permutation keys from namespaces are contained in the single file cpp/include/labwords/labwords.hpp. There are no external runtime dependencies.

#include <labwords/labwords.hpp>

auto mnemonic = labwords::generate(0, "PMT");
auto mnemonics = labwords::generate_many(100, "PMT");
auto serial = labwords::decode("LYRIC LAMP", "PMT");
auto hashes = labwords::wordlist_hashes();

The basic namespace type is std::string_view. In addition to strings, it can receive any byte sequence whose length is explicitly provided. The dictionaries are embedded in the header as fixed-width, newline-separated strings. When a dictionary is first used, the implementation verifies the SHA-256 hash, word count, word length, uppercase ASCII form, and duplicates of the byte sequence actually in use.

CMake provides an INTERFACE target named labwords::labwords.

cmake -S cpp -B cpp/build
cmake --build cpp/build
ctest --test-dir cpp/build --output-on-failure

The build produces cpp/build/labwords in addition to the test binary.

./cpp/build/labwords --namespace PMT --serial 10
# COBRA COLA

./cpp/build/labwords --namespace PMT --serial 10 --count 3
# COBRA COLA
# HELPS JOBS
# GAUGE POLO

./cpp/build/labwords --namespace PMT --decode "LYRIC LAMP"
# 0

./cpp/build/labwords --namespace PMT --key
# e1873c093bf22185bbd6959d28cc21fb

./cpp/build/labwords --check-wordlists

If --namespace is omitted, the empty namespace is used. --count prints consecutive mnemonics beginning at --serial, one per line.

The main files are:

  • cpp/include/labwords/labwords.hpp
    • Embedded dictionaries
    • Small SHA-256 implementation
    • Core implementation and public API
  • cpp/src/labwords.cpp
    • Command-line interface that accepts arguments
  • cpp/tests/test_labwords.cpp
    • Test vectors, arbitrary-byte namespaces, inverse transformation, dictionary hashes, and full-domain uniqueness
  • cpp/CMakeLists.txt
    • Header-only target, tests, and installable package

JavaScript

This dependency-free ES module targets Node.js 16 or later and modern browsers. The dictionaries, 17-bit Feistel implementation, and synchronous pure-JavaScript SHA-256 are contained in javascript/src/index.js.

Install from npm as follows.

npm install labwords
import {
  decode,
  generate,
  generateMany,
  verifyWordlists,
} from "labwords";

generate(0, "PMT");
generateMany(100, "PMT");
decode("LYRIC LAMP", "PMT");
verifyWordlists();

A namespace is specified as either a string or a Uint8Array. Strings are converted to UTF-8. A Node.js Buffer can also be used as a Uint8Array.

The package also includes a CLI.

npx labwords --namespace PMT --serial 10
npx labwords --namespace PMT --serial 10 --count 3
npx labwords --namespace PMT --decode "LYRIC LAMP"
npx labwords --namespace PMT --key
npx labwords --check-wordlists

The main files are:

  • javascript/src/index.js
    • Embedded dictionaries
    • Pure-JavaScript SHA-256
    • Core implementation and public API
    • Hash verification of the embedded dictionaries actually in use
  • javascript/src/cli.js
    • Command-line interface that accepts arguments
  • javascript/test/index.test.js
    • Test vectors, arbitrary-byte namespaces, inverse transformation, dictionary hashes, full-domain uniqueness, and CLI
  • javascript/package.json
    • ESM entry point, CLI, and npm distribution settings

Run the tests and build the distribution from javascript/.

npm test
npm pack

Google Spreadsheet

Use google-spreadsheet/Code.gs as an Apps Script bound to a Google Sheet. Open the Apps Script editor from Extensions and paste in the source to make the following custom functions available.

=LABWORDS(0, "PMT")
=LABWORDS_LIST(100, "PMT", 0)
=LABWORDS_DECODE("LYRIC LAMP", "PMT")
=LABWORDS_KEY("PMT")
=LABWORDS_VERIFY_WORDLISTS()

LABWORDS_LIST returns a two-dimensional array in one call and spills the results vertically. The dictionaries are embedded in Code.gs, and LABWORDS_VERIFY_WORDLISTS reconstructs the dictionaries actually in use and checks their SHA-256 hashes, word counts, word lengths, uppercase ASCII form, and duplicates.

Example

The Apps Script implementation's test vectors, dictionary hashes, and uniqueness over all 131,072 values can be verified locally as follows.

node google-spreadsheet/test.mjs

Dictionary design details

This section preserves notes about considerations made while constructing the dictionaries.

Evaluating confusability

For the set of words in each dictionary, the following should not occur:

  • Signature collisions
  • Words that differ by one letter and have confusingly similar pronunciation, e.g. LIGHT/RIGHT
  • Homophones

For spelling, words are evaluated with attention to:

  • Levenshtein distance
  • Damerau-Levenshtein distance
  • Common prefix length
  • Common suffix length
  • Character bigram/trigram similarity

For pronunciation, words are evaluated with attention to the following.

Candidates that are commonly confused:

/b/ <-> /p/
/d/ <-> /t/
/g/ <-> /k/
/m/ <-> /n/
/f/ <-> /v/
/s/ <-> /z/

Candidates easily confused by non-native English speakers, especially Japanese speakers:

/l/ <-> /r/
/b/ <-> /v/
/s/ <-> /theta/
/z/ <-> /eth/
/f/ <-> /h/
/ae/ <-> /ʌ/ <-> /ɑ/
/ɪ/ <-> /i:/
/ʊ/ <-> /u:/

When otherwise equivalent candidates are available, words with the following characteristics are also excluded.

  • Sequences of three or more consonants
  • Difficult initial or final consonant clusters
  • Mismatch between spelling and pronunciation
  • Multiple common pronunciations
  • Silent letters
  • Visual similarity
  • Many letters in the same positions
  • Potential to look like a different word when dirty or damaged
  • I/L, O/Q, C/G, U/V, M/N, P/R

The dictionaries were constructed by implementing these criteria approximately, solving an optimization problem, and then making arbitrary choices according to the creator's preferences. The condition that words be "unlikely to be mistaken for equipment names or safety instructions in experimental facilities involving physics, chemistry, or underground environments" may not hold for every user's use case. In such cases, the following are examples of possible replacement words. They were not adopted in this specification, but may be useful as references for a custom implementation.

POSTS REPAY HOBBY RIDER POKER BLACK ELITE ARISE KEEPS
PLANT FAIRY SPEND EXIST SHOWS BUILD SHOTS PLANS FLOUR
SERVE WROTE TEAMS BEGAN ABIDE SEIZE LYNCH BADLY ABUSE
ANKLE SINCE TOWEL GIVES SWAMP FADED HONEY QUITE LATER
APART TAXES STRAP SHALL FLUTE CYCLE SMILE

WITH SORT SHIP BOYS PACE TYPE SALT DOES
SNAP KNEW PIPE ENDS COPY BABY GUNS SUIT
LONG THAN THEM LETS TIRE WHOM TALE

About

Method and a set of word lists for deterministically assigning a two-word mnemonic to an integer ID

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages