UNPKG

9.29 kBJavaScriptView Raw
1var assert = require('nanoassert')
2var b2wasm = require('blake2b-wasm')
3
4// 64-bit unsigned addition
5// Sets v[a,a+1] += v[b,b+1]
6// v should be a Uint32Array
7function ADD64AA (v, a, b) {
8 var o0 = v[a] + v[b]
9 var o1 = v[a + 1] + v[b + 1]
10 if (o0 >= 0x100000000) {
11 o1++
12 }
13 v[a] = o0
14 v[a + 1] = o1
15}
16
17// 64-bit unsigned addition
18// Sets v[a,a+1] += b
19// b0 is the low 32 bits of b, b1 represents the high 32 bits
20function ADD64AC (v, a, b0, b1) {
21 var o0 = v[a] + b0
22 if (b0 < 0) {
23 o0 += 0x100000000
24 }
25 var o1 = v[a + 1] + b1
26 if (o0 >= 0x100000000) {
27 o1++
28 }
29 v[a] = o0
30 v[a + 1] = o1
31}
32
33// Little-endian byte access
34function B2B_GET32 (arr, i) {
35 return (arr[i] ^
36 (arr[i + 1] << 8) ^
37 (arr[i + 2] << 16) ^
38 (arr[i + 3] << 24))
39}
40
41// G Mixing function
42// The ROTRs are inlined for speed
43function B2B_G (a, b, c, d, ix, iy) {
44 var x0 = m[ix]
45 var x1 = m[ix + 1]
46 var y0 = m[iy]
47 var y1 = m[iy + 1]
48
49 ADD64AA(v, a, b) // v[a,a+1] += v[b,b+1] ... in JS we must store a uint64 as two uint32s
50 ADD64AC(v, a, x0, x1) // v[a, a+1] += x ... x0 is the low 32 bits of x, x1 is the high 32 bits
51
52 // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated to the right by 32 bits
53 var xor0 = v[d] ^ v[a]
54 var xor1 = v[d + 1] ^ v[a + 1]
55 v[d] = xor1
56 v[d + 1] = xor0
57
58 ADD64AA(v, c, d)
59
60 // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 24 bits
61 xor0 = v[b] ^ v[c]
62 xor1 = v[b + 1] ^ v[c + 1]
63 v[b] = (xor0 >>> 24) ^ (xor1 << 8)
64 v[b + 1] = (xor1 >>> 24) ^ (xor0 << 8)
65
66 ADD64AA(v, a, b)
67 ADD64AC(v, a, y0, y1)
68
69 // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated right by 16 bits
70 xor0 = v[d] ^ v[a]
71 xor1 = v[d + 1] ^ v[a + 1]
72 v[d] = (xor0 >>> 16) ^ (xor1 << 16)
73 v[d + 1] = (xor1 >>> 16) ^ (xor0 << 16)
74
75 ADD64AA(v, c, d)
76
77 // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 63 bits
78 xor0 = v[b] ^ v[c]
79 xor1 = v[b + 1] ^ v[c + 1]
80 v[b] = (xor1 >>> 31) ^ (xor0 << 1)
81 v[b + 1] = (xor0 >>> 31) ^ (xor1 << 1)
82}
83
84// Initialization Vector
85var BLAKE2B_IV32 = new Uint32Array([
86 0xF3BCC908, 0x6A09E667, 0x84CAA73B, 0xBB67AE85,
87 0xFE94F82B, 0x3C6EF372, 0x5F1D36F1, 0xA54FF53A,
88 0xADE682D1, 0x510E527F, 0x2B3E6C1F, 0x9B05688C,
89 0xFB41BD6B, 0x1F83D9AB, 0x137E2179, 0x5BE0CD19
90])
91
92var SIGMA8 = [
93 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
94 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
95 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
96 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
97 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
98 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
99 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
100 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
101 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
102 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
103 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
104 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3
105]
106
107// These are offsets into a uint64 buffer.
108// Multiply them all by 2 to make them offsets into a uint32 buffer,
109// because this is Javascript and we don't have uint64s
110var SIGMA82 = new Uint8Array(SIGMA8.map(function (x) { return x * 2 }))
111
112// Compression function. 'last' flag indicates last block.
113// Note we're representing 16 uint64s as 32 uint32s
114var v = new Uint32Array(32)
115var m = new Uint32Array(32)
116function blake2bCompress (ctx, last) {
117 var i = 0
118
119 // init work variables
120 for (i = 0; i < 16; i++) {
121 v[i] = ctx.h[i]
122 v[i + 16] = BLAKE2B_IV32[i]
123 }
124
125 // low 64 bits of offset
126 v[24] = v[24] ^ ctx.t
127 v[25] = v[25] ^ (ctx.t / 0x100000000)
128 // high 64 bits not supported, offset may not be higher than 2**53-1
129
130 // last block flag set ?
131 if (last) {
132 v[28] = ~v[28]
133 v[29] = ~v[29]
134 }
135
136 // get little-endian words
137 for (i = 0; i < 32; i++) {
138 m[i] = B2B_GET32(ctx.b, 4 * i)
139 }
140
141 // twelve rounds of mixing
142 for (i = 0; i < 12; i++) {
143 B2B_G(0, 8, 16, 24, SIGMA82[i * 16 + 0], SIGMA82[i * 16 + 1])
144 B2B_G(2, 10, 18, 26, SIGMA82[i * 16 + 2], SIGMA82[i * 16 + 3])
145 B2B_G(4, 12, 20, 28, SIGMA82[i * 16 + 4], SIGMA82[i * 16 + 5])
146 B2B_G(6, 14, 22, 30, SIGMA82[i * 16 + 6], SIGMA82[i * 16 + 7])
147 B2B_G(0, 10, 20, 30, SIGMA82[i * 16 + 8], SIGMA82[i * 16 + 9])
148 B2B_G(2, 12, 22, 24, SIGMA82[i * 16 + 10], SIGMA82[i * 16 + 11])
149 B2B_G(4, 14, 16, 26, SIGMA82[i * 16 + 12], SIGMA82[i * 16 + 13])
150 B2B_G(6, 8, 18, 28, SIGMA82[i * 16 + 14], SIGMA82[i * 16 + 15])
151 }
152
153 for (i = 0; i < 16; i++) {
154 ctx.h[i] = ctx.h[i] ^ v[i] ^ v[i + 16]
155 }
156}
157
158// reusable parameter_block
159var parameter_block = new Uint8Array([
160 0, 0, 0, 0, // 0: outlen, keylen, fanout, depth
161 0, 0, 0, 0, // 4: leaf length, sequential mode
162 0, 0, 0, 0, // 8: node offset
163 0, 0, 0, 0, // 12: node offset
164 0, 0, 0, 0, // 16: node depth, inner length, rfu
165 0, 0, 0, 0, // 20: rfu
166 0, 0, 0, 0, // 24: rfu
167 0, 0, 0, 0, // 28: rfu
168 0, 0, 0, 0, // 32: salt
169 0, 0, 0, 0, // 36: salt
170 0, 0, 0, 0, // 40: salt
171 0, 0, 0, 0, // 44: salt
172 0, 0, 0, 0, // 48: personal
173 0, 0, 0, 0, // 52: personal
174 0, 0, 0, 0, // 56: personal
175 0, 0, 0, 0 // 60: personal
176])
177
178// Creates a BLAKE2b hashing context
179// Requires an output length between 1 and 64 bytes
180// Takes an optional Uint8Array key
181function Blake2b (outlen, key, salt, personal) {
182 // zero out parameter_block before usage
183 parameter_block.fill(0)
184 // state, 'param block'
185
186 this.b = new Uint8Array(128)
187 this.h = new Uint32Array(16)
188 this.t = 0 // input count
189 this.c = 0 // pointer within buffer
190 this.outlen = outlen // output length in bytes
191
192 parameter_block[0] = outlen
193 if (key) parameter_block[1] = key.length
194 parameter_block[2] = 1 // fanout
195 parameter_block[3] = 1 // depth
196
197 if (salt) parameter_block.set(salt, 32)
198 if (personal) parameter_block.set(personal, 48)
199
200 // initialize hash state
201 for (var i = 0; i < 16; i++) {
202 this.h[i] = BLAKE2B_IV32[i] ^ B2B_GET32(parameter_block, i * 4)
203 }
204
205 // key the hash, if applicable
206 if (key) {
207 blake2bUpdate(this, key)
208 // at the end
209 this.c = 128
210 }
211}
212
213Blake2b.prototype.update = function (input) {
214 assert(input != null, 'input must be Uint8Array or Buffer')
215 blake2bUpdate(this, input)
216 return this
217}
218
219Blake2b.prototype.digest = function (out) {
220 var buf = (!out || out === 'binary' || out === 'hex') ? new Uint8Array(this.outlen) : out
221 assert(buf.length >= this.outlen, 'out must have at least outlen bytes of space')
222 blake2bFinal(this, buf)
223 if (out === 'hex') return hexSlice(buf)
224 return buf
225}
226
227Blake2b.prototype.final = Blake2b.prototype.digest
228
229Blake2b.ready = function (cb) {
230 b2wasm.ready(function () {
231 cb() // ignore the error
232 })
233}
234
235// Updates a BLAKE2b streaming hash
236// Requires hash context and Uint8Array (byte array)
237function blake2bUpdate (ctx, input) {
238 for (var i = 0; i < input.length; i++) {
239 if (ctx.c === 128) { // buffer full ?
240 ctx.t += ctx.c // add counters
241 blake2bCompress(ctx, false) // compress (not last)
242 ctx.c = 0 // counter to zero
243 }
244 ctx.b[ctx.c++] = input[i]
245 }
246}
247
248// Completes a BLAKE2b streaming hash
249// Returns a Uint8Array containing the message digest
250function blake2bFinal (ctx, out) {
251 ctx.t += ctx.c // mark last block offset
252
253 while (ctx.c < 128) { // fill up with zeros
254 ctx.b[ctx.c++] = 0
255 }
256 blake2bCompress(ctx, true) // final block flag = 1
257
258 for (var i = 0; i < ctx.outlen; i++) {
259 out[i] = ctx.h[i >> 2] >> (8 * (i & 3))
260 }
261 return out
262}
263
264function hexSlice (buf) {
265 var str = ''
266 for (var i = 0; i < buf.length; i++) str += toHex(buf[i])
267 return str
268}
269
270function toHex (n) {
271 if (n < 16) return '0' + n.toString(16)
272 return n.toString(16)
273}
274
275var Proto = Blake2b
276
277module.exports = function createHash (outlen, key, salt, personal, noAssert) {
278 if (noAssert !== true) {
279 assert(outlen >= BYTES_MIN, 'outlen must be at least ' + BYTES_MIN + ', was given ' + outlen)
280 assert(outlen <= BYTES_MAX, 'outlen must be at most ' + BYTES_MAX + ', was given ' + outlen)
281 if (key != null) assert(key.length >= KEYBYTES_MIN, 'key must be at least ' + KEYBYTES_MIN + ', was given ' + key.length)
282 if (key != null) assert(key.length <= KEYBYTES_MAX, 'key must be at least ' + KEYBYTES_MAX + ', was given ' + key.length)
283 if (salt != null) assert(salt.length === SALTBYTES, 'salt must be exactly ' + SALTBYTES + ', was given ' + salt.length)
284 if (personal != null) assert(personal.length === PERSONALBYTES, 'personal must be exactly ' + PERSONALBYTES + ', was given ' + personal.length)
285 }
286
287 return new Proto(outlen, key, salt, personal)
288}
289
290module.exports.ready = function (cb) {
291 b2wasm.ready(function () { // ignore errors
292 cb()
293 })
294}
295
296module.exports.WASM_SUPPORTED = b2wasm.SUPPORTED
297module.exports.WASM_LOADED = false
298
299var BYTES_MIN = module.exports.BYTES_MIN = 16
300var BYTES_MAX = module.exports.BYTES_MAX = 64
301var BYTES = module.exports.BYTES = 32
302var KEYBYTES_MIN = module.exports.KEYBYTES_MIN = 16
303var KEYBYTES_MAX = module.exports.KEYBYTES_MAX = 64
304var KEYBYTES = module.exports.KEYBYTES = 32
305var SALTBYTES = module.exports.SALTBYTES = 16
306var PERSONALBYTES = module.exports.PERSONALBYTES = 16
307
308b2wasm.ready(function (err) {
309 if (!err) {
310 module.exports.WASM_LOADED = true
311 Proto = b2wasm
312 }
313})