I hate computers now and the letter "a" has stopped working without mashing it

This commit is contained in:
2026-08-21 17:22:30 +09:00
parent 3d3e90a6c6
commit 7493b473a7
3 changed files with 642 additions and 0 deletions
@@ -0,0 +1,594 @@
/*
* Copyright (c) 2026 QPQ AG <info@qpq.swiss>. All rights reserved.
* Project: Gajumaru Core Java Libraries <gajumaru.io>
*
* This program is dual-licensed:
* 1) Under the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version (AGPL-3.0-or-later).
*
* 2) Under a commercial/proprietary license available directly from QPQ AG.
* If you wish to use this software outside the strict constraints of the
* AGPLv3 (e.g. within a closed-source or proprietary product), you must
* purchase a commercial license from QPQ AG.
*
* Authors:
* - Craig Everett <craigeverett@qpq.swiss>
*
* SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-QPQ-Commercial
*/
package swiss.qpq.gajumaru.core.encoding;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
// Mnemonic provides Gajumaru-style mnemonic phrase encoding and decoding.
// Port of hz_key_master.erl.
//
// Uses raw bit manipulation on byte[] to avoid BigInteger artifacts on the heap.
// Returns byte[][] for phrases to allow for explicit memory scrubbing.
public final class Mnemonic {
private static final int DICT_SIZE = 4096;
private static final int WIDTH = 12; // bits per word
private static final int MAX_DATA_CHUNKS = 22; // For 256-bit seed
private static final String[] WORDS = {
"aardvark", "abacus", "abalone", "abandon", "abbey", "abdomen", "abduct", "abhor", "abide",
"ability", "able", "abnormal", "aboard", "abolish", "abort", "above", "abrasive", "abridged",
"abroad", "abrupt", "abscond", "absence", "absinthe", "absorb", "abstract", "absurd", "abundant",
"abuser", "abyss", "acacia", "academic", "accent", "accident", "acclaim", "account", "accredit",
"accuse", "acetone", "achieve", "acid", "acne", "acolyte", "acoustic", "acquire", "acreage",
"acrobat", "acrylic", "activity", "actor", "actress", "actual", "acuity", "acumen", "acute",
"adage", "adamant", "adapt", "addendum", "addict", "address", "adequate", "adhesive", "adjacent",
"adjoin", "adjust", "admiral", "admonish", "adobe", "adoption", "adorn", "adrenal", "adult",
"advance", "advert", "advisor", "advocate", "aerobic", "affair", "affirm", "afflict", "afford",
"affront", "afraid", "africa", "again", "aged", "agency", "agile", "agitate", "agnostic", "agony",
"agrarian", "agree", "ahead", "ailment", "aimless", "airbrush", "airdrop", "airfare", "airline",
"airmail", "airport", "airship", "airtight", "aisle", "ajar", "alarm", "albacore", "albino",
"album", "alchemy", "alcove", "alert", "alfalfa", "algae", "algebra", "alias", "alibi", "alien",
"alimony", "alive", "alkaline", "alley", "allied", "allocate", "allure", "almanac", "almond",
"alone", "aloof", "alpaca", "alpha", "alpine", "alto", "altruism", "aluminum", "amateur", "amaze",
"amber", "ambition", "ambrosia", "ambush", "amend", "amethyst", "amicable", "amiss", "ammonia",
"amnesia", "amoeba", "amorous", "amount", "amperage", "amplify", "amputate", "amulet", "amuse",
"anaconda", "anagram", "analysis", "anarchy", "anatomy", "ancestor", "anchor", "ancient",
"android", "anecdote", "anemic", "aneurism", "angel", "angler", "angry", "anguish", "animal",
"ankle", "annex", "announce", "annual", "anoint", "anomaly", "anorexia", "another", "answer",
"antacid", "antenna", "anthem", "antique", "antonym", "anvil", "anxiety", "aorta", "apart",
"apathy", "aperture", "apex", "aphid", "apogee", "apology", "apostle", "apparel", "appear",
"apple", "appoint", "approve", "apricot", "apron", "aptitude", "aquatic", "arachnid", "arcade",
"archery", "arctic", "ardent", "arduous", "arena", "argue", "argyle", "arise", "armada",
"armchair", "armor", "armpit", "army", "aroma", "arouse", "arrange", "arrest", "arrive", "arrow",
"arsenal", "arson", "artefact", "artist", "artwork", "asbestos", "ascend", "ascot", "ashamed",
"ashtray", "ashy", "asia", "askew", "aspect", "asphalt", "aspirin", "assassin", "asset", "assist",
"assorted", "assume", "asteroid", "asthma", "astound", "astride", "astute", "asylum", "atheism",
"athlete", "atlas", "atoll", "atom", "atrium", "atrocity", "attack", "attend", "attic", "attorney",
"attract", "auburn", "auction", "audacity", "audit", "augment", "august", "aura", "aurora",
"austere", "author", "autopsy", "autumn", "avail", "avarice", "avatar", "avenger", "average",
"aviation", "avocado", "avoid", "await", "awake", "award", "awesome", "awkward", "awning", "awry",
"axe", "axiom", "axis", "azalea", "azimuth", "azure", "baboon", "babysit", "bachelor", "backhand",
"bacon", "bacteria", "badge", "baffle", "bagel", "baggage", "bagpipe", "bailiff", "bakery",
"balance", "balcony", "balder", "ballroom", "balmy", "baloney", "bamboo", "banana", "bandage",
"bane", "bangle", "banister", "banjo", "banknote", "banner", "banquet", "banshee", "baptize",
"barbecue", "barefoot", "bargain", "baritone", "bark", "barley", "barman", "barnyard", "baroness",
"barrel", "basalt", "baseball", "bashful", "basic", "basket", "bassinet", "baste", "bathe",
"battle", "bay", "bayonet", "bazooka", "beaker", "beam", "beanbag", "beard", "beastly", "beaten",
"beauty", "because", "beckon", "become", "bedbug", "bedroom", "bedsore", "beefy", "beehive",
"beeline", "beeswax", "beetle", "befall", "before", "befuddle", "beggar", "begin", "begrudge",
"beguile", "behavior", "behead", "behind", "behold", "beige", "believe", "bellhop", "belong",
"bemuse", "bench", "benefit", "benign", "bequeath", "berate", "beret", "berserk", "beseech",
"beside", "bespoke", "best", "beta", "betray", "between", "beverage", "beware", "bewilder",
"beyond", "biased", "bible", "bicep", "bicker", "bicycle", "bidding", "bifocal", "biggest",
"bigmouth", "bigotry", "bigwig", "bike", "bikini", "billfold", "binary", "binder", "bingo",
"binomial", "biology", "bionic", "biopsy", "bipedal", "birch", "birdcage", "birthday", "biscuit",
"bisect", "bisque", "bistro", "bitter", "bizarre", "blackout", "blade", "blamed", "blanket",
"blast", "blatant", "blazer", "bleak", "bleed", "blemish", "bless", "blimp", "blind", "blister",
"blitz", "blizzard", "bloated", "blob", "blockade", "blogger", "blonde", "blooper", "blossom",
"blouse", "blowgun", "blubber", "bludgeon", "bluejay", "bluffer", "blunder", "blur", "blustery",
"boastful", "boater", "bobcat", "bobsled", "bobtail", "bodega", "bodice", "bodywork", "bogey",
"bohemian", "boil", "boldface", "bolt", "bombard", "bonanza", "bond", "boneless", "bonfire",
"bonnet", "bonsai", "bonus", "boogie", "book", "boost", "bootleg", "borax", "bordered", "boredom",
"borrow", "bosom", "boss", "bosun", "botanist", "botched", "bother", "bottom", "botulism",
"boulder", "boundary", "bouquet", "bourbon", "boutique", "bovine", "bowler", "boxer", "boycott",
"boyhood", "bracelet", "brag", "braille", "bramble", "branch", "brass", "bratty", "brave",
"brawler", "brazen", "breathe", "breeze", "brethren", "brevity", "brewery", "briar", "bribery",
"brick", "bright", "brim", "brine", "brisket", "brittle", "broach", "broccoli", "broiler",
"broken", "bronze", "broom", "browse", "bruise", "brunt", "brute", "bubble", "buckle", "buddy",
"budget", "buffet", "builder", "bulb", "bulge", "bulimia", "bulky", "bulletin", "bummed", "bumpy",
"bundle", "bungalow", "bunion", "bunker", "buoyant", "burden", "bureau", "burger", "burial",
"burlap", "burnout", "blurp", "burrito", "burst", "bushel", "business", "bustle", "busy", "butane",
"butcher", "butler", "button", "buxom", "buyer", "buyout", "buzz", "bylaw", "bypass", "cabaret",
"cabbage", "cabin", "cactus", "cadaver", "cadet", "caffeine", "caftan", "cage", "cairn", "cajole",
"calamity", "calcium", "calendar", "calico", "callous", "calm", "calorie", "calypso", "camera",
"campus", "canal", "cancel", "candy", "canine", "cannibal", "canoe", "canteen", "canvas", "canyon",
"capacity", "capital", "capsule", "capture", "caramel", "carbon", "carcass", "card", "careful",
"cargo", "caribou", "carnival", "carousel", "carry", "carsick", "cartoon", "carve", "cascade",
"cashew", "casino", "cassette", "castle", "casual", "catalog", "catcher", "category", "catnap",
"catwalk", "cauldron", "causeway", "caution", "cavalry", "caveman", "cavity", "ceiling", "celery",
"celibate", "cellmate", "cement", "censored", "center", "ceramic", "ceremony", "certain", "cesar",
"cesium", "cesspool", "chaff", "chagrin", "chair", "chalice", "champion", "change", "chaotic",
"chapter", "charity", "chase", "chat", "cheap", "checkers", "cheddar", "cheese", "chemical",
"cherry", "chestnut", "chevron", "chew", "chicken", "chief", "chiffon", "child", "chimney",
"china", "chipmunk", "chirp", "chisel", "chive", "chlorine", "choice", "choke", "cholera", "chomp",
"choppy", "chorus", "chowder", "chronic", "chubby", "chuckle", "chug", "chummy", "chunk", "churn",
"chutney", "cicada", "cider", "cigar", "cilantro", "cinema", "cinnamon", "cipher", "circle",
"cistern", "citadel", "citizen", "citrus", "city", "civil", "claim", "clammy", "clang", "clarify",
"class", "clatter", "clavicle", "clay", "cleanup", "cleft", "clemency", "clench", "clerk",
"clever", "client", "cliff", "climate", "clinic", "clipped", "cloaked", "clock", "clog",
"cloister", "closet", "clothing", "cloudy", "clove", "clown", "clubfoot", "clueless", "clump",
"clunky", "cluster", "clutch", "coach", "coastal", "coated", "cobalt", "cobbler", "cobra",
"cobweb", "coccyx", "cocktail", "coconut", "code", "coerce", "coffee", "cognac", "coherent",
"cohort", "coiled", "coin", "colander", "colder", "coleslaw", "coliseum", "collect", "color",
"column", "comatose", "combine", "comedy", "comfort", "comic", "common", "company", "comrade",
"concert", "conduct", "confirm", "congress", "conical", "conjoin", "connect", "conquer", "consume",
"control", "convince", "cookbook", "cool", "copper", "copy", "corduroy", "corner", "coronary",
"corporal", "correct", "corset", "cortex", "cosmetic", "cosplay", "costume", "cotton", "cougar",
"counter", "coupon", "courier", "cousin", "cover", "cowardly", "cowboy", "cowlick", "coyote",
"crabby", "crackle", "cradle", "craft", "cram", "crane", "crater", "craving", "crawl", "crayon",
"crazy", "creamy", "credit", "creep", "cremate", "crescent", "crevice", "cricket", "criminal",
"cringe", "crisis", "critical", "croak", "crochet", "crooked", "crop", "croquet", "crossbow",
"crouch", "crowd", "crucial", "cruel", "cruiser", "crumble", "crunch", "crush", "crux", "cryptic",
"crystal", "cube", "cuckoo", "cucumber", "cuddle", "cudgel", "cuff", "cuisine", "culinary",
"culprit", "cultural", "culvert", "cumin", "cumulus", "cunning", "cupboard", "cupcake", "cupid",
"curator", "curb", "curfew", "curled", "currency", "cursive", "curtsy", "curvy", "cushion", "cuss",
"custody", "cutback", "cutest", "cuticle", "cutlery", "cutout", "cycle", "cylinder", "cynic",
"cypress", "cyst", "dabble", "daffodil", "dainty", "daiquiri", "daisy", "damage", "damsel",
"dance", "dandruff", "danger", "dapper", "darkness", "darling", "dart", "dash", "database",
"dateline", "daughter", "daunting", "dawdle", "daybreak", "daydream", "daylight", "dazed",
"dazzle", "deadline", "dealer", "dean", "deathbed", "debate", "debrief", "debtor", "debut",
"decade", "deceased", "decision", "deck", "declare", "decorate", "decrease", "dedicate", "deduct",
"deed", "deepest", "deface", "defense", "define", "deflate", "deformed", "defraud", "deft",
"defuse", "degree", "deity", "dejected", "delay", "delegate", "deliver", "delta", "delusion",
"delve", "demand", "demeanor", "demise", "democrat", "demure", "denial", "denounce", "density",
"dentist", "deny", "depart", "depend", "depict", "deploy", "deposit", "depress", "depth", "deputy",
"derail", "derby", "derelict", "derive", "describe", "deserter", "desire", "desktop", "desolate",
"despair", "destroy", "detach", "detect", "detour", "devalue", "develop", "device", "devote",
"dewdrop", "diabetic", "diagnose", "dialogue", "diamond", "diaper", "diary", "diatribe", "dicey",
"dictate", "diesel", "diet", "differ", "digest", "digital", "dignity", "digress", "dilemma",
"diligent", "dilute", "diminish", "dimmer", "dimpled", "dingy", "dinner", "dinosaur", "diorama",
"diploma", "direct", "dirty", "disabled", "disburse", "disco", "disdain", "disease", "disguise",
"dishevel", "dismal", "dispense", "disrupt", "dissuade", "distance", "dive", "divide", "divorce",
"divulge", "dizzy", "docility", "dockyard", "doctor", "document", "dodge", "dodo", "dogged",
"doghouse", "dogmatic", "doldrums", "doll", "dolphin", "domain", "domestic", "dominant", "donate",
"donkey", "doomsday", "door", "dorky", "dorm", "dorsal", "dosage", "dossier", "dotted", "doubt",
"doughnut", "downtown", "dowry", "dozen", "draftee", "dragon", "drainage", "dramatic", "drapery",
"drastic", "draw", "dream", "dredge", "dress", "dribble", "dried", "drift", "drink", "driveway",
"drizzle", "drool", "droplet", "drought", "drove", "drowsy", "drudgery", "drug", "druid",
"drummer", "drywall", "dubious", "duckling", "dugout", "duke", "dumbbell", "dumpster", "dungeon",
"duo", "duplex", "duration", "dust", "dutchess", "dutiful", "duty", "duvet", "dwarf", "dwell",
"dwindle", "dynamic", "dyslexia", "eager", "eagle", "eardrum", "earl", "earmark", "earner",
"earphone", "earring", "earshot", "earth", "earwig", "easel", "eastward", "easy", "eatery", "ebb",
"ebony", "echo", "eclectic", "eclipse", "ecology", "economy", "ecstasy", "edge", "edible",
"edifice", "editor", "educate", "eel", "eery", "effigy", "effort", "eggnog", "eggplant",
"eggshell", "ego", "elapse", "elastic", "elated", "elbow", "elder", "election", "elegance",
"element", "elephant", "elevator", "eligible", "elite", "elixir", "ellipsis", "elm", "elongate",
"elope", "eloquent", "elude", "elusive", "emaciate", "email", "emanate", "embark", "embezzle",
"emblem", "embody", "embrace", "emerald", "emigrant", "eminent", "emission", "emoji", "emotion",
"empathy", "emperor", "emphasis", "employer", "empower", "empty", "emu", "emulate", "enamel",
"enchant", "enclose", "encoder", "encrypt", "encumber", "endeavor", "endless", "endorse", "endure",
"enemy", "energize", "engage", "engine", "engraver", "engulf", "enhance", "enigma", "enjoy",
"enlist", "enmity", "enormity", "enraged", "enrich", "enroll", "ensemble", "ensnare", "entangle",
"enthrone", "entire", "entrance", "entwine", "envelope", "envision", "envy", "enzyme", "epic",
"epidemic", "epigram", "epilepsy", "episode", "epitaph", "epoch", "epoxy", "equation", "equinox",
"eraser", "erect", "erode", "errand", "error", "erupt", "escape", "escort", "escrow", "esoteric",
"espresso", "essay", "essence", "estate", "esteem", "estimate", "estrange", "estuary", "eternal",
"ethereal", "ethical", "ethnic", "eulogy", "euphoric", "eureka", "euro", "evade", "evaluate",
"evasion", "event", "evict", "evidence", "evil", "evoke", "evolve", "exact", "exalted", "example",
"excavate", "excerpt", "exchange", "excite", "exclude", "excrete", "excuse", "execute", "exempt",
"exercise", "exhaust", "exhibit", "exhume", "exile", "exist", "exodus", "exorcist", "exotic",
"expand", "expert", "expire", "explain", "expose", "express", "extend", "extinct", "extort",
"extra", "eyeball", "eyeglass", "eyelash", "fabled", "fabric", "fabulous", "facade", "facelift",
"facility", "fact", "faculty", "faded", "failure", "fainter", "fairy", "faith", "fake", "falcon",
"fallout", "false", "famished", "famous", "fanatic", "fanboy", "fancy", "fanfare", "fang",
"fantasy", "farewell", "farmer", "farther", "fashion", "fasten", "fatal", "fathom", "fatigue",
"fatty", "faucet", "fault", "favorite", "fax", "fealty", "fearless", "feast", "feature", "federal",
"fedora", "fee", "feeble", "feedback", "feeler", "feign", "feisty", "feline", "felon", "feminine",
"femur", "fence", "feral", "fern", "ferocity", "ferret", "fertile", "fervent", "festival", "fetch",
"fetid", "feud", "fever", "fiasco", "fiber", "fiction", "fiddler", "fidelity", "fidget",
"fiendish", "fiery", "fiesta", "figure", "filament", "filch", "filet", "filigree", "filling",
"filter", "finance", "fine", "finger", "finish", "firewood", "firm", "first", "fiscal", "fishery",
"fissure", "fitful", "fixate", "fizz", "fjord", "flabby", "flag", "flail", "flaky", "flame",
"flannel", "flapjack", "flash", "flatten", "flaunt", "flavor", "flawless", "fleece", "fleshy",
"flexible", "flick", "flight", "flimsy", "fling", "flip", "flirt", "float", "floor", "floppy",
"floral", "floss", "flotsam", "flourish", "flower", "fluent", "fluff", "fluid", "flummox", "flunk",
"fluoride", "flurry", "flusher", "flute", "flux", "flypaper", "flywheel", "foam", "focus",
"fodder", "fog", "fold", "foliage", "folklore", "follow", "fondue", "font", "foolish", "football",
"forager", "forbid", "force", "forecast", "forfeit", "forget", "forklift", "forlorn", "formal",
"forsake", "fortune", "forum", "forward", "fossil", "fought", "foul", "founder", "foxhound",
"foxtrot", "foxy", "foyer", "fraction", "fragment", "frailty", "frantic", "fraught", "freaky",
"freckled", "freeway", "freight", "frenzy", "frequent", "freshman", "fret", "fridge", "friend",
"frighten", "fringed", "frisky", "fritter", "frizzy", "frock", "frolic", "frontier", "frost",
"froth", "frown", "frozen", "fructose", "frugal", "fruit", "fugitive", "fulcrum", "fulfill",
"fullback", "fumigate", "fund", "funeral", "fungus", "funny", "furious", "furl", "furnace",
"furrow", "furthest", "fuselage", "fusion", "fussy", "futile", "futon", "future", "fuzzy",
"gadget", "galaxy", "gallery", "gambler", "game", "gangster", "gap", "garage", "garden", "gargle",
"garish", "garlic", "garment", "garnet", "garrison", "garter", "gaseous", "gaslight", "gasoline",
"gastric", "gatepost", "gather", "gaudy", "gauge", "gauntlet", "gavel", "gawk", "gazette",
"gearbox", "gecko", "geeky", "geezer", "gelatin", "gemstone", "general", "genius", "genre",
"gentle", "genuine", "geology", "geometry", "gerbil", "germ", "gesture", "getaway", "geyser",
"ghastly", "ghetto", "ghost", "ghoul", "giddy", "gifted", "gigantic", "giggle", "gilded",
"gimmick", "giraffe", "girdle", "girlish", "girth", "gist", "gizmo", "gizzard", "glacier", "glad",
"glamour", "glance", "glare", "glassy", "glaucoma", "glazed", "gleam", "gleeful", "glen", "glib",
"glide", "glimpse", "glint", "glitter", "globe", "gloom", "glory", "glossary", "gloved", "glow",
"glucose", "glue", "gluttony", "glycerin", "glyph", "gnarled", "gnash", "gnaw", "gnome", "goalie",
"goatee", "goblet", "goddess", "goldfish", "golfer", "gondola", "good", "gooey", "goose", "gopher",
"gorge", "gorilla", "gosling", "gospel", "gossip", "gothic", "gourmet", "govern", "gown",
"grabber", "gracious", "graduate", "graffiti", "grainy", "grammar", "grant", "grape", "grasp",
"grateful", "gravity", "gray", "greasy", "green", "gremlin", "grew", "gridlock", "grief", "grill",
"grimace", "grin", "gristle", "gritty", "grizzly", "grocery", "groggy", "grommet", "groove",
"gross", "grotto", "grout", "grovel", "grownup", "grub", "gruesome", "gruff", "grumpy", "grungy",
"gryphon", "guard", "guava", "guess", "guidance", "guilty", "guitar", "gullible", "gulp", "gumbo",
"gumdrop", "gumption", "gunsmith", "gurney", "guru", "gusty", "gut", "guttural", "gym", "gymnast",
"gypsy", "gyration", "gyro", "habit", "hacksaw", "haggler", "haiku", "haircut", "halberd", "half",
"halibut", "hallway", "halogen", "halter", "hamlet", "hammer", "hamster", "handrail", "hangover",
"happy", "harass", "harbor", "hardwood", "harmonic", "harness", "harpoon", "harsh", "harvest",
"hashtag", "hassle", "hatchet", "hateful", "hatred", "hauler", "haunch", "havoc", "haystack",
"haywire", "hazard", "hazelnut", "hazmat", "headset", "health", "hearsay", "heat", "heavy",
"heckler", "hectic", "hedgehog", "hedonism", "heedful", "hegemony", "height", "heinous",
"heirloom", "heliport", "hello", "helmet", "helpful", "hemlock", "hen", "henchman", "henna",
"herald", "herbal", "heresy", "heritage", "hernia", "heron", "herring", "hesitate", "hexagon",
"hiatus", "hibiscus", "hiccup", "hickory", "hidden", "hideaway", "highway", "hijacker", "hiker",
"hilarity", "hill", "hinge", "hint", "hip", "hippo", "history", "hither", "hoagie", "hoarder",
"hoax", "hobby", "hobo", "hockey", "hoedown", "hoggish", "hoist", "holiday", "holler", "hologram",
"holster", "holy", "homage", "home", "homicide", "homonym", "honeydew", "honk", "honor", "hoodie",
"hookworm", "hooligan", "hoop", "hooray", "hopeful", "horizon", "hormone", "hornet", "horror",
"horseman", "hospital", "hostess", "hotel", "hourly", "housing", "howdy", "howitzer", "hub",
"hubcap", "hubris", "huge", "hula", "human", "humble", "humdrum", "humidity", "hummus", "humpback",
"hungry", "hunter", "hurdle", "hurry", "hurt", "husband", "hush", "husky", "hustler", "hyacinth",
"hybrid", "hydrate", "hyena", "hygiene", "hyper", "hyphen", "hypnosis", "hysteria", "iceberg",
"icicle", "icon", "icy", "idea", "identify", "ideology", "idiot", "idler", "idolize", "idyllic",
"igloo", "ignite", "ignore", "iguana", "illicit", "illusion", "imagery", "imbibe", "imbue",
"imitate", "immense", "immolate", "immune", "impasse", "impede", "implode", "impostor", "impress",
"impunity", "inbox", "incense", "inch", "incision", "include", "income", "incubate", "index",
"indicate", "industry", "inept", "inertia", "infant", "inferno", "infinity", "inflict", "info",
"infrared", "ingest", "ingot", "inhale", "inherit", "inhibit", "initial", "inject", "injure",
"inkwell", "inlet", "inmate", "innocent", "innuendo", "input", "inquiry", "insane", "insert",
"insignia", "insomnia", "inspect", "instruct", "insult", "intact", "interest", "intimate",
"intruder", "invasion", "investor", "invite", "invoke", "iodine", "ionize", "iris", "irksome",
"ironwork", "irritate", "island", "isolate", "isotope", "issue", "itchy", "item", "iterate",
"ivory", "jabber", "jackal", "jade", "jagged", "jaguar", "jailer", "jamboree", "janitor", "jargon",
"jasmine", "jaundice", "javelin", "jaw", "jawbone", "jaywalk", "jazz", "jealousy", "jeans",
"jeopardy", "jerky", "jersey", "jester", "jet", "jettison", "jewelry", "jiffy", "jigsaw", "jinx",
"jittery", "jock", "jogger", "joint", "joke", "jolly", "jostle", "journey", "joust", "joy",
"joyride", "joystick", "jubilant", "judge", "judicial", "judo", "jug", "juggler", "juicy",
"jujitsu", "jukebox", "jump", "junction", "junior", "junk", "juror", "jury", "justify", "juvenile",
"kabob", "kale", "kangaroo", "karaoke", "karma", "kayak", "kazoo", "keen", "keepsake", "keg",
"kennel", "keratin", "kerchief", "kerosene", "kestrel", "ketchup", "keyboard", "keyhole",
"keynote", "keystone", "keyword", "khaki", "kick", "kidder", "kidney", "killjoy", "kilogram",
"kilt", "kimono", "kind", "kinetic", "kinfolk", "kingdom", "kinsman", "kiosk", "kiss", "kitchen",
"kite", "kitten", "kiwi", "klutzy", "knapsack", "knee", "knife", "knitted", "knockout", "know",
"knuckle", "koala", "kumquat", "lab", "label", "labor", "lacerate", "lackey", "lacquer",
"lacrosse", "lactose", "ladder", "ladybug", "laggard", "lagoon", "lair", "lament", "laminate",
"lamp", "lancer", "landlord", "language", "lanky", "lantern", "lanyard", "laptop", "larceny",
"large", "larvae", "larynx", "lasagna", "lasso", "latex", "latitude", "latrine", "lattice",
"laugh", "laundry", "laureate", "lava", "lavender", "lavish", "lawful", "lawn", "lawyer",
"laxative", "layaway", "layout", "lazy", "leader", "leaflet", "league", "leaky", "leap", "learn",
"leash", "leathery", "lecture", "ledger", "leeway", "lefty", "legacy", "legend", "legible",
"legume", "legwork", "leisure", "lemming", "lemonade", "lend", "length", "leniency", "lentil",
"leopard", "leprosy", "lesion", "lesser", "lethargy", "letter", "level", "levitate", "levy",
"lexicon", "liaison", "liberty", "library", "license", "lichen", "lieu", "lifespan", "lift",
"ligament", "lighter", "likable", "lilac", "limbo", "lime", "limit", "linchpin", "linen",
"linoleum", "linseed", "lion", "lipid", "lipstick", "liquid", "lisp", "listen", "literary",
"lithium", "litigate", "little", "livery", "lizard", "llama", "loaded", "loaf", "loaner", "loathe",
"lobbyist", "lobotomy", "lobster", "location", "lockjaw", "locust", "logic", "logo", "loiterer",
"lollipop", "lonesome", "long", "lookout", "loopy", "looter", "lopsided", "lordship", "loser",
"lotion", "lottery", "lotus", "loud", "lounge", "lousy", "lovely", "lowland", "loyalty", "lozenge",
"lucid", "luck", "luggage", "lukewarm", "lullaby", "lumber", "luminous", "lunar", "lunch", "lure",
"luxury", "lychee", "lymph", "lyric", "macaroni", "machine", "macro", "mad", "maestro", "magazine",
"magenta", "maggot", "magic", "magma", "magnet", "mahogany", "maiden", "mailman", "maimed",
"maintain", "majestic", "majority", "makeup", "malaria", "malice", "mallard", "malted", "malware",
"mammal", "manager", "mandolin", "maneuver", "mango", "manhole", "manicure", "mankind", "manly",
"manpower", "mansion", "mantra", "manual", "maple", "marathon", "marble", "march", "mare",
"margin", "marine", "market", "marmot", "maroon", "marriage", "marshal", "martini", "marvel",
"mascara", "mashup", "masked", "mason", "massive", "master", "matador", "matchbox", "material",
"math", "matrix", "mattress", "maturity", "maverick", "maximum", "mayhem", "mayor", "meadow",
"meander", "measure", "meatball", "mechanic", "medalist", "medical", "medley", "meeting",
"megabyte", "melanoma", "mellow", "melody", "melt", "member", "meme", "memory", "menace", "mental",
"menu", "meow", "merchant", "merge", "merit", "mermaid", "mesh", "message", "metallic", "meteor",
"method", "metric", "miasma", "microbe", "midair", "midday", "midnight", "midpoint", "midriff",
"midst", "midterm", "midwife", "midyear", "mighty", "migraine", "mild", "mileage", "military",
"milkman", "million", "mimic", "mimosa", "minced", "mindful", "mineral", "minister", "minnow",
"minstrel", "minty", "minute", "miracle", "mirror", "mischief", "misery", "misfit", "mishap",
"missile", "mistake", "mitosis", "mitt", "mixture", "mnemonic", "mobile", "moccasin", "mocha",
"mockery", "modern", "modify", "module", "mogul", "moisture", "molasses", "moldy", "molecule",
"mollusk", "molten", "moment", "momma", "monarch", "money", "mongoose", "monitor", "monocle",
"monster", "month", "monument", "moocher", "moon", "mop", "moped", "moral", "morgue", "morning",
"morocco", "morphine", "morsel", "mortgage", "mosaic", "mosquito", "mossy", "motherly", "motivate",
"motley", "motor", "motto", "mountain", "mourn", "mouse", "mouthful", "move", "mucky", "mucus",
"muffin", "mugger", "mulch", "mullet", "multiply", "mummify", "mundane", "murmur", "muscle",
"museum", "mushroom", "musical", "musket", "mustang", "mutant", "mute", "mutilate", "mutter",
"mutual", "myopia", "myriad", "mystery", "mythical", "nacho", "nail", "naive", "naked", "namesake",
"nanny", "napkin", "narcotic", "narrator", "narwhal", "nasal", "nasty", "national", "nature",
"naughty", "nausea", "nautical", "navigate", "nearest", "nebula", "necklace", "nectar", "needle",
"negative", "neglect", "neighbor", "nemesis", "neon", "neoprene", "nephew", "nepotism", "nerd",
"nerve", "nestle", "network", "neuron", "neutral", "newborn", "newlywed", "newscast", "newton",
"next", "nexus", "niche", "nickel", "nicotine", "niece", "nifty", "nightcap", "nihilist", "nimble",
"ninja", "nippy", "nirvana", "nitpick", "nitrogen", "nitwit", "noble", "nobody", "nocturne",
"noise", "nomad", "nominee", "nonsense", "noodle", "normalcy", "north", "nosedive", "nostril",
"nosy", "notary", "notch", "notepad", "notice", "noun", "nourish", "novel", "noxious", "nozzle",
"nuance", "nuclear", "nugget", "nuisance", "nullify", "numb", "numeral", "nunnery", "nurse",
"nurture", "nutmeg", "nutrient", "nutshell", "nutty", "nylon", "oak", "oasis", "oatmeal",
"obedient", "obelisk", "obese", "obey", "obituary", "object", "oblige", "oblong", "oboe",
"obscure", "observe", "obsidian", "obsolete", "obstacle", "obtain", "obtuse", "obvious",
"occasion", "occupant", "ocean", "ocelot", "octave", "octopus", "ocular", "oddity", "odometer",
"odyssey", "offer", "offhand", "office", "offload", "offshore", "often", "ogre", "oilskin",
"ointment", "okay", "oligarch", "omelet", "omit", "omnivore", "oncoming", "onion", "online",
"onset", "onward", "onyx", "ooze", "opaque", "opera", "opinion", "oppose", "oppress", "option",
"opulent", "oracle", "orange", "orbit", "orchard", "order", "ordinary", "oregano", "organize",
"original", "ornament", "orphan", "orthodox", "osmosis", "ostrich", "otter", "ottoman", "ounce",
"outage", "outburst", "outcome", "outdoor", "outfit", "outgrow", "outhouse", "outlaw", "output",
"outrun", "outside", "outtake", "outward", "oval", "oven", "overall", "owl", "owner", "oxford",
"oxygen", "oxymoron", "oyster", "ozone", "pacific", "package", "paddle", "padlock", "pageant",
"pagoda", "painful", "pajamas", "palpable", "palsy", "paltry", "pamphlet", "panacea", "pancake",
"panda", "panel", "panic", "panorama", "panther", "papaya", "paper", "paprika", "papyrus",
"parade", "parcel", "pardon", "parental", "pariah", "parka", "parlor", "parody", "parrot",
"parsley", "particle", "passport", "pasta", "patchy", "patent", "pathway", "patio", "patrol",
"pattern", "pave", "pavilion", "pawnshop", "payday", "payload", "peaceful", "peanut", "pearly",
"peasant", "pebble", "pecan", "pectoral", "peculiar", "pedantic", "peddler", "pedestal",
"pedicure", "peerless", "pelican", "pellet", "penalty", "pencil", "pendant", "penguin", "penny",
"pensive", "pentagon", "pepper", "percent", "perfect", "period", "perjury", "perk", "permit",
"perplex", "person", "perturb", "peruse", "perverse", "pesky", "petal", "petition", "petrify",
"petunia", "pewter", "phalanx", "phantom", "pharmacy", "phlegm", "phobia", "phoenix", "phonetic",
"photo", "phrase", "physical", "piano", "pickup", "picnic", "picture", "pierce", "piety", "pigeon",
"piglet", "pigment", "pile", "pilfer", "pilgrim", "pillow", "pinball", "pincer", "pinhole", "pink",
"pinnacle", "pinpoint", "pinto", "pioneer", "pious", "pirate", "piston", "pitch", "pitfall",
"pitiful", "pitted", "pivot", "pixel", "pixie", "pizza", "placard", "plan", "plaque", "plasma",
"platform", "playlist", "plaza", "plead", "pledge", "plenty", "plethora", "pliable", "plot",
"plumage", "plunge", "plural", "plushy", "plywood", "poacher", "pockmark", "podcast", "podiatry",
"poem", "poignant", "pointy", "poison", "poker", "polarize", "polished", "polka", "pollen", "polo",
"polygon", "pomade", "pompom", "poncho", "pontoon", "ponytail", "pooch", "popcorn", "popular",
"porous", "porridge", "portion", "positive", "possible", "post", "potato", "potency", "pothole",
"potluck", "poultry", "poverty", "powder", "powerful", "pox", "practice", "prairie", "praline",
"prance", "prawn", "prayer", "preach", "precise", "predator", "prefer", "preheat", "prelude",
"premium", "prepare", "prequel", "pressure", "pretty", "prevent", "price", "priest", "primary",
"print", "priority", "prisoner", "privacy", "problem", "process", "produce", "profile", "program",
"prohibit", "project", "prologue", "promise", "pronoun", "proof", "property", "prorate",
"prospect", "protest", "proud", "provide", "prowl", "proxy", "prudish", "prune", "psalm", "pseudo",
"psychic", "puberty", "public", "pucker", "pudding", "pudgy", "puffy", "pugilist", "pulley",
"pulpit", "pulse", "puma", "pummel", "pumpkin", "puncture", "pundit", "pungent", "punish", "puny",
"pupil", "puppy", "purchase", "puree", "purity", "purple", "pursuit", "purveyor", "pushup",
"putrid", "putt", "puzzle", "pyramid", "pyre", "python", "quadrant", "quagmire", "quail", "quake",
"quality", "quantity", "quarter", "quasar", "queasy", "queen", "quell", "quench", "query", "quest",
"quick", "quiet", "quilted", "quirky", "quitter", "quiver", "quiz", "quote", "rabbit", "rabies",
"raccoon", "race", "radar", "radio", "radon", "rafter", "raggedy", "ragtag", "raider", "railroad",
"rainbow", "raisin", "rally", "rampage", "ramrod", "rancher", "random", "ransack", "rapid",
"rarity", "rascal", "raspy", "rat", "ration", "raunchy", "ravage", "raven", "ravioli", "razor",
"reaction", "ready", "realize", "reaper", "rebel", "rebound", "rebuttal", "receiver", "recharge",
"recipe", "reckless", "recliner", "recorder", "recruit", "rectify", "recycle", "redeemer",
"redhead", "redneck", "reduce", "redwood", "reef", "referee", "refinery", "reflect", "reform",
"refrain", "refugee", "regalia", "regency", "reggae", "region", "regret", "regular", "rehab",
"rehearse", "reject", "rejoice", "relaxed", "relevant", "relic", "reload", "remark", "remedy",
"reminder", "remnant", "removal", "render", "renegade", "renovate", "rent", "repair", "repeater",
"replica", "report", "reprisal", "reptile", "repute", "requiem", "rescue", "resemble", "resident",
"resonate", "response", "restroom", "result", "retailer", "retina", "retrieve", "reunion",
"reveler", "revive", "revolt", "reward", "rhapsody", "rhetoric", "rhino", "rhodium", "rhombus",
"rhubarb", "rhythm", "rib", "ribbon", "rich", "rickshaw", "ricochet", "riddle", "ride", "ridicule",
"riff", "rifle", "rightful", "rigid", "ringtone", "rinse", "riot", "ripple", "risk", "ritual",
"ritzy", "rival", "river", "roadwork", "roar", "roast", "robbery", "robe", "robin", "robot",
"robust", "rocky", "rodeo", "roguish", "romantic", "romp", "roofing", "rookie", "roommate",
"rosemary", "roster", "rotate", "rotten", "rouge", "roulette", "round", "routine", "rowboat",
"royal", "rubber", "rubric", "rucksack", "rudder", "rueful", "ruffian", "rugby", "rugged", "ruin",
"ruler", "ruminate", "rummage", "rumor", "rumple", "runner", "runoff", "runway", "rupture",
"rural", "rusted", "ruthless", "saber", "sabotage", "sadistic", "sadness", "safari", "safe",
"saffron", "saga", "said", "sailor", "saint", "salary", "salesman", "saliva", "salon", "salsa",
"salt", "salute", "salvage", "sampler", "samurai", "sanctum", "sandwich", "sanguine", "sanitize",
"sapling", "sapphire", "sarcasm", "sardine", "sassy", "satchel", "satisfy", "saturate", "sauce",
"sauna", "savanna", "savior", "savory", "savvy", "sawdust", "sawhorse", "sawmill", "scab",
"scaffold", "scale", "scamper", "scandal", "scapula", "scared", "scatter", "scavenge", "scenery",
"scepter", "scheme", "schism", "schnapps", "scholar", "science", "scimitar", "scissor", "scoff",
"scold", "scooter", "scope", "scorpion", "scotch", "scout", "scowl", "scramble", "screen",
"script", "scroll", "scrub", "scuba", "scuffed", "sculpt", "scumbag", "scurry", "scuttle",
"scythe", "seabird", "seafood", "sealant", "seamless", "seaplane", "search", "season", "seaweed",
"secluded", "second", "secret", "section", "security", "sedan", "sediment", "seek", "seepage",
"seesaw", "seethe", "segment", "seismic", "seizure", "seldom", "select", "self", "sellout",
"seltzer", "semantic", "semester", "seminar", "senator", "senior", "sensory", "sentence", "sepia",
"sepsis", "sequence", "serenade", "serfdom", "sergeant", "serious", "serpent", "serrated", "serum",
"service", "sesame", "session", "setback", "settle", "setup", "severity", "sewage", "sewing",
"sextant", "shabby", "shackle", "shadow", "shaft", "shaggy", "shaky", "shallow", "shame", "sharp",
"shawl", "sheathe", "sheet", "shelter", "shepherd", "sheriff", "shield", "shifty", "shimmy",
"shinbone", "shipyard", "shiver", "shock", "shoelace", "shop", "short", "shotgun", "shoulder",
"shove", "showoff", "shrapnel", "shred", "shrine", "shroud", "shrug", "shudder", "shuffle",
"shutdown", "sibling", "sickle", "sidewalk", "siege", "sierra", "signal", "silent", "silicone",
"silk", "silly", "silver", "similar", "simple", "simulate", "since", "sinew", "single", "sinkhole",
"sinus", "siphon", "siren", "sirloin", "sister", "sitcom", "size", "sizzle", "skate", "skeleton",
"skeptic", "sketch", "skewer", "skier", "skillet", "skimmed", "skin", "skirt", "skittish", "skull",
"skunk", "skydive", "skyline", "skyward", "slacker", "slalom", "slammer", "slant", "slather",
"sleaze", "sled", "sleepy", "slender", "sleuth", "slice", "slim", "slinky", "slipper", "slobber",
"slogan", "sloped", "sloth", "slouch", "sluggish", "slurp", "slush", "smart", "smash", "smear",
"smell", "smile", "smith", "smoke", "smolder", "smooth", "smother", "smudge", "smug", "snack",
"snag", "snake", "snapshot", "snarl", "snazzy", "sneaker", "sneeze", "snicker", "snide", "sniff",
"snip", "snobbish", "snooze", "snore", "snot", "snowball", "snuggle", "soaked", "soap", "sob",
"soccer", "society", "socket", "soda", "sodium", "soft", "soggy", "solar", "soldier", "solemn",
"solid", "soloist", "solstice", "solution", "solve", "sombrero", "somebody", "sonata", "songbird",
"sonic", "sooner", "soothe", "soprano", "sorbet", "sorcerer", "sorority", "sortie", "soulmate",
"source", "south", "souvenir", "soybean", "space", "spandex", "spark", "spasm", "spatula", "spawn",
"speak", "special", "speech", "spend", "spew", "sphere", "sphinx", "spicy", "spider", "spiffy",
"spigot", "spill", "spine", "spirit", "spit", "splash", "spleen", "splint", "splotchy", "splurge",
"spoil", "sponsor", "spoon", "sporty", "spotter", "spouse", "spray", "spreader", "sprinkle",
"sprout", "spruce", "spud", "spunky", "spurn", "spy", "spyglass", "square", "squeeze", "squirrel",
"sriracha", "stable", "staccato", "stadium", "stage", "stairway", "stalker", "stamp", "standard",
"stapler", "starve", "station", "staunch", "stay", "steady", "steer", "stellar", "stencil",
"stereo", "steward", "stick", "stifle", "stigma", "stilt", "stimulus", "stingray", "stipend",
"stir", "stockade", "stoic", "stolen", "stomach", "stone", "stool", "stopper", "storm", "stow",
"strategy", "street", "strike", "strong", "struggle", "stub", "stucco", "student", "stuff",
"stumble", "stunt", "stupor", "sturgeon", "stutter", "stylus", "stymie", "suave", "subdue",
"subject", "sublime", "submit", "subplot", "subsidy", "subtitle", "suburbia", "subvert", "subway",
"success", "sudden", "sudsy", "suffer", "sugar", "suggest", "suitable", "sulfur", "sullen",
"sultan", "summer", "sumo", "sunburn", "sundial", "sunken", "sunlight", "sunroof", "sunset",
"superior", "support", "supreme", "surface", "surgery", "surmount", "surname", "surprise",
"surround", "survive", "sushi", "suspect", "sustain", "swaddle", "swagger", "swampy", "swan",
"swarm", "swath", "sweater", "sweeper", "swerve", "swift", "swimmer", "swindler", "swipe",
"switch", "swivel", "swollen", "swoop", "sworn", "sycamore", "syllabus", "symbolic", "symmetry",
"sympathy", "synapse", "sync", "syndrome", "synergy", "synopsis", "syntax", "syringe", "syrup",
"system", "tablet", "taboo", "tacit", "tackle", "taco", "tactile", "tadpole", "taffy", "tag",
"tailpipe", "takeout", "talent", "talisman", "tall", "tamper", "tandem", "tangy", "tankard",
"tanned", "tantrum", "tapestry", "tapioca", "tardy", "target", "tariff", "tarmac", "tarnish",
"tarp", "tarrier", "tartar", "task", "tassel", "tasteful", "tattoo", "taunt", "tavern", "taxation",
"taxi", "teacher", "teal", "teamwork", "teapot", "teardrop", "teaser", "techno", "tedium",
"teenager", "teeth", "telecast", "teller", "temple", "tenant", "tendency", "tennis", "tenor",
"tension", "tentacle", "tenure", "tepid", "tequila", "terminal", "terrain", "terse", "tertiary",
"testify", "tetanus", "tether", "texture", "thank", "thatch", "thaw", "theater", "theft", "theme",
"theory", "therapy", "thesis", "thick", "thigh", "thimble", "thinner", "thirst", "thistle",
"thorn", "thought", "thrall", "threat", "thrive", "throaty", "thrum", "thud", "thumb", "thunder",
"thwart", "thyroid", "tiara", "tibia", "ticket", "tidal", "tidbit", "tidy", "tiger", "tight",
"timber", "timeline", "timid", "tinfoil", "tinker", "tinsel", "tinted", "tipsy", "tiptoe",
"tirade", "tired", "titanium", "title", "toad", "toaster", "tobacco", "toboggan", "today",
"toddler", "toenail", "tofu", "together", "toggle", "toilet", "token", "tolerate", "tomato",
"tomb", "tomcat", "tomorrow", "tonality", "toned", "tongs", "tonight", "tonnage", "tonsil",
"toolbox", "tooth", "topaz", "topology", "topple", "topsoil", "torch", "torment", "tornado",
"torpedo", "torque", "torrid", "torso", "torture", "torus", "total", "tote", "toucan", "tourist",
"toward", "tower", "township", "toxic", "track", "trader", "traffic", "tragic", "train",
"trample", "transfer", "trapeze", "trash", "trauma", "traveler", "treaty", "trek", "tremble",
"trend", "trespass", "trial", "tribe", "tricycle", "trident", "trigger", "trilogy", "trinket",
"trip", "triumph", "trivia", "trod", "troll", "trooper", "tropic", "trouble", "truant", "trucker",
"trudge", "truffle", "trumpet", "trunk", "trust", "truth", "try", "tsunami", "tuba", "tubby",
"tubular", "tuft", "tugboat", "tuition", "tulip", "tumbler", "tummy", "tumult", "tundra", "tuner",
"tungsten", "tunic", "tunnel", "turbine", "turf", "turkey", "turmoil", "turnip", "turret",
"turtle", "tussle", "tutor", "tutu", "tuxedo", "tweak", "tweet", "twerp", "twice", "twiddle",
"twilight", "twin", "twirl", "twist", "tycoon", "type", "typhoon", "typical", "tyrant", "ubiquity",
"ukulele", "ulcer", "ulterior", "ultimate", "ultra", "umbrella", "umpire", "uncle", "uncouth",
"under", "undo", "undulate", "unicycle", "uniform", "unique", "unisex", "unite", "universe",
"unkempt", "until", "unwieldy", "upbeat", "upchuck", "upcoming", "updraft", "upfront", "upgrade",
"upheaval", "uphill", "upkeep", "uplift", "upload", "upper", "upright", "uproar", "upscale",
"upset", "upstream", "uptake", "uptown", "upward", "uranium", "urban", "urchin", "urge", "useful",
"useless", "username", "usher", "usual", "usurper", "utensil", "utility", "utmost", "utopia",
"uvula", "vacant", "vaccine", "vacuum", "vagabond", "vagrant", "vague", "valet", "valid",
"valuable", "valve", "vampire", "vandal", "vanguard", "vanish", "vanquish", "vapor", "variety",
"varsity", "vascular", "vassal", "vast", "vector", "veer", "vegan", "veggie", "vehement",
"vehicle", "velocity", "velvet", "vendor", "veneer", "vengeful", "venison", "venom", "venture",
"venue", "veranda", "verb", "verdict", "verify", "vermin", "version", "vertebra", "vessel",
"vestige", "veteran", "veto", "viable", "viaduct", "vibrant", "vicinity", "victim", "video",
"view", "vigilant", "vigorous", "village", "vinegar", "vintage", "vinyl", "violence", "virtual",
"virus", "visa", "visceral", "visitor", "visor", "visual", "vital", "vitriol", "vivid", "vocal",
"voice", "volatile", "volcano", "volition", "volley", "voltage", "volume", "voodoo", "voter",
"voucher", "vowel", "voyage", "vulture", "wacky", "wafer", "waft", "waggle", "wagon", "waitress",
"waiver", "walkway", "wallet", "walnut", "walrus", "waltz", "wanderer", "wardrobe", "warhorse",
"warlord", "warmth", "warped", "warrior", "warthog", "washroom", "wasp", "wasted", "watch",
"waterbed", "wavy", "waxed", "wayward", "weaken", "wealthy", "weapon", "weary", "weather",
"weaver", "webbed", "webcam", "website", "wedding", "weedy", "weekend", "weep", "weird", "welcome",
"welfare", "western", "wetland", "whack", "whaler", "wharf", "wheeze", "whelp", "whiff", "whim",
"whinny", "whiplash", "whirl", "whisper", "white", "wicked", "widow", "wife", "wig", "wildfire",
"willowy", "wimpy", "windpipe", "winery", "wingtip", "winter", "wiper", "wireless", "wiry",
"wisdom", "wish", "wistful", "withdraw", "witness", "witty", "wizardry", "wobble", "woe", "wolf",
"woman", "wombat", "wonder", "woodwork", "woolen", "woozy", "work", "world", "wormhole", "worry",
"worship", "worthy", "wounded", "wraith", "wrangle", "wrapper", "wreath", "wreckage", "wrench",
"wrestle", "wretched", "wriggle", "wrinkle", "wrist", "written", "wrong", "xenon", "yacht", "yam",
"yank", "yarn", "year", "yelp", "yeoman", "yes", "yeti", "yield", "yodel", "yoga", "yogurt",
"yolk", "young", "yuletide", "yuppie", "zany", "zealot", "zebra", "zenith", "zeppelin", "zero",
"zesty", "zinc", "zipper", "zodiac", "zombie", "zoom", "zucchini", "zygote"
};
private static final Map<String, Integer> WORD_MAP = new HashMap<>(DICT_SIZE);
static {
for (int i = 0; i < WORDS.length; i++) {
WORD_MAP.put(WORDS[i], i);
}
}
private Mnemonic() {}
public static byte[][] encode(byte[] seed) {
if (seed.length != 32) {
throw new IllegalArgumentException("Seed must be 32 bytes");
}
int[] allChunks = new int[MAX_DATA_CHUNKS];
for (int i = 0; i < MAX_DATA_CHUNKS; i++) {
allChunks[i] = read12Bits(seed, i);
}
// Find the first non-zero data chunk (leading zero suppression)
int firstNonZero = -1;
for (int i = 0; i < MAX_DATA_CHUNKS; i++) {
if (allChunks[i] != 0) {
firstNonZero = i;
break;
}
}
int numDataChunks = (firstNonZero == -1) ? 0 : (MAX_DATA_CHUNKS - firstNonZero);
int checksum = 0;
for (int c : allChunks) {
checksum ^= c;
}
byte[][] phrase = new byte[numDataChunks + 1][];
phrase[0] = WORDS[checksum].getBytes(StandardCharsets.UTF_8);
for (int i = 0; i < numDataChunks; i++) {
phrase[i + 1] = WORDS[allChunks[firstNonZero + i]].getBytes(StandardCharsets.UTF_8);
}
return phrase;
}
public static byte[] decode(byte[][] phrase) {
if (phrase.length < 1) {
throw new IllegalArgumentException("Phrase too short");
}
int[] chunks = new int[phrase.length];
for (int i = 0; i < phrase.length; i++) {
String word = new String(phrase[i], StandardCharsets.UTF_8);
Integer idx = WORD_MAP.get(word);
if (idx == null) {
throw new IllegalArgumentException("Unknown word in mnemonic at index " + i);
}
chunks[i] = idx;
}
int expectedChecksum = chunks[0];
int actualChecksum = 0;
for (int i = 1; i < chunks.length; i++) {
actualChecksum ^= chunks[i];
}
if (expectedChecksum != actualChecksum) {
throw new RuntimeException("Mnemonic checksum failed");
}
int numDataChunks = chunks.length - 1;
byte[] result = new byte[32];
for (int i = 0; i < numDataChunks; i++) {
int chunkIdx = MAX_DATA_CHUNKS - numDataChunks + i;
write12Bits(result, chunkIdx, chunks[i + 1]);
}
return result;
}
private static int read12Bits(byte[] seed, int chunkIdx) {
int bitStart = chunkIdx * WIDTH;
int val = 0;
for (int i = 0; i < WIDTH; i++) {
int pos = bitStart + i;
if (pos >= 8) { // Skip 8-bit leading zero padding
int seedBitPos = pos - 8;
int byteIdx = seedBitPos / 8;
int bitInByte = 7 - (seedBitPos % 8); // Big-endian bit order
if (((seed[byteIdx] & 0xFF) >> bitInByte & 1) == 1) {
val |= (1 << (11 - i));
}
}
}
return val;
}
private static void write12Bits(byte[] seed, int chunkIdx, int val) {
int bitStart = chunkIdx * WIDTH;
for (int i = 0; i < WIDTH; i++) {
int pos = bitStart + i;
if (pos >= 8) {
int seedBitPos = pos - 8;
int byteIdx = seedBitPos / 8;
int bitInByte = 7 - (seedBitPos % 8);
if (((val >> (11 - i)) & 1) == 1) {
seed[byteIdx] |= (byte) (1 << bitInByte);
} else {
seed[byteIdx] &= (byte) ~(1 << bitInByte);
}
}
}
}
}
+33
View File
@@ -17,6 +17,7 @@ import swiss.qpq.gajumaru.core.crypto.Ed25519;
import swiss.qpq.gajumaru.core.data.Id;
import swiss.qpq.gajumaru.core.data.SpendTx;
import swiss.qpq.gajumaru.core.data.SignedTx;
import swiss.qpq.gajumaru.core.encoding.Mnemonic;
import swiss.qpq.gajumaru.core.tools.CryptoUtils;
public class Testinator {
@@ -43,6 +44,7 @@ public class Testinator {
case "id_serialization" -> { System.out.print(id_serialization(args[1])); }
case "spend_tx" -> { System.out.print(spend_tx(args[1])); }
case "signed_tx" -> { System.out.print(signed_tx(args[1])); }
case "mnemonic" -> { System.out.print(mnemonic(args[1])); }
case "fe_parity" -> { System.out.print(fe_parity(args[1])); }
case "reduce_parity" -> { System.out.print(reduce_parity(args[1])); }
case "smb_parity" -> { System.out.print(smb_parity(args[1])); }
@@ -460,4 +462,35 @@ public class Testinator {
Files.write(resPath, results);
return resPath.toString();
}
private static String mnemonic(String workingPath) throws IOException {
Path testPath = Path.of(workingPath, "mnemonic.test");
Path resPath = Path.of(workingPath, "mnemonic.java.txt");
List<String> lines = Files.readAllLines(testPath);
List<String> results = new ArrayList<>();
for (String hex : lines) {
if (hex.trim().isEmpty()) continue;
byte[] seed = CryptoUtils.hexToBin(hex);
byte[][] phrase = Mnemonic.encode(seed);
// Join words with space
StringBuilder sb = new StringBuilder();
for (int i = 0; i < phrase.length; i++) {
if (i > 0) sb.append(" ");
sb.append(new String(phrase[i], java.nio.charset.StandardCharsets.UTF_8));
}
results.add(sb.toString());
// Roundtrip test
byte[] decoded = Mnemonic.decode(phrase);
if (!java.util.Arrays.equals(seed, decoded)) {
throw new RuntimeException("Mnemonic roundtrip failed in Java!");
}
CryptoUtils.wipe(seed);
for (byte[] word : phrase) CryptoUtils.wipe(word);
}
Files.write(resPath, results);
return resPath.toString();
}
}
+15
View File
@@ -33,6 +33,7 @@ mods() ->
"id_serialization" => fun id_serialization/0,
"spend_tx" => fun spend_tx/0,
"signed_tx" => fun signed_tx/0,
"mnemonic" => fun mnemonic/0,
"fe_parity" => fun fe_parity/0,
"reduce_parity" => fun reduce_parity/0,
"smb_parity" => fun smb_parity/0,
@@ -420,6 +421,20 @@ serialize_signed_tx(Fields) ->
SigsHex ++ "|" ++ TxHex.
mnemonic() ->
Temp = temp_dir(),
TestFile = filename:join(Temp, "mnemonic.test"),
ok = filelib:ensure_dir(TestFile),
Cases = [rand:bytes(32) || _ <- lists:seq(1, 20)],
ok = file:write_file(TestFile, [[bin_to_hex(S), "\n"] || S <- Cases]),
Expected = [unicode:characters_to_list(hz_key_master:encode(S)) || S <- Cases],
Run = "bin/run mnemonic " ++ Temp,
Out = trim(os:cmd(Run)),
{ok, JOutContent} = file:read_file(trim(Out)),
JResults = string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all),
same_same(Expected, JResults).
fe_parity() ->
Temp = temp_dir(),
TestFile = filename:join(Temp, "fe.test"),