Skip to main content

lys_core/
pairing_words.rs

1//! The words a pairing code is made of (AGENTS-020 R1): two hundred and
2//! fifty-six common, short English words, no two of which sound alike, so a
3//! person can read four of them aloud over a phone and the one listening
4//! writes down the same four. Each byte of a code picks one word, so four
5//! bytes from the operating system make one code.
6//!
7//! Kept beside the handed link (DIRECTORY-112), which is a token a person
8//! clicks; this is the list a person says.
9
10/// The words, one per byte value.
11pub const WORDS: [&str; 256] = [
12    "acorn", "amber", "anchor", "apple", "apron", "javelin", "attic", "autumn", "badge", "bagel",
13    "bamboo", "banjo", "barrel", "basket", "beacon", "beetle", "bison", "blanket", "blossom",
14    "bottle", "bridge", "broom", "bubble", "bucket", "biscuit", "button", "cabin", "cactus",
15    "camel", "candle", "canoe", "canyon", "carpet", "carrot", "castle", "cedar", "cello", "cherry",
16    "chimney", "custard", "circus", "clover", "cobalt", "coconut", "coffee", "comet", "compass",
17    "copper", "coral", "denim", "cradle", "peacock", "cricket", "crystal", "cupcake", "curtain",
18    "daisy", "dolphin", "domino", "donkey", "dragon", "drum", "eagle", "echo", "elbow", "flamingo",
19    "engine", "falcon", "feather", "fiddle", "finch", "fossil", "fountain", "garden", "garlic",
20    "gecko", "ginger", "glacier", "goblet", "goose", "granite", "guitar", "hammer", "hammock",
21    "sailor", "harvest", "hazel", "helmet", "heron", "beaver", "honey", "iceberg", "igloo",
22    "island", "ivory", "jacket", "jaguar", "jasmine", "jelly", "jigsaw", "jungle", "kayak",
23    "kettle", "kitten", "koala", "ladder", "lantern", "lemon", "leopard", "lettuce", "lizard",
24    "llama", "lobster", "kangaroo", "lotus", "magnet", "mango", "marble", "prairie", "parsnip",
25    "glove", "gorilla", "mosaic", "muffin", "mushroom", "napkin", "nectar", "needle", "paprika",
26    "nutmeg", "oasis", "octopus", "olive", "onion", "orbit", "orchid", "ostrich", "otter",
27    "oyster", "oatmeal", "pyramid", "porridge", "panda", "toucan", "pasta", "peanut", "pebble",
28    "pelican", "pencil", "penguin", "saffron", "piano", "pickle", "pigeon", "pillow", "pirate",
29    "nebula", "magpie", "poodle", "poppy", "potato", "pretzel", "pumpkin", "puppet", "puzzle",
30    "quilt", "rabbit", "raccoon", "radish", "rainbow", "raisin", "raven", "ribbon", "river",
31    "spinach", "rocket", "rooster", "rubber", "saddle", "salmon", "tortoise", "satchel", "scarf",
32    "scooter", "shadow", "sheep", "shovel", "silver", "sketch", "loafer", "snail", "soccer",
33    "sofa", "sparrow", "spider", "sponge", "spoon", "squirrel", "stable", "stapler", "sticker",
34    "stork", "summer", "sunset", "sweater", "tablet", "clarinet", "teapot", "temple", "tennis",
35    "thimble", "thunder", "wombat", "tiger", "toaster", "turnip", "tractor", "trumpet", "tulip",
36    "tunnel", "vulture", "turtle", "umbrella", "unicorn", "velvet", "violet", "trombone",
37    "volcano", "waffle", "wagon", "walnut", "walrus", "goblin", "wasabi", "harp", "window",
38    "snowman", "sapphire", "pudding", "zebra", "zipper", "zucchini", "bronze", "cobweb", "dinghy",
39    "flannel", "gravel", "hedgehog", "kiwi", "lagoon", "mammoth", "platypus", "pistol", "quartz",
40    "sardine", "lentil",
41];
42
43/// The code four bytes name: four words from [`WORDS`], one per byte,
44/// separated by single spaces.
45#[must_use]
46pub fn code_from(bytes: [u8; 4]) -> String {
47    bytes
48        .iter()
49        .map(|byte| WORDS[usize::from(*byte)])
50        .collect::<Vec<_>>()
51        .join(" ")
52}
53
54#[cfg(test)]
55mod tests {
56    use super::{WORDS, code_from};
57
58    #[test]
59    fn pairing_words_are_distinct_lowercase_short_and_two_hundred_and_fifty_six() {
60        let mut seen = std::collections::BTreeSet::new();
61        for word in WORDS {
62            assert!(
63                word.len() >= 3 && word.len() <= 8,
64                "{word} is not short enough to say"
65            );
66            assert!(
67                word.bytes().all(|byte| byte.is_ascii_lowercase()),
68                "{word} is not lowercase ascii"
69            );
70            assert!(seen.insert(word), "{word} is listed twice");
71        }
72        assert_eq!(seen.len(), 256);
73    }
74
75    #[test]
76    fn pairing_code_takes_one_word_per_byte() {
77        assert_eq!(code_from([0, 1, 2, 255]), "acorn amber anchor lentil");
78        let code = code_from([7, 7, 7, 7]);
79        let words: Vec<&str> = code.split(' ').collect();
80        assert_eq!(words, ["autumn"; 4]);
81    }
82}