packages feed

haskoin-core-0.21.0: src/Haskoin/Keys/Mnemonic.hs

{-# LANGUAGE OverloadedStrings #-}

{- |
Module      : Haskoin.Keys.Mnemonic
Copyright   : No rights reserved
License     : MIT
Maintainer  : jprupp@protonmail.ch
Stability   : experimental
Portability : POSIX

Mnemonic keys (BIP-39). Only English dictionary.
-}
module Haskoin.Keys.Mnemonic (
    -- * Mnemonic Sentences
    Entropy,
    Mnemonic,
    Passphrase,
    Seed,
    toMnemonic,
    fromMnemonic,
    mnemonicToSeed,
) where

import Control.Monad (when)
import Crypto.Hash (SHA256 (..), hashWith)
import Crypto.KDF.PBKDF2 (Parameters (..), fastPBKDF2_SHA512)
import Data.Bits (shiftL, shiftR)
import qualified Data.ByteArray as BA
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.List
import qualified Data.Map.Strict as M
import Data.Maybe
import Data.String.Conversions (cs)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Data.Vector (Vector, (!))
import qualified Data.Vector as V
import Haskoin.Util

{- | Random data used to create a mnemonic sentence. Use a good entropy source.
 You will get your coins stolen if you don't. You have been warned.
-}
type Entropy = ByteString

-- | Human-readable mnemonic sentence.
type Mnemonic = Text

-- | Optional passphrase for mnemnoic sentence.
type Passphrase = Text

-- | Seed for a private key from a mnemonic sentence.
type Seed = ByteString

-- | Mnemonic key checksum.
type Checksum = ByteString

-- | Paremeters for PBKDF2 function.
pbkdfParams :: Parameters
pbkdfParams = Parameters{iterCounts = 2048, outputLength = 64}

{- | Provide intial 'Entropy' as a 'ByteString' of length multiple of 4 bytes.
 Output a 'Mnemonic' sentence.
-}
toMnemonic :: Entropy -> Either String Mnemonic
toMnemonic ent = do
    when (BS.null ent) $
        Left "toMnemonic: entropy can not be empty"
    when (remainder /= 0) $
        Left "toMnemonic: entropy must be multiples of 4 bytes"
    when (cs_len > 16) $
        Left "toMnemonic: maximum entropy is 64 bytes (512 bits)"
    return ms
  where
    (cs_len, remainder) = BS.length ent `quotRem` 4
    c = calcCS cs_len ent
    indices = bsToIndices $ ent `BS.append` c
    ms = T.unwords $ map (wl !) indices

{- | Revert 'toMnemonic'. Do not use this to generate a 'Seed'. Instead use
 'mnemonicToSeed'. This outputs the original 'Entropy' used to generate a
 'Mnemonic' sentence.
-}
fromMnemonic :: Mnemonic -> Either String Entropy
fromMnemonic ms = do
    when (T.null ms) $
        Left "fromMnemonic: empty mnemonic"
    when (word_count > 48) $
        Left $ "fromMnemonic: too many words: " ++ show word_count
    when (word_count `mod` 3 /= 0) $
        Left $ "fromMnemonic: wrong number of words:" ++ show word_count
    ms_bs <- indicesToBS =<< getIndices ms_words
    let (ms_ent, ms_cs) = BS.splitAt (ent_len * 4) ms_bs
        ms_cs_num = numCS cs_len ms_cs
        ent_cs_num = numCS cs_len $ calcCS cs_len ms_ent
    when (ent_cs_num /= ms_cs_num) $
        Left $ "fromMnemonic: checksum failed: " ++ sh ent_cs_num ms_cs_num
    return ms_ent
  where
    ms_words = T.words ms
    word_count = length ms_words
    (ent_len, cs_len) = (word_count * 11) `quotRem` 32
    sh cs_a cs_b = show cs_a ++ " /= " ++ show cs_b

-- | Compute 'Checksum'.
calcCS :: Int -> Entropy -> Checksum
calcCS len = getBits len . BA.convert . hashWith SHA256

numCS :: Int -> Entropy -> Integer
numCS len =
    shiftCS . bsToInteger
  where
    shiftCS = case 8 - len `mod` 8 of
        8 -> id
        x -> flip shiftR x

{- | Turn an arbitrary sequence of characters into a 512-bit 'Seed'. Use
 'mnemonicToSeed' to get a seed from a 'Mnemonic' sentence. Warning: Does not
 perform NFKD normalization.
-}
anyToSeed :: Passphrase -> Mnemonic -> Seed
anyToSeed pf ms =
    fastPBKDF2_SHA512
        pbkdfParams
        (E.encodeUtf8 ms)
        ("mnemonic" `mappend` E.encodeUtf8 pf)

{- | Get a 512-bit 'Seed' from a 'Mnemonic' sentence. Will validate checksum.
 'Passphrase' can be used to protect the 'Mnemonic'. Use an empty string as
 'Passphrase' if none is required.
-}
mnemonicToSeed :: Passphrase -> Mnemonic -> Either String Seed
mnemonicToSeed pf ms = do
    ent <- fromMnemonic ms
    mnm <- toMnemonic ent
    return $ anyToSeed pf mnm

-- | Get indices of words in word list.
getIndices :: [Text] -> Either String [Int]
getIndices ws
    | null n = return $ catMaybes i
    | otherwise = Left $ "getIndices: words not found: " ++ cs w
  where
    i = map (`M.lookup` wl') ws
    n = elemIndices Nothing i
    w = T.unwords $ map (ws !!) n

-- | Turn a list of 11-bit numbers into a 'ByteString'
indicesToBS :: [Int] -> Either String ByteString
indicesToBS is = do
    when lrg $ Left "indicesToBS: index larger or equal than 2048"
    return . pad . integerToBS $ foldl' f 0 is `shiftL` shift_width
  where
    lrg = isJust $ find (>= 2048) is
    (q, r) = (length is * 11) `quotRem` 8
    shift_width =
        if r == 0
            then 0
            else 8 - r
    bl =
        if r == 0
            then q
            else q + 1 -- length of resulting ByteString
    pad bs = BS.append (BS.replicate (bl - BS.length bs) 0x00) bs
    f acc x = (acc `shiftL` 11) + fromIntegral x

-- | Turn a 'ByteString' into a list of 11-bit numbers.
bsToIndices :: ByteString -> [Int]
bsToIndices bs =
    reverse . go q $ bsToInteger bs `shiftR` r
  where
    (q, r) = (BS.length bs * 8) `quotRem` 11
    go 0 _ = []
    go n i = fromIntegral (i `mod` 2048) : go (n - 1) (i `shiftR` 11)

wl' :: M.Map Text Int
wl' = V.ifoldr' (flip M.insert) M.empty wl

-- | Standard English dictionary from BIP-39 specification.
wl :: Vector Text
wl =
    V.fromListN
        2048
        [ "abandon"
        , "ability"
        , "able"
        , "about"
        , "above"
        , "absent"
        , "absorb"
        , "abstract"
        , "absurd"
        , "abuse"
        , "access"
        , "accident"
        , "account"
        , "accuse"
        , "achieve"
        , "acid"
        , "acoustic"
        , "acquire"
        , "across"
        , "act"
        , "action"
        , "actor"
        , "actress"
        , "actual"
        , "adapt"
        , "add"
        , "addict"
        , "address"
        , "adjust"
        , "admit"
        , "adult"
        , "advance"
        , "advice"
        , "aerobic"
        , "affair"
        , "afford"
        , "afraid"
        , "again"
        , "age"
        , "agent"
        , "agree"
        , "ahead"
        , "aim"
        , "air"
        , "airport"
        , "aisle"
        , "alarm"
        , "album"
        , "alcohol"
        , "alert"
        , "alien"
        , "all"
        , "alley"
        , "allow"
        , "almost"
        , "alone"
        , "alpha"
        , "already"
        , "also"
        , "alter"
        , "always"
        , "amateur"
        , "amazing"
        , "among"
        , "amount"
        , "amused"
        , "analyst"
        , "anchor"
        , "ancient"
        , "anger"
        , "angle"
        , "angry"
        , "animal"
        , "ankle"
        , "announce"
        , "annual"
        , "another"
        , "answer"
        , "antenna"
        , "antique"
        , "anxiety"
        , "any"
        , "apart"
        , "apology"
        , "appear"
        , "apple"
        , "approve"
        , "april"
        , "arch"
        , "arctic"
        , "area"
        , "arena"
        , "argue"
        , "arm"
        , "armed"
        , "armor"
        , "army"
        , "around"
        , "arrange"
        , "arrest"
        , "arrive"
        , "arrow"
        , "art"
        , "artefact"
        , "artist"
        , "artwork"
        , "ask"
        , "aspect"
        , "assault"
        , "asset"
        , "assist"
        , "assume"
        , "asthma"
        , "athlete"
        , "atom"
        , "attack"
        , "attend"
        , "attitude"
        , "attract"
        , "auction"
        , "audit"
        , "august"
        , "aunt"
        , "author"
        , "auto"
        , "autumn"
        , "average"
        , "avocado"
        , "avoid"
        , "awake"
        , "aware"
        , "away"
        , "awesome"
        , "awful"
        , "awkward"
        , "axis"
        , "baby"
        , "bachelor"
        , "bacon"
        , "badge"
        , "bag"
        , "balance"
        , "balcony"
        , "ball"
        , "bamboo"
        , "banana"
        , "banner"
        , "bar"
        , "barely"
        , "bargain"
        , "barrel"
        , "base"
        , "basic"
        , "basket"
        , "battle"
        , "beach"
        , "bean"
        , "beauty"
        , "because"
        , "become"
        , "beef"
        , "before"
        , "begin"
        , "behave"
        , "behind"
        , "believe"
        , "below"
        , "belt"
        , "bench"
        , "benefit"
        , "best"
        , "betray"
        , "better"
        , "between"
        , "beyond"
        , "bicycle"
        , "bid"
        , "bike"
        , "bind"
        , "biology"
        , "bird"
        , "birth"
        , "bitter"
        , "black"
        , "blade"
        , "blame"
        , "blanket"
        , "blast"
        , "bleak"
        , "bless"
        , "blind"
        , "blood"
        , "blossom"
        , "blouse"
        , "blue"
        , "blur"
        , "blush"
        , "board"
        , "boat"
        , "body"
        , "boil"
        , "bomb"
        , "bone"
        , "bonus"
        , "book"
        , "boost"
        , "border"
        , "boring"
        , "borrow"
        , "boss"
        , "bottom"
        , "bounce"
        , "box"
        , "boy"
        , "bracket"
        , "brain"
        , "brand"
        , "brass"
        , "brave"
        , "bread"
        , "breeze"
        , "brick"
        , "bridge"
        , "brief"
        , "bright"
        , "bring"
        , "brisk"
        , "broccoli"
        , "broken"
        , "bronze"
        , "broom"
        , "brother"
        , "brown"
        , "brush"
        , "bubble"
        , "buddy"
        , "budget"
        , "buffalo"
        , "build"
        , "bulb"
        , "bulk"
        , "bullet"
        , "bundle"
        , "bunker"
        , "burden"
        , "burger"
        , "burst"
        , "bus"
        , "business"
        , "busy"
        , "butter"
        , "buyer"
        , "buzz"
        , "cabbage"
        , "cabin"
        , "cable"
        , "cactus"
        , "cage"
        , "cake"
        , "call"
        , "calm"
        , "camera"
        , "camp"
        , "can"
        , "canal"
        , "cancel"
        , "candy"
        , "cannon"
        , "canoe"
        , "canvas"
        , "canyon"
        , "capable"
        , "capital"
        , "captain"
        , "car"
        , "carbon"
        , "card"
        , "cargo"
        , "carpet"
        , "carry"
        , "cart"
        , "case"
        , "cash"
        , "casino"
        , "castle"
        , "casual"
        , "cat"
        , "catalog"
        , "catch"
        , "category"
        , "cattle"
        , "caught"
        , "cause"
        , "caution"
        , "cave"
        , "ceiling"
        , "celery"
        , "cement"
        , "census"
        , "century"
        , "cereal"
        , "certain"
        , "chair"
        , "chalk"
        , "champion"
        , "change"
        , "chaos"
        , "chapter"
        , "charge"
        , "chase"
        , "chat"
        , "cheap"
        , "check"
        , "cheese"
        , "chef"
        , "cherry"
        , "chest"
        , "chicken"
        , "chief"
        , "child"
        , "chimney"
        , "choice"
        , "choose"
        , "chronic"
        , "chuckle"
        , "chunk"
        , "churn"
        , "cigar"
        , "cinnamon"
        , "circle"
        , "citizen"
        , "city"
        , "civil"
        , "claim"
        , "clap"
        , "clarify"
        , "claw"
        , "clay"
        , "clean"
        , "clerk"
        , "clever"
        , "click"
        , "client"
        , "cliff"
        , "climb"
        , "clinic"
        , "clip"
        , "clock"
        , "clog"
        , "close"
        , "cloth"
        , "cloud"
        , "clown"
        , "club"
        , "clump"
        , "cluster"
        , "clutch"
        , "coach"
        , "coast"
        , "coconut"
        , "code"
        , "coffee"
        , "coil"
        , "coin"
        , "collect"
        , "color"
        , "column"
        , "combine"
        , "come"
        , "comfort"
        , "comic"
        , "common"
        , "company"
        , "concert"
        , "conduct"
        , "confirm"
        , "congress"
        , "connect"
        , "consider"
        , "control"
        , "convince"
        , "cook"
        , "cool"
        , "copper"
        , "copy"
        , "coral"
        , "core"
        , "corn"
        , "correct"
        , "cost"
        , "cotton"
        , "couch"
        , "country"
        , "couple"
        , "course"
        , "cousin"
        , "cover"
        , "coyote"
        , "crack"
        , "cradle"
        , "craft"
        , "cram"
        , "crane"
        , "crash"
        , "crater"
        , "crawl"
        , "crazy"
        , "cream"
        , "credit"
        , "creek"
        , "crew"
        , "cricket"
        , "crime"
        , "crisp"
        , "critic"
        , "crop"
        , "cross"
        , "crouch"
        , "crowd"
        , "crucial"
        , "cruel"
        , "cruise"
        , "crumble"
        , "crunch"
        , "crush"
        , "cry"
        , "crystal"
        , "cube"
        , "culture"
        , "cup"
        , "cupboard"
        , "curious"
        , "current"
        , "curtain"
        , "curve"
        , "cushion"
        , "custom"
        , "cute"
        , "cycle"
        , "dad"
        , "damage"
        , "damp"
        , "dance"
        , "danger"
        , "daring"
        , "dash"
        , "daughter"
        , "dawn"
        , "day"
        , "deal"
        , "debate"
        , "debris"
        , "decade"
        , "december"
        , "decide"
        , "decline"
        , "decorate"
        , "decrease"
        , "deer"
        , "defense"
        , "define"
        , "defy"
        , "degree"
        , "delay"
        , "deliver"
        , "demand"
        , "demise"
        , "denial"
        , "dentist"
        , "deny"
        , "depart"
        , "depend"
        , "deposit"
        , "depth"
        , "deputy"
        , "derive"
        , "describe"
        , "desert"
        , "design"
        , "desk"
        , "despair"
        , "destroy"
        , "detail"
        , "detect"
        , "develop"
        , "device"
        , "devote"
        , "diagram"
        , "dial"
        , "diamond"
        , "diary"
        , "dice"
        , "diesel"
        , "diet"
        , "differ"
        , "digital"
        , "dignity"
        , "dilemma"
        , "dinner"
        , "dinosaur"
        , "direct"
        , "dirt"
        , "disagree"
        , "discover"
        , "disease"
        , "dish"
        , "dismiss"
        , "disorder"
        , "display"
        , "distance"
        , "divert"
        , "divide"
        , "divorce"
        , "dizzy"
        , "doctor"
        , "document"
        , "dog"
        , "doll"
        , "dolphin"
        , "domain"
        , "donate"
        , "donkey"
        , "donor"
        , "door"
        , "dose"
        , "double"
        , "dove"
        , "draft"
        , "dragon"
        , "drama"
        , "drastic"
        , "draw"
        , "dream"
        , "dress"
        , "drift"
        , "drill"
        , "drink"
        , "drip"
        , "drive"
        , "drop"
        , "drum"
        , "dry"
        , "duck"
        , "dumb"
        , "dune"
        , "during"
        , "dust"
        , "dutch"
        , "duty"
        , "dwarf"
        , "dynamic"
        , "eager"
        , "eagle"
        , "early"
        , "earn"
        , "earth"
        , "easily"
        , "east"
        , "easy"
        , "echo"
        , "ecology"
        , "economy"
        , "edge"
        , "edit"
        , "educate"
        , "effort"
        , "egg"
        , "eight"
        , "either"
        , "elbow"
        , "elder"
        , "electric"
        , "elegant"
        , "element"
        , "elephant"
        , "elevator"
        , "elite"
        , "else"
        , "embark"
        , "embody"
        , "embrace"
        , "emerge"
        , "emotion"
        , "employ"
        , "empower"
        , "empty"
        , "enable"
        , "enact"
        , "end"
        , "endless"
        , "endorse"
        , "enemy"
        , "energy"
        , "enforce"
        , "engage"
        , "engine"
        , "enhance"
        , "enjoy"
        , "enlist"
        , "enough"
        , "enrich"
        , "enroll"
        , "ensure"
        , "enter"
        , "entire"
        , "entry"
        , "envelope"
        , "episode"
        , "equal"
        , "equip"
        , "era"
        , "erase"
        , "erode"
        , "erosion"
        , "error"
        , "erupt"
        , "escape"
        , "essay"
        , "essence"
        , "estate"
        , "eternal"
        , "ethics"
        , "evidence"
        , "evil"
        , "evoke"
        , "evolve"
        , "exact"
        , "example"
        , "excess"
        , "exchange"
        , "excite"
        , "exclude"
        , "excuse"
        , "execute"
        , "exercise"
        , "exhaust"
        , "exhibit"
        , "exile"
        , "exist"
        , "exit"
        , "exotic"
        , "expand"
        , "expect"
        , "expire"
        , "explain"
        , "expose"
        , "express"
        , "extend"
        , "extra"
        , "eye"
        , "eyebrow"
        , "fabric"
        , "face"
        , "faculty"
        , "fade"
        , "faint"
        , "faith"
        , "fall"
        , "false"
        , "fame"
        , "family"
        , "famous"
        , "fan"
        , "fancy"
        , "fantasy"
        , "farm"
        , "fashion"
        , "fat"
        , "fatal"
        , "father"
        , "fatigue"
        , "fault"
        , "favorite"
        , "feature"
        , "february"
        , "federal"
        , "fee"
        , "feed"
        , "feel"
        , "female"
        , "fence"
        , "festival"
        , "fetch"
        , "fever"
        , "few"
        , "fiber"
        , "fiction"
        , "field"
        , "figure"
        , "file"
        , "film"
        , "filter"
        , "final"
        , "find"
        , "fine"
        , "finger"
        , "finish"
        , "fire"
        , "firm"
        , "first"
        , "fiscal"
        , "fish"
        , "fit"
        , "fitness"
        , "fix"
        , "flag"
        , "flame"
        , "flash"
        , "flat"
        , "flavor"
        , "flee"
        , "flight"
        , "flip"
        , "float"
        , "flock"
        , "floor"
        , "flower"
        , "fluid"
        , "flush"
        , "fly"
        , "foam"
        , "focus"
        , "fog"
        , "foil"
        , "fold"
        , "follow"
        , "food"
        , "foot"
        , "force"
        , "forest"
        , "forget"
        , "fork"
        , "fortune"
        , "forum"
        , "forward"
        , "fossil"
        , "foster"
        , "found"
        , "fox"
        , "fragile"
        , "frame"
        , "frequent"
        , "fresh"
        , "friend"
        , "fringe"
        , "frog"
        , "front"
        , "frost"
        , "frown"
        , "frozen"
        , "fruit"
        , "fuel"
        , "fun"
        , "funny"
        , "furnace"
        , "fury"
        , "future"
        , "gadget"
        , "gain"
        , "galaxy"
        , "gallery"
        , "game"
        , "gap"
        , "garage"
        , "garbage"
        , "garden"
        , "garlic"
        , "garment"
        , "gas"
        , "gasp"
        , "gate"
        , "gather"
        , "gauge"
        , "gaze"
        , "general"
        , "genius"
        , "genre"
        , "gentle"
        , "genuine"
        , "gesture"
        , "ghost"
        , "giant"
        , "gift"
        , "giggle"
        , "ginger"
        , "giraffe"
        , "girl"
        , "give"
        , "glad"
        , "glance"
        , "glare"
        , "glass"
        , "glide"
        , "glimpse"
        , "globe"
        , "gloom"
        , "glory"
        , "glove"
        , "glow"
        , "glue"
        , "goat"
        , "goddess"
        , "gold"
        , "good"
        , "goose"
        , "gorilla"
        , "gospel"
        , "gossip"
        , "govern"
        , "gown"
        , "grab"
        , "grace"
        , "grain"
        , "grant"
        , "grape"
        , "grass"
        , "gravity"
        , "great"
        , "green"
        , "grid"
        , "grief"
        , "grit"
        , "grocery"
        , "group"
        , "grow"
        , "grunt"
        , "guard"
        , "guess"
        , "guide"
        , "guilt"
        , "guitar"
        , "gun"
        , "gym"
        , "habit"
        , "hair"
        , "half"
        , "hammer"
        , "hamster"
        , "hand"
        , "happy"
        , "harbor"
        , "hard"
        , "harsh"
        , "harvest"
        , "hat"
        , "have"
        , "hawk"
        , "hazard"
        , "head"
        , "health"
        , "heart"
        , "heavy"
        , "hedgehog"
        , "height"
        , "hello"
        , "helmet"
        , "help"
        , "hen"
        , "hero"
        , "hidden"
        , "high"
        , "hill"
        , "hint"
        , "hip"
        , "hire"
        , "history"
        , "hobby"
        , "hockey"
        , "hold"
        , "hole"
        , "holiday"
        , "hollow"
        , "home"
        , "honey"
        , "hood"
        , "hope"
        , "horn"
        , "horror"
        , "horse"
        , "hospital"
        , "host"
        , "hotel"
        , "hour"
        , "hover"
        , "hub"
        , "huge"
        , "human"
        , "humble"
        , "humor"
        , "hundred"
        , "hungry"
        , "hunt"
        , "hurdle"
        , "hurry"
        , "hurt"
        , "husband"
        , "hybrid"
        , "ice"
        , "icon"
        , "idea"
        , "identify"
        , "idle"
        , "ignore"
        , "ill"
        , "illegal"
        , "illness"
        , "image"
        , "imitate"
        , "immense"
        , "immune"
        , "impact"
        , "impose"
        , "improve"
        , "impulse"
        , "inch"
        , "include"
        , "income"
        , "increase"
        , "index"
        , "indicate"
        , "indoor"
        , "industry"
        , "infant"
        , "inflict"
        , "inform"
        , "inhale"
        , "inherit"
        , "initial"
        , "inject"
        , "injury"
        , "inmate"
        , "inner"
        , "innocent"
        , "input"
        , "inquiry"
        , "insane"
        , "insect"
        , "inside"
        , "inspire"
        , "install"
        , "intact"
        , "interest"
        , "into"
        , "invest"
        , "invite"
        , "involve"
        , "iron"
        , "island"
        , "isolate"
        , "issue"
        , "item"
        , "ivory"
        , "jacket"
        , "jaguar"
        , "jar"
        , "jazz"
        , "jealous"
        , "jeans"
        , "jelly"
        , "jewel"
        , "job"
        , "join"
        , "joke"
        , "journey"
        , "joy"
        , "judge"
        , "juice"
        , "jump"
        , "jungle"
        , "junior"
        , "junk"
        , "just"
        , "kangaroo"
        , "keen"
        , "keep"
        , "ketchup"
        , "key"
        , "kick"
        , "kid"
        , "kidney"
        , "kind"
        , "kingdom"
        , "kiss"
        , "kit"
        , "kitchen"
        , "kite"
        , "kitten"
        , "kiwi"
        , "knee"
        , "knife"
        , "knock"
        , "know"
        , "lab"
        , "label"
        , "labor"
        , "ladder"
        , "lady"
        , "lake"
        , "lamp"
        , "language"
        , "laptop"
        , "large"
        , "later"
        , "latin"
        , "laugh"
        , "laundry"
        , "lava"
        , "law"
        , "lawn"
        , "lawsuit"
        , "layer"
        , "lazy"
        , "leader"
        , "leaf"
        , "learn"
        , "leave"
        , "lecture"
        , "left"
        , "leg"
        , "legal"
        , "legend"
        , "leisure"
        , "lemon"
        , "lend"
        , "length"
        , "lens"
        , "leopard"
        , "lesson"
        , "letter"
        , "level"
        , "liar"
        , "liberty"
        , "library"
        , "license"
        , "life"
        , "lift"
        , "light"
        , "like"
        , "limb"
        , "limit"
        , "link"
        , "lion"
        , "liquid"
        , "list"
        , "little"
        , "live"
        , "lizard"
        , "load"
        , "loan"
        , "lobster"
        , "local"
        , "lock"
        , "logic"
        , "lonely"
        , "long"
        , "loop"
        , "lottery"
        , "loud"
        , "lounge"
        , "love"
        , "loyal"
        , "lucky"
        , "luggage"
        , "lumber"
        , "lunar"
        , "lunch"
        , "luxury"
        , "lyrics"
        , "machine"
        , "mad"
        , "magic"
        , "magnet"
        , "maid"
        , "mail"
        , "main"
        , "major"
        , "make"
        , "mammal"
        , "man"
        , "manage"
        , "mandate"
        , "mango"
        , "mansion"
        , "manual"
        , "maple"
        , "marble"
        , "march"
        , "margin"
        , "marine"
        , "market"
        , "marriage"
        , "mask"
        , "mass"
        , "master"
        , "match"
        , "material"
        , "math"
        , "matrix"
        , "matter"
        , "maximum"
        , "maze"
        , "meadow"
        , "mean"
        , "measure"
        , "meat"
        , "mechanic"
        , "medal"
        , "media"
        , "melody"
        , "melt"
        , "member"
        , "memory"
        , "mention"
        , "menu"
        , "mercy"
        , "merge"
        , "merit"
        , "merry"
        , "mesh"
        , "message"
        , "metal"
        , "method"
        , "middle"
        , "midnight"
        , "milk"
        , "million"
        , "mimic"
        , "mind"
        , "minimum"
        , "minor"
        , "minute"
        , "miracle"
        , "mirror"
        , "misery"
        , "miss"
        , "mistake"
        , "mix"
        , "mixed"
        , "mixture"
        , "mobile"
        , "model"
        , "modify"
        , "mom"
        , "moment"
        , "monitor"
        , "monkey"
        , "monster"
        , "month"
        , "moon"
        , "moral"
        , "more"
        , "morning"
        , "mosquito"
        , "mother"
        , "motion"
        , "motor"
        , "mountain"
        , "mouse"
        , "move"
        , "movie"
        , "much"
        , "muffin"
        , "mule"
        , "multiply"
        , "muscle"
        , "museum"
        , "mushroom"
        , "music"
        , "must"
        , "mutual"
        , "myself"
        , "mystery"
        , "myth"
        , "naive"
        , "name"
        , "napkin"
        , "narrow"
        , "nasty"
        , "nation"
        , "nature"
        , "near"
        , "neck"
        , "need"
        , "negative"
        , "neglect"
        , "neither"
        , "nephew"
        , "nerve"
        , "nest"
        , "net"
        , "network"
        , "neutral"
        , "never"
        , "news"
        , "next"
        , "nice"
        , "night"
        , "noble"
        , "noise"
        , "nominee"
        , "noodle"
        , "normal"
        , "north"
        , "nose"
        , "notable"
        , "note"
        , "nothing"
        , "notice"
        , "novel"
        , "now"
        , "nuclear"
        , "number"
        , "nurse"
        , "nut"
        , "oak"
        , "obey"
        , "object"
        , "oblige"
        , "obscure"
        , "observe"
        , "obtain"
        , "obvious"
        , "occur"
        , "ocean"
        , "october"
        , "odor"
        , "off"
        , "offer"
        , "office"
        , "often"
        , "oil"
        , "okay"
        , "old"
        , "olive"
        , "olympic"
        , "omit"
        , "once"
        , "one"
        , "onion"
        , "online"
        , "only"
        , "open"
        , "opera"
        , "opinion"
        , "oppose"
        , "option"
        , "orange"
        , "orbit"
        , "orchard"
        , "order"
        , "ordinary"
        , "organ"
        , "orient"
        , "original"
        , "orphan"
        , "ostrich"
        , "other"
        , "outdoor"
        , "outer"
        , "output"
        , "outside"
        , "oval"
        , "oven"
        , "over"
        , "own"
        , "owner"
        , "oxygen"
        , "oyster"
        , "ozone"
        , "pact"
        , "paddle"
        , "page"
        , "pair"
        , "palace"
        , "palm"
        , "panda"
        , "panel"
        , "panic"
        , "panther"
        , "paper"
        , "parade"
        , "parent"
        , "park"
        , "parrot"
        , "party"
        , "pass"
        , "patch"
        , "path"
        , "patient"
        , "patrol"
        , "pattern"
        , "pause"
        , "pave"
        , "payment"
        , "peace"
        , "peanut"
        , "pear"
        , "peasant"
        , "pelican"
        , "pen"
        , "penalty"
        , "pencil"
        , "people"
        , "pepper"
        , "perfect"
        , "permit"
        , "person"
        , "pet"
        , "phone"
        , "photo"
        , "phrase"
        , "physical"
        , "piano"
        , "picnic"
        , "picture"
        , "piece"
        , "pig"
        , "pigeon"
        , "pill"
        , "pilot"
        , "pink"
        , "pioneer"
        , "pipe"
        , "pistol"
        , "pitch"
        , "pizza"
        , "place"
        , "planet"
        , "plastic"
        , "plate"
        , "play"
        , "please"
        , "pledge"
        , "pluck"
        , "plug"
        , "plunge"
        , "poem"
        , "poet"
        , "point"
        , "polar"
        , "pole"
        , "police"
        , "pond"
        , "pony"
        , "pool"
        , "popular"
        , "portion"
        , "position"
        , "possible"
        , "post"
        , "potato"
        , "pottery"
        , "poverty"
        , "powder"
        , "power"
        , "practice"
        , "praise"
        , "predict"
        , "prefer"
        , "prepare"
        , "present"
        , "pretty"
        , "prevent"
        , "price"
        , "pride"
        , "primary"
        , "print"
        , "priority"
        , "prison"
        , "private"
        , "prize"
        , "problem"
        , "process"
        , "produce"
        , "profit"
        , "program"
        , "project"
        , "promote"
        , "proof"
        , "property"
        , "prosper"
        , "protect"
        , "proud"
        , "provide"
        , "public"
        , "pudding"
        , "pull"
        , "pulp"
        , "pulse"
        , "pumpkin"
        , "punch"
        , "pupil"
        , "puppy"
        , "purchase"
        , "purity"
        , "purpose"
        , "purse"
        , "push"
        , "put"
        , "puzzle"
        , "pyramid"
        , "quality"
        , "quantum"
        , "quarter"
        , "question"
        , "quick"
        , "quit"
        , "quiz"
        , "quote"
        , "rabbit"
        , "raccoon"
        , "race"
        , "rack"
        , "radar"
        , "radio"
        , "rail"
        , "rain"
        , "raise"
        , "rally"
        , "ramp"
        , "ranch"
        , "random"
        , "range"
        , "rapid"
        , "rare"
        , "rate"
        , "rather"
        , "raven"
        , "raw"
        , "razor"
        , "ready"
        , "real"
        , "reason"
        , "rebel"
        , "rebuild"
        , "recall"
        , "receive"
        , "recipe"
        , "record"
        , "recycle"
        , "reduce"
        , "reflect"
        , "reform"
        , "refuse"
        , "region"
        , "regret"
        , "regular"
        , "reject"
        , "relax"
        , "release"
        , "relief"
        , "rely"
        , "remain"
        , "remember"
        , "remind"
        , "remove"
        , "render"
        , "renew"
        , "rent"
        , "reopen"
        , "repair"
        , "repeat"
        , "replace"
        , "report"
        , "require"
        , "rescue"
        , "resemble"
        , "resist"
        , "resource"
        , "response"
        , "result"
        , "retire"
        , "retreat"
        , "return"
        , "reunion"
        , "reveal"
        , "review"
        , "reward"
        , "rhythm"
        , "rib"
        , "ribbon"
        , "rice"
        , "rich"
        , "ride"
        , "ridge"
        , "rifle"
        , "right"
        , "rigid"
        , "ring"
        , "riot"
        , "ripple"
        , "risk"
        , "ritual"
        , "rival"
        , "river"
        , "road"
        , "roast"
        , "robot"
        , "robust"
        , "rocket"
        , "romance"
        , "roof"
        , "rookie"
        , "room"
        , "rose"
        , "rotate"
        , "rough"
        , "round"
        , "route"
        , "royal"
        , "rubber"
        , "rude"
        , "rug"
        , "rule"
        , "run"
        , "runway"
        , "rural"
        , "sad"
        , "saddle"
        , "sadness"
        , "safe"
        , "sail"
        , "salad"
        , "salmon"
        , "salon"
        , "salt"
        , "salute"
        , "same"
        , "sample"
        , "sand"
        , "satisfy"
        , "satoshi"
        , "sauce"
        , "sausage"
        , "save"
        , "say"
        , "scale"
        , "scan"
        , "scare"
        , "scatter"
        , "scene"
        , "scheme"
        , "school"
        , "science"
        , "scissors"
        , "scorpion"
        , "scout"
        , "scrap"
        , "screen"
        , "script"
        , "scrub"
        , "sea"
        , "search"
        , "season"
        , "seat"
        , "second"
        , "secret"
        , "section"
        , "security"
        , "seed"
        , "seek"
        , "segment"
        , "select"
        , "sell"
        , "seminar"
        , "senior"
        , "sense"
        , "sentence"
        , "series"
        , "service"
        , "session"
        , "settle"
        , "setup"
        , "seven"
        , "shadow"
        , "shaft"
        , "shallow"
        , "share"
        , "shed"
        , "shell"
        , "sheriff"
        , "shield"
        , "shift"
        , "shine"
        , "ship"
        , "shiver"
        , "shock"
        , "shoe"
        , "shoot"
        , "shop"
        , "short"
        , "shoulder"
        , "shove"
        , "shrimp"
        , "shrug"
        , "shuffle"
        , "shy"
        , "sibling"
        , "sick"
        , "side"
        , "siege"
        , "sight"
        , "sign"
        , "silent"
        , "silk"
        , "silly"
        , "silver"
        , "similar"
        , "simple"
        , "since"
        , "sing"
        , "siren"
        , "sister"
        , "situate"
        , "six"
        , "size"
        , "skate"
        , "sketch"
        , "ski"
        , "skill"
        , "skin"
        , "skirt"
        , "skull"
        , "slab"
        , "slam"
        , "sleep"
        , "slender"
        , "slice"
        , "slide"
        , "slight"
        , "slim"
        , "slogan"
        , "slot"
        , "slow"
        , "slush"
        , "small"
        , "smart"
        , "smile"
        , "smoke"
        , "smooth"
        , "snack"
        , "snake"
        , "snap"
        , "sniff"
        , "snow"
        , "soap"
        , "soccer"
        , "social"
        , "sock"
        , "soda"
        , "soft"
        , "solar"
        , "soldier"
        , "solid"
        , "solution"
        , "solve"
        , "someone"
        , "song"
        , "soon"
        , "sorry"
        , "sort"
        , "soul"
        , "sound"
        , "soup"
        , "source"
        , "south"
        , "space"
        , "spare"
        , "spatial"
        , "spawn"
        , "speak"
        , "special"
        , "speed"
        , "spell"
        , "spend"
        , "sphere"
        , "spice"
        , "spider"
        , "spike"
        , "spin"
        , "spirit"
        , "split"
        , "spoil"
        , "sponsor"
        , "spoon"
        , "sport"
        , "spot"
        , "spray"
        , "spread"
        , "spring"
        , "spy"
        , "square"
        , "squeeze"
        , "squirrel"
        , "stable"
        , "stadium"
        , "staff"
        , "stage"
        , "stairs"
        , "stamp"
        , "stand"
        , "start"
        , "state"
        , "stay"
        , "steak"
        , "steel"
        , "stem"
        , "step"
        , "stereo"
        , "stick"
        , "still"
        , "sting"
        , "stock"
        , "stomach"
        , "stone"
        , "stool"
        , "story"
        , "stove"
        , "strategy"
        , "street"
        , "strike"
        , "strong"
        , "struggle"
        , "student"
        , "stuff"
        , "stumble"
        , "style"
        , "subject"
        , "submit"
        , "subway"
        , "success"
        , "such"
        , "sudden"
        , "suffer"
        , "sugar"
        , "suggest"
        , "suit"
        , "summer"
        , "sun"
        , "sunny"
        , "sunset"
        , "super"
        , "supply"
        , "supreme"
        , "sure"
        , "surface"
        , "surge"
        , "surprise"
        , "surround"
        , "survey"
        , "suspect"
        , "sustain"
        , "swallow"
        , "swamp"
        , "swap"
        , "swarm"
        , "swear"
        , "sweet"
        , "swift"
        , "swim"
        , "swing"
        , "switch"
        , "sword"
        , "symbol"
        , "symptom"
        , "syrup"
        , "system"
        , "table"
        , "tackle"
        , "tag"
        , "tail"
        , "talent"
        , "talk"
        , "tank"
        , "tape"
        , "target"
        , "task"
        , "taste"
        , "tattoo"
        , "taxi"
        , "teach"
        , "team"
        , "tell"
        , "ten"
        , "tenant"
        , "tennis"
        , "tent"
        , "term"
        , "test"
        , "text"
        , "thank"
        , "that"
        , "theme"
        , "then"
        , "theory"
        , "there"
        , "they"
        , "thing"
        , "this"
        , "thought"
        , "three"
        , "thrive"
        , "throw"
        , "thumb"
        , "thunder"
        , "ticket"
        , "tide"
        , "tiger"
        , "tilt"
        , "timber"
        , "time"
        , "tiny"
        , "tip"
        , "tired"
        , "tissue"
        , "title"
        , "toast"
        , "tobacco"
        , "today"
        , "toddler"
        , "toe"
        , "together"
        , "toilet"
        , "token"
        , "tomato"
        , "tomorrow"
        , "tone"
        , "tongue"
        , "tonight"
        , "tool"
        , "tooth"
        , "top"
        , "topic"
        , "topple"
        , "torch"
        , "tornado"
        , "tortoise"
        , "toss"
        , "total"
        , "tourist"
        , "toward"
        , "tower"
        , "town"
        , "toy"
        , "track"
        , "trade"
        , "traffic"
        , "tragic"
        , "train"
        , "transfer"
        , "trap"
        , "trash"
        , "travel"
        , "tray"
        , "treat"
        , "tree"
        , "trend"
        , "trial"
        , "tribe"
        , "trick"
        , "trigger"
        , "trim"
        , "trip"
        , "trophy"
        , "trouble"
        , "truck"
        , "true"
        , "truly"
        , "trumpet"
        , "trust"
        , "truth"
        , "try"
        , "tube"
        , "tuition"
        , "tumble"
        , "tuna"
        , "tunnel"
        , "turkey"
        , "turn"
        , "turtle"
        , "twelve"
        , "twenty"
        , "twice"
        , "twin"
        , "twist"
        , "two"
        , "type"
        , "typical"
        , "ugly"
        , "umbrella"
        , "unable"
        , "unaware"
        , "uncle"
        , "uncover"
        , "under"
        , "undo"
        , "unfair"
        , "unfold"
        , "unhappy"
        , "uniform"
        , "unique"
        , "unit"
        , "universe"
        , "unknown"
        , "unlock"
        , "until"
        , "unusual"
        , "unveil"
        , "update"
        , "upgrade"
        , "uphold"
        , "upon"
        , "upper"
        , "upset"
        , "urban"
        , "urge"
        , "usage"
        , "use"
        , "used"
        , "useful"
        , "useless"
        , "usual"
        , "utility"
        , "vacant"
        , "vacuum"
        , "vague"
        , "valid"
        , "valley"
        , "valve"
        , "van"
        , "vanish"
        , "vapor"
        , "various"
        , "vast"
        , "vault"
        , "vehicle"
        , "velvet"
        , "vendor"
        , "venture"
        , "venue"
        , "verb"
        , "verify"
        , "version"
        , "very"
        , "vessel"
        , "veteran"
        , "viable"
        , "vibrant"
        , "vicious"
        , "victory"
        , "video"
        , "view"
        , "village"
        , "vintage"
        , "violin"
        , "virtual"
        , "virus"
        , "visa"
        , "visit"
        , "visual"
        , "vital"
        , "vivid"
        , "vocal"
        , "voice"
        , "void"
        , "volcano"
        , "volume"
        , "vote"
        , "voyage"
        , "wage"
        , "wagon"
        , "wait"
        , "walk"
        , "wall"
        , "walnut"
        , "want"
        , "warfare"
        , "warm"
        , "warrior"
        , "wash"
        , "wasp"
        , "waste"
        , "water"
        , "wave"
        , "way"
        , "wealth"
        , "weapon"
        , "wear"
        , "weasel"
        , "weather"
        , "web"
        , "wedding"
        , "weekend"
        , "weird"
        , "welcome"
        , "west"
        , "wet"
        , "whale"
        , "what"
        , "wheat"
        , "wheel"
        , "when"
        , "where"
        , "whip"
        , "whisper"
        , "wide"
        , "width"
        , "wife"
        , "wild"
        , "will"
        , "win"
        , "window"
        , "wine"
        , "wing"
        , "wink"
        , "winner"
        , "winter"
        , "wire"
        , "wisdom"
        , "wise"
        , "wish"
        , "witness"
        , "wolf"
        , "woman"
        , "wonder"
        , "wood"
        , "wool"
        , "word"
        , "work"
        , "world"
        , "worry"
        , "worth"
        , "wrap"
        , "wreck"
        , "wrestle"
        , "wrist"
        , "write"
        , "wrong"
        , "yard"
        , "year"
        , "yellow"
        , "you"
        , "young"
        , "youth"
        , "zebra"
        , "zero"
        , "zone"
        , "zoo"
        ]