diff --git a/README.md b/README.md new file mode 100644 index 0000000..8d18095 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Storage for random stuff. diff --git a/js/KummerScalarmult.js b/js/KummerScalarmult.js new file mode 100644 index 0000000..e379c7e --- /dev/null +++ b/js/KummerScalarmult.js @@ -0,0 +1,602 @@ +/** + * kummer scalar multiplication - ref5 + * + * ported from SUPERCOP 20140529 + * + * see for details: http://bench.cr.yp.to/supercop.html + */ +var KummerScalarmult = (function() { + + /* bitwise dance helper*/ + function bits(high, low) { + this.high = (high + Math.floor(Math.ceil(low) / 4294967296)) >> 0; + this.low = low >>> 0; + }; + + function mulBits(x, y) { + var high = 0, low = 0, i; + if ((y.low & 1) !== 0) { + high = x.high; + low = x.low; + } + for (i = 1; i < 32; i++) { + if ((y.low & 1<>> (32 - i); + low += (x.low << i) >>> 0; + } + } + for (i = 0; i < 32; i++) { + if ((y.high & 1<> y, (x.low >>> y | x.high << (32 - y)) >>> 0); + } + if (y < 64) { + return new bits(x.high >> 31, (x.high >> (y - 32)) >>> 0); + } + if (x.high < 0) { + return new bits(-1, 4294967295); + } + return new bits(0, 0); + }; + + function shl(x, y) { + if (y === 0) return x; + if (y < 32) { + return new bits(x.high << y | x.low >>> (32 - y), (x.low << y) >>> 0); + } + if (y < 64) { + return new bits(x.low << (y - 32), 0); + } + return new bits(0, 0); + }; + + function sub(x, y) { + return new bits(x.high - y.high, x.low - y.low); + }; + + function flatten(bits) { + return bits.high * 4294967296 + bits.low; + }; + + function mul(x, y) { + return mulBits(new bits(0, x), new bits(0, y)); + }; + + function add(x, y) { + return new bits(x.high + y.high, x.low + y.low); + }; + + /* end bitwise helper */ + + function fieldElement() { + this.v = new Array(5); + }; + + function gfe_add(r, x, y) { + for (var i = 0; i < 5; i++) { + r.v[i] = (x.v[i] + y.v[i]);// >> 0; + } + }; + + function gfe_sub(r, x, y) { + for (var i = 0; i < 5; i++) { + r.v[i] = (x.v[i] - y.v[i]);// >> 0; + } + }; + + function carry(t) { + var c = shr(t[0], 26); + t[1] = add(t[1], c); + t[0] = sub(t[0], shl(c, 26)); + + c = shr(t[1], 25); + t[2] = add(t[2], c); + t[1] = sub(t[1], shl(c, 25)); + + c = shr(t[2], 26); + t[3] = add(t[3], c); + t[2] = sub(t[2], shl(c, 26)); + + c = shr(t[3], 25); + t[4] = add(t[4], c); + t[3] = sub(t[3], shl(c, 25)); + + c = shr(t[4], 25); + t[0] = add(t[0], c); + t[4] = sub(t[4], shl(c, 25)); + + c = shr(t[0], 26); + t[1] = add(t[1], c); + t[0] = sub(t[0], shl(c, 26)); + }; + + function gfe_mul(r, a, b) { + var t = [], xyz = [], t0 = [], t1 = [], t2 = [], t3 = [], t4 = []; + + xyz[1] = a.v[1] << 1 >> 0; + xyz[2] = a.v[2] << 1 >> 0; + xyz[3] = a.v[3] << 1 >> 0; + xyz[4] = a.v[4] << 1 >> 0; + + t0[0] = mul(a.v[0], b.v[0]); + t0[1] = mul(xyz[1], b.v[4]); + t0[2] = mul(xyz[2], b.v[3]); + t0[3] = mul(xyz[3], b.v[2]); + t0[4] = mul(xyz[4], b.v[1]); + + t0[5] = add(t0[0], t0[1]); + t0[6] = add(t0[5], t0[2]); + t0[7] = add(t0[6], t0[3]); + + t[0] = add(t0[7], t0[4]); + + t1[0] = mul(a.v[0], b.v[1]); + t1[1] = mul(a.v[1], b.v[0]); + t1[2] = mul(a.v[2], b.v[4]); + t1[3] = mul(xyz[3], b.v[3]); + t1[4] = mul(a.v[4], b.v[2]); + + t1[5] = add(t1[0], t1[1]); + t1[6] = add(t1[5], t1[2]); + t1[7] = add(t1[6], t1[3]); + + t[1] = add(t1[7], t1[4]); + + t2[0] = mul(a.v[0], b.v[2]); + t2[1] = mul(xyz[1], b.v[1]); + t2[2] = mul(a.v[2], b.v[0]); + t2[3] = mul(xyz[3], b.v[4]); + t2[4] = mul(xyz[4], b.v[3]); + + t2[5] = add(t2[0], t2[1]); + t2[6] = add(t2[5], t2[2]); + t2[7] = add(t2[6], t2[3]); + + t[2] = add(t2[7], t2[4]); + + t3[0] = mul(a.v[0], b.v[3]); + t3[1] = mul(a.v[1], b.v[2]); + t3[2] = mul(a.v[2], b.v[1]); + t3[3] = mul(a.v[3], b.v[0]); + t3[4] = mul(a.v[4], b.v[4]); + + t3[5] = add(t3[0], t3[1]); + t3[6] = add(t3[5], t3[2]); + t3[7] = add(t3[6], t3[3]); + + t[3] = add(t3[7], t3[4]); + + t4[0] = mul(a.v[0], b.v[4]); + t4[1] = mul(xyz[1], b.v[3]); + t4[2] = mul(a.v[2], b.v[2]); + t4[3] = mul(xyz[3], b.v[1]); + t4[4] = mul(a.v[4], b.v[0]); + + t4[5] = add(t4[0], t4[1]); + t4[6] = add(t4[5], t4[2]); + t4[7] = add(t4[6], t4[3]); + + t[4] = add(t4[7], t4[4]); + + carry(t); + + r.v[0] = flatten(t[0]) >> 0; + r.v[1] = flatten(t[1]) >> 0; + r.v[2] = flatten(t[2]) >> 0; + r.v[3] = flatten(t[3]) >> 0; + r.v[4] = flatten(t[4]) >> 0; + }; + + function gfe_square(r, x) { + gfe_mul(r, x ,x); + }; + + function gfe_mulConst(r, a, cst) { + var t = []; + + t[0] = mul(a.v[0], cst); + t[1] = mul(a.v[1], cst); + t[2] = mul(a.v[2], cst); + t[3] = mul(a.v[3], cst); + t[4] = mul(a.v[4], cst); + + carry(t); + + r.v[0] = flatten(t[0]) >> 0; + r.v[1] = flatten(t[1]) >> 0; + r.v[2] = flatten(t[2]) >> 0; + r.v[3] = flatten(t[3]) >> 0; + r.v[4] = flatten(t[4]) >> 0; + }; + + function gfe_invert(r, x) { + var x2 = new fieldElement(), x3 = new fieldElement(), x6 = new fieldElement(), + x12 = new fieldElement(), x15 = new fieldElement(), x30 = new fieldElement(), + x_5_0 = new fieldElement(), x_10_0 = new fieldElement(), x_20_0 = new fieldElement(), + x_40_0 = new fieldElement(), x_80_0 = new fieldElement(), x_120_0 = new fieldElement(), + x_125_0 = new fieldElement(), t = new fieldElement(), i = 0; + + gfe_square(x2, x); /* 2 */ + gfe_mul(x3,x2,x); /* 3 mult */ + gfe_square(x6,x3); /* 6 */ + gfe_square(x12,x6); /* 12 */ + gfe_mul(x15,x12,x3); /* 15 mult */ + gfe_square(x30, x15); /* 30 */ + gfe_mul(x_5_0, x30, x); /* 31 = 2^5-1 mult */ + + gfe_square(t, x_5_0); + for(i=6;i<10;i++) gfe_square(t, t); /* 2^10-2^5 */ + gfe_mul(x_10_0,t,x_5_0); /* 2^10-1 mult */ + + gfe_square(t, x_10_0); + for(i=11;i<20;i++) gfe_square(t, t); /* 2^20-2^10 */ + gfe_mul(x_20_0,t,x_10_0); /* 2^20-1 mult */ + + gfe_square(t, x_20_0); + for(i=21;i<40;i++) gfe_square(t, t); /* 2^40-2^20 */ + gfe_mul(x_40_0,t,x_20_0); /* 2^40-1 mult */ + + gfe_square(t, x_40_0); + for(i=41;i<80;i++) gfe_square(t, t); /* 2^80-2^40 */ + gfe_mul(x_80_0,t,x_40_0); /* 2^80-1 mult */ + + gfe_square(t, x_80_0); + for(i=81;i<120;i++) gfe_square(t, t); /* 2^120-2^40 */ + gfe_mul(x_120_0,t,x_40_0); /* 2^80-1 mult */ + + gfe_square(t, x_120_0); + for(i=121;i<125;i++) gfe_square(t, t);/* 2^120-2^40 */ + gfe_mul(x_125_0, t, x_5_0); + + gfe_square(t, x_125_0); /* 2^126-2^1 */ + gfe_square(t, t); /* 2^127-2^2 */ + gfe_mul(r,t,x); /* 2^127-3 */ + }; + + function gfe_hadamard(r0, r1, r2, r3) { + var a = new fieldElement(), b = new fieldElement(), + c = new fieldElement(), d = new fieldElement(); + + gfe_add(a, r0, r1); + gfe_add(b, r2, r3); + gfe_sub(c, r0, r1); + gfe_sub(d, r2, r3); + + gfe_add(r0, a, b); + gfe_sub(r1, a, b); + gfe_add(r2, c, d); + gfe_sub(r3, c, d); + }; + + function ladderStep(work) { + gfe_hadamard(work[7], work[8], work[9], work[10]); + gfe_hadamard(work[3], work[4], work[5], work[ 6]); + + gfe_mul(work[ 7], work[ 7], work[3]); + gfe_mul(work[ 8], work[ 8], work[4]); + gfe_mul(work[ 9], work[ 9], work[5]); + gfe_mul(work[10], work[10], work[6]); + + gfe_square(work[3], work[3]); + gfe_square(work[4], work[4]); + gfe_square(work[5], work[5]); + gfe_square(work[6], work[6]); + + gfe_mulConst(work[ 7], work[ 7], 9163); + gfe_mulConst(work[ 8], work[ 8], -27489); + gfe_mulConst(work[ 9], work[ 9], -17787); + gfe_mulConst(work[10], work[10], -6171); + + gfe_mulConst(work[3], work[3], 9163); + gfe_mulConst(work[4], work[4], -27489); + gfe_mulConst(work[5], work[5], -17787); + gfe_mulConst(work[6], work[6], -6171); + + gfe_hadamard(work[7], work[8], work[9], work[10]); + gfe_hadamard(work[3], work[4], work[5], work[ 6]); + + gfe_square(work[ 7], work[ 7]); + gfe_square(work[ 8], work[ 8]); + gfe_square(work[ 9], work[ 9]); + gfe_square(work[10], work[10]); + + gfe_square(work[3], work[3]); + gfe_square(work[4], work[4]); + gfe_square(work[5], work[5]); + gfe_square(work[6], work[6]); + + gfe_mul(work[ 8], work[ 8], work[0]); + gfe_mul(work[ 9], work[ 9], work[1]); + gfe_mul(work[10], work[10], work[2]); + + gfe_mulConst(work[3], work[3], -1254); + gfe_mulConst(work[4], work[4], 627); + gfe_mulConst(work[5], work[5], 726); + gfe_mulConst(work[6], work[6], 4598); + }; + + function cswap4x(x, xpos, y, ypos, b) { + var db = -b, t, xp, yp; + for(var i=0;i<4;++i) { + xp = i+xpos; + yp = i+ypos; + for (var j=0;j<5;j++) { + t = (x[xp].v[j] ^ y[yp].v[j]) >> 0; + t &= db; + x[xp].v[j] = (x[xp].v[j] ^ t) >> 0; + y[yp].v[j] = (y[yp].v[j] ^ t) >> 0; + } + } + }; + + function ladder(work, scalar) { + var j = 2, bit; + for (var i = 31; i >= 0; --i) { + for (j = j; j >= 0; --j) { + bit = (scalar[i]>>j) & 1; + cswap4x(work, 3, work, 7, bit); + ladderStep(work); + cswap4x(work, 3, work, 7, bit); + } + j = 7; + } + }; + + function gfe_unpack(r, b) { + r.v[0] = (b[0] & 0xff); + r.v[0] |= (b[1] & 0xff) << 8; + r.v[0] |= (b[2] & 0xff) << 16; + r.v[0] |= ((b[3]&3) & 0xff) << 24; + + r.v[1] = (b[3] & 0xff) >> 2; + r.v[1] |= (b[4] & 0xff) << 6; + r.v[1] |= (b[5] & 0xff) << 14; + r.v[1] |= ((b[6]&7) & 0xff) << 22; + + r.v[2] = (b[6] & 0xff) >> 3; + r.v[2] |= (b[7] & 0xff) << 5; + r.v[2] |= (b[8] & 0xff) << 13; + r.v[2] |= ((b[9]&31) & 0xff) << 21; + + r.v[3] = (b[9] & 0xff) >> 5; + r.v[3] |= (b[10] & 0xff) << 3; + r.v[3] |= (b[11] & 0xff) << 11; + r.v[3] |= ((b[12]&63) & 0xff) << 19; + + r.v[4] = (b[12] & 0xff) >> 6; + r.v[4] |= (b[13] & 0xff) << 2; + r.v[4] |= (b[14] & 0xff) << 10; + r.v[4] |= ((b[15]&127) & 0xff) << 18; + }; + + function gfe_pack(r, x) { + var c, t = x; + // i think x is small enough to do the bitwise dance + t.v[0] += ((1<<28)-4); + c = t.v[0] >> 26; + t.v[1] = t.v[1] + c; + c <<= 26; + t.v[0] = t.v[0] - c; + + t.v[1] += ((1<<27)-4); + c = t.v[1] >> 25; + t.v[2] = t.v[2] + c; + c <<= 25; + t.v[1] = t.v[1] - c; + + t.v[2] += ((1<<28)-4); + c = t.v[2] >> 26; + t.v[3] = t.v[3] + c; + c <<= 26; + t.v[2] = t.v[2] - c; + + t.v[3] += ((1<<27)-4); + c = t.v[3] >> 25; + t.v[4] = t.v[4] + c; + c <<= 25; + t.v[3] = t.v[3] - c; + + t.v[4] += ((1<<27)-4); + c = t.v[4] >> 25; + t.v[0] += c; + c <<= 25; + t.v[4] -= c; + + c = t.v[0] >> 26; + t.v[1] += c; + c <<= 26; + t.v[0] -= c; + + c = t.v[1] >> 25; + t.v[2] += c; + c <<= 25; + t.v[1] -= c; + + c = t.v[2] >> 26; + t.v[3] += c; + c <<= 26; + t.v[2] -= c; + + c = t.v[3] >> 25; + t.v[4] += c; + c <<= 25; + t.v[3] -= c; + + c = t.v[4] >> 25; + t.v[0] += c; + c <<= 25; + t.v[4] -= c; + + c = t.v[0] >> 26; + t.v[1] += c; + c <<= 26; + t.v[0] -= c; + + r.push(t.v[0] & 0xff); + r.push((t.v[0]>>8) & 0xff); + r.push((t.v[0]>>16)& 0xff); + r.push((t.v[0]>>24) | ((t.v[1] & 0x3f) << 2)); + r.push((t.v[1]>>6) & 0xff); + r.push((t.v[1]>>14)& 0xff); + r.push((t.v[1]>>22) | ((t.v[2] & 0x1f) << 3)); + r.push((t.v[2]>>5) & 0xff); + r.push((t.v[2]>>13) & 0xff); + r.push((t.v[2]>>21) | ((t.v[3] & 0x7) << 5)); + r.push((t.v[3]>>3) & 0xff); + r.push((t.v[3]>>11) & 0xff); + r.push((t.v[3]>>19) | ((t.v[4] & 0x3) << 6)); + r.push((t.v[4]>>2) & 0xff); + r.push((t.v[4]>>10) & 0xff); + r.push((t.v[4]>>18) & 0x7f); + }; + + return function(input, scalar) { + if (typeof scalar === "undefined") { + // 48 byte + var basepoint = [6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x68,0x30,0x1e,0x6b,0x4d,0xaf,0xc7,0x56,0x9d,0x1f,0xa7,0xf8,0x71,0x39,0x37,0x6b,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + return new KummerScalarmult(input, basepoint); + } + // simple check + if ((typeof input !== "object") || (typeof scalar !== "object")) { + throw new Error('input/scalar must be an (array) object'); + } + if ((input.length < 32) || (scalar.length < 48)) { + throw new Error('input must be 32 byte, scalar must be 48 byte'); + } + + var work = [], out = []; + var yz = new fieldElement(), yzt = new fieldElement(), + r = new fieldElement(), tr = new fieldElement(); + + for (var i =0;i < 11;++i) work[i] = new fieldElement(); + + gfe_unpack(work[0], scalar); + gfe_unpack(work[1], scalar.slice(16)); + gfe_unpack(work[2], scalar.slice(32)); + + work[3].v[0] = 11; + work[4].v[0] = -22; + work[5].v[0] = -19; + work[6].v[0] = -3; + + gfe_mul(work[10], work[ 0], work[1]); + gfe_mul(work[ 9], work[ 0], work[2]); + gfe_mul(work[ 8], work[ 1], work[2]); + gfe_mul(work[ 7], work[10], work[2]); + + ladder(work, input); + + gfe_mul(yz, work[4], work[5]); + gfe_mul(yzt, yz, work[6]); + gfe_invert(r,yzt); + gfe_mul(r, r, work[3]); + gfe_mul(tr, r, work[6]); + gfe_mul(work[5], work[5], tr); + gfe_pack(out, work[5]); + gfe_mul(work[4], work[4], tr); + gfe_pack(out, work[4]); + gfe_mul(yz, yz ,r); + gfe_pack(out, yz); + + return out; + }; + +})(); + +//---------- test ----------------------------------------------------// + +function randombytes(n) { + var out = [], values; + if (typeof window !== 'undefined' && window.crypto) { + values = new Uint8Array(n); + window.crypto.getRandomValues(values); + } else if (typeof require !== 'undefined') { + var prng = require('crypto'); + values = prng ? prng.randomBytes(n) : null; + } else { + throw new Error('no PRNG'); + } + if (!values || values.length !== n) { + throw new Error('PRNG failed'); + } + for (var i = 0; i < values.length; i++) { + out[i] = values[i]; + } + return out; +} + +function fromString(s) { + var arr = []; + for (var i = 0,l = s.length;i < l;++i) { + var c = s.charCodeAt(i); + if (c < 128) { + arr.push(c); + } else if (c > 127 && c < 2048) { + arr.push((c >> 6) | 192); + arr.push((c & 63) | 128); + } else { + arr.push((c >> 12) | 224); + arr.push(((c >> 6) & 63) | 128); + arr.push((c & 64) | 128); + } + } + return arr; +}; + +function fromHex(h) { + h.replace(' ', '').replace('\x', ''); + var out = [], len = h.length, w = ''; + for (var i = 0; i < len; i += 2) { + w = h[i]; + if (((i+1) >= len) || typeof h[i+1] === 'undefined') { + w += '0'; + } else { + w += h[i+1]; + } + out.push(parseInt(w, 16)); + } + return out; +}; + +function toHex(arr) { + var hex = [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + ]; + var out = ''; + for (var i = 0, l = arr.length;i < l;++i) { + out += hex[(arr[i] >> 4) & 0xf]; + out += hex[arr[i] & 0xf]; + } + return out; +}; + + +var aliceKey = randombytes(32);//fromHex("b199e432eb45590eab4054930738bcbe34d5c694a7e7c043aea2a980a094591c"); +var alicePublic = KummerScalarmult(aliceKey); + +var bobKey = randombytes(32);//fromHex("d8a326178d98cda59fff281f04357cbce73c98dc5362015f5a8d811a7324ac6d"); +var bobPublic = KummerScalarmult(bobKey); + +var aliceSharedSecret = KummerScalarmult(aliceKey, bobPublic); + +var bobSharedSecret = KummerScalarmult(bobKey, alicePublic); + +console.log('alice secret key :', toHex(aliceKey)); +console.log('alice public key :', toHex(alicePublic)); + +console.log('bob secret key :', toHex(bobKey)); +console.log('bob public key :', toHex(bobPublic)); + +console.log('alice shared secret :', toHex(aliceSharedSecret)); +console.log('bob shared secret :', toHex(bobSharedSecret)); + +//phantom.exit(); diff --git a/js/blake2b.js b/js/blake2b.js new file mode 100644 index 0000000..730f260 --- /dev/null +++ b/js/blake2b.js @@ -0,0 +1,264 @@ +// Blake2b + +// Ported by Devi Mandiri. Public domain. + +var u64 = function (h, l) { + h = h|0; l = l|0; + this.hi = h >>> 0; + this.lo = l >>> 0; +}; + +function new64(num) { + var hi = 0, lo = num >>> 0; + if ((+(Math.abs(num))) >= 1) { + if (num > 0) { + hi = ((Math.min((+(Math.floor(num/4294967296))), 4294967295))|0) >>> 0; + } else { + hi = (~~((+(Math.ceil((num - +(((~~(num)))>>>0))/4294967296))))) >>> 0; + } + } + return new u64(hi, lo); +} + +function add64() { + var l = 0, h = 0, t; + for (var i = 0; i < arguments.length; ++i) { + t = l; l = (t + arguments[i].lo)>>>0; + h = (h + arguments[i].hi + ((l < t) ? 1 : 0))>>>0; + } + return new u64(h, l); +} + +function xor64(x, y) { + return new u64(x.hi ^ y.hi, x.lo ^ y.lo); +} + +function rotr64(x, c) { + c = 64 - c; + + var h0 = 0, l0 = 0, h1 = 0, l1 = 0, c1 = 64 - c; + + // shl + if (c < 32) { + h0 = (x.hi << c) | ((x.lo & (((1 << c) - 1)|0) << (32 - c)) >>> (32 - c)); + l0 = x.lo << c; + } else { + h0 = x.lo << (c - 32); + } + + // shr + if (c1 < 32) { + h1 = x.hi >>> c1; + l1 = (x.lo >>> c1) | (x.hi & (((1 << c1) - 1)|0)) << (32 - c1); + } else { + l1 = x.hi >>> (c1 - 32); + } + + return new u64(h0 | h1, l0 | l1); +} + +function flatten64(x) { + return (x.hi * 4294967296 + x.lo); +} + +function load64(x, i) { + var l = x[i] | (x[i+1]<<8) | (x[i+2]<<16) | (x[i+3]<<24); + var h = x[i+4] | (x[i+5]<<8) | (x[i+6]<<16) | (x[i+7]<<24); + return new u64(h, l); +} + +function store64(x, i, u) { + x[i] = (u.lo & 0xff); u.lo >>>= 8; + x[i+1] = (u.lo & 0xff); u.lo >>>= 8; + x[i+2] = (u.lo & 0xff); u.lo >>>= 8; + x[i+3] = (u.lo & 0xff); + x[i+4] = (u.hi & 0xff); u.hi >>>= 8; + x[i+5] = (u.hi & 0xff); u.hi >>>= 8; + x[i+6] = (u.hi & 0xff); u.hi >>>= 8; + x[i+7] = (u.hi & 0xff); +} + + +var BLOCKBYTES = 128, + OUTBYTES = 64, + KEYBYTES = 64; + +var iv = [ + new u64(0x6a09e667, 0xf3bcc908), new u64(0xbb67ae85, 0x84caa73b), + new u64(0x3c6ef372, 0xfe94f82b), new u64(0xa54ff53a, 0x5f1d36f1), + new u64(0x510e527f, 0xade682d1), new u64(0x9b05688c, 0x2b3e6c1f), + new u64(0x1f83d9ab, 0xfb41bd6b), new u64(0x5be0cd19, 0x137e2179) +]; + +var State = function() { + this.h = iv.slice(0); + this.t = [new u64(0,0), new u64(0,0)]; + this.f = [new u64(0,0), new u64(0,0)]; + this.buf = new Array(256); + for (var i = 256; i--;) this.buf[i] = 0; + this.buflen = 0; +}; + +var sigma = [ + [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], + [ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], + [ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], + [ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], + [ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], + [ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], + [ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], + [ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], + [ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0], + [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3] +]; + +function G(v, m, r, i, a, b, c, d) { + v[a] = add64(v[a], v[b], m[sigma[r][2*i+0]]); + v[d] = rotr64(xor64(v[d], v[a]), 32); + v[c] = add64(v[c], v[d]); + v[b] = rotr64(xor64(v[b], v[c]), 24); + v[a] = add64(v[a], v[b], m[sigma[r][2*i+1]]); + v[d] = rotr64(xor64(v[d], v[a]), 16); + v[c] = add64(v[c], v[d]); + v[b] = rotr64(xor64(v[b], v[c]), 63); +} + +function compress(ctx, block) { + var m = new Array(16); + var v = new Array(16); + var i = 0; + + for (i = 16; i--;) m[i] = load64(block, i*8); + + for (i = 8; i--;) v[i] = ctx.h[i]; + + v[ 8] = iv[0]; + v[ 9] = iv[1]; + v[10] = iv[2]; + v[11] = iv[3]; + + v[12] = xor64(ctx.t[0], iv[4]); + v[13] = xor64(ctx.t[1], iv[5]); + v[14] = xor64(ctx.f[0], iv[6]); + v[15] = xor64(ctx.f[1], iv[7]); + + for (i = 0; i < 12; i++) { + G(v, m, i, 0, 0, 4, 8,12); + G(v, m, i, 1, 1, 5, 9,13); + G(v, m, i, 2, 2, 6,10,14); + G(v, m, i, 3, 3, 7,11,15); + G(v, m, i, 4, 0, 5,10,15); + G(v, m, i, 5, 1, 6,11,12); + G(v, m, i, 6, 2, 7, 8,13); + G(v, m, i, 7, 3, 4, 9,14); + } + + for (i = 0; i < 8; i++) { + ctx.h[i] = xor64(ctx.h[i], xor64(v[i], v[i+8])); + } +} + +function increment_counter(ctx, inc) { + var t = new64(inc); + ctx.t[0] = add64(ctx.t[0], t); + if (flatten64(ctx.t[0]) < inc) { + ctx.t[1] = add64(ctx.t[1], new64(1)); + } +} + +function update(ctx, p, plen) { + var i = 0, offset = 0, left = 0, fill = 0; + while (plen > 0) { + left = ctx.buflen; + fill = 256 - left; + + if (plen > fill) { + for (i = 0; i < fill; i++) { + ctx.buf[i+left] = p[i+offset]; + } + + ctx.buflen += fill; + + increment_counter(ctx, 128); + compress(ctx, ctx.buf); + + for (i = 128; i--;) { + ctx.buf[i] = ctx.buf[i+128]; + } + + ctx.buflen -= 128; + offset += fill; + plen -= fill; + } else { + for (i = plen; i--;) { + ctx.buf[i+left] = p[i+offset]; + } + ctx.buflen += plen; + offset += plen; + plen -= plen; + } + } +} + +function finish(ctx, out) { + var i = 0; + + if (ctx.buflen > 128) { + increment_counter(ctx, 128); + compress(ctx, ctx.buf); + ctx.buflen -= 128; + for (i = ctx.buflen; i--;) { + ctx.buf[i] = ctx.buf[i+128]; + } + } + + increment_counter(ctx, ctx.buflen); + ctx.f[0] = new u64(0xffffffff, 0xffffffff); + + for (i = 256 - ctx.buflen; i--;) + ctx.buf[i+ctx.buflen] = 0; + + compress(ctx, ctx.buf); + + for (i = 0; i < 8; i++) { + store64(out, i*8, ctx.h[i]); + } +} + +function init(key, outlen) { + var ctx = new State(); + var p = new Array(64); + var klen = 0; + var dlen = 64; + var i = 0; + + for (i = 64; i--;) p[i] = 0; + + if (typeof key !== 'undefined') { + if (key.length > 64) return false; + klen = key.length; + } + + if (typeof outlen !== 'undefined') { + if (outlen > 64) return false; + dlen = outlen; + } + + p[0] = dlen; // digest_length + p[1] = klen; // key_length + p[2] = 1; // fanout + p[3] = 1; // depth + + ctx.h[0] = xor64(ctx.h[0], load64(p, 0)); + + if (klen > 0) { + var block = new Array(128); + for (i = 128; i--;) block[i] = 0; + for (i = klen; i--;) block[i] = key[i]; + update(ctx, block, 128); + } + + return ctx; +} diff --git a/js/blake2s.js b/js/blake2s.js new file mode 100644 index 0000000..54b5bed --- /dev/null +++ b/js/blake2s.js @@ -0,0 +1,188 @@ +// BLAKE2s + +// Ported by Devi Mandiri. Public domain. + +var BLOCKBYTES = 64, + OUTBYTES = 32, + KEYBYTES = 32; + +var iv = [ + 1779033703, 3144134277, 1013904242, 2773480762, + 1359893119, 2600822924, 528734635, 1541459225 +]; + +var sigma = [ + [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15], + [14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3], + [11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4], + [ 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8], + [ 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13], + [ 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9], + [12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11], + [13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10], + [ 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5], + [10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13 ,0] +]; + +var State = function() { + this.h = iv.slice(0); + this.t = [0,0]; + this.f = [0,0]; + this.buf = new Array(128); + this.buflen = 0; +}; + +function load32(x, i) { + var u = x[i] & 0xff; + u |= (x[i+1] & 0xff) << 8; + u |= (x[i+2] & 0xff) << 16; + u |= (x[i+3] & 0xff) << 24; + return u; +} + +function store32(x, pos, u) { + x[pos] = u & 0xff; u >>>= 8; + x[pos+1] = u & 0xff; u >>>= 8; + x[pos+2] = u & 0xff; u >>>= 8; + x[pos+3] = u & 0xff; +} + +function plus() { + var x = 0; + for (var i = 0; i < arguments.length; i++) { + x = (x + arguments[i])>>>0; + } + return x; +} + +function rotr(v, n) { + return ((v >>> n) | (v << (32 - n)))>>>0; +} + +var v = [], m = []; + +function G(r, i, a, b, c, d) { + v[a] = plus(v[a], v[b], m[sigma[r][2*i]]); + v[d] = rotr(v[d] ^ v[a], 16); + v[c] = plus(v[c], v[d]); + v[b] = rotr(v[b] ^ v[c], 12); + v[a] = plus(v[a], v[b], m[sigma[r][2*i+1]]); + v[d] = rotr(v[d] ^ v[a], 8); + v[c] = plus(v[c], v[d]); + v[b] = rotr(v[b] ^ v[c], 7); +} + +function compress(state, inc) { + state.t[0] += inc; + state.t[1] += ((state.t[0] < inc)?1:0); // just in case + + var i = 0; + + for (i = 16; i--;) { + m[i] = load32(state.buf, i*4); + } + for (i = 8; i--;) { + v[i] = state.h[i]; + } + + v[ 8] = iv[0]; + v[ 9] = iv[1]; + v[10] = iv[2]; + v[11] = iv[3]; + v[12] = (iv[4] ^ state.t[0])>>>0; + v[13] = (iv[5] ^ state.t[1])>>>0; + v[14] = (iv[6] ^ state.f[0])>>>0; + v[15] = (iv[7] ^ state.f[1])>>>0; + + for (i = 0; i < 10; i++) { + G(i, 0, 0, 4, 8, 12); + G(i, 1, 1, 5, 9, 13); + G(i, 2, 2, 6, 10, 14); + G(i, 3, 3, 7, 11, 15); + G(i, 4, 0, 5, 10, 15); + G(i, 5, 1, 6, 11, 12); + G(i, 6, 2, 7, 8, 13); + G(i, 7, 3, 4, 9, 14); + } + + for (i = 8; i--;) { + state.h[i] ^= v[i] ^ v[i+8]; + } +} + +function update (state, p, length) { + length = length|0; + var i = 0, pos = 0; + while (length > 0) { + var left = state.buflen, fill = 128 - left; + if (length > fill) { + for (i = fill; i--;) { + state.buf[i+left] = p[i+pos]; + } + state.buflen += fill; + compress(state, 64); + for (i = 64; i--;) { + state.buf[i] = state.buf[i+64]; + } + state.buflen -= 64; + pos += fill; + length -= fill; + } else { + for (i = length; i--;) { + state.buf[i+left] = p[i+pos]; + } + state.buflen += length; + pos += length; + length -= length; + } + } +} + +function finish(state) { + var i = 0; + if (state.buflen > 64) { + compress(state, 64); + state.buflen -= 64; + for (i = state.buflen; i--;) { + state.buf[i] = state.buf[i+64]; + } + } + state.f[0] = 0xffffffff; + for (i = state.buflen; i < 128; i++) { + state.buf[i] = 0; + } + compress(state, state.buflen); + + var out = new Array(32); + for (i = 8; i--;) { + store32(out, i*4, state.h[i]); + } + return out; +} + +function decodeString(s) { + var b = []; + s = unescape(encodeURIComponent(s)); + for (var i = s.length; i--;) { + b[i] = s.charCodeAt(i); + } + return b; +} + +function init(key) { + var k = (typeof key == 'string') ? decodeString(key) : key; + var len = (typeof key !== 'undefined') ? key.length : 0; + + if (len > 32) len = 32; // truncate + + var s = new State(); + s.h[0] ^= load32([32, len, 1, 1], 0); + + if (len > 0) { + var block = [], i; + for (i = 64; i--;) block[i] = 0; + for (i = len; i--;) block[i] = k[i]; + update(s, block, 64); + } + return s; +} diff --git a/js/chacha20.js b/js/chacha20.js new file mode 100644 index 0000000..bb46fed --- /dev/null +++ b/js/chacha20.js @@ -0,0 +1,187 @@ +/* chacha20 - 256 bits */ + +// Written in 2014 by Devi Mandiri. Public domain. +// +// Implementation derived from chacha-ref.c version 20080118 +// See for details: http://cr.yp.to/chacha/chacha-20080128.pdf + +var Chacha20KeySize = 32; +var Chacha20NonceSize = 8; + +var Chacha20Ctx = function() { + this.input = new Array(16); +}; + +function load32(x, i) { + return x[i] | (x[i+1]<<8) | (x[i+2]<<16) | (x[i+3]<<24); +} + +function store32(x, i, u) { + x[i] = u & 0xff; u >>>= 8; + x[i+1] = u & 0xff; u >>>= 8; + x[i+2] = u & 0xff; u >>>= 8; + x[i+3] = u & 0xff; +} + +function rotl32(v, c) { + return (v << c) | (v >>> (32 - c)); +} + +function chacha20_round(x, a, b, c, d) { + x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); + x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); + x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); + x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7); +} + +function chacha20_init(key, nonce) { + var x = new Chacha20Ctx(); + + x.input[0] = 1634760805; + x.input[1] = 857760878; + x.input[2] = 2036477234; + x.input[3] = 1797285236; + x.input[12] = 0; + x.input[13] = 0; + x.input[14] = load32(nonce, 0); + x.input[15] = load32(nonce, 4); + + for (var i = 0; i < 8; i++) { + x.input[i+4] = load32(key, i*4); + } + return x; +} + +function chacha20_keystream(ctx, dst, src, len) { + var x = new Array(16); + var buf = new Array(64); + var i = 0, dpos = 0, spos = 0; + + while (len > 0 ) { + for (i = 16; i--;) x[i] = ctx.input[i]; + for (i = 20; i > 0; i -= 2) { + chacha20_round(x, 0, 4, 8,12); + chacha20_round(x, 1, 5, 9,13); + chacha20_round(x, 2, 6,10,14); + chacha20_round(x, 3, 7,11,15); + chacha20_round(x, 0, 5,10,15); + chacha20_round(x, 1, 6,11,12); + chacha20_round(x, 2, 7, 8,13); + chacha20_round(x, 3, 4, 9,14); + } + for (i = 16; i--;) x[i] += ctx.input[i]; + for (i = 16; i--;) store32(buf, 4*i, x[i]); + + ctx.input[12] += 1; + if (!ctx.input[12]) { + ctx.input[13] += 1; + } + if (len <= 64) { + for (i = len; i--;) { + dst[i+dpos] = src[i+spos] ^ buf[i]; + } + return; + } + for (i = 64; i--;) { + dst[i+dpos] = src[i+spos] ^ buf[i]; + } + len -= 64; + spos += 64; + dpos += 64; + } +} + +//--------------------------- test -----------------------------// +function fromHex(h) { + h.replace(' ', ''); + var out = [], len = h.length, w = ''; + for (var i = 0; i < len; i += 2) { + w = h[i]; + if (((i+1) >= len) || typeof h[i+1] === 'undefined') { + w += '0'; + } else { + w += h[i+1]; + } + out.push(parseInt(w, 16)); + } + return out; +} + +function bytesEqual(a, b) { + var dif = 0; + if (a.length !== b.length) return 0; + for (var i = 0; i < a.length; i++) { + dif |= (a[i] ^ b[i]); + } + dif = (dif - 1) >>> 31; + return (dif & 1); +} + +// testVectors from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#page-11 +var testVectors = [ + { + key: fromHex('0000000000000000000000000000000000000000000000000000000000000000'), + nonce: fromHex('0000000000000000'), + keystream: fromHex( + '76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc' + + '8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11c' + + 'c387b669b2ee6586' + ), + }, + { + key: fromHex('0000000000000000000000000000000000000000000000000000000000000001'), + nonce: fromHex('0000000000000000'), + keystream: fromHex( + '4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952' + + 'ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea81' + + '7e9ad275ae546963' + ), + }, + { + key: fromHex('0000000000000000000000000000000000000000000000000000000000000000'), + nonce: fromHex('0000000000000001'), + keystream: fromHex( + 'de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df1' + + '37821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e' + + '445f41e3' + ), + }, + { + key: fromHex('0000000000000000000000000000000000000000000000000000000000000000'), + nonce: fromHex('0100000000000000'), + keystream: fromHex( + 'ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd1' + + '38e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d' + + '6bbdb0041b2f586b' + ), + }, + { + key: fromHex('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'), + nonce: fromHex('0001020304050607'), + keystream: fromHex( + 'f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56' + + 'f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f1' + + '5916155c2be8241a38008b9a26bc35941e2444177c8ade6689de9526' + + '4986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e' + + '09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a4750' + + '32b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c5' + + '07b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f7' + + '6dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2' + + 'ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab7' + + '8fab78c9' + ), + }, +]; + +var vect, ctx, klen, out; +for (var i = 0; i < testVectors.length; i++) { + vect = testVectors[i]; + klen = vect.keystream.length; + out = new Array(klen); + + ctx = chacha20_init(vect.key, vect.nonce); + + chacha20_keystream(ctx, out, out, klen); + + console.log(bytesEqual(vect.keystream, out)); +} diff --git a/js/crypto_hash_sha256.js b/js/crypto_hash_sha256.js new file mode 100644 index 0000000..97f07d8 --- /dev/null +++ b/js/crypto_hash_sha256.js @@ -0,0 +1,116 @@ +/* crypto_hash - sha256 */ + +// Written in 2014 by Devi Mandiri. Public domain. +// +// Implementation derived from TweetNaCl version 20140427. +// See for details: http://tweetnacl.cr.yp.to/ +// +function load(x, pos) { + return x[pos+3] | (x[pos+2]<<8) | (x[pos+1]<<16) | (x[pos]<<24); +} + +function store(x, pos, u) { + x[pos+3] = u & 0xff; u >>= 8; + x[pos+2] = u & 0xff; u >>= 8; + x[pos+1] = u & 0xff; u >>= 8; + x[pos] = u & 0xff; +} + +function SHR(x, c) { return x >>> c; } +function ROTR(x, c) { return (x >>> c) | (x << (32 - c)); } +function Ch(x, y, z) { return ((x & y) ^ (~x & z)); } +function Maj(x, y, z) { return ((x & y) ^ (x & z) ^ (y & z)); } +function Sigma0(x) { return (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)); } +function Sigma1(x) { return (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)); } +function sigma0(x) { return (ROTR(x, 7) ^ ROTR(x,18) ^ SHR( x, 3)); } +function sigma1(x) { return (ROTR(x,17) ^ ROTR(x,19) ^ SHR( x,10)); } + +var K = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +]; + +function crypto_hashblocks(x, m, n) { + var z = new Uint32Array(8), + b = new Uint32Array(8), + a = new Uint32Array(8), + w = new Uint32Array(16), + t, i, j, pos = 0; + + for (i = 8; i--;) z[i] = a[i] = load(x, 4*i); + + while (n >= 64) { + for (i = 16; i--;) w[i] = load(m, 4*i+pos); + + for (i = 0; i < 64; i++) { + for (j = 8; j--;) b[j] = a[j]; + + t = a[7] + Sigma1(a[4]) + Ch(a[4], a[5], a[6]) + K[i] + w[i%16]; + b[7] = t + Sigma0(a[0]) + Maj(a[0], a[1], a[2]); + b[3] += t; + + for (j = 8; j--;) a[(j+1)%8] = b[j]; + + if (i%16 == 15) { + for (j = 0; j < 16; j++) { + w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]); + } + } + } + + for (i = 0; i < 8; i++) { + a[i] += z[i]; z[i] = a[i]; + } + pos += 64; + n -= 64; + } + + for (i = 0; i < 8; i++) store(x, 4*i, z[i]); + + return n; +} + +var iv = [ + 0x6a, 0x09, 0xe6, 0x67, + 0xbb, 0x67, 0xae, 0x85, + 0x3c, 0x6e, 0xf3, 0x72, + 0xa5, 0x4f, 0xf5, 0x3a, + 0x51, 0x0e, 0x52, 0x7f, + 0x9b, 0x05, 0x68, 0x8c, + 0x1f, 0x83, 0xd9, 0xab, + 0x5b, 0xe0, 0xcd, 0x19, +]; + +function crypto_hash(out, m, n) { + var h = new Uint32Array(iv), + x = new Uint32Array(128), + i, b = n << 3, len = n; + + crypto_hashblocks(h, m, n); + n &= 63; + + for (i = n; i--;) x[i] = m[len-n+i]; + x[n] = 128; + + n = 128-64*(n<56); + for (i = 1; i < 9; i++) { + x[n-i] = b; b >>=8; + } + crypto_hashblocks(h, x, n); + + for (i = 32; i--;) out[i] = h[i]; +} diff --git a/js/hashbang.js b/js/hashbang.js new file mode 100644 index 0000000..08a434d --- /dev/null +++ b/js/hashbang.js @@ -0,0 +1,35 @@ +// jquery hashbang(#!) +function hasbang(){ + $('a').each(function(){ + var o = $(this), url = o.attr('href'), p = url.match('^https?://'); + var h1 = location.hostname, h2 = h1.replace(/^www\./i,''); + + if (url == '#') { + o.attr('href','javascript:void(0);'); + return; + } + + if (url.match('^#!') || url.match('^javascript:')) + return; + + if (!p || url.match(h1) || url.match(h2)){ + if (p){ + url = url.substr(p[0].length); + if(url.indexOf('/') != -1) + url = url.substr(url.indexOf('/')); + else + url = ''; + } + if (url.charAt(0) == '#') + return; + if (url.charAt(0) == '/') + url = url.substr(1); + if (!url){ + o.attr('href',location.protocol + '//'+ h1); + return; + } + url = '#!'+url.replace(/\#\!/g,''); + o.attr('href',url); + } + }); +} \ No newline at end of file diff --git a/js/keccak-compat.js b/js/keccak-compat.js new file mode 100644 index 0000000..4e4c567 --- /dev/null +++ b/js/keccak-compat.js @@ -0,0 +1,209 @@ +// keccak +// +// Implementation derived from https://github.com/floodyberry/scrypt-jane +// +// Ported by Devi Mandiri. Public domain +// +var u64 = function (h, l) { + h = h|0; l = l|0; + this.hi = h >>> 0; + this.lo = l >>> 0; +} + +function xor64() { + var a = arguments, h = a[0].hi, l = a[0].lo; + for (var i = 1, len = a.length; i < len; i++) { + h = (h ^ a[i].hi) >>> 0; + l = (l ^ a[i].lo) >>> 0; + } + return new u64(h, l); +} + +function rotl64(x, c) { + var h0 = 0, l0 = 0, h1 = 0, l1 = 0, c1 = 64 - c; + + // shift left + if (c < 32) { + h0 = (x.hi << c) | ((x.lo & (((1 << c) - 1)|0) << (32 - c)) >>> (32 - c)); + l0 = x.lo << c; + } else { + h0 = x.lo << (c - 32); + } + + // shift right + if (c1 < 32) { + h1 = x.hi >>> c1; + l1 = (x.lo >>> c1) | (x.hi & (((1 << c1) - 1)|0)) << (32 - c1); + } else { + l1 = x.hi >>> (c1 - 32); + } + + return new u64(h0 | h1, l0 | l1); +} + +function xnd64(x, y, z) { + return new u64(x.hi ^ ((~y.hi) & z.hi), x.lo ^ ((~y.lo) & z.lo)); +} + +function load64(x, i) { + var l = x[i] | (x[i+1]<<8) | (x[i+2]<<16) | (x[i+3]<<24); + var h = x[i+4] | (x[i+5]<<8) | (x[i+6]<<16) | (x[i+7]<<24); + return new u64(h, l); +} + +var DigestSize = 64; // default keccak-512 +var Keccak_F = 1600; +var Keccak_C = 0; +var Keccak_R = 0; +var BlockSize = 0; + +var Context = function() { + var i = 25; + + this.state = new Array(i); + this.leftover = 0; + this.buffer = new Uint8Array(BlockSize); + + for (;i--;) this.state[i] = new u64(0, 0); + for (i = BlockSize; i--;) this.buffer[i] = 0; +}; + +var keccak_rounds = [ + new u64(0x00000000, 0x00000001), new u64(0x00000000, 0x00008082), + new u64(0x80000000, 0x0000808a), new u64(0x80000000, 0x80008000), + new u64(0x00000000, 0x0000808b), new u64(0x00000000, 0x80000001), + new u64(0x80000000, 0x80008081), new u64(0x80000000, 0x00008009), + new u64(0x00000000, 0x0000008a), new u64(0x00000000, 0x00000088), + new u64(0x00000000, 0x80008009), new u64(0x00000000, 0x8000000a), + new u64(0x00000000, 0x8000808b), new u64(0x80000000, 0x0000008b), + new u64(0x80000000, 0x00008089), new u64(0x80000000, 0x00008003), + new u64(0x80000000, 0x00008002), new u64(0x80000000, 0x00000080), + new u64(0x00000000, 0x0000800a), new u64(0x80000000, 0x8000000a), + new u64(0x80000000, 0x80008081), new u64(0x80000000, 0x00008080), + new u64(0x00000000, 0x80000001), new u64(0x80000000, 0x80008008) +]; + +var keccak_rotate=[1,3,6,10,15,21,28,36,45,55,2,14,27,41,56,8,25,43,62,18,39,61,20,44]; + +var keccak_pi=[10,7,11,17,18,3,5,16,8,21,24,4,15,23,19,13,12,2,20,14,22,9,6,1]; + +function blocks(state, input, pos) { + var i, x, y, t, bc = new Array(5); + + for (i = 0; i < BlockSize / 8; i++) { + state[i] = xor64(state[i], load64(input, i*8+pos)); + } + + for (i = 0; i < 24; ++i) { + for (x = 5; x--;) { + bc[x] = xor64(state[x], state[5+x], state[10+x], state[15+x], state[20+x]); + } + + for (x = 0; x < 5; ++x) { + t = xor64(bc[(x+4)%5], rotl64(bc[(x+1)%5], 1)); + for (y = 0; y < 25; y += 5) { + state[y+x] = xor64(state[y+x], t); + } + } + + t = state[1]; + for (x = 0; x < 24; ++x) { + bc[0] = state[keccak_pi[x]]; + state[keccak_pi[x]] = rotl64(t, keccak_rotate[x]); + t = bc[0]; + } + + for (y = 0; y < 25; y += 5) { + for (x = 5; x--;) { + bc[x] = state[y+x]; + } + for (x = 5; x--;) { + state[y+x] = xnd64(bc[x], bc[(x+1)%5], bc[(x+2)%5]); + } + } + + state[0] = xor64(state[0], keccak_rounds[i]); + } +} + +function init() { + if (typeof arguments[0] !== 'undefined') { + switch (arguments[0]) { + case 0: + DigestSize = 28; // keccak-224 + break; + case 1: + DigestSize = 32; // keccak-256 + break; + case 2: + DigestSize = 48; // keccak-384 + break; + default: + DigestSize = 64; // keccak-512 + } + } + + Keccak_C = DigestSize * 8 * 2; + Keccak_R = Keccak_F - Keccak_C; + BlockSize = Keccak_R / 8; + + return new Context(); +} + +function update(ctx, input, inlen) { + var pos = 0; + + if (ctx.leftover) { + var want = BlockSize - ctx.leftover; + want = (want < inlen) ? want : inlen; + for (var i = want; i--;) + ctx.buffer[i+ctx.leftover] = input[i+pos]; + ctx.leftover += want; + if (ctx.leftover < BlockSize) + return; + pos += want; + inlen -= want; + blocks(ctx.state, ctx.buffer, 0); + } + + while (inlen >= BlockSize) { + blocks(ctx.state, input, pos); + pos += BlockSize; + inlen -= BlockSize; + } + + ctx.leftover = inlen; + if (ctx.leftover) { + for (var i = ctx.leftover; i--;) { + ctx.buffer[i] = input[i+pos]; + } + } +} + +function finish(ctx, out) { + var i = 0, u = 0; + + ctx.buffer[ctx.leftover] = 0x01; + for (i = BlockSize - (ctx.leftover + 1); i--;) { + ctx.buffer[i+ctx.leftover+1] = 0; + } + ctx.buffer[BlockSize-1] |= 0x80; + blocks(ctx.state, ctx.buffer, 0); + + + for (i = 0; i < DigestSize; i += 8) { + u = ctx.state[i/8]; + + out[i] = (u.lo & 0xff); u.lo >>>= 8; + out[i+1] = (u.lo & 0xff); u.lo >>>= 8; + out[i+2] = (u.lo & 0xff); u.lo >>>= 8; + out[i+3] = (u.lo & 0xff); + + if (i !== 24 || DigestSize !== 28) { + out[i+4] = (u.hi & 0xff); u.hi >>>= 8; + out[i+5] = (u.hi & 0xff); u.hi >>>= 8; + out[i+6] = (u.hi & 0xff); u.hi >>>= 8; + out[i+7] = (u.hi & 0xff); + } + } +} diff --git a/js/keccak.js b/js/keccak.js new file mode 100644 index 0000000..8903997 --- /dev/null +++ b/js/keccak.js @@ -0,0 +1,268 @@ +// keccak +// +// Implementation derived from https://github.com/floodyberry/scrypt-jane +// +// Ported by Devi Mandiri. Public domain +// +var u64 = function (h, l) { + h = h|0; l = l|0; + this.hi = h >>> 0; + this.lo = l >>> 0; +} + +function xor64() { + var a = arguments, h = a[0].hi, l = a[0].lo; + for (var i = 1, len = a.length; i < len; i++) { + h = (h ^ a[i].hi) >>> 0; + l = (l ^ a[i].lo) >>> 0; + } + return new u64(h, l); +} + +function rotl64(x, c) { + var h0 = 0, l0 = 0, h1 = 0, l1 = 0, c1 = 64 - c; + + // shift left + if (c < 32) { + h0 = (x.hi << c) | ((x.lo & (((1 << c) - 1)|0) << (32 - c)) >>> (32 - c)); + l0 = x.lo << c; + } else { + h0 = x.lo << (c - 32); + } + + // shift right + if (c1 < 32) { + h1 = x.hi >>> c1; + l1 = (x.lo >>> c1) | (x.hi & (((1 << c1) - 1)|0)) << (32 - c1); + } else { + l1 = x.hi >>> (c1 - 32); + } + + return new u64(h0 | h1, l0 | l1); +} + +function xnd64(x, y, z) { + return new u64(x.hi ^ ((~y.hi) & z.hi), x.lo ^ ((~y.lo) & z.lo)); +} + +function load64(x, i) { + var l = x[i] | (x[i+1]<<8) | (x[i+2]<<16) | (x[i+3]<<24); + var h = x[i+4] | (x[i+5]<<8) | (x[i+6]<<16) | (x[i+7]<<24); + return new u64(h, l); +} + +var DigestSize = 64; // default keccak-512 +var Keccak_F = 1600; +var Keccak_C = 0; +var Keccak_R = 0; +var BlockSize = 0; + +var Context = function() { + var i = 25; + + this.state = new Array(i); + this.leftover = 0; + this.buffer = new Uint8Array(BlockSize); + + for (;i--;) this.state[i] = new u64(0, 0); + for (i = BlockSize; i--;) this.buffer[i] = 0; +}; + +var keccak_round_constants = [ + new u64(0x00000000, 0x00000001), new u64(0x00000000, 0x00008082), + new u64(0x80000000, 0x0000808a), new u64(0x80000000, 0x80008000), + new u64(0x00000000, 0x0000808b), new u64(0x00000000, 0x80000001), + new u64(0x80000000, 0x80008081), new u64(0x80000000, 0x00008009), + new u64(0x00000000, 0x0000008a), new u64(0x00000000, 0x00000088), + new u64(0x00000000, 0x80008009), new u64(0x00000000, 0x8000000a), + new u64(0x00000000, 0x8000808b), new u64(0x80000000, 0x0000008b), + new u64(0x80000000, 0x00008089), new u64(0x80000000, 0x00008003), + new u64(0x80000000, 0x00008002), new u64(0x80000000, 0x00000080), + new u64(0x00000000, 0x0000800a), new u64(0x80000000, 0x8000000a), + new u64(0x80000000, 0x80008081), new u64(0x80000000, 0x00008080), + new u64(0x00000000, 0x80000001), new u64(0x80000000, 0x80008008) +]; + +function blocks(ctx, input, pos) { + var i = 0, + s = ctx.state, + t = new Array(5), + u = new Array(5), + v, w; + + for (i = 0; i < BlockSize / 8; i++) { // 256=8 512=16 + s[i] = xor64(s[i], load64(input, i*8+pos)); + } + + for (i = 0; i < 24; i++) { + t[0] = xor64(s[0], s[5], s[10], s[15], s[20]); + t[1] = xor64(s[1], s[6], s[11], s[16], s[21]); + t[2] = xor64(s[2], s[7], s[12], s[17], s[22]); + t[3] = xor64(s[3], s[8], s[13], s[18], s[23]); + t[4] = xor64(s[4], s[9], s[14], s[19], s[24]); + + u[0] = xor64(t[4], rotl64(t[1], 1)); + u[1] = xor64(t[0], rotl64(t[2], 1)); + u[2] = xor64(t[1], rotl64(t[3], 1)); + u[3] = xor64(t[2], rotl64(t[4], 1)); + u[4] = xor64(t[3], rotl64(t[0], 1)); + + s[0] = xor64(s[0], u[0]); s[5] = xor64(s[5], u[0]); s[10] = xor64(s[10], u[0]); s[15] = xor64(s[15], u[0]); s[20] = xor64(s[20], u[0]); + s[1] = xor64(s[1], u[1]); s[6] = xor64(s[6], u[1]); s[11] = xor64(s[11], u[1]); s[16] = xor64(s[16], u[1]); s[21] = xor64(s[21], u[1]); + s[2] = xor64(s[2], u[2]); s[7] = xor64(s[7], u[2]); s[12] = xor64(s[12], u[2]); s[17] = xor64(s[17], u[2]); s[22] = xor64(s[22], u[2]); + s[3] = xor64(s[3], u[3]); s[8] = xor64(s[8], u[3]); s[13] = xor64(s[13], u[3]); s[18] = xor64(s[18], u[3]); s[23] = xor64(s[23], u[3]); + s[4] = xor64(s[4], u[4]); s[9] = xor64(s[9], u[4]); s[14] = xor64(s[14], u[4]); s[19] = xor64(s[19], u[4]); s[24] = xor64(s[24], u[4]); + + v = s[1]; + s[ 1] = rotl64(s[ 6], 44); + s[ 6] = rotl64(s[ 9], 20); + s[ 9] = rotl64(s[22], 61); + s[22] = rotl64(s[14], 39); + s[14] = rotl64(s[20], 18); + s[20] = rotl64(s[ 2], 62); + s[ 2] = rotl64(s[12], 43); + s[12] = rotl64(s[13], 25); + s[13] = rotl64(s[19], 8); + s[19] = rotl64(s[23], 56); + s[23] = rotl64(s[15], 41); + s[15] = rotl64(s[ 4], 27); + s[ 4] = rotl64(s[24], 14); + s[24] = rotl64(s[21], 2); + s[21] = rotl64(s[ 8], 55); + s[ 8] = rotl64(s[16], 45); + s[16] = rotl64(s[ 5], 36); + s[ 5] = rotl64(s[ 3], 28); + s[ 3] = rotl64(s[18], 21); + s[18] = rotl64(s[17], 15); + s[17] = rotl64(s[11], 10); + s[11] = rotl64(s[ 7], 6); + s[ 7] = rotl64(s[10], 3); + s[10] = rotl64(v , 1); + + v = s[0]; + w = s[1]; + s[0] = xnd64(s[0], w , s[2]); + s[1] = xnd64(s[1], s[2], s[3]); + s[2] = xnd64(s[2], s[3], s[4]); + s[3] = xnd64(s[3], s[4], v); + s[4] = xnd64(s[4], v , w); + + v = s[5]; + w = s[6]; + s[5] = xnd64(s[5], w , s[7]); + s[6] = xnd64(s[6], s[7], s[8]); + s[7] = xnd64(s[7], s[8], s[9]); + s[8] = xnd64(s[8], s[9], v); + s[9] = xnd64(s[9], v , w); + + v = s[10]; + w = s[11]; + s[10] = xnd64(s[10], w , s[12]); + s[11] = xnd64(s[11], s[12], s[13]); + s[12] = xnd64(s[12], s[13], s[14]); + s[13] = xnd64(s[13], s[14], v); + s[14] = xnd64(s[14], v , w); + + v = s[15]; + w = s[16]; + s[15] = xnd64(s[15], w , s[17]); + s[16] = xnd64(s[16], s[17], s[18]); + s[17] = xnd64(s[17], s[18], s[19]); + s[18] = xnd64(s[18], s[19], v); + s[19] = xnd64(s[19], v , w); + + v = s[20]; + w = s[21]; + s[20] = xnd64(s[20], w , s[22]); + s[21] = xnd64(s[21], s[22], s[23]); + s[22] = xnd64(s[22], s[23], s[24]); + s[23] = xnd64(s[23], s[24], v); + s[24] = xnd64(s[24], v , w); + + s[0] = xor64(s[0], keccak_round_constants[i]); + } + + ctx.state = s; +} + +function init() { + if (typeof arguments[0] !== 'undefined') { + switch (arguments[0]) { + case 0: + DigestSize = 28; // keccak-224 + break; + case 1: + DigestSize = 32; // keccak-256 + break; + case 2: + DigestSize = 48; // keccak-384 + break; + default: + DigestSize = 64; // keccak-512 + } + } + + Keccak_C = DigestSize * 8 * 2; + Keccak_R = Keccak_F - Keccak_C; + BlockSize = Keccak_R / 8; + + return new Context(); +} + +function update(ctx, input, inlen) { + var pos = 0; + + if (ctx.leftover) { + var want = BlockSize - ctx.leftover; + want = (want < inlen) ? want : inlen; + for (var i = want; i--;) + ctx.buffer[i+ctx.leftover] = input[i+pos]; + ctx.leftover += want; + if (ctx.leftover < BlockSize) + return; + pos += want; + inlen -= want; + blocks(ctx, ctx.buffer, 0); + } + + while (inlen >= BlockSize) { + blocks(ctx, input, pos); + pos += BlockSize; + inlen -= BlockSize; + } + + ctx.leftover = inlen; + if (ctx.leftover) { + for (var i = ctx.leftover; i--;) { + ctx.buffer[i] = input[i+pos]; + } + } +} + +function finish(ctx, out) { + var i = 0, u = 0; + + ctx.buffer[ctx.leftover] = 0x01; + for (i = BlockSize - (ctx.leftover + 1); i--;) { + ctx.buffer[i+ctx.leftover+1] = 0; + } + ctx.buffer[BlockSize-1] |= 0x80; + blocks(ctx, ctx.buffer, 0); + + + for (i = 0; i < DigestSize; i += 8) { + u = ctx.state[i/8]; + + out[i] = (u.lo & 0xff); u.lo >>>= 8; + out[i+1] = (u.lo & 0xff); u.lo >>>= 8; + out[i+2] = (u.lo & 0xff); u.lo >>>= 8; + out[i+3] = (u.lo & 0xff); + + if (i !== 24 || DigestSize !== 28) { + out[i+4] = (u.hi & 0xff); u.hi >>>= 8; + out[i+5] = (u.hi & 0xff); u.hi >>>= 8; + out[i+6] = (u.hi & 0xff); u.hi >>>= 8; + out[i+7] = (u.hi & 0xff); + } + } +} diff --git a/js/poly1305.js b/js/poly1305.js new file mode 100644 index 0000000..4379fc9 --- /dev/null +++ b/js/poly1305.js @@ -0,0 +1,252 @@ +/* poly1305 */ + +// Written in 2014 by Devi Mandiri. Public domain. +// +// Implementation derived from poly1305-donna-16.h +// See for details: https://github.com/floodyberry/poly1305-donna + +var Poly1305BlockSize = 16; + +var Poly1305Ctx = function() { + this.buffer = new Array(Poly1305BlockSize); + this.leftover = 0; + this.r = new Array(10); + this.h = new Array(10); + this.pad = new Array(8); + this.finished = 0; +}; + +function U8TO16(p, pos) { + return ((p[pos] & 0xff) & 0xffff) | (((p[pos+1] & 0xff) & 0xffff) << 8); +} + +function U16TO8(p, pos, v) { + p[pos] = (v ) & 0xff; + p[pos+1] = (v >>> 8) & 0xff; +} + +function poly1305_init(ctx, key) { + var t = [], i = 0; + + for (i = 8; i--;) t[i] = U8TO16(key, i*2); + + ctx.r[0] = t[0] & 0x1fff; + ctx.r[1] = ((t[0] >>> 13) | (t[1] << 3)) & 0x1fff; + ctx.r[2] = ((t[1] >>> 10) | (t[2] << 6)) & 0x1f03; + ctx.r[3] = ((t[2] >>> 7) | (t[3] << 9)) & 0x1fff; + ctx.r[4] = ((t[3] >>> 4) | (t[4] << 12)) & 0x00ff; + ctx.r[5] = (t[4] >>> 1) & 0x1ffe; + ctx.r[6] = ((t[4] >>> 14) | (t[5] << 2)) & 0x1fff; + ctx.r[7] = ((t[5] >>> 11) | (t[6] << 5)) & 0x1f81; + ctx.r[8] = ((t[6] >>> 8) | (t[7] << 8)) & 0x1fff; + ctx.r[9] = (t[7] >>> 5) & 0x007f; + + for (i = 8; i--;) { + ctx.h[i] = 0; + ctx.pad[i] = U8TO16(key, 16+(2*i)); + } + ctx.h[8] = 0; + ctx.h[9] = 0; + ctx.leftover = 0; + ctx.finished = 0; +} + +function poly1305_blocks(ctx, m, mpos, bytes) { + var hibit = ctx.finished ? 0 : (1 << 11); + var t = [], d = [], c = 0, i = 0, j = 0; + + while (bytes >= Poly1305BlockSize) { + for (i = 8; i--;) t[i] = U8TO16(m, i*2+mpos); + + ctx.h[0] += t[0] & 0x1fff; + ctx.h[1] += ((t[0] >>> 13) | (t[1] << 3)) & 0x1fff; + ctx.h[2] += ((t[1] >>> 10) | (t[2] << 6)) & 0x1fff; + ctx.h[3] += ((t[2] >>> 7) | (t[3] << 9)) & 0x1fff; + ctx.h[4] += ((t[3] >>> 4) | (t[4] << 12)) & 0x1fff; + ctx.h[5] += (t[4] >>> 1) & 0x1fff; + ctx.h[6] += ((t[4] >>> 14) | (t[5] << 2)) & 0x1fff; + ctx.h[7] += ((t[5] >>> 11) | (t[6] << 5)) & 0x1fff; + ctx.h[8] += ((t[6] >>> 8) | (t[7] << 8)) & 0x1fff; + ctx.h[9] += (t[7] >>> 5) | hibit; + + for (i = 0, c = 0; i < 10; i++) { + d[i] = c; + for (j = 0; j < 10; j++) { + d[i] += (ctx.h[j] & 0xffffffff) * ((j <= i) ? ctx.r[i-j] : (5 * ctx.r[i+10-j])); + if (j === 4) { + c = (d[i] >>> 13); + d[i] &= 0x1fff; + } + } + c += (d[i] >>> 13); + d[i] &= 0x1fff; + } + c = ((c << 2) + c); + c += d[0]; + d[0] = ((c & 0xffff) & 0x1fff); + c = (c >>> 13); + d[1] += c; + + for (i = 10; i--;) ctx.h[i] = d[i] & 0xffff; + + mpos += Poly1305BlockSize; + bytes -= Poly1305BlockSize; + } +} + +function poly1305_update(ctx, m, bytes) { + var want = 0, i = 0, mpos = 0; + + if (ctx.leftover) { + want = (Poly1305BlockSize - ctx.leftover); + if (want > bytes) + want = bytes; + for (i = want; i--;) { + ctx.buffer[ctx.leftover+i] = m[i+mpos]; + } + bytes -= want; + mpos += want; + ctx.leftover += want; + if (ctx.leftover < Poly1305BlockSize) + return; + poly1305_blocks(ctx, ctx.buffer, 0, Poly1305BlockSize); + ctx.leftover = 0; + } + + if (bytes >= Poly1305BlockSize) { + want = (bytes & ~(Poly1305BlockSize - 1)); + poly1305_blocks(ctx, m, mpos, want); + mpos += want; + bytes -= want; + } + + if (bytes) { + for (i = bytes; i--;) { + ctx.buffer[ctx.leftover+i] = m[i+mpos]; + } + ctx.leftover += bytes; + } +} + +function poly1305_finish(ctx, mac) { + var g = [], c = 0, mask = 0, f = 0, i = 0; + + if (ctx.leftover) { + i = ctx.leftover; + ctx.buffer[i++] = 1; + for (; i < Poly1305BlockSize; i++) { + ctx.buffer[i] = 0; + } + ctx.finished = 1; + poly1305_blocks(ctx, ctx.buffer, 0, Poly1305BlockSize); + } + + c = ctx.h[1] >>> 13; + ctx.h[1] &= 0x1fff; + for (i = 2; i < 10; i++) { + ctx.h[i] += c; + c = ctx.h[i] >>> 13; + ctx.h[i] &= 0x1fff; + } + ctx.h[0] += (c * 5); + c = ctx.h[0] >>> 13; + ctx.h[0] &= 0x1fff; + ctx.h[1] += c; + c = ctx.h[1] >>> 13; + ctx.h[1] &= 0x1fff; + ctx.h[2] += c; + + g[0] = ctx.h[0] + 5; + c = g[0] >>> 13; + g[0] &= 0x1fff; + for (i = 1; i < 10; i++) { + g[i] = ctx.h[i] + c; + c = g[i] >>> 13; + g[i] &= 0x1fff; + } + g[9] -= (1 << 13); + g[9] &= 0xffff; + + mask = (g[9] >>> 15) - 1; + for (i = 10; i--;) g[i] &= mask; + mask = ~mask; + for (i = 10; i--;) { + ctx.h[i] = (ctx.h[i] & mask) | g[i]; + } + + ctx.h[0] = ((ctx.h[0] ) | (ctx.h[1] << 13)) & 0xffff; + ctx.h[1] = ((ctx.h[1] >> 3) | (ctx.h[2] << 10)) & 0xffff; + ctx.h[2] = ((ctx.h[2] >> 6) | (ctx.h[3] << 7)) & 0xffff; + ctx.h[3] = ((ctx.h[3] >> 9) | (ctx.h[4] << 4)) & 0xffff; + ctx.h[4] = ((ctx.h[4] >> 12) | (ctx.h[5] << 1) | (ctx.h[6] << 14)) & 0xffff; + ctx.h[5] = ((ctx.h[6] >> 2) | (ctx.h[7] << 11)) & 0xffff; + ctx.h[6] = ((ctx.h[7] >> 5) | (ctx.h[8] << 8)) & 0xffff; + ctx.h[7] = ((ctx.h[8] >> 8) | (ctx.h[9] << 5)) & 0xffff; + + f = (ctx.h[0] & 0xffffffff) + ctx.pad[0]; + ctx.h[0] = f & 0xffff; + for (i = 1; i < 8; i++) { + f = (ctx.h[i] & 0xffffffff) + ctx.pad[i] + (f >>> 16); + ctx.h[i] = f & 0xffff; + } + + for (i = 8; i--;) { + U16TO8(mac, i*2, ctx.h[i]); + ctx.pad[i] = 0; + } + for (i = 10; i--;) { + ctx.h[i] = 0; + ctx.r[i] = 0; + } +} + +function poly1305_auth(mac, m, bytes, key) { + var ctx = new Poly1305Ctx(); + poly1305_init(ctx, key); + poly1305_update(ctx, m, bytes); + poly1305_finish(ctx, mac); +} + +function poly1305_verify(mac1, mac2) { + var dif = 0; + for (var i = 0; i < 16; i++) { + dif |= (mac1[i] ^ mac2[i]); + } + dif = (dif - 1) >>> 31; + return (dif & 1); +} + +//--------------------------- test -----------------------------// +function fromHex(h) { + var out = [], len = h.length, w = ''; + for (var i = 0; i < len; i += 2) { + w = h[i]; + if (((i+1) >= len) || typeof h[i+1] === 'undefined') { + w += '0'; + } else { + w += h[i+1]; + } + out.push(parseInt(w, 16)); + } + return out; +} + +// testVectors from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#page-11 +var testVectors = [ + { + input: fromHex('0000000000000000000000000000000000000000000000000000000000000000'), + key: fromHex('746869732069732033322d62797465206b657920666f7220506f6c7931333035'), + tag: fromHex('49ec78090e481ec6c26b33b91ccc0307'), + }, + { + input: fromHex('48656c6c6f20776f726c6421'), + key: fromHex('746869732069732033322d62797465206b657920666f7220506f6c7931333035'), + tag: fromHex('a6f745008f81c916a20dcc74eef2b2f0'), + } +]; + +var mac = []; +for (var i = 0; i < testVectors.length; i++) { + poly1305_auth(mac, testVectors[i].input, testVectors[i].input.length, testVectors[i].key); + console.log(poly1305_verify(testVectors[i].tag, mac)); +} diff --git a/js/sha512.js b/js/sha512.js new file mode 100644 index 0000000..2df694b --- /dev/null +++ b/js/sha512.js @@ -0,0 +1,272 @@ +/* sha512 */ + +// Written in 2014 by Devi Mandiri. Public domain. +// +// Implementation derived from TweetNaCl version 20140427. +// See for details: http://tweetnacl.cr.yp.to/ +// +var u64 = function (h, l) { + h = h|0; l = l|0; + this.hi = h >>> 0; + this.lo = l >>> 0; +}; + +function dl64(x, i) { + var h = (x[i] << 24) | (x[i+1] << 16) | (x[i+2] << 8) | x[i+3]; + var l = (x[i+4] << 24) | (x[i+5] << 16) | (x[i+6] << 8) | x[i+7]; + return new u64(h, l); +} + +function ts64(x, i, u) { + x[i] = (u.hi >>> 24) & 0xff; + x[i+1] = (u.hi >>> 16) & 0xff; + x[i+2] = (u.hi >>> 8) & 0xff; + x[i+3] = u.hi & 0xff; + x[i+4] = (u.lo >>> 24) & 0xff; + x[i+5] = (u.lo >>> 16) & 0xff; + x[i+6] = (u.lo >>> 8) & 0xff; + x[i+7] = u.lo & 0xff; +} + +function add64() { + var l = 0, h = 0, c; + for (var i = 0; i < arguments.length; i++) { + l = (l + arguments[i].lo)>>>0; + c = (l < (arguments[i].lo>>>0))|0; + h = (h + arguments[i].hi + c)>>>0; + } + return new u64(h, l); +} + +function shr(x, c) { + var h = 0, l = 0; + if (c < 32) { + l = (x.lo >>> c) | (x.hi & (((1 << c) - 1)|0)) << (32 - c); + h = x.hi >>> c; + } else { + l = x.hi >>> (c - 32); + } + return new u64(h, l); +} + +function R(x, c) { + var h = 0, l = 0, t = shr(x, c), c = 64 - c; + if (c < 32) { + h = (x.hi << c) | ((x.lo & (((1 << c) - 1)|0) << (32 - c)) >>> (32 - c)); + l = x.lo << c; + } else { + h = x.lo << (c - 32); + } + return new u64(t.hi | h, t.lo | l); +} + +function Ch(x, y, z) { + var h = (x.hi & y.hi) ^ (~x.hi & z.hi), + l = (x.lo & y.lo) ^ (~x.lo & z.lo); + return new u64(h, l); +} + +function Maj(x, y, z) { + var h = (x.hi & y.hi) ^ (x.hi & z.hi) ^ (y.hi & z.hi), + l = (x.lo & y.lo) ^ (x.lo & z.lo) ^ (y.lo & z.lo); + return new u64(h, l); +} + +function Sigma0(x) { + var s = [], h, l; + s[0] = R(x, 28); s[1] = R(x, 34); s[2] = R(x, 39); + h = s[0].hi ^ s[1].hi ^ s[2].hi; + l = s[0].lo ^ s[1].lo ^ s[2].lo; + return new u64(h, l); +} + +function Sigma1(x) { + var s = [], h, l; + s[0] = R(x, 14); s[1] = R(x, 18); s[2] = R(x, 41); + h = s[0].hi ^ s[1].hi ^ s[2].hi; + l = s[0].lo ^ s[1].lo ^ s[2].lo; + return new u64(h, l); +} + +function sigma0(x) { + var s = [], h, l; + s[0] = R(x, 1); s[1] = R(x, 8); s[2] = shr(x, 7); + h = s[0].hi ^ s[1].hi ^ s[2].hi; + l = s[0].lo ^ s[1].lo ^ s[2].lo; + return new u64(h, l); +} + +function sigma1(x) { + var s = [], h, l; + s[0] = R(x, 19); s[1] = R(x, 61); s[2] = shr(x, 6); + h = s[0].hi ^ s[1].hi ^ s[2].hi; + l = s[0].lo ^ s[1].lo ^ s[2].lo; + return new u64(h, l); +} + +var K = [ + new u64(0x428a2f98, 0xd728ae22), new u64(0x71374491, 0x23ef65cd), + new u64(0xb5c0fbcf, 0xec4d3b2f), new u64(0xe9b5dba5, 0x8189dbbc), + new u64(0x3956c25b, 0xf348b538), new u64(0x59f111f1, 0xb605d019), + new u64(0x923f82a4, 0xaf194f9b), new u64(0xab1c5ed5, 0xda6d8118), + new u64(0xd807aa98, 0xa3030242), new u64(0x12835b01, 0x45706fbe), + new u64(0x243185be, 0x4ee4b28c), new u64(0x550c7dc3, 0xd5ffb4e2), + new u64(0x72be5d74, 0xf27b896f), new u64(0x80deb1fe, 0x3b1696b1), + new u64(0x9bdc06a7, 0x25c71235), new u64(0xc19bf174, 0xcf692694), + new u64(0xe49b69c1, 0x9ef14ad2), new u64(0xefbe4786, 0x384f25e3), + new u64(0x0fc19dc6, 0x8b8cd5b5), new u64(0x240ca1cc, 0x77ac9c65), + new u64(0x2de92c6f, 0x592b0275), new u64(0x4a7484aa, 0x6ea6e483), + new u64(0x5cb0a9dc, 0xbd41fbd4), new u64(0x76f988da, 0x831153b5), + new u64(0x983e5152, 0xee66dfab), new u64(0xa831c66d, 0x2db43210), + new u64(0xb00327c8, 0x98fb213f), new u64(0xbf597fc7, 0xbeef0ee4), + new u64(0xc6e00bf3, 0x3da88fc2), new u64(0xd5a79147, 0x930aa725), + new u64(0x06ca6351, 0xe003826f), new u64(0x14292967, 0x0a0e6e70), + new u64(0x27b70a85, 0x46d22ffc), new u64(0x2e1b2138, 0x5c26c926), + new u64(0x4d2c6dfc, 0x5ac42aed), new u64(0x53380d13, 0x9d95b3df), + new u64(0x650a7354, 0x8baf63de), new u64(0x766a0abb, 0x3c77b2a8), + new u64(0x81c2c92e, 0x47edaee6), new u64(0x92722c85, 0x1482353b), + new u64(0xa2bfe8a1, 0x4cf10364), new u64(0xa81a664b, 0xbc423001), + new u64(0xc24b8b70, 0xd0f89791), new u64(0xc76c51a3, 0x0654be30), + new u64(0xd192e819, 0xd6ef5218), new u64(0xd6990624, 0x5565a910), + new u64(0xf40e3585, 0x5771202a), new u64(0x106aa070, 0x32bbd1b8), + new u64(0x19a4c116, 0xb8d2d0c8), new u64(0x1e376c08, 0x5141ab53), + new u64(0x2748774c, 0xdf8eeb99), new u64(0x34b0bcb5, 0xe19b48a8), + new u64(0x391c0cb3, 0xc5c95a63), new u64(0x4ed8aa4a, 0xe3418acb), + new u64(0x5b9cca4f, 0x7763e373), new u64(0x682e6ff3, 0xd6b2b8a3), + new u64(0x748f82ee, 0x5defb2fc), new u64(0x78a5636f, 0x43172f60), + new u64(0x84c87814, 0xa1f0ab72), new u64(0x8cc70208, 0x1a6439ec), + new u64(0x90befffa, 0x23631e28), new u64(0xa4506ceb, 0xde82bde9), + new u64(0xbef9a3f7, 0xb2c67915), new u64(0xc67178f2, 0xe372532b), + new u64(0xca273ece, 0xea26619c), new u64(0xd186b8c7, 0x21c0c207), + new u64(0xeada7dd6, 0xcde0eb1e), new u64(0xf57d4f7f, 0xee6ed178), + new u64(0x06f067aa, 0x72176fba), new u64(0x0a637dc5, 0xa2c898a6), + new u64(0x113f9804, 0xbef90dae), new u64(0x1b710b35, 0x131c471b), + new u64(0x28db77f5, 0x23047d84), new u64(0x32caab7b, 0x40c72493), + new u64(0x3c9ebe0a, 0x15c9bebc), new u64(0x431d67c4, 0x9c100d4c), + new u64(0x4cc5d4be, 0xcb3e42b6), new u64(0x597f299c, 0xfc657e2a), + new u64(0x5fcb6fab, 0x3ad6faec), new u64(0x6c44198c, 0x4a475817) +]; + +var iv = [ + 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, + 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, + 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, + 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, + 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, + 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, + 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, + 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 +]; + +function crypto_hashblocks(x, m, n) { + var z = [], b = [], a = [], w = [], t, i, j; + + for (i = 0; i < 8; i++) z[i] = a[i] = dl64(x, 8*i); + + var pos = 0; + while (n >= 128) { + for (i = 0; i < 16; i++) w[i] = dl64(m, 8*i+pos); + for (i = 0; i < 80; i++) { + for (j = 0; j < 8; j++) b[j] = a[j]; + t = add64(a[7], Sigma1(a[4]), Ch(a[4], a[5], a[6]), K[i], w[i%16]); + b[7] = add64(t, Sigma0(a[0]), Maj(a[0], a[1], a[2])); + b[3] = add64(b[3], t); + for (j = 0; j < 8; j++) a[(j+1)%8] = b[j]; + if (i%16 == 15) { + for (j = 0; j < 16; j++) { + w[j] = add64(w[j], w[(j+9)%16], sigma0(w[(j+1)%16]), sigma1(w[(j+14)%16])); + } + } + } + + for (i = 0; i < 8; i++) { + a[i] = add64(a[i], z[i]); + z[i] = a[i]; + } + + pos += 128; + n -= 128; + } + + for (i = 0; i < 8; i++) ts64(x, 8*i, z[i]); + return n; +} + +function crypto_hash(out, m, n) { + var h = iv.slice(0), x = new Array(256); + var i, b = n; + + crypto_hashblocks(h, m, n); + n &= 127; + + for (i = 0; i < 256; i++) x[i] = 0; + for (i = 0; i < n; i++) x[i] = m[b-n+i]; + x[n] = 128; + + n = 256-128*(n<112); + x[n-9] = b >> 61; + ts64(x, n-8, new u64(0, b << 3)); + crypto_hashblocks(h, x, n); + + for (i = 0; i < 64; i++) out[i] = h[i]; +} + +function bytesEqual(a, b) { + var dif = 0; + if (a.length !== b.length) return 0; + for (var i = 0; i < a.length; i++) { + dif |= (a[i] ^ b[i]); + } + dif = (dif - 1) >>> 31; + return (dif & 1); +} + +function crypto_hash_test() { + // golden taken from https://code.google.com/p/go/source/browse/src/pkg/crypto/sha512/sha512_test.go + var golden = [ + [[207,131,225,53,126,239,184,189,241,84,40,80,214,109,128,7,214,32,228,5,11,87,21,220,131,244,169,33,211,108,233,206,71,208,209,60,93,133,242,176,255,131,24,210,135,126,236,47,99,185,49,189,71,65,122,129,165,56,50,122,249,39,218,62 ],[]], + [[31,64,252,146,218,36,22,148,117,9,121,238,108,245,130,242,213,215,210,142,24,51,93,224,90,188,84,208,86,14,15,83,2,134,12,101,43,240,141,86,2,82,170,94,116,33,5,70,243,105,251,187,206,140,18,207,199,149,123,38,82,254,154,117 ],[ 97]], + [[45,64,138,7,23,236,24,129,88,39,138,121,108,104,144,68,54,29,198,253,222,40,214,240,73,115,184,8,150,225,130,57,117,205,191,18,235,99,249,224,89,19,40,238,35,93,128,233,181,191,26,166,164,79,70,23,255,60,175,100,0,235,23,45 ],[ 97,98]], + [[221,175,53,161,147,97,122,186,204,65,115,73,174,32,65,49,18,230,250,78,137,169,126,162,10,158,238,230,75,85,211,154,33,146,153,42,39,79,193,168,54,186,60,35,163,254,235,189,69,77,68,35,100,60,232,14,42,154,201,79,165,76,164,159 ],[ 97,98,99]], + [[216,2,47,32,96,173,110,253,41,122,183,61,204,83,85,201,178,20,5,75,13,23,118,161,54,166,105,210,106,125,59,20,247,58,160,208,235,255,25,238,51,51,104,240,22,75,100,25,169,109,164,158,62,72,23,83,231,233,107,113,107,220,203,111 ],[ 97,98,99,100]], + [[135,138,230,90,146,232,108,172,1,26,87,13,76,48,167,234,236,68,43,133,206,142,202,12,41,82,181,227,204,6,40,194,231,157,136,154,212,213,199,198,38,152,109,69,45,216,99,116,182,255,170,124,216,182,118,101,190,242,40,154,92,112,176,161 ],[ 97,98,99,100,101]], + [[227,46,241,150,35,232,237,157,38,127,101,122,129,148,75,61,7,173,187,118,133,24,6,142,136,67,87,69,86,78,141,65,80,160,167,3,190,42,125,136,182,30,61,57,12,43,185,126,45,76,49,31,220,105,214,177,38,127,5,245,154,169,32,231 ],[ 97,98,99,100,101,102]], + [[215,22,164,24,133,105,182,138,177,182,223,172,23,142,87,1,20,205,240,234,58,28,192,227,20,134,195,228,18,65,188,106,118,66,78,140,55,171,38,240,150,252,133,239,152,134,200,203,99,65,135,244,253,223,246,69,251,9,159,31,245,76,107,140 ],[ 97,98,99,100,101,102,103]], + [[163,168,200,27,201,124,37,96,1,13,115,137,188,136,170,201,116,161,4,224,226,56,18,32,198,224,132,196,220,205,29,45,23,212,248,109,179,28,42,133,29,200,14,102,129,215,71,51,197,93,205,3,221,150,246,6,44,221,161,42,41,26,230,206 ],[ 97,98,99,100,101,102,103,104]], + [[242,45,81,210,82,146,202,29,15,104,246,154,237,199,137,112,25,48,140,201,219,70,239,183,90,3,221,73,79,199,241,38,192,16,232,173,230,160,10,12,26,95,27,117,216,30,14,213,169,60,233,141,201,184,51,219,120,57,36,123,29,156,36,254 ],[ 97,98,99,100,101,102,103,104,105]], + [[239,107,151,50,31,52,177,254,162,22,154,125,185,225,150,11,71,26,161,51,2,169,136,8,115,87,197,32,190,149,124,161,25,195,186,104,230,180,152,44,1,158,200,157,227,134,92,207,106,60,218,31,225,30,89,249,141,153,241,80,44,139,151,69 ],[ 97,98,99,100,101,102,103,104,105,106]], + [[34,16,217,154,249,200,189,236,218,27,75,239,248,34,19,103,83,216,52,37,5,221,206,55,241,49,78,44,219,180,136,198,1,107,218,169,189,47,250,81,61,213,222,46,75,80,240,49,57,61,138,182,31,119,59,14,1,48,215,56,30,15,138,29 ],[ 68,105,115,99,97,114,100,32,109,101,100,105,99,105,110,101,32,109,111,114,101,32,116,104,97,110,32,116,119,111,32,121,101,97,114,115,32,111,108,100,46]], + [[166,135,168,152,91,77,141,10,36,241,21,254,39,34,85,198,175,175,57,9,34,88,56,84,97,89,193,237,104,92,33,26,32,55,150,174,142,204,76,129,165,182,49,89,25,179,166,79,16,113,61,160,126,52,31,205,187,8,84,27,240,48,102,206 ],[ 72,101,32,119,104,111,32,104,97,115,32,97,32,115,104,97,100,121,32,112,97,115,116,32,107,110,111,119,115,32,116,104,97,116,32,110,105,99,101,32,103,117,121,115,32,102,105,110,105,115,104,32,108,97,115,116,46]], + [[141,219,3,146,232,24,183,213,133,171,34,118,154,80,223,102,13,159,109,85,156,202,58,252,86,145,184,202,145,184,69,19,116,228,43,205,171,214,69,137,237,124,145,216,95,98,101,150,34,138,92,133,114,103,126,185,139,198,182,36,190,251,122,248 ],[ 73,32,119,111,117,108,100,110,39,116,32,109,97,114,114,121,32,104,105,109,32,119,105,116,104,32,97,32,116,101,110,32,102,111,111,116,32,112,111,108,101,46]], + [[38,237,143,108,167,248,212,75,106,138,84,174,57,100,15,168,173,92,103,63,112,238,156,224,116,186,78,240,212,131,238,160,11,171,47,97,216,105,93,107,52,223,156,108,72,174,54,36,99,98,32,14,216,32,68,139,220,3,167,32,54,106,135,198 ],[ 70,114,101,101,33,32,70,114,101,101,33,47,65,32,116,114,105,112,47,116,111,32,77,97,114,115,47,102,111,114,32,57,48,48,47,101,109,112,116,121,32,106,97,114,115,47,66,117,114,109,97,32,83,104,97,118,101]], + [[229,161,75,240,68,190,105,97,90,173,232,154,252,241,171,3,137,213,252,48,42,136,77,64,53,121,209,56,106,36,0,192,137,176,219,179,135,237,15,70,63,158,227,66,248,36,77,90,56,207,188,14,129,157,169,82,159,191,247,131,104,201,169,130 ],[ 84,104,101,32,100,97,121,115,32,111,102,32,116,104,101,32,100,105,103,105,116,97,108,32,119,97,116,99,104,32,97,114,101,32,110,117,109,98,101,114,101,100,46,32,32,45,84,111,109,32,83,116,111,112,112,97,114,100]], + [[66,10,31,170,72,145,158,20,101,27,237,69,114,90,190,15,122,88,224,240,153,66,76,78,90,73,25,73,70,227,139,70,193,248,3,75,24,239,22,155,46,49,5,13,22,72,224,185,130,56,101,149,247,223,71,218,75,111,209,142,85,51,48,21 ],[ 78,101,112,97,108,32,112,114,101,109,105,101,114,32,119,111,110,39,116,32,114,101,115,105,103,110,46]], + [[217,38,168,99,190,173,178,1,52,219,7,104,53,53,199,32,7,176,230,149,4,88,118,37,79,52,29,220,204,222,19,42,144,140,90,245,123,170,106,106,156,99,230,100,155,186,12,33,61,192,95,173,207,154,188,206,160,159,35,220,251,99,127,190 ],[ 70,111,114,32,101,118,101,114,121,32,97,99,116,105,111,110,32,116,104,101,114,101,32,105,115,32,97,110,32,101,113,117,97,108,32,97,110,100,32,111,112,112,111,115,105,116,101,32,103,111,118,101,114,110,109,101,110,116,32,112,114,111,103,114,97,109,46]], + [[154,152,221,155,182,125,13,167,191,131,218,83,19,223,244,253,96,164,186,192,9,79,27,5,99,54,144,255,167,246,214,29,233,161,212,248,97,121,55,213,96,131,58,154,170,156,202,254,63,210,77,180,24,208,231,40,131,53,69,202,221,58,217,45 ],[ 72,105,115,32,109,111,110,101,121,32,105,115,32,116,119,105,99,101,32,116,97,105,110,116,101,100,58,32,39,116,97,105,110,116,32,121,111,117,114,115,32,97,110,100,32,39,116,97,105,110,116,32,109,105,110,101,46]], + [[215,253,226,210,53,30,250,222,82,244,33,29,55,70,160,120,10,38,238,195,223,155,46,213,117,54,138,138,28,9,236,69,36,2,41,58,142,164,236,235,90,79,96,6,78,162,155,19,205,216,105,24,205,122,79,175,54,97,96,176,9,128,65,7 ],[ 84,104,101,114,101,32,105,115,32,110,111,32,114,101,97,115,111,110,32,102,111,114,32,97,110,121,32,105,110,100,105,118,105,100,117,97,108,32,116,111,32,104,97,118,101,32,97,32,99,111,109,112,117,116,101,114,32,105,110,32,116,104,101,105,114,32,104,111,109,101,46,32,45,75,101,110,32,79,108,115,101,110,44,32,49,57,55,55]], + [[176,243,95,250,38,151,53,156,51,165,111,92,12,247,21,199,174,237,150,218,153,5,202,38,152,172,173,176,143,188,158,102,155,245,102,182,189,93,97,163,232,109,194,41,153,188,201,242,34,78,51,209,212,243,42,34,140,249,208,52,158,45,181,24 ],[ 73,116,39,115,32,97,32,116,105,110,121,32,99,104,97,110,103,101,32,116,111,32,116,104,101,32,99,111,100,101,32,97,110,100,32,110,111,116,32,99,111,109,112,108,101,116,101,108,121,32,100,105,115,103,117,115,116,105,110,103,46,32,45,32,66,111,98,32,77,97,110,99,104,101,107]], + [[61,46,95,145,119,140,158,102,247,224,97,41,58,170,138,143,199,66,221,59,46,79,72,55,114,70,75,17,68,24,155,73,39,62,97,14,92,204,215,168,26,25,202,31,167,15,22,177,15,26,16,10,77,140,19,114,51,107,232,72,76,100,179,17 ],[ 115,105,122,101,58,32,32,97,46,111,117,116,58,32,32,98,97,100,32,109,97,103,105,99]], + [[178,246,143,245,138,192,21,239,177,201,76,144,139,13,140,43,240,111,73,30,77,232,230,48,44,73,1,111,127,138,51,234,195,233,89,133,108,127,221,188,70,77,230,24,112,19,56,164,180,111,118,219,250,249,161,229,38,43,95,64,99,151,113,199 ],[ 84,104,101,32,109,97,106,111,114,32,112,114,111,98,108,101,109,32,105,115,32,119,105,116,104,32,115,101,110,100,109,97,105,108,46,32,32,45,77,97,114,107,32,72,111,114,116,111,110]], + [[216,201,45,181,253,245,44,248,33,94,77,243,180,144,157,41,32,63,244,208,14,154,208,182,74,106,78,4,222,197,231,79,98,231,195,92,127,184,129,189,93,233,84,66,18,61,248,245,122,72,155,10,230,22,189,50,111,132,209,0,33,18,28,87 ],[ 71,105,118,101,32,109,101,32,97,32,114,111,99,107,44,32,112,97,112,101,114,32,97,110,100,32,115,99,105,115,115,111,114,115,32,97,110,100,32,73,32,119,105,108,108,32,109,111,118,101,32,116,104,101,32,119,111,114,108,100,46,32,32,67,67,70,101,115,116,111,111,110]], + [[25,169,248,220,10,35,62,70,78,133,102,173,60,169,185,30,69,154,123,140,71,128,152,91,1,87,118,225,191,35,154,25,188,35,61,5,86,52,62,43,10,155,194,32,144,11,78,191,79,139,223,137,255,142,254,175,121,96,45,104,73,230,247,46 ],[ 73,102,32,116,104,101,32,101,110,101,109,121,32,105,115,32,119,105,116,104,105,110,32,114,97,110,103,101,44,32,116,104,101,110,32,115,111,32,97,114,101,32,121,111,117,46]], + [[0,180,196,31,48,123,222,135,48,28,220,91,90,177,174,154,89,46,142,203,178,2,29,215,188,75,52,226,172,230,7,65,204,54,37,96,190,197,102,186,53,23,133,149,169,25,50,184,213,53,126,44,156,236,146,211,147,176,250,120,49,133,36,118 ],[ 73,116,39,115,32,119,101,108,108,32,119,101,32,99,97,110,110,111,116,32,104,101,97,114,32,116,104,101,32,115,99,114,101,97,109,115,47,84,104,97,116,32,119,101,32,99,114,101,97,116,101,32,105,110,32,111,116,104,101,114,115,39,32,100,114,101,97,109,115,46]], + [[145,236,204,61,83,117,253,2,110,77,103,135,135,75,29,206,32,28,236,216,162,125,189,237,80,101,114,140,178,208,156,88,163,212,103,187,31,175,53,59,247,186,86,126,0,82,69,213,50,27,85,188,52,79,124,7,185,28,182,242,108,149,155,231 ],[ 89,111,117,32,114,101,109,105,110,100,32,109,101,32,111,102,32,97,32,84,86,32,115,104,111,119,44,32,98,117,116,32,116,104,97,116,39,115,32,97,108,108,32,114,105,103,104,116,58,32,73,32,119,97,116,99,104,32,105,116,32,97,110,121,119,97,121,46]], + [[250,187,190,34,24,15,31,19,124,253,201,85,109,37,112,231,117,209,174,2,165,151,222,212,58,114,164,15,155,72,93,80,0,67,183,190,18,143,185,252,217,130,184,49,89,160,217,154,168,85,169,231,204,66,64,192,13,192,26,155,223,130,24,215 ],[ 67,32,105,115,32,97,115,32,112,111,114,116,97,98,108,101,32,97,115,32,83,116,111,110,101,104,101,100,103,101,33,33]], + [[46,205,236,35,92,31,164,252,42,21,77,143,186,29,221,184,167,42,26,215,56,56,181,29,121,35,49,209,67,248,185,106,159,111,203,15,52,215,202,163,81,254,109,136,119,28,79,16,80,64,224,57,47,6,224,98,22,137,211,59,47,59,169,46 ],[ 69,118,101,110,32,105,102,32,73,32,99,111,117,108,100,32,98,101,32,83,104,97,107,101,115,112,101,97,114,101,44,32,73,32,116,104,105,110,107,32,73,32,115,104,111,117,108,100,32,115,116,105,108,108,32,99,104,111,111,115,101,32,116,111,32,98,101,32,70,97,114,97,100,97,121,46,32,45,32,65,46,32,72,117,120,108,101,121]], + [[122,214,129,246,249,111,130,247,171,250,126,204,3,52,232,250,22,211,220,28,220,69,182,11,122,244,63,228,7,93,35,87,192,193,214,14,152,53,15,26,251,31,47,231,164,215,205,42,213,91,136,228,88,224,107,115,196,11,67,115,49,245,218,180 ],[ 84,104,101,32,102,117,103,97,99,105,116,121,32,111,102,32,97,32,99,111,110,115,116,105,116,117,101,110,116,32,105,110,32,97,32,109,105,120,116,117,114,101,32,111,102,32,103,97,115,101,115,32,97,116,32,97,32,103,105,118,101,110,32,116,101,109,112,101,114,97,116,117,114,101,32,105,115,32,112,114,111,112,111,114,116,105,111,110,97,108,32,116,111,32,105,116,115,32,109,111,108,101,32,102,114,97,99,116,105,111,110,46,32,32,76,101,119,105,115,45,82,97,110,100,97,108,108,32,82,117,108,101]], + [[131,63,146,72,171,74,59,158,81,49,247,69,253,161,255,210,221,67,91,48,233,101,149,126,120,41,28,122,183,54,5,253,25,18,176,121,78,92,35,58,176,161,45,32,90,57,119,141,25,184,53,21,214,164,112,3,241,156,222,229,29,152,199,224 ],[ 72,111,119,32,99,97,110,32,121,111,117,32,119,114,105,116,101,32,97,32,98,105,103,32,115,121,115,116,101,109,32,119,105,116,104,111,117,116,32,67,43,43,63,32,32,45,80,97,117,108,32,71,108,105,99,107]], + ]; + + + for (var i = 0; i < golden.length; i++) { + var out = []; + crypto_hash(out, golden[i][1], golden[i][1].length); + if (!bytesEqual(out, golden[i][0])) { + console.log(i, 'differ'); + } else { + console.log(i, 'OK'); + } + } +} + +crypto_hash_test(); diff --git a/js/u64.js b/js/u64.js new file mode 100644 index 0000000..cd28af4 --- /dev/null +++ b/js/u64.js @@ -0,0 +1,103 @@ +// helper for dealing with uint64 +var u64 = function (h, l) { + h = h|0; l = l|0; + this.hi = h >>> 0; + this.lo = l >>> 0; +} + +function new64(num) { + var hi = 0, lo = num >>> 0; + if ((+(Math.abs(num))) >= 1) { + if (num > 0) { + hi = ((Math.min((+(Math.floor(num/4294967296))), 4294967295))|0) >>> 0; + } else { + hi = (~~((+(Math.ceil((num - +(((~~(num)))>>>0))/4294967296))))) >>> 0; + } + } + return new u64(hi, lo); +} + +function shr64(x, c) { + var h = 0, l = 0; + if (c < 32) { + l = (x.lo >>> c) | (x.hi & (((1 << c) - 1)|0)) << (32 - c); + h = x.hi >>> c; + } else { + l = x.hi >>> (c - 32); + } + return new u64(h, l); +} + +function shl64(x, c) { + var h = 0, l = 0; + if (c < 32) { + h = (x.hi << c) | ((x.lo & (((1 << c) - 1)|0) << (32 - c)) >>> (32 - c)); + l = x.lo << c; + } else { + h = x.lo << (c - 32); + } + return new u64(h, l); +} + +function rotl64(x, c) { + var t1 = shl64(x, c); + var t2 = shr64(x, 64 - c); + return new u64(t1.hi | t2.hi, t1.lo | t2.lo); +} + +function rotr64(x, c) { + return rotl64(x, 64 - c); +} + +function mul(a, b, make64) { + make64 = make64|0; + var ah, al, bh, bl, c, d, e, x, y, z; // TODO: reduce variable + + ah = a >>> 16; al = a & 0xffff; + bh = b >>> 16; bl = b & 0xffff; + c = al*bl; d = ah*bl; e = al*bh; + + var l = (c + ((d + e) << 16) >>> 0)|0; + + if (!make64) return l; + + x = d + (c >>> 16); + y = (e + (x & 0xffff)) >>> 16; + z = x >>> 16; + + return new u64((ah*bh + y + z), l); +} + +function mul64(x, y) { + var z = mul(x.lo, y.lo, 1); + z.hi += ((mul(x.hi, y.lo) + mul(y.hi, x.lo))|0); + return z; +} + +function add64() { + var a = arguments, t, + l = a[0].lo, h = a[0].hi; + for (var i = 1; i < a.length; i++) { + t = l; l = (t + a[i].lo)>>>0; + h = (h + a[i].hi + ((l < t) ? 1 : 0))>>>0; + } + return new u64(h, l); +} + +function sub64(x, y) { + return new u64(x.hi - y.hi - ((x.lo < y.lo) ? 1 : 0), x.lo - y.lo); +} + +function flatten64(x) { + // caveat: it will loose precision with big numbers + return (x.hi * 4294967296 + x.lo); +} + +function xor64() { + var a = arguments, h = a[0].hi, l = a[0].lo; + for (var i = 1; i < a.length; i++) { + h = (h ^ a[i].hi) >>> 0; + l = (l ^ a[i].lo) >>> 0; + } + return new u64(h, l); +} diff --git a/php/hierarchy.php b/php/hierarchy.php new file mode 100644 index 0000000..25d7cf8 --- /dev/null +++ b/php/hierarchy.php @@ -0,0 +1,329 @@ +table = $table_name; + + if ($closure_table !== NULL) + $this->closure_table = $closure_table; + } + + /** + * Add a node (as last child). + * + * @param int node id + * @param int target id + * @return boolean + */ + public function add($node_id, $target_id = 0) + { + $query = DB::select(DB::expr('ancestor, '.$node_id.', lvl+1')) + ->from($this->closure_table) + ->where('descendant', '=', $target_id); + + $query1 = DB::select(DB::expr($node_id.','.$node_id.',0')) + ->union($query); + + $query2 = 'INSERT INTO '.$this->closure_table.' (ancestor, descendant,lvl) '.$query1; + + $result = DB::query(Database::INSERT, $query2)->execute(); + + return ($result AND count($result)>0); + } + + /** + * Check if current node has children. + * + * @param int node id + * @return boolean + */ + public function has_children($node_id) + { + $descendants = DB::select('descendant') + ->from($this->closure_table) + ->where('ancestor','=', $node_id); + + return (bool) DB::select(array('COUNT("*")', 'total')) + ->from($this->closure_table) + ->where('ancestor', 'IN', DB::expr('('.$descendants.')')) + ->where('descendant', '<>', $node_id) + ->execute() + ->get('total'); + } + + /** + * Get parent(s) of current node. + * + * @param int current node id + * @param boolean include current node on result + * @param int level up (e.g direct parent = 1) + * @param array column/field name(s) + * @return mixed array if succeed + */ + public function get_parent( + $node_id, + $self = FALSE, + $level = NULL, + array $column = NULL + ){ + if ($column !== NULL) + { + if ( ! in_array('id', $column)) + array_unshift($column, 'id'); + + $column = 't.'.implode(',t.', $column); + } + else + { + $column = 't.*'; + } + + $query = DB::select($column, array('c.lvl', 'level')) + ->from(array($this->table, 't')) + ->join(array($this->closure_table, 'c')) + ->on('t.id', '=', 'c.ancestor') + ->where('c.descendant', '=', $node_id) + ->where('t.safe_url', 'IS NOT', NULL); + + if ( ! $self) + $query->where('c.ancestor', '<>', $node_id); + + if ($level) + $query->where('c.lvl' ,'=', $level); + + $query = $query->order_by('t.id')->execute(); + + if ($query->count()) + { + $query = $query->as_array(); + + if ($level) + { + return $query[0]; + } + + return $query; + } + + return FALSE; + } + + /** + * Fetch children(s). + * + * Example to generate nested tree: + * + * $h = new Hierarchy('refrence_table'); + * $data = $h->get_children(1, TRUE, FALSE, NULL, TRUE); + * print_r($data); + * + * If level/depth specified then self will be ignore. + * + * @param int node id + * @param boolean include current node on result + * @param int node level/depth (e.g direct children = 1) + * @param array column/field name(s) + * @param boolean nestify the result + * @return mixed + */ + public function get_children( + $node_id = 1, + $self = FALSE, + $level = FALSE, + array $column = NULL, + $nested = FALSE + ){ + if ($column !== NULL) + { + if ( ! in_array('id', $column)) + array_unshift($column, 'id'); + + $column = 't.'.implode(',t.', $column); + } + else + { + $column = 't.*'; + } + + $query = DB::select( + $column, + array('c2.ancestor', 'parent'), + array('c1.lvl', 'level') + ) + ->from(array($this->closure_table, 'c1')) + ->join(array($this->table, 't')) + ->on('t.id', '=','c1.descendant') + ->join(array($this->closure_table, 'c2'), 'LEFT') + ->on( + 'c2.lvl', + '=', + DB::expr('1 AND c2.descendant = c1.descendant ') + ) + ->where('c1.ancestor', '=', $node_id); + + if ( ! $self) + $query->where('c1.descendant', '<>', $node_id); + + if ($level) + $query->where('c1.lvl','=', $level); + + $query = $query->execute(); + + if ( ! $query->count()) + return FALSE; + + $result = $query->as_array(); + + if ($nested AND ! $level) + { + $refs = array(); + + foreach ($result as $node) + { + $current = &$refs[$node['id']]; + + $current['data'] = $node; + + if ($node['parent']) + $refs[$node['parent']]['children'][$node['id']] = &$current; + } + + $result = $refs[$node_id]; + } + + return $result; + } + + /** + * TODO: optional recursion + * + * Delete node. + * + * @param int node id + * @param boolean delete data from reference table + * @return mixed + */ + public function delete($node_id, $delete_reference = TRUE) + { + $operand = DB::select('descendant') + ->from($this->closure_table) + ->where('ancestor', '=', $node_id); + + $query = DB::select('id','descendant') + ->from($this->closure_table) + ->where('descendant','IN', DB::expr('('.$operand.')')) + ->execute(); + + if ($query->count()) + { + $descendants = Arr::pluck($query, 'id'); + + $result = DB::delete($this->closure_table) + ->where( + 'id', + 'IN', + DB::expr('('.implode(',',$descendants).')') + ) + ->execute(); + + if ($delete_reference) + { + $descendants = Arr::pluck($query, 'descendant'); + + $result = DB::delete($this->table) + ->where( + 'id', + 'IN', + DB::expr('('.implode(',',$descendants).')') + ) + ->execute(); + } + + return $result; + } + + return FALSE; + } + + /** + * Move node with its children to another node. + * + * @link http://www.mysqlperformanceblog.com/2011/02/14/moving-subtrees-in-closure-table/ + * + * @param int node to be moved + * @param int target node + * @return void + */ + public function move($node_id, $target_id) + { + // MySQL’s multi-table DELETE + $query1 = 'DELETE a FROM '.$this->closure_table.' AS a '; + $query1 .= 'JOIN '.$this->closure_table.' AS d ON a.descendant = d.descendant '; + $query1 .= 'LEFT JOIN '.$this->closure_table.' AS x '; + $query1 .= 'ON x.ancestor = d.ancestor AND x.descendant = a.ancestor '; + $query1 .= 'WHERE d.ancestor = '.$node_id.' AND x.ancestor IS NULL'; + + DB::query(Database::DELETE, $query1)->execute(); + + $query2 = 'INSERT INTO '.$this->closure_table.' (ancestor, descendant, lvl) '; + $query2 .= 'SELECT a.ancestor, b.descendant, a.lvl+b.lvl+1 '; + $query2 .= 'FROM '.$this->closure_table.' AS a JOIN '.$this->closure_table.' AS b '; + $query2 .= 'WHERE b.ancestor = '.$node_id.' AND a.descendant = '.$target_id; + + DB::query(Database::INSERT, $query2)->execute(); + } + + /** + * Get (all) root nodes. + * + * @param array column/field name(s) + * @return mixed + */ + public function get_root(array $column = NULL) + { + if ($column !== NULL) + { + $column = 't.'.implode(',t.', $column); + } + else + { + $column = 't.*'; + } + + $query = DB::select($column) + ->from(array($this->closure_table, 'c')) + ->join(array($this->table, 't')) + ->on('t.id', '=', 'c.ancestor') + ->join(array($this->closure_table, 'anc'), 'LEFT OUTER') + ->on('anc.descendant', '=', DB::expr( + 'c.descendant AND anc.ancestor <> c.ancestor' + )) + ->where('anc.ancestor', 'IS', NULL) + ->execute(); + + return $query->count() ? $query->as_array() : FALSE; + } + +} diff --git a/php/pagination.php b/php/pagination.php new file mode 100644 index 0000000..2e61591 --- /dev/null +++ b/php/pagination.php @@ -0,0 +1,123 @@ +total = (int) $total; + $this->limit = (int) $limit; + $this->page = (int) $page; + $this->adjacents = (int) $adjacents; + + if ($this->page < 1) + { + $this->page = 1; + } + } + + public function render() + { + $last = ceil($this->total / $this->limit); + + if ($last < 2 or $this->page > $last) + { + return FALSE; + } + + $arr = array( + 'current' => $this->page, + 'limit' => $this->limit, + 'total' => $this->total, + 'pages' => $last + ); + + if ($this->page > 1) + { + $arr['previous'] = $this->page - 1; + } + + if ($this->page < $last) + { + $arr['next'] = $this->page + 1; + } + + $r1 = ($this->page - 1) * $this->limit + 1; + + $r2 = $r1 + $this->limit - 1; + + $r2 = ($this->total < $r2) ? $this->total : $r2; + + $arr['displaying'] = array( + 'items' => $r2 - $r1 + 1, + 'from' => $r1, + 'to' => $r2 + ); + + if ($last < 5 + ($this->adjacents * 2)) + { + for ($counter = 1; $counter <= $last; $counter++) + { + $arr['links'][] = $this->_numbers($counter); + } + } + elseif ($last >= 5 + ($this->adjacents * 2)) + { + if ($this->page < 1 + ($this->adjacents * 2)) + { + $arr['last'] = TRUE; + + for ($counter = 1; $counter < 2 + ($this->adjacents * 2); $counter++) + { + $arr['links'][] = $this->_numbers($counter); + } + } + elseif ($last - ($this->adjacents * 2) >= $this->page AND $this->page > ($this->adjacents * 2)) + { + $arr['first'] = TRUE; + $arr['last'] = TRUE; + + for ($counter = $this->page - $this->adjacents; $counter <= $this->page + $this->adjacents; $counter++) + { + $arr['links'][] = $this->_numbers($counter); + } + } + else + { + $arr['first'] = TRUE; + + for ($counter = $last - ($this->adjacents * 2); $counter <= $last; $counter++) + { + $arr['links'][] = $this->_numbers($counter); + } + } + } + + return $arr; + } + + protected function _numbers($num) + { + if ($num == $this->page) + { + return array('active' => TRUE, 'number' => $num); + } + else + { + return array('number' => $num); + } + } + +} // End Pagination