]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2013 Pavol Rusnak | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of | |
5 | * this software and associated documentation files (the "Software"), to deal in | |
6 | * the Software without restriction, including without limitation the rights to | |
7 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
8 | * of the Software, and to permit persons to whom the Software is furnished to do | |
9 | * so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in all | |
12 | * copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
19 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
20 | */ | |
21 | ||
22 | /* | |
23 | * Javascript port from python by Ian Coleman | |
24 | * | |
25 | * Includes code from asmCrypto | |
26 | * https://github.com/tresorit/asmcrypto.js | |
27 | */ | |
28 | ||
29 | var Mnemonic = function(language) { | |
30 | ||
31 | var PBKDF2_ROUNDS = 2048; | |
32 | var RADIX = 2048; | |
33 | ||
34 | var self = this; | |
35 | var wordlist = []; | |
36 | ||
37 | function init() { | |
38 | wordlist = WORDLISTS[language]; | |
39 | if (wordlist.length != RADIX) { | |
40 | err = 'Wordlist should contain ' + RADIX + ' words, but it contains ' + wordlist.length + ' words.'; | |
41 | throw err; | |
42 | } | |
43 | } | |
44 | ||
45 | self.generate = function(strength) { | |
46 | strength = strength || 128; | |
47 | var r = strength % 32; | |
48 | if (r > 0) { | |
49 | throw 'Strength should be divisible by 32, but it is not (' + r + ').'; | |
50 | } | |
51 | var hasStrongCrypto = 'crypto' in window && window['crypto'] !== null; | |
52 | if (!hasStrongCrypto) { | |
53 | throw 'Mnemonic should be generated with strong randomness, but crypto.getRandomValues is unavailable'; | |
54 | } | |
55 | var buffer = new Uint8Array(strength / 8); | |
56 | var data = crypto.getRandomValues(buffer); | |
57 | return self.toMnemonic(data); | |
58 | } | |
59 | ||
60 | self.toMnemonic = function(data) { | |
61 | if (data.length % 4 > 0) { | |
62 | throw 'Data length in bits should be divisible by 32, but it is not (' + data.length + ' bytes = ' + data.length*8 + ' bits).' | |
63 | } | |
64 | ||
65 | //h = hashlib.sha256(data).hexdigest() | |
66 | var uintArray = new Uint8Array(data); | |
67 | var h = asmCrypto.SHA256.bytes(uintArray); | |
68 | ||
69 | // b is a binary string, eg '00111010101100...' | |
70 | //b = bin(int(binascii.hexlify(data), 16))[2:].zfill(len(data) * 8) + \ | |
71 | // bin(int(h, 16))[2:].zfill(256)[:len(data) * 8 / 32] | |
72 | // | |
73 | // a = bin(int(binascii.hexlify(data), 16))[2:].zfill(len(data) * 8) | |
74 | // c = bin(int(h, 16))[2:].zfill(256) | |
75 | // d = c[:len(data) * 8 / 32] | |
76 | var a = byteArrayToBinaryString(data); | |
77 | var c = byteArrayToBinaryString(h); | |
78 | var d = c.substring(0, data.length * 8 / 32); | |
79 | // b = line1 + line2 | |
80 | var b = a + d; | |
81 | ||
82 | var result = []; | |
83 | var blen = b.length / 11; | |
84 | for (var i=0; i<blen; i++) { | |
85 | var idx = parseInt(b.substring(i * 11, (i + 1) * 11), 2); | |
86 | result.push(wordlist[idx]); | |
87 | } | |
88 | return result.join(' '); | |
89 | } | |
90 | ||
91 | self.check = function(mnemonic) { | |
92 | var mnemonic = mnemonic.split(' ') | |
93 | if (mnemonic.length % 3 > 0) { | |
94 | return false | |
95 | } | |
96 | // idx = map(lambda x: bin(self.wordlist.index(x))[2:].zfill(11), mnemonic) | |
97 | var idx = []; | |
98 | for (var i=0; i<mnemonic.length; i++) { | |
99 | var word = mnemonic[i]; | |
100 | var wordIndex = wordlist.indexOf(word); | |
101 | if (wordIndex == -1) { | |
102 | return false; | |
103 | } | |
104 | var binaryIndex = zfill(wordIndex.toString(2), 11); | |
105 | idx.push(binaryIndex); | |
106 | } | |
107 | var b = idx.join(''); | |
108 | var l = b.length; | |
109 | //d = b[:l / 33 * 32] | |
110 | //h = b[-l / 33:] | |
111 | var d = b.substring(0, l / 33 * 32); | |
112 | var h = b.substring(l - l / 33, l); | |
113 | //nd = binascii.unhexlify(hex(int(d, 2))[2:].rstrip('L').zfill(l / 33 * 8)) | |
114 | //nh = bin(int(hashlib.sha256(nd).hexdigest(), 16))[2:].zfill(256)[:l / 33] | |
115 | var nd = binaryStringToByteArray(d); | |
116 | var ndHash = asmCrypto.SHA256.bytes(nd); | |
117 | var ndBstr = zfill(byteArrayToBinaryString(ndHash), 256); | |
118 | var nh = ndBstr.substring(0,l/33); | |
119 | return h == nh; | |
120 | } | |
121 | ||
122 | self.toSeed = function(mnemonic, passphrase) { | |
123 | passphrase = passphrase || ''; | |
124 | mnemonic = normalizeString(mnemonic) | |
125 | passphrase = normalizeString(passphrase) | |
126 | passphrase = "mnemonic" + passphrase; | |
127 | //return PBKDF2(mnemonic, 'mnemonic' + passphrase, iterations=PBKDF2_ROUNDS, macmodule=hmac, digestmodule=hashlib.sha512).read(64) | |
128 | return asmCrypto.PBKDF2_HMAC_SHA512.hex(mnemonic, passphrase, PBKDF2_ROUNDS, 512/8); | |
129 | } | |
130 | ||
131 | function normalizeString(str) { | |
132 | if (typeof str.normalize == "function") { | |
133 | return str.normalize("NFKD"); | |
134 | } | |
135 | else { | |
136 | // TODO find a library to do this | |
137 | // Not supported on firefox mobile | |
138 | console.warn("NFKD Normalization is unavailable"); | |
139 | return str; | |
140 | } | |
141 | } | |
142 | ||
143 | function byteArrayToBinaryString(data) { | |
144 | var bin = ""; | |
145 | for (var i=0; i<data.length; i++) { | |
146 | bin += zfill(data[i].toString(2), 8); | |
147 | } | |
148 | return bin; | |
149 | } | |
150 | ||
151 | function binaryStringToByteArray(str) { | |
152 | var arrayLen = str.length / 8; | |
153 | var array = new Uint8Array(arrayLen); | |
154 | for (var i=0; i<arrayLen; i++) { | |
155 | var valueStr = str.substring(0,8); | |
156 | var value = parseInt(valueStr, 2); | |
157 | array[i] = value; | |
158 | str = str.slice(8); | |
159 | } | |
160 | return array; | |
161 | } | |
162 | ||
163 | // Pad a numeric string on the left with zero digits until the given width | |
164 | // is reached. | |
165 | // Note this differs to the python implementation because it does not | |
166 | // handle numbers starting with a sign. | |
167 | function zfill(source, length) { | |
168 | source = source.toString(); | |
169 | while (source.length < length) { | |
170 | source = '0' + source; | |
171 | } | |
172 | return source; | |
173 | } | |
174 | ||
175 | init(); | |
176 | ||
177 | } | |
178 | ||
179 | WORDLISTS = { | |
180 | "english": [ | |
181 | "abandon","ability","able","about","above","absent","absorb","abstract","absurd","abuse", | |
182 | "access","accident","account","accuse","achieve","acid","acoustic","acquire","across","act", | |
183 | "action","actor","actress","actual","adapt","add","addict","address","adjust","admit", | |
184 | "adult","advance","advice","aerobic","affair","afford","afraid","again","age","agent", | |
185 | "agree","ahead","aim","air","airport","aisle","alarm","album","alcohol","alert", | |
186 | "alien","all","alley","allow","almost","alone","alpha","already","also","alter", | |
187 | "always","amateur","amazing","among","amount","amused","analyst","anchor","ancient","anger", | |
188 | "angle","angry","animal","ankle","announce","annual","another","answer","antenna","antique", | |
189 | "anxiety","any","apart","apology","appear","apple","approve","april","arch","arctic", | |
190 | "area","arena","argue","arm","armed","armor","army","around","arrange","arrest", | |
191 | "arrive","arrow","art","artefact","artist","artwork","ask","aspect","assault","asset", | |
192 | "assist","assume","asthma","athlete","atom","attack","attend","attitude","attract","auction", | |
193 | "audit","august","aunt","author","auto","autumn","average","avocado","avoid","awake", | |
194 | "aware","away","awesome","awful","awkward","axis","baby","bachelor","bacon","badge", | |
195 | "bag","balance","balcony","ball","bamboo","banana","banner","bar","barely","bargain", | |
196 | "barrel","base","basic","basket","battle","beach","bean","beauty","because","become", | |
197 | "beef","before","begin","behave","behind","believe","below","belt","bench","benefit", | |
198 | "best","betray","better","between","beyond","bicycle","bid","bike","bind","biology", | |
199 | "bird","birth","bitter","black","blade","blame","blanket","blast","bleak","bless", | |
200 | "blind","blood","blossom","blouse","blue","blur","blush","board","boat","body", | |
201 | "boil","bomb","bone","bonus","book","boost","border","boring","borrow","boss", | |
202 | "bottom","bounce","box","boy","bracket","brain","brand","brass","brave","bread", | |
203 | "breeze","brick","bridge","brief","bright","bring","brisk","broccoli","broken","bronze", | |
204 | "broom","brother","brown","brush","bubble","buddy","budget","buffalo","build","bulb", | |
205 | "bulk","bullet","bundle","bunker","burden","burger","burst","bus","business","busy", | |
206 | "butter","buyer","buzz","cabbage","cabin","cable","cactus","cage","cake","call", | |
207 | "calm","camera","camp","can","canal","cancel","candy","cannon","canoe","canvas", | |
208 | "canyon","capable","capital","captain","car","carbon","card","cargo","carpet","carry", | |
209 | "cart","case","cash","casino","castle","casual","cat","catalog","catch","category", | |
210 | "cattle","caught","cause","caution","cave","ceiling","celery","cement","census","century", | |
211 | "cereal","certain","chair","chalk","champion","change","chaos","chapter","charge","chase", | |
212 | "chat","cheap","check","cheese","chef","cherry","chest","chicken","chief","child", | |
213 | "chimney","choice","choose","chronic","chuckle","chunk","churn","cigar","cinnamon","circle", | |
214 | "citizen","city","civil","claim","clap","clarify","claw","clay","clean","clerk", | |
215 | "clever","click","client","cliff","climb","clinic","clip","clock","clog","close", | |
216 | "cloth","cloud","clown","club","clump","cluster","clutch","coach","coast","coconut", | |
217 | "code","coffee","coil","coin","collect","color","column","combine","come","comfort", | |
218 | "comic","common","company","concert","conduct","confirm","congress","connect","consider","control", | |
219 | "convince","cook","cool","copper","copy","coral","core","corn","correct","cost", | |
220 | "cotton","couch","country","couple","course","cousin","cover","coyote","crack","cradle", | |
221 | "craft","cram","crane","crash","crater","crawl","crazy","cream","credit","creek", | |
222 | "crew","cricket","crime","crisp","critic","crop","cross","crouch","crowd","crucial", | |
223 | "cruel","cruise","crumble","crunch","crush","cry","crystal","cube","culture","cup", | |
224 | "cupboard","curious","current","curtain","curve","cushion","custom","cute","cycle","dad", | |
225 | "damage","damp","dance","danger","daring","dash","daughter","dawn","day","deal", | |
226 | "debate","debris","decade","december","decide","decline","decorate","decrease","deer","defense", | |
227 | "define","defy","degree","delay","deliver","demand","demise","denial","dentist","deny", | |
228 | "depart","depend","deposit","depth","deputy","derive","describe","desert","design","desk", | |
229 | "despair","destroy","detail","detect","develop","device","devote","diagram","dial","diamond", | |
230 | "diary","dice","diesel","diet","differ","digital","dignity","dilemma","dinner","dinosaur", | |
231 | "direct","dirt","disagree","discover","disease","dish","dismiss","disorder","display","distance", | |
232 | "divert","divide","divorce","dizzy","doctor","document","dog","doll","dolphin","domain", | |
233 | "donate","donkey","donor","door","dose","double","dove","draft","dragon","drama", | |
234 | "drastic","draw","dream","dress","drift","drill","drink","drip","drive","drop", | |
235 | "drum","dry","duck","dumb","dune","during","dust","dutch","duty","dwarf", | |
236 | "dynamic","eager","eagle","early","earn","earth","easily","east","easy","echo", | |
237 | "ecology","economy","edge","edit","educate","effort","egg","eight","either","elbow", | |
238 | "elder","electric","elegant","element","elephant","elevator","elite","else","embark","embody", | |
239 | "embrace","emerge","emotion","employ","empower","empty","enable","enact","end","endless", | |
240 | "endorse","enemy","energy","enforce","engage","engine","enhance","enjoy","enlist","enough", | |
241 | "enrich","enroll","ensure","enter","entire","entry","envelope","episode","equal","equip", | |
242 | "era","erase","erode","erosion","error","erupt","escape","essay","essence","estate", | |
243 | "eternal","ethics","evidence","evil","evoke","evolve","exact","example","excess","exchange", | |
244 | "excite","exclude","excuse","execute","exercise","exhaust","exhibit","exile","exist","exit", | |
245 | "exotic","expand","expect","expire","explain","expose","express","extend","extra","eye", | |
246 | "eyebrow","fabric","face","faculty","fade","faint","faith","fall","false","fame", | |
247 | "family","famous","fan","fancy","fantasy","farm","fashion","fat","fatal","father", | |
248 | "fatigue","fault","favorite","feature","february","federal","fee","feed","feel","female", | |
249 | "fence","festival","fetch","fever","few","fiber","fiction","field","figure","file", | |
250 | "film","filter","final","find","fine","finger","finish","fire","firm","first", | |
251 | "fiscal","fish","fit","fitness","fix","flag","flame","flash","flat","flavor", | |
252 | "flee","flight","flip","float","flock","floor","flower","fluid","flush","fly", | |
253 | "foam","focus","fog","foil","fold","follow","food","foot","force","forest", | |
254 | "forget","fork","fortune","forum","forward","fossil","foster","found","fox","fragile", | |
255 | "frame","frequent","fresh","friend","fringe","frog","front","frost","frown","frozen", | |
256 | "fruit","fuel","fun","funny","furnace","fury","future","gadget","gain","galaxy", | |
257 | "gallery","game","gap","garage","garbage","garden","garlic","garment","gas","gasp", | |
258 | "gate","gather","gauge","gaze","general","genius","genre","gentle","genuine","gesture", | |
259 | "ghost","giant","gift","giggle","ginger","giraffe","girl","give","glad","glance", | |
260 | "glare","glass","glide","glimpse","globe","gloom","glory","glove","glow","glue", | |
261 | "goat","goddess","gold","good","goose","gorilla","gospel","gossip","govern","gown", | |
262 | "grab","grace","grain","grant","grape","grass","gravity","great","green","grid", | |
263 | "grief","grit","grocery","group","grow","grunt","guard","guess","guide","guilt", | |
264 | "guitar","gun","gym","habit","hair","half","hammer","hamster","hand","happy", | |
265 | "harbor","hard","harsh","harvest","hat","have","hawk","hazard","head","health", | |
266 | "heart","heavy","hedgehog","height","hello","helmet","help","hen","hero","hidden", | |
267 | "high","hill","hint","hip","hire","history","hobby","hockey","hold","hole", | |
268 | "holiday","hollow","home","honey","hood","hope","horn","horror","horse","hospital", | |
269 | "host","hotel","hour","hover","hub","huge","human","humble","humor","hundred", | |
270 | "hungry","hunt","hurdle","hurry","hurt","husband","hybrid","ice","icon","idea", | |
271 | "identify","idle","ignore","ill","illegal","illness","image","imitate","immense","immune", | |
272 | "impact","impose","improve","impulse","inch","include","income","increase","index","indicate", | |
273 | "indoor","industry","infant","inflict","inform","inhale","inherit","initial","inject","injury", | |
274 | "inmate","inner","innocent","input","inquiry","insane","insect","inside","inspire","install", | |
275 | "intact","interest","into","invest","invite","involve","iron","island","isolate","issue", | |
276 | "item","ivory","jacket","jaguar","jar","jazz","jealous","jeans","jelly","jewel", | |
277 | "job","join","joke","journey","joy","judge","juice","jump","jungle","junior", | |
278 | "junk","just","kangaroo","keen","keep","ketchup","key","kick","kid","kidney", | |
279 | "kind","kingdom","kiss","kit","kitchen","kite","kitten","kiwi","knee","knife", | |
280 | "knock","know","lab","label","labor","ladder","lady","lake","lamp","language", | |
281 | "laptop","large","later","latin","laugh","laundry","lava","law","lawn","lawsuit", | |
282 | "layer","lazy","leader","leaf","learn","leave","lecture","left","leg","legal", | |
283 | "legend","leisure","lemon","lend","length","lens","leopard","lesson","letter","level", | |
284 | "liar","liberty","library","license","life","lift","light","like","limb","limit", | |
285 | "link","lion","liquid","list","little","live","lizard","load","loan","lobster", | |
286 | "local","lock","logic","lonely","long","loop","lottery","loud","lounge","love", | |
287 | "loyal","lucky","luggage","lumber","lunar","lunch","luxury","lyrics","machine","mad", | |
288 | "magic","magnet","maid","mail","main","major","make","mammal","man","manage", | |
289 | "mandate","mango","mansion","manual","maple","marble","march","margin","marine","market", | |
290 | "marriage","mask","mass","master","match","material","math","matrix","matter","maximum", | |
291 | "maze","meadow","mean","measure","meat","mechanic","medal","media","melody","melt", | |
292 | "member","memory","mention","menu","mercy","merge","merit","merry","mesh","message", | |
293 | "metal","method","middle","midnight","milk","million","mimic","mind","minimum","minor", | |
294 | "minute","miracle","mirror","misery","miss","mistake","mix","mixed","mixture","mobile", | |
295 | "model","modify","mom","moment","monitor","monkey","monster","month","moon","moral", | |
296 | "more","morning","mosquito","mother","motion","motor","mountain","mouse","move","movie", | |
297 | "much","muffin","mule","multiply","muscle","museum","mushroom","music","must","mutual", | |
298 | "myself","mystery","myth","naive","name","napkin","narrow","nasty","nation","nature", | |
299 | "near","neck","need","negative","neglect","neither","nephew","nerve","nest","net", | |
300 | "network","neutral","never","news","next","nice","night","noble","noise","nominee", | |
301 | "noodle","normal","north","nose","notable","note","nothing","notice","novel","now", | |
302 | "nuclear","number","nurse","nut","oak","obey","object","oblige","obscure","observe", | |
303 | "obtain","obvious","occur","ocean","october","odor","off","offer","office","often", | |
304 | "oil","okay","old","olive","olympic","omit","once","one","onion","online", | |
305 | "only","open","opera","opinion","oppose","option","orange","orbit","orchard","order", | |
306 | "ordinary","organ","orient","original","orphan","ostrich","other","outdoor","outer","output", | |
307 | "outside","oval","oven","over","own","owner","oxygen","oyster","ozone","pact", | |
308 | "paddle","page","pair","palace","palm","panda","panel","panic","panther","paper", | |
309 | "parade","parent","park","parrot","party","pass","patch","path","patient","patrol", | |
310 | "pattern","pause","pave","payment","peace","peanut","pear","peasant","pelican","pen", | |
311 | "penalty","pencil","people","pepper","perfect","permit","person","pet","phone","photo", | |
312 | "phrase","physical","piano","picnic","picture","piece","pig","pigeon","pill","pilot", | |
313 | "pink","pioneer","pipe","pistol","pitch","pizza","place","planet","plastic","plate", | |
314 | "play","please","pledge","pluck","plug","plunge","poem","poet","point","polar", | |
315 | "pole","police","pond","pony","pool","popular","portion","position","possible","post", | |
316 | "potato","pottery","poverty","powder","power","practice","praise","predict","prefer","prepare", | |
317 | "present","pretty","prevent","price","pride","primary","print","priority","prison","private", | |
318 | "prize","problem","process","produce","profit","program","project","promote","proof","property", | |
319 | "prosper","protect","proud","provide","public","pudding","pull","pulp","pulse","pumpkin", | |
320 | "punch","pupil","puppy","purchase","purity","purpose","purse","push","put","puzzle", | |
321 | "pyramid","quality","quantum","quarter","question","quick","quit","quiz","quote","rabbit", | |
322 | "raccoon","race","rack","radar","radio","rail","rain","raise","rally","ramp", | |
323 | "ranch","random","range","rapid","rare","rate","rather","raven","raw","razor", | |
324 | "ready","real","reason","rebel","rebuild","recall","receive","recipe","record","recycle", | |
325 | "reduce","reflect","reform","refuse","region","regret","regular","reject","relax","release", | |
326 | "relief","rely","remain","remember","remind","remove","render","renew","rent","reopen", | |
327 | "repair","repeat","replace","report","require","rescue","resemble","resist","resource","response", | |
328 | "result","retire","retreat","return","reunion","reveal","review","reward","rhythm","rib", | |
329 | "ribbon","rice","rich","ride","ridge","rifle","right","rigid","ring","riot", | |
330 | "ripple","risk","ritual","rival","river","road","roast","robot","robust","rocket", | |
331 | "romance","roof","rookie","room","rose","rotate","rough","round","route","royal", | |
332 | "rubber","rude","rug","rule","run","runway","rural","sad","saddle","sadness", | |
333 | "safe","sail","salad","salmon","salon","salt","salute","same","sample","sand", | |
334 | "satisfy","satoshi","sauce","sausage","save","say","scale","scan","scare","scatter", | |
335 | "scene","scheme","school","science","scissors","scorpion","scout","scrap","screen","script", | |
336 | "scrub","sea","search","season","seat","second","secret","section","security","seed", | |
337 | "seek","segment","select","sell","seminar","senior","sense","sentence","series","service", | |
338 | "session","settle","setup","seven","shadow","shaft","shallow","share","shed","shell", | |
339 | "sheriff","shield","shift","shine","ship","shiver","shock","shoe","shoot","shop", | |
340 | "short","shoulder","shove","shrimp","shrug","shuffle","shy","sibling","sick","side", | |
341 | "siege","sight","sign","silent","silk","silly","silver","similar","simple","since", | |
342 | "sing","siren","sister","situate","six","size","skate","sketch","ski","skill", | |
343 | "skin","skirt","skull","slab","slam","sleep","slender","slice","slide","slight", | |
344 | "slim","slogan","slot","slow","slush","small","smart","smile","smoke","smooth", | |
345 | "snack","snake","snap","sniff","snow","soap","soccer","social","sock","soda", | |
346 | "soft","solar","soldier","solid","solution","solve","someone","song","soon","sorry", | |
347 | "sort","soul","sound","soup","source","south","space","spare","spatial","spawn", | |
348 | "speak","special","speed","spell","spend","sphere","spice","spider","spike","spin", | |
349 | "spirit","split","spoil","sponsor","spoon","sport","spot","spray","spread","spring", | |
350 | "spy","square","squeeze","squirrel","stable","stadium","staff","stage","stairs","stamp", | |
351 | "stand","start","state","stay","steak","steel","stem","step","stereo","stick", | |
352 | "still","sting","stock","stomach","stone","stool","story","stove","strategy","street", | |
353 | "strike","strong","struggle","student","stuff","stumble","style","subject","submit","subway", | |
354 | "success","such","sudden","suffer","sugar","suggest","suit","summer","sun","sunny", | |
355 | "sunset","super","supply","supreme","sure","surface","surge","surprise","surround","survey", | |
356 | "suspect","sustain","swallow","swamp","swap","swarm","swear","sweet","swift","swim", | |
357 | "swing","switch","sword","symbol","symptom","syrup","system","table","tackle","tag", | |
358 | "tail","talent","talk","tank","tape","target","task","taste","tattoo","taxi", | |
359 | "teach","team","tell","ten","tenant","tennis","tent","term","test","text", | |
360 | "thank","that","theme","then","theory","there","they","thing","this","thought", | |
361 | "three","thrive","throw","thumb","thunder","ticket","tide","tiger","tilt","timber", | |
362 | "time","tiny","tip","tired","tissue","title","toast","tobacco","today","toddler", | |
363 | "toe","together","toilet","token","tomato","tomorrow","tone","tongue","tonight","tool", | |
364 | "tooth","top","topic","topple","torch","tornado","tortoise","toss","total","tourist", | |
365 | "toward","tower","town","toy","track","trade","traffic","tragic","train","transfer", | |
366 | "trap","trash","travel","tray","treat","tree","trend","trial","tribe","trick", | |
367 | "trigger","trim","trip","trophy","trouble","truck","true","truly","trumpet","trust", | |
368 | "truth","try","tube","tuition","tumble","tuna","tunnel","turkey","turn","turtle", | |
369 | "twelve","twenty","twice","twin","twist","two","type","typical","ugly","umbrella", | |
370 | "unable","unaware","uncle","uncover","under","undo","unfair","unfold","unhappy","uniform", | |
371 | "unique","unit","universe","unknown","unlock","until","unusual","unveil","update","upgrade", | |
372 | "uphold","upon","upper","upset","urban","urge","usage","use","used","useful", | |
373 | "useless","usual","utility","vacant","vacuum","vague","valid","valley","valve","van", | |
374 | "vanish","vapor","various","vast","vault","vehicle","velvet","vendor","venture","venue", | |
375 | "verb","verify","version","very","vessel","veteran","viable","vibrant","vicious","victory", | |
376 | "video","view","village","vintage","violin","virtual","virus","visa","visit","visual", | |
377 | "vital","vivid","vocal","voice","void","volcano","volume","vote","voyage","wage", | |
378 | "wagon","wait","walk","wall","walnut","want","warfare","warm","warrior","wash", | |
379 | "wasp","waste","water","wave","way","wealth","weapon","wear","weasel","weather", | |
380 | "web","wedding","weekend","weird","welcome","west","wet","whale","what","wheat", | |
381 | "wheel","when","where","whip","whisper","wide","width","wife","wild","will", | |
382 | "win","window","wine","wing","wink","winner","winter","wire","wisdom","wise", | |
383 | "wish","witness","wolf","woman","wonder","wood","wool","word","work","world", | |
384 | "worry","worth","wrap","wreck","wrestle","wrist","write","wrong","yard","year", | |
385 | "yellow","you","young","youth","zebra","zero","zone","zoo"] | |
386 | }; |