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/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +676 -0
- data/README.md +57 -0
- data/Rakefile +1 -0
- data/lib/sixword.rb +164 -0
- data/lib/sixword/version.rb +3 -0
- data/lib/sixword/words.rb +266 -0
- data/sixword.gemspec +32 -0
- metadata +94 -0
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,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
|