sixword 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # Sixword
2
+
3
+ Sixword implements the 6-word binary encoding created for S/Key (tm) and
4
+ standardized by RFC 2289, RFC 1760, and RFC 1751. Binary data may be
5
+ encoded using a dictionary of 2048 English words of 1-4 characters in
6
+ length. Each block of 64 bits is encoded using 6 words, which includes 2
7
+ parity bits. It is ideal for transmitting binary data such as cryptographic
8
+ keys where humans must communicate or enter the values.
9
+
10
+ ## Comparison to other encodings
11
+
12
+ - Bubble Babble does not use full words, so it is more difficult for humans to
13
+ type or communicate over the phone.
14
+
15
+ - The PGP Word List is optimized for communicating fingerprints, so it uses
16
+ much longer and more distinct words. This is less convenient when you
17
+ actually expect a human to type the whole sentence. Sixword handles error
18
+ detection with the built-in parity bits.
19
+
20
+ - Diceware is optimized for creating passphrases by a roll of standard 6-sided
21
+ dice, so it uses a word list that is a power of 6. This is not very
22
+ convenient as an encoding for arbitrary binary data.
23
+
24
+ - Base64 is well suited as a machine encoding where an ASCII transport is
25
+ desired. It is not very convenient for humans, and has no parity built in.
26
+
27
+ - Base32 is somewhat better for humans than Base64 because it is case
28
+ insensitive and doesn't include 0 or 1. However it is still not very
29
+ convenient for humans to type or visually inspect.
30
+
31
+ See also: Bubble Babble, PGP Word List, Diceware, Base64, Base32
32
+
33
+ ## Installation
34
+
35
+ Add this line to your application's Gemfile:
36
+
37
+ gem 'sixword'
38
+
39
+ And then execute:
40
+
41
+ $ bundle
42
+
43
+ Or install it yourself as:
44
+
45
+ $ gem install sixword
46
+
47
+ ## Usage
48
+
49
+ TODO: Write usage instructions here
50
+
51
+ ## Contributing
52
+
53
+ 1. Fork it
54
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
55
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
56
+ 4. Push to the branch (`git push origin my-new-feature`)
57
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/lib/sixword.rb ADDED
@@ -0,0 +1,164 @@
1
+ require_relative 'sixword/version'
2
+ require_relative 'sixword/words'
3
+
4
+ module Sixword
5
+
6
+ # Parent class for inputs that could plausibly occur at runtime.
7
+ class InputError < ArgumentError; end
8
+
9
+ class InvalidParity < InputError; end
10
+ class UnknownWord < InputError; end
11
+ class InvalidWord < InputError; end
12
+
13
+ def self.encode(byte_string)
14
+ encode_iter(byte_string).to_a
15
+ end
16
+
17
+ def self.encode_iter(byte_string)
18
+ unless block_given?
19
+ return Enumerator.new(self, :encode_iter, byte_string)
20
+ end
21
+
22
+ unless byte_string.bytesize % 8 == 0
23
+ raise ArgumentError.new(
24
+ "Must pad bytes to multiple of 8 or use pad_encode")
25
+ end
26
+
27
+ byte_string.each_byte.each_slice(8) do |slice|
28
+ encode_64_bits(slice).each do |word|
29
+ yield word
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.decode(byte_string)
35
+ raise NotImplementedErrror.new
36
+ end
37
+
38
+ def self.hex_encode(hex_string)
39
+ hex_encode_iter(hex_string).to_a
40
+ end
41
+
42
+ def self.hex_encode_iter(hex_string)
43
+ unless block_given?
44
+ return Enumerator.new(self, :hex_encode_iter, hex_string)
45
+ end
46
+ int = Integer(hex_string.gsub(/[^a-fA-F0-9]/, ''), 16)
47
+ arr = []
48
+
49
+ while int > 0
50
+ arr.unshift (int & 255)
51
+ int >>= 8
52
+ end
53
+
54
+ arr.each_slice(8) do |slice|
55
+ encode_64_bits(slice).each do |word|
56
+ yield word
57
+ end
58
+ end
59
+ end
60
+
61
+ private
62
+ def self.encode_64_bits(byte_array)
63
+ unless byte_array.length == 8
64
+ raise ArgumentError.new("Must pass an 8-byte array")
65
+ end
66
+
67
+ int = byte_array_to_int(byte_array)
68
+
69
+ parity_bits = parity_int(int)
70
+
71
+ encoded = Array.new(6)
72
+
73
+ last_index = ((int & 511) << 2) | parity_bits
74
+ encoded[5] = WORDS.fetch(last_index)
75
+ int >>= 9
76
+
77
+ 4.downto(0) do |i|
78
+ encoded[i] = WORDS.fetch(int & 2047)
79
+ int >>= 11
80
+ end
81
+
82
+ encoded
83
+ end
84
+
85
+ def self.decode_6_words(word_array)
86
+ unless word_array.length == 6
87
+ raise ArgumentError.new("Must pass a six-word array")
88
+ end
89
+
90
+ bits_array = word_array.map {|w| word_to_bits(w) }
91
+
92
+ bits_array.each do |bits|
93
+ if bits >= 2048 || bits < 0
94
+ raise RuntimeError.new("Somehow got bits of #{bits.inspect}")
95
+ end
96
+ end
97
+
98
+ int = 0
99
+ (0..4).each do |i|
100
+ int <<= 11
101
+ int += bits_array.fetch(i)
102
+ end
103
+
104
+ # slice out parity from last word
105
+ parity = bits_array.fetch(5) & 0b11
106
+ int <<= 9
107
+ int += bits_array.fetch(5) >> 2
108
+
109
+
110
+ # check parity
111
+ unless parity_int(int) == parity
112
+ raise InvalidParity.new("Parity bits do not match")
113
+ end
114
+
115
+ int
116
+ end
117
+
118
+ def self.word_to_bits(word)
119
+ word = word.upcase
120
+ return WORDS_HASH.fetch(word)
121
+ rescue KeyError
122
+ if (1..4).include?(word.length)
123
+ raise UnknownWord.new("Unknown word: #{word.inspect}")
124
+ else
125
+ raise InvalidWord.new("Word must be 1-4 chars, not #{word.inspect}")
126
+ end
127
+ end
128
+
129
+ # Compute two-bit parity on a byte array by summing each pair of bits.
130
+ def self.parity_array(byte_array)
131
+
132
+ # sum pairs of bits through the whole array
133
+ parity = 0
134
+ byte_array.each do |byte|
135
+ while byte > 0
136
+ parity += byte & 0b11
137
+ byte >>= 2
138
+ end
139
+ end
140
+
141
+ # return the least significant two bits
142
+ parity & 0b11
143
+ end
144
+
145
+ # Compute parity in a different way. TODO: figure out which is faster
146
+ def self.parity_int(int)
147
+ parity = 0
148
+ while int > 0
149
+ parity += int & 0b11
150
+ int >>= 2
151
+ end
152
+
153
+ parity & 0b11
154
+ end
155
+
156
+ def self.byte_array_to_int(byte_array)
157
+ int = 0
158
+ byte_array.each do |byte|
159
+ int <<= 8
160
+ int |= byte
161
+ end
162
+ int
163
+ end
164
+ end
@@ -0,0 +1,3 @@
1
+ module Sixword
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,266 @@
1
+ module Sixword
2
+
3
+ # Dictionary from RFC 2289 Appendix D
4
+ # http://tools.ietf.org/html/rfc2289#appendix-D
5
+ WORDS = [ "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD",
6
+ "AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY",
7
+ "AN", "ANA", "AND", "ANN", "ANT", "ANY", "APE", "APS",
8
+ "APT", "ARC", "ARE", "ARK", "ARM", "ART", "AS", "ASH",
9
+ "ASK", "AT", "ATE", "AUG", "AUK", "AVE", "AWE", "AWK",
10
+ "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM",
11
+ "BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG",
12
+ "BEN", "BET", "BEY", "BIB", "BID", "BIG", "BIN", "BIT",
13
+ "BOB", "BOG", "BON", "BOO", "BOP", "BOW", "BOY", "BUB",
14
+ "BUD", "BUG", "BUM", "BUN", "BUS", "BUT", "BUY", "BY",
15
+ "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT",
16
+ "CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT",
17
+ "COW", "COY", "CRY", "CUB", "CUE", "CUP", "CUR", "CUT",
18
+ "DAB", "DAD", "DAM", "DAN", "DAR", "DAY", "DEE", "DEL",
19
+ "DEN", "DES", "DEW", "DID", "DIE", "DIG", "DIN", "DIP",
20
+ "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB",
21
+ "DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL",
22
+ "EGG", "EGO", "ELI", "ELK", "ELM", "ELY", "EM", "END",
23
+ "EST", "ETC", "EVA", "EVE", "EWE", "EYE", "FAD", "FAN",
24
+ "FAR", "FAT", "FAY", "FED", "FEE", "FEW", "FIB", "FIG",
25
+ "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR",
26
+ "FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL",
27
+ "GAM", "GAP", "GAS", "GAY", "GEE", "GEL", "GEM", "GET",
28
+ "GIG", "GIL", "GIN", "GO", "GOT", "GUM", "GUN", "GUS",
29
+ "GUT", "GUY", "GYM", "GYP", "HA", "HAD", "HAL", "HAM",
30
+ "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM",
31
+ "HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP",
32
+ "HIS", "HIT", "HO", "HOB", "HOC", "HOE", "HOG", "HOP",
33
+ "HOT", "HOW", "HUB", "HUE", "HUG", "HUH", "HUM", "HUT",
34
+ "I", "ICY", "IDA", "IF", "IKE", "ILL", "INK", "INN",
35
+ "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT",
36
+ "ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW",
37
+ "JAY", "JET", "JIG", "JIM", "JO", "JOB", "JOE", "JOG",
38
+ "JOT", "JOY", "JUG", "JUT", "KAY", "KEG", "KEN", "KEY",
39
+ "KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC", "LAD",
40
+ "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE",
41
+ "LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN",
42
+ "LIP", "LIT", "LO", "LOB", "LOG", "LOP", "LOS", "LOT",
43
+ "LOU", "LOW", "LOY", "LUG", "LYE", "MA", "MAC", "MAD",
44
+ "MAE", "MAN", "MAO", "MAP", "MAT", "MAW", "MAY", "ME",
45
+ "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT",
46
+ "MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW",
47
+ "MUD", "MUG", "MUM", "MY", "NAB", "NAG", "NAN", "NAP",
48
+ "NAT", "NAY", "NE", "NED", "NEE", "NET", "NEW", "NIB",
49
+ "NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON", "NOR",
50
+ "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF",
51
+ "OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT",
52
+ "OH", "OIL", "OK", "OLD", "ON", "ONE", "OR", "ORB",
53
+ "ORE", "ORR", "OS", "OTT", "OUR", "OUT", "OVA", "OW",
54
+ "OWE", "OWL", "OWN", "OX", "PA", "PAD", "PAL", "PAM",
55
+ "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG",
56
+ "PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE",
57
+ "PIN", "PIT", "PLY", "PO", "POD", "POE", "POP", "POT",
58
+ "POW", "PRO", "PRY", "PUB", "PUG", "PUN", "PUP", "PUT",
59
+ "QUO", "RAG", "RAM", "RAN", "RAP", "RAT", "RAW", "RAY",
60
+ "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM",
61
+ "RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW",
62
+ "ROY", "RUB", "RUE", "RUG", "RUM", "RUN", "RYE", "SAC",
63
+ "SAD", "SAG", "SAL", "SAM", "SAN", "SAP", "SAT", "SAW",
64
+ "SAY", "SEA", "SEC", "SEE", "SEN", "SET", "SEW", "SHE",
65
+ "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY",
66
+ "SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY",
67
+ "SPA", "SPY", "SUB", "SUD", "SUE", "SUM", "SUN", "SUP",
68
+ "TAB", "TAD", "TAG", "TAN", "TAP", "TAR", "TEA", "TED",
69
+ "TEE", "TEN", "THE", "THY", "TIC", "TIE", "TIM", "TIN",
70
+ "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP",
71
+ "TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO",
72
+ "UN", "UP", "US", "USE", "VAN", "VAT", "VET", "VIE",
73
+ "WAD", "WAG", "WAR", "WAS", "WAY", "WE", "WEB", "WED",
74
+ "WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK", "WON",
75
+ "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE",
76
+ "YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE",
77
+ "ABUT", "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM",
78
+ "ADDS", "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA",
79
+ "AIDE", "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA",
80
+ "ALIA", "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA",
81
+ "AMEN", "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY",
82
+ "ANEW", "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH",
83
+ "AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS",
84
+ "ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON",
85
+ "AVOW", "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE",
86
+ "BAIL", "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL",
87
+ "BALM", "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE",
88
+ "BARK", "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE",
89
+ "BATH", "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR",
90
+ "BEAT", "BEAU", "BECK", "BEEF", "BEEN", "BEER", "BEET", "BELA",
91
+ "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT", "BESS",
92
+ "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", "BIEN", "BILE",
93
+ "BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB",
94
+ "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", "BLOW", "BLUE",
95
+ "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY",
96
+ "BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", "BOMB", "BONA",
97
+ "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", "BOOM", "BOON",
98
+ "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", "BOTH", "BOUT",
99
+ "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN", "BRAY", "BRED",
100
+ "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", "BUFF", "BULB",
101
+ "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", "BURL", "BURN",
102
+ "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE",
103
+ "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM",
104
+ "CAME", "CANE", "CANT", "CARD", "CARE", "CARL", "CARR", "CART",
105
+ "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", "CELL", "CENT",
106
+ "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF", "CHEN", "CHEW",
107
+ "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", "CHUM", "CITE",
108
+ "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY", "CLOD", "CLOG",
109
+ "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", "COCK", "COCO",
110
+ "CODA", "CODE", "CODY", "COED", "COIL", "COIN", "COKE", "COLA",
111
+ "COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON",
112
+ "COOT", "CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL",
113
+ "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB", "CROW", "CRUD",
114
+ "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", "CURB", "CURD",
115
+ "CURE", "CURL", "CURT", "CUTS", "DADE", "DALE", "DAME", "DANA",
116
+ "DANE", "DANG", "DANK", "DARE", "DARK", "DARN", "DART", "DASH",
117
+ "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS", "DEAD", "DEAF",
118
+ "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM", "DEER",
119
+ "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", "DICE",
120
+ "DIED", "DIET", "DIME", "DINE", "DING", "DINT", "DIRE", "DIRT",
121
+ "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL",
122
+ "DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA", "DOSE", "DOTE",
123
+ "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", "DRAM", "DRAW",
124
+ "DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", "DUCT", "DUEL",
125
+ "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", "DUSK", "DUST",
126
+ "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", "EASY", "EBEN",
127
+ "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", "EDNA", "EGAN",
128
+ "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", "ENDS",
129
+ "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", "FACE", "FACT",
130
+ "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG",
131
+ "FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL",
132
+ "FEET", "FELL", "FELT", "FEND", "FERN", "FEST", "FEUD", "FIEF",
133
+ "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", "FINK", "FIRE",
134
+ "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE", "FLAG", "FLAK",
135
+ "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", "FLIT", "FLOC",
136
+ "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", "FOGY", "FOIL",
137
+ "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", "FORD",
138
+ "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL",
139
+ "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM",
140
+ "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS",
141
+ "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA", "GALE", "GALL",
142
+ "GALT", "GAME", "GANG", "GARB", "GARY", "GASH", "GATE", "GAUL",
143
+ "GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE", "GENT", "GERM",
144
+ "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", "GINA", "GIRD",
145
+ "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", "GLIB", "GLOB",
146
+ "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", "GOAT",
147
+ "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF",
148
+ "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", "GRAD", "GRAY",
149
+ "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW",
150
+ "GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH", "GUST", "GWEN",
151
+ "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", "HALE", "HALF",
152
+ "HALL", "HALO", "HALT", "HAND", "HANG", "HANK", "HANS", "HARD",
153
+ "HARK", "HARM", "HART", "HASH", "HAST", "HATE", "HATH", "HAUL",
154
+ "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT", "HEBE",
155
+ "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", "HELM", "HERB",
156
+ "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE",
157
+ "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", "HIRE", "HISS",
158
+ "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT",
159
+ "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", "HOOT", "HORN",
160
+ "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", "HOYT", "HUCK",
161
+ "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", "HULL", "HUNK",
162
+ "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE", "HYMN", "IBIS",
163
+ "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", "INTO", "IONS",
164
+ "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", "ITCH", "ITEM",
165
+ "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN",
166
+ "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE",
167
+ "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE",
168
+ "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", "JUJU", "JUKE",
169
+ "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST", "JUTE", "KAHN",
170
+ "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", "KEEN", "KENO",
171
+ "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL", "KIND", "KING",
172
+ "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", "KNIT", "KNOB",
173
+ "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE",
174
+ "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE",
175
+ "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS",
176
+ "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS", "LAYS", "LEAD",
177
+ "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", "LEFT", "LEND",
178
+ "LENS", "LENT", "LEON", "LESK", "LESS", "LEST", "LETS", "LIAR",
179
+ "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", "LIFE", "LIFT",
180
+ "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB", "LIME", "LIND",
181
+ "LINE", "LINK", "LINT", "LION", "LISA", "LIST", "LIVE", "LOAD",
182
+ "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", "LOLA",
183
+ "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", "LORE", "LOSE",
184
+ "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE",
185
+ "LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE", "LURK", "LUSH",
186
+ "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", "MADE", "MAGI",
187
+ "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI", "MALL", "MALT",
188
+ "MANA", "MANN", "MANY", "MARC", "MARE", "MARK", "MARS", "MART",
189
+ "MARY", "MASH", "MASK", "MASS", "MAST", "MATE", "MATH", "MAUL",
190
+ "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", "MEET", "MELD",
191
+ "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", "MICE",
192
+ "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", "MIMI", "MIND",
193
+ "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE",
194
+ "MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL",
195
+ "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", "MOOR", "MOOT",
196
+ "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", "MOVE", "MUCH",
197
+ "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK", "MUSH", "MUST",
198
+ "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", "NAIR", "NAME",
199
+ "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", "NEAT", "NECK",
200
+ "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", "NEWS",
201
+ "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH",
202
+ "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE",
203
+ "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY",
204
+ "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY", "OLAF", "OLDY",
205
+ "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", "ONES", "ONLY",
206
+ "ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS", "OTTO", "OUCH",
207
+ "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", "OWNS", "QUAD",
208
+ "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", "RAGE", "RAID",
209
+ "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", "RATE",
210
+ "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED",
211
+ "REEF", "REEK", "REEL", "REID", "REIN", "RENA", "REND", "RENT",
212
+ "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME",
213
+ "RING", "RINK", "RISE", "RISK", "RITE", "ROAD", "ROAM", "ROAR",
214
+ "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", "ROOD", "ROOF",
215
+ "ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", "ROSY", "ROTH",
216
+ "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", "RUDE", "RUDY",
217
+ "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH", "RUSK",
218
+ "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", "SAID", "SAIL",
219
+ "SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK",
220
+ "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", "SCAT", "SCOT",
221
+ "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN",
222
+ "SEES", "SELF", "SELL", "SEND", "SENT", "SETS", "SEWN", "SHAG",
223
+ "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", "SHOD", "SHOE",
224
+ "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", "SIFT", "SIGH",
225
+ "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE", "SING", "SINK",
226
+ "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", "SKID", "SKIM",
227
+ "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", "SLED", "SLEW",
228
+ "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG",
229
+ "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB",
230
+ "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL",
231
+ "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", "SORT", "SOUL",
232
+ "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR", "STAY", "STEM",
233
+ "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", "SUDS", "SUIT",
234
+ "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF", "SWAB", "SWAG",
235
+ "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", "TACK", "TACT",
236
+ "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", "TATE",
237
+ "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET",
238
+ "TELL", "TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN",
239
+ "THAT", "THEE", "THEM", "THEN", "THEY", "THIN", "THIS", "THUD",
240
+ "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", "TILE", "TILL",
241
+ "TILT", "TIME", "TINA", "TINE", "TINT", "TINY", "TIRE", "TOAD",
242
+ "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", "TONY", "TOOK",
243
+ "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR", "TOUT", "TOWN",
244
+ "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM", "TRIO",
245
+ "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", "TUFT",
246
+ "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", "TWIG", "TWIN",
247
+ "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH",
248
+ "VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST", "VEAL", "VEDA",
249
+ "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", "VETO", "VICE",
250
+ "VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE", "WACK", "WADE",
251
+ "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", "WALL", "WALT",
252
+ "WAND", "WANE", "WANG", "WANT", "WARD", "WARM", "WARN", "WART",
253
+ "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", "WAYS", "WEAK",
254
+ "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", "WELL",
255
+ "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", "WHAT", "WHEE",
256
+ "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL",
257
+ "WIND", "WINE", "WING", "WINK", "WINO", "WIRE", "WISE", "WISH",
258
+ "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", "WORE", "WORK",
259
+ "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", "YANG", "YANK",
260
+ "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", "YELL", "YOGA",
261
+ "YOKE" ]
262
+ WORDS.freeze
263
+
264
+ WORDS_HASH = Hash[WORDS.each_with_index.to_a]
265
+ WORDS_HASH.freeze
266
+ end