UNPKG

3.95 kBJavaScriptView Raw
1var fs = require('fs')
2var assert = require('nanoassert')
3var toUint8Array = require('base64-to-uint8array')
4var buf = toUint8Array(fs.readFileSync(__dirname + '/blake2b.wasm', 'base64'))
5var rdy
6
7var head = 64
8var mod = null
9var memory = null
10var freeList = []
11
12module.exports = Blake2b
13var BYTES_MIN = module.exports.BYTES_MIN = 16
14var BYTES_MAX = module.exports.BYTES_MAX = 64
15var BYTES = module.exports.BYTES = 32
16var KEYBYTES_MIN = module.exports.KEYBYTES_MIN = 16
17var KEYBYTES_MAX = module.exports.KEYBYTES_MAX = 64
18var KEYBYTES = module.exports.KEYBYTES = 32
19var SALTBYTES = module.exports.SALTBYTES = 16
20var PERSONALBYTES = module.exports.PERSONALBYTES = 16
21
22function Blake2b (digestLength, key, salt, personal, noAssert) {
23 if (!(this instanceof Blake2b)) return new Blake2b(digestLength, key, salt, personal, noAssert)
24 if (!mod) throw new Error('WASM not loaded. Wait for Blake2b.ready(cb)')
25 if (!digestLength) digestLength = 32
26
27 if (noAssert !== true) {
28 assert(digestLength >= BYTES_MIN, 'digestLength must be at least ' + BYTES_MIN + ', was given ' + digestLength)
29 assert(digestLength <= BYTES_MAX, 'digestLength must be at most ' + BYTES_MAX + ', was given ' + digestLength)
30 if (key != null) assert(key.length >= KEYBYTES_MIN, 'key must be at least ' + KEYBYTES_MIN + ', was given ' + key.length)
31 if (key != null) assert(key.length <= KEYBYTES_MAX, 'key must be at least ' + KEYBYTES_MAX + ', was given ' + key.length)
32 if (salt != null) assert(salt.length === SALTBYTES, 'salt must be exactly ' + SALTBYTES + ', was given ' + salt.length)
33 if (personal != null) assert(personal.length === PERSONALBYTES, 'personal must be exactly ' + PERSONALBYTES + ', was given ' + personal.length)
34 }
35
36 if (!freeList.length) {
37 freeList.push(head)
38 head += 216
39 }
40
41 this.digestLength = digestLength
42 this.finalized = false
43 this.pointer = freeList.pop()
44
45 memory.fill(0, 0, 64)
46 memory[0] = this.digestLength
47 memory[1] = key ? key.length : 0
48 memory[2] = 1 // fanout
49 memory[3] = 1 // depth
50
51 if (salt) memory.set(salt, 32)
52 if (personal) memory.set(personal, 48)
53
54 mod.blake2b_init(this.pointer, this.digestLength)
55
56 if (key) {
57 this.update(key)
58 memory.fill(0, head, head + key.length) // whiteout key
59 memory[this.pointer + 200] = 128
60 }
61}
62
63Blake2b.prototype.ready = Blake2b.ready
64
65Blake2b.prototype.update = function (input) {
66 assert(this.finalized === false, 'Hash instance finalized')
67 assert(input, 'input must be TypedArray or Buffer')
68
69 memory.set(input, head)
70 mod.blake2b_update(this.pointer, head, head + input.length)
71 return this
72}
73
74Blake2b.prototype.digest = function (enc) {
75 assert(this.finalized === false, 'Hash instance finalized')
76 this.finalized = true
77
78 freeList.push(this.pointer)
79 mod.blake2b_final(this.pointer)
80
81 if (!enc || enc === 'binary') {
82 return memory.slice(this.pointer + 128, this.pointer + 128 + this.digestLength)
83 }
84
85 if (enc === 'hex') {
86 return hexSlice(memory, this.pointer + 128, this.digestLength)
87 }
88
89 assert(enc.length >= this.digestLength, 'input must be TypedArray or Buffer')
90 for (var i = 0; i < this.digestLength; i++) {
91 enc[i] = memory[this.pointer + 128 + i]
92 }
93
94 return enc
95}
96
97// libsodium compat
98Blake2b.prototype.final = Blake2b.prototype.digest
99
100Blake2b.WASM = buf
101Blake2b.SUPPORTED = typeof WebAssembly !== 'undefined'
102
103Blake2b.ready = function (cb) {
104 if (!cb) cb = noop
105 if (!Blake2b.SUPPORTED) return cb(new Error('WebAssembly not supported'))
106
107 if (!rdy) {
108 rdy = WebAssembly.instantiate(buf).then(setup)
109 }
110
111 return rdy.then(cb).catch(cb)
112}
113
114function noop () {}
115
116function hexSlice (buf, start, len) {
117 var str = ''
118 for (var i = 0; i < len; i++) str += toHex(buf[start + i])
119 return str
120}
121
122function toHex (n) {
123 if (n < 16) return '0' + n.toString(16)
124 return n.toString(16)
125}
126
127function setup (w) {
128 mod = w.instance.exports
129 memory = new Uint8Array(w.instance.exports.memory.buffer)
130}