xsalsa20
Version:
XSalsa20 implemented in Javascript and WebAssembly
456 lines (389 loc) • 13 kB
JavaScript
var xsalsa20 = typeof WebAssembly !== "undefined" && require('./xsalsa20')()
var SIGMA = new Uint8Array([101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107])
var head = 144
var top = head
var free = []
module.exports = XSalsa20
XSalsa20.NONCEBYTES = 24
XSalsa20.KEYBYTES = 32
XSalsa20.core_hsalsa20 = core_hsalsa20
XSalsa20.SIGMA = SIGMA
function XSalsa20 (nonce, key) {
if (!(this instanceof XSalsa20)) return new XSalsa20(nonce, key)
if (!nonce || nonce.length < 24) throw new Error('nonce must be at least 24 bytes')
if (!key || key.length < 32) throw new Error('key must be at least 32 bytes')
this._xor = xsalsa20 ? new WASM(nonce, key) : new Fallback(nonce, key)
}
XSalsa20.prototype.update = function (input, output) {
if (!input) throw new Error('input must be Uint8Array or Buffer')
if (!output) output = new Uint8Array(input.length)
if (input.length) this._xor.update(input, output)
return output
}
XSalsa20.prototype.final =
XSalsa20.prototype.finalize = function () {
this._xor.finalize()
this._xor = null
}
function WASM (nonce, key) {
if (!free.length) {
free.push(head)
head += 64
}
this._pointer = free.pop()
this._nonce = this._pointer + 8
this._key = this._nonce + 24
this._overflow = 0
this._memory = new Uint8Array(xsalsa20.memory.buffer)
this._memory.fill(0, this._pointer, this._pointer + 8)
this._memory.set(nonce, this._nonce)
this._memory.set(key, this._key)
}
WASM.prototype.realloc = function (size) {
xsalsa20.memory.grow(Math.ceil(Math.abs(size - this._memory.length) / 65536))
this._memory = new Uint8Array(xsalsa20.memory.buffer)
}
WASM.prototype.update = function (input, output) {
var len = this._overflow + input.length
var start = head + this._overflow
top = head + len
if (top >= this._memory.length) this.realloc(top)
this._memory.set(input, start)
xsalsa20.xsalsa20_xor(this._pointer, head, head, len, this._nonce, this._key)
output.set(this._memory.subarray(start, head + len))
this._overflow = len & 63
}
WASM.prototype.finalize = function () {
this._memory.fill(0, this._pointer, this._key + 32)
if (top > head) {
this._memory.fill(0, head, top)
top = 0
}
free.push(this._pointer)
}
function Fallback (nonce, key) {
this._s = new Uint8Array(32)
this._z = new Uint8Array(16)
this._overflow = 0
core_hsalsa20(this._s, nonce, key, SIGMA)
for (var i = 0; i < 8; i++) this._z[i] = nonce[i + 16]
}
Fallback.prototype.update = function (input, output) {
var x = new Uint8Array(64)
var u = 0
var i = this._overflow
var b = input.length + this._overflow
var z = this._z
var mpos = -this._overflow
var cpos = -this._overflow
while (b >= 64) {
core_salsa20(x, z, this._s, SIGMA)
for (; i < 64; i++) output[cpos + i] = input[mpos + i] ^ x[i]
u = 1
for (i = 8; i < 16; i++) {
u += (z[i] & 0xff) | 0
z[i] = u & 0xff
u >>>= 8
}
b -= 64
cpos += 64
mpos += 64
i = 0
}
if (b > 0) {
core_salsa20(x, z, this._s, SIGMA)
for (; i < b; i++) output[cpos + i] = input[mpos + i] ^ x[i]
}
this._overflow = b & 63
}
Fallback.prototype.finalize = function () {
this._s.fill(0)
this._z.fill(0)
}
// below methods are ported from tweet nacl
function core_salsa20(o, p, k, c) {
var j0 = c[ 0] & 0xff | (c[ 1] & 0xff) << 8 | (c[ 2] & 0xff) << 16 | (c[ 3] & 0xff) << 24,
j1 = k[ 0] & 0xff | (k[ 1] & 0xff) << 8 | (k[ 2] & 0xff) << 16 | (k[ 3] & 0xff) << 24,
j2 = k[ 4] & 0xff | (k[ 5] & 0xff) << 8 | (k[ 6] & 0xff) << 16 | (k[ 7] & 0xff) << 24,
j3 = k[ 8] & 0xff | (k[ 9] & 0xff) << 8 | (k[10] & 0xff) << 16 | (k[11] & 0xff) << 24,
j4 = k[12] & 0xff | (k[13] & 0xff) << 8 | (k[14] & 0xff) << 16 | (k[15] & 0xff) << 24,
j5 = c[ 4] & 0xff | (c[ 5] & 0xff) << 8 | (c[ 6] & 0xff) << 16 | (c[ 7] & 0xff) << 24,
j6 = p[ 0] & 0xff | (p[ 1] & 0xff) << 8 | (p[ 2] & 0xff) << 16 | (p[ 3] & 0xff) << 24,
j7 = p[ 4] & 0xff | (p[ 5] & 0xff) << 8 | (p[ 6] & 0xff) << 16 | (p[ 7] & 0xff) << 24,
j8 = p[ 8] & 0xff | (p[ 9] & 0xff) << 8 | (p[10] & 0xff) << 16 | (p[11] & 0xff) << 24,
j9 = p[12] & 0xff | (p[13] & 0xff) << 8 | (p[14] & 0xff) << 16 | (p[15] & 0xff) << 24,
j10 = c[ 8] & 0xff | (c[ 9] & 0xff) << 8 | (c[10] & 0xff) << 16 | (c[11] & 0xff) << 24,
j11 = k[16] & 0xff | (k[17] & 0xff) << 8 | (k[18] & 0xff) << 16 | (k[19] & 0xff) << 24,
j12 = k[20] & 0xff | (k[21] & 0xff) << 8 | (k[22] & 0xff) << 16 | (k[23] & 0xff) << 24,
j13 = k[24] & 0xff | (k[25] & 0xff) << 8 | (k[26] & 0xff) << 16 | (k[27] & 0xff) << 24,
j14 = k[28] & 0xff | (k[29] & 0xff) << 8 | (k[30] & 0xff) << 16 | (k[31] & 0xff) << 24,
j15 = c[12] & 0xff | (c[13] & 0xff) << 8 | (c[14] & 0xff) << 16 | (c[15] & 0xff) << 24
var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7,
x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14,
x15 = j15, u
for (var i = 0; i < 20; i += 2) {
u = x0 + x12 | 0
x4 ^= u << 7 | u >>> 25
u = x4 + x0 | 0
x8 ^= u << 9 | u >>> 23
u = x8 + x4 | 0
x12 ^= u << 13 | u >>> 19
u = x12 + x8 | 0
x0 ^= u << 18 | u >>> 14
u = x5 + x1 | 0
x9 ^= u << 7 | u >>> 25
u = x9 + x5 | 0
x13 ^= u << 9 | u >>> 23
u = x13 + x9 | 0
x1 ^= u << 13 | u >>> 19
u = x1 + x13 | 0
x5 ^= u << 18 | u >>> 14
u = x10 + x6 | 0
x14 ^= u << 7 | u >>> 25
u = x14 + x10 | 0
x2 ^= u << 9 | u >>> 23
u = x2 + x14 | 0
x6 ^= u << 13 | u >>> 19
u = x6 + x2 | 0
x10 ^= u << 18 | u >>> 14
u = x15 + x11 | 0
x3 ^= u << 7 | u >>> 25
u = x3 + x15 | 0
x7 ^= u << 9 | u >>> 23
u = x7 + x3 | 0
x11 ^= u << 13 | u >>> 19
u = x11 + x7 | 0
x15 ^= u << 18 | u >>> 14
u = x0 + x3 | 0
x1 ^= u << 7 | u >>> 25
u = x1 + x0 | 0
x2 ^= u << 9 | u >>> 23
u = x2 + x1 | 0
x3 ^= u << 13 | u >>> 19
u = x3 + x2 | 0
x0 ^= u << 18 | u >>> 14
u = x5 + x4 | 0
x6 ^= u << 7 | u >>> 25
u = x6 + x5 | 0
x7 ^= u << 9 | u >>> 23
u = x7 + x6 | 0
x4 ^= u << 13 | u >>> 19
u = x4 + x7 | 0
x5 ^= u << 18 | u >>> 14
u = x10 + x9 | 0
x11 ^= u << 7 | u >>> 25
u = x11 + x10 | 0
x8 ^= u << 9 | u >>> 23
u = x8 + x11 | 0
x9 ^= u << 13 | u >>> 19
u = x9 + x8 | 0
x10 ^= u << 18 | u >>> 14
u = x15 + x14 | 0
x12 ^= u << 7 | u >>> 25
u = x12 + x15 | 0
x13 ^= u << 9 | u >>> 23
u = x13 + x12 | 0
x14 ^= u << 13 | u >>> 19
u = x14 + x13 | 0
x15 ^= u << 18 | u >>> 14
}
x0 = x0 + j0 | 0
x1 = x1 + j1 | 0
x2 = x2 + j2 | 0
x3 = x3 + j3 | 0
x4 = x4 + j4 | 0
x5 = x5 + j5 | 0
x6 = x6 + j6 | 0
x7 = x7 + j7 | 0
x8 = x8 + j8 | 0
x9 = x9 + j9 | 0
x10 = x10 + j10 | 0
x11 = x11 + j11 | 0
x12 = x12 + j12 | 0
x13 = x13 + j13 | 0
x14 = x14 + j14 | 0
x15 = x15 + j15 | 0
o[ 0] = x0 >>> 0 & 0xff
o[ 1] = x0 >>> 8 & 0xff
o[ 2] = x0 >>> 16 & 0xff
o[ 3] = x0 >>> 24 & 0xff
o[ 4] = x1 >>> 0 & 0xff
o[ 5] = x1 >>> 8 & 0xff
o[ 6] = x1 >>> 16 & 0xff
o[ 7] = x1 >>> 24 & 0xff
o[ 8] = x2 >>> 0 & 0xff
o[ 9] = x2 >>> 8 & 0xff
o[10] = x2 >>> 16 & 0xff
o[11] = x2 >>> 24 & 0xff
o[12] = x3 >>> 0 & 0xff
o[13] = x3 >>> 8 & 0xff
o[14] = x3 >>> 16 & 0xff
o[15] = x3 >>> 24 & 0xff
o[16] = x4 >>> 0 & 0xff
o[17] = x4 >>> 8 & 0xff
o[18] = x4 >>> 16 & 0xff
o[19] = x4 >>> 24 & 0xff
o[20] = x5 >>> 0 & 0xff
o[21] = x5 >>> 8 & 0xff
o[22] = x5 >>> 16 & 0xff
o[23] = x5 >>> 24 & 0xff
o[24] = x6 >>> 0 & 0xff
o[25] = x6 >>> 8 & 0xff
o[26] = x6 >>> 16 & 0xff
o[27] = x6 >>> 24 & 0xff
o[28] = x7 >>> 0 & 0xff
o[29] = x7 >>> 8 & 0xff
o[30] = x7 >>> 16 & 0xff
o[31] = x7 >>> 24 & 0xff
o[32] = x8 >>> 0 & 0xff
o[33] = x8 >>> 8 & 0xff
o[34] = x8 >>> 16 & 0xff
o[35] = x8 >>> 24 & 0xff
o[36] = x9 >>> 0 & 0xff
o[37] = x9 >>> 8 & 0xff
o[38] = x9 >>> 16 & 0xff
o[39] = x9 >>> 24 & 0xff
o[40] = x10 >>> 0 & 0xff
o[41] = x10 >>> 8 & 0xff
o[42] = x10 >>> 16 & 0xff
o[43] = x10 >>> 24 & 0xff
o[44] = x11 >>> 0 & 0xff
o[45] = x11 >>> 8 & 0xff
o[46] = x11 >>> 16 & 0xff
o[47] = x11 >>> 24 & 0xff
o[48] = x12 >>> 0 & 0xff
o[49] = x12 >>> 8 & 0xff
o[50] = x12 >>> 16 & 0xff
o[51] = x12 >>> 24 & 0xff
o[52] = x13 >>> 0 & 0xff
o[53] = x13 >>> 8 & 0xff
o[54] = x13 >>> 16 & 0xff
o[55] = x13 >>> 24 & 0xff
o[56] = x14 >>> 0 & 0xff
o[57] = x14 >>> 8 & 0xff
o[58] = x14 >>> 16 & 0xff
o[59] = x14 >>> 24 & 0xff
o[60] = x15 >>> 0 & 0xff
o[61] = x15 >>> 8 & 0xff
o[62] = x15 >>> 16 & 0xff
o[63] = x15 >>> 24 & 0xff
}
function core_hsalsa20(o,p,k,c) {
var j0 = c[ 0] & 0xff | (c[ 1] & 0xff) << 8 | (c[ 2] & 0xff) << 16 | (c[ 3] & 0xff) << 24,
j1 = k[ 0] & 0xff | (k[ 1] & 0xff) << 8 | (k[ 2] & 0xff) << 16 | (k[ 3] & 0xff) << 24,
j2 = k[ 4] & 0xff | (k[ 5] & 0xff) << 8 | (k[ 6] & 0xff) << 16 | (k[ 7] & 0xff) << 24,
j3 = k[ 8] & 0xff | (k[ 9] & 0xff) << 8 | (k[10] & 0xff) << 16 | (k[11] & 0xff) << 24,
j4 = k[12] & 0xff | (k[13] & 0xff) << 8 | (k[14] & 0xff) << 16 | (k[15] & 0xff) << 24,
j5 = c[ 4] & 0xff | (c[ 5] & 0xff) << 8 | (c[ 6] & 0xff) << 16 | (c[ 7] & 0xff) << 24,
j6 = p[ 0] & 0xff | (p[ 1] & 0xff) << 8 | (p[ 2] & 0xff) << 16 | (p[ 3] & 0xff) << 24,
j7 = p[ 4] & 0xff | (p[ 5] & 0xff) << 8 | (p[ 6] & 0xff) << 16 | (p[ 7] & 0xff) << 24,
j8 = p[ 8] & 0xff | (p[ 9] & 0xff) << 8 | (p[10] & 0xff) << 16 | (p[11] & 0xff) << 24,
j9 = p[12] & 0xff | (p[13] & 0xff) << 8 | (p[14] & 0xff) << 16 | (p[15] & 0xff) << 24,
j10 = c[ 8] & 0xff | (c[ 9] & 0xff) << 8 | (c[10] & 0xff) << 16 | (c[11] & 0xff) << 24,
j11 = k[16] & 0xff | (k[17] & 0xff) << 8 | (k[18] & 0xff) << 16 | (k[19] & 0xff) << 24,
j12 = k[20] & 0xff | (k[21] & 0xff) << 8 | (k[22] & 0xff) << 16 | (k[23] & 0xff) << 24,
j13 = k[24] & 0xff | (k[25] & 0xff) << 8 | (k[26] & 0xff) << 16 | (k[27] & 0xff) << 24,
j14 = k[28] & 0xff | (k[29] & 0xff) << 8 | (k[30] & 0xff) << 16 | (k[31] & 0xff) << 24,
j15 = c[12] & 0xff | (c[13] & 0xff) << 8 | (c[14] & 0xff) << 16 | (c[15] & 0xff) << 24
var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7,
x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14,
x15 = j15, u
for (var i = 0; i < 20; i += 2) {
u = x0 + x12 | 0
x4 ^= u << 7 | u >>> 25
u = x4 + x0 | 0
x8 ^= u << 9 | u >>> 23
u = x8 + x4 | 0
x12 ^= u << 13 | u >>> 19
u = x12 + x8 | 0
x0 ^= u << 18 | u >>> 14
u = x5 + x1 | 0
x9 ^= u << 7 | u >>> 25
u = x9 + x5 | 0
x13 ^= u << 9 | u >>> 23
u = x13 + x9 | 0
x1 ^= u << 13 | u >>> 19
u = x1 + x13 | 0
x5 ^= u << 18 | u >>> 14
u = x10 + x6 | 0
x14 ^= u << 7 | u >>> 25
u = x14 + x10 | 0
x2 ^= u << 9 | u >>> 23
u = x2 + x14 | 0
x6 ^= u << 13 | u >>> 19
u = x6 + x2 | 0
x10 ^= u << 18 | u >>> 14
u = x15 + x11 | 0
x3 ^= u << 7 | u >>> 25
u = x3 + x15 | 0
x7 ^= u << 9 | u >>> 23
u = x7 + x3 | 0
x11 ^= u << 13 | u >>> 19
u = x11 + x7 | 0
x15 ^= u << 18 | u >>> 14
u = x0 + x3 | 0
x1 ^= u << 7 | u >>> 25
u = x1 + x0 | 0
x2 ^= u << 9 | u >>> 23
u = x2 + x1 | 0
x3 ^= u << 13 | u >>> 19
u = x3 + x2 | 0
x0 ^= u << 18 | u >>> 14
u = x5 + x4 | 0
x6 ^= u << 7 | u >>> 25
u = x6 + x5 | 0
x7 ^= u << 9 | u >>> 23
u = x7 + x6 | 0
x4 ^= u << 13 | u >>> 19
u = x4 + x7 | 0
x5 ^= u << 18 | u >>> 14
u = x10 + x9 | 0
x11 ^= u << 7 | u >>> 25
u = x11 + x10 | 0
x8 ^= u << 9 | u >>> 23
u = x8 + x11 | 0
x9 ^= u << 13 | u >>> 19
u = x9 + x8 | 0
x10 ^= u << 18 | u >>> 14
u = x15 + x14 | 0
x12 ^= u << 7 | u >>> 25
u = x12 + x15 | 0
x13 ^= u << 9 | u >>> 23
u = x13 + x12 | 0
x14 ^= u << 13 | u >>> 19
u = x14 + x13 | 0
x15 ^= u << 18 | u >>> 14
}
o[ 0] = x0 >>> 0 & 0xff
o[ 1] = x0 >>> 8 & 0xff
o[ 2] = x0 >>> 16 & 0xff
o[ 3] = x0 >>> 24 & 0xff
o[ 4] = x5 >>> 0 & 0xff
o[ 5] = x5 >>> 8 & 0xff
o[ 6] = x5 >>> 16 & 0xff
o[ 7] = x5 >>> 24 & 0xff
o[ 8] = x10 >>> 0 & 0xff
o[ 9] = x10 >>> 8 & 0xff
o[10] = x10 >>> 16 & 0xff
o[11] = x10 >>> 24 & 0xff
o[12] = x15 >>> 0 & 0xff
o[13] = x15 >>> 8 & 0xff
o[14] = x15 >>> 16 & 0xff
o[15] = x15 >>> 24 & 0xff
o[16] = x6 >>> 0 & 0xff
o[17] = x6 >>> 8 & 0xff
o[18] = x6 >>> 16 & 0xff
o[19] = x6 >>> 24 & 0xff
o[20] = x7 >>> 0 & 0xff
o[21] = x7 >>> 8 & 0xff
o[22] = x7 >>> 16 & 0xff
o[23] = x7 >>> 24 & 0xff
o[24] = x8 >>> 0 & 0xff
o[25] = x8 >>> 8 & 0xff
o[26] = x8 >>> 16 & 0xff
o[27] = x8 >>> 24 & 0xff
o[28] = x9 >>> 0 & 0xff
o[29] = x9 >>> 8 & 0xff
o[30] = x9 >>> 16 & 0xff
o[31] = x9 >>> 24 & 0xff
}