forked from shabda/humanhash-coffeescript
-
Notifications
You must be signed in to change notification settings - Fork 1
/
firebase-humanhash.coffee
83 lines (75 loc) · 4.14 KB
/
firebase-humanhash.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
((root, factory) ->
if typeof define is "function" and define.amd
define [], factory
else if typeof exports is "object"
module.exports = factory()
else
root.HH = factory()
return
) this, ->
"use strict"
DEFAULT_WORDLIST = [
"ack", "alabama", "alanine", "alaska", "alpha", "angel", "apart", "april",
"arizona", "arkansas", "artist", "asparagus", "aspen", "august", "autumn",
"avocado", "bacon", "bakerloo", "batman", "beer", "berlin", "beryllium",
"black", "blossom", "blue", "bluebird", "bravo", "bulldog", "burger",
"butter", "california", "carbon", "cardinal", "carolina", "carpet", "cat",
"ceiling", "charlie", "chicken", "coffee", "cola", "cold", "colorado",
"comet", "connecticut", "crazy", "cup", "dakota", "december", "delaware",
"delta", "diet", "don", "double", "early", "earth", "east", "echo",
"edward", "eight", "eighteen", "eleven", "emma", "enemy", "equal",
"failed", "fanta", "fifteen", "fillet", "finch", "fish", "five", "fix",
"floor", "florida", "football", "four", "fourteen", "foxtrot", "freddie",
"friend", "fruit", "gee", "georgia", "glucose", "golf", "green", "grey",
"hamper", "happy", "harry", "hawaii", "helium", "high", "hot", "hotel",
"hydrogen", "idaho", "illinois", "india", "indigo", "ink", "iowa",
"island", "item", "jersey", "jig", "johnny", "juliet", "july", "jupiter",
"kansas", "kentucky", "kilo", "king", "kitten", "lactose", "lake", "lamp",
"lemon", "leopard", "lima", "lion", "lithium", "london", "louisiana",
"low", "magazine", "magnesium", "maine", "mango", "march", "mars",
"maryland", "massachusetts", "may", "mexico", "michigan", "mike",
"minnesota", "mirror", "mississippi", "missouri", "mobile", "mockingbird",
"monkey", "montana", "moon", "mountain", "muppet", "music", "nebraska",
"neptune", "network", "nevada", "nine", "nineteen", "nitrogen", "north",
"november", "nuts", "october", "ohio", "oklahoma", "one", "orange",
"oranges", "oregon", "oscar", "oven", "oxygen", "papa", "paris", "pasta",
"pennsylvania", "pip", "pizza", "pluto", "potato", "princess", "purple",
"quebec", "queen", "quiet", "red", "river", "robert", "robin", "romeo",
"rugby", "sad", "salami", "saturn", "september", "seven", "seventeen",
"shade", "sierra", "single", "sink", "six", "sixteen", "skylark", "snake",
"social", "sodium", "solar", "south", "spaghetti", "speaker", "spring",
"stairway", "steak", "stream", "summer", "sweet", "table", "tango", "ten",
"tennessee", "tennis", "texas", "thirteen", "three", "timing", "triple",
"twelve", "twenty", "two", "uncle", "undress", "uniform", "uranus", "utah",
"vegan", "venus", "vermont", "victor", "video", "violet", "virginia",
"washington", "west", "whiskey", "white", "william", "winner", "winter",
"wisconsin", "wolfram", "wyoming", "xray", "yankee", "yellow", "zebra",
"zulu"]
NUMBER_WORDLIST = [0..255].map (n) -> ("000" + n.toString()).slice(-3)
class HumanHasher
constructor: (@wordlist=DEFAULT_WORDLIST) ->
throw "Wordlist must have exactly 256 items" if @wordlist.length isnt 256
bytes = (digest) ->
zips = []
for el, i in digest
if i isnt digest.length-1 and i%2 is 0
zips.push [digest[i], digest[i+1]]
parseInt el.join(""), 16 for el in zips
xor = (iterable) ->
start = 0
start ^= el for el in iterable
start
compress = (bytes, target) ->
seg_size = parseInt bytes.length / target
segments = (bytes[i*seg_size...(i+1)*seg_size] for i in [0...target])
last = segments[target-1]
last.push.apply last, bytes[target*seg_size..]
segments = (xor el for el in segments)
humanize: (push_id, words=4, separator="-") ->
throw "Words must be between 1 and 19" if words < 1 or words > 19
in_bytes = bytes (push_id.slice(1).split("").map (c) -> c.charCodeAt(0).toString 16).join ""
compressed = compress in_bytes, words
(@wordlist[el] for el in compressed).join separator
DEFAULT_WORDLIST: DEFAULT_WORDLIST
NUMBER_WORDLIST: NUMBER_WORDLIST
HumanHasher: HumanHasher