UNPKG

ardorjs

Version:

Local transaction signing for ardor transactions, and ardor address creations

1,177 lines (1,109 loc) 37.4 kB
// Copyright (c) 2007 Michele Bini // Konstantin Welke, 2008: // - moved into .js file, renamed all c255lname to curve25519_name // - added curve25519_clamp() // - functions to read from/to 8bit string // - removed base32/hex functions (cleanup) // - removed setbit function (cleanup, had a bug anyway) // BloodyRookie 2014: // - ported part of the java implementation by Dmitry Skiba to js and merged into this file // - profiled for higher speed // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // // The original curve25519 library was released into the public domain // by Daniel J. Bernstein var curve25519_zero = function () { return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; }; var curve25519_one = function () { return [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; }; var curve25519_two = function () { return [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; }; var curve25519_nine = function () { return [9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; }; var curve25519_486671 = function () { return [27919, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; }; var curve25519_39420360 = function () { return [33224, 601, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; }; var curve25519_r2y = function () { return [ 0x1670, 0x4000, 0xf219, 0xd369, 0x2248, 0x4845, 0x679a, 0x884d, 0x5d19, 0x16bf, 0xda74, 0xe57d, 0x5e53, 0x3705, 0x3526, 0x17c0, ]; }; var curve25519_2y = function () { return [ 0x583b, 0x0262, 0x74bb, 0xac2c, 0x3c9b, 0x2507, 0x6503, 0xdb85, 0x5d66, 0x116e, 0x45a7, 0x3fc2, 0xf296, 0x8ebe, 0xccbc, 0x3ea3, ]; }; var curve25519_clamp = function (curve) { curve[0] &= 0xfff8; curve[15] &= 0x7fff; curve[15] |= 0x4000; return curve; }; var curve25519_getbit = function (curve, c) { return ~~(curve[~~(c / 16)] / Math.pow(2, c % 16)) % 2; }; var curve25519_prime = [ 0xffff - 18, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x7fff, ]; /* group order (a prime near 2^252+2^124) */ var curve25519_order = [ 237, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, ]; var curve25519_order_times_8 = [ 104, 159, 174, 231, 210, 24, 147, 192, 178, 230, 188, 23, 245, 206, 247, 166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, ]; var curve25519_convertToByteArray = function (a) { var b = new Int8Array(32); var i; for (i = 0; i < 16; i++) { b[2 * i] = a[i] & 0xff; b[2 * i + 1] = a[i] >> 8; } return b; }; var curve25519_convertToShortArray = function (a) { var b = new Array(16); var i, val1, val2; for (i = 0; i < 16; i++) { val1 = a[i * 2]; if (val1 < 0) { val1 += 256; } val2 = a[i * 2 + 1]; if (val2 < 0) { val2 += 256; } b[i] = val1 + val2 * 256; } return b; }; var curve25519_fillShortArray = function (src, dest) { var i; for (i = 0; i < 16; i++) { dest[i] = src[i]; } }; var curve25519_fillByteArray = function (src, dest) { var i; for (i = 0; i < 32; i++) { dest[i] = src[i]; } }; var curve25519_log16 = function (text, a) { var b = shortArray_to_hex_string(a); addText(text + b); }; var curve25519_log32 = function (text, a) { var b = byteArray_to_hex_string(a); addText(text + b); }; var curve25519_cpy32 = function (a) { var b = new Int8Array(32); for (i = 0; i < 32; i++) { b[i] = a[i]; } return b; }; var curve25519_mula_small = function (p, q, m, x, n, z) { var v = 0; for (j = 0; j < n; ++j) { v += (q[j + m] & 0xff) + z * (x[j] & 0xff); p[j + m] = v & 0xff; v >>= 8; } return v; }; var curve25519_mula32 = function (p, x, y, t, z) { var n = 31; var w = 0; for (i = 0; i < t; i++) { zy = z * (y[i] & 0xff); w += curve25519_mula_small(p, p, i, x, n, zy) + (p[i + n] & 0xff) + zy * (x[n] & 0xff); p[i + n] = w & 0xff; w >>= 8; } p[i + n] = (w + (p[i + n] & 0xff)) & 0xff; return w >> 8; }; var curve25519_divmod = function (q, r, n, d, t) { var rn = 0, z = 0; var dt = (d[t - 1] & 0xff) << 8; if (t > 1) { dt |= d[t - 2] & 0xff; } while (n-- >= t) { z = (rn << 16) | ((r[n] & 0xff) << 8); if (n > 0) { z |= r[n - 1] & 0xff; } z = parseInt(z / dt); rn += curve25519_mula_small(r, r, n - t + 1, d, t, -z); q[n - t + 1] = (z + rn) & 0xff; // rn is 0 or -1 (underflow) curve25519_mula_small(r, r, n - t + 1, d, t, -rn); rn = r[n] & 0xff; r[n] = 0; } r[t - 1] = rn & 0xff; }; var curve25519_numsize = function (x, n) { while (n-- != 0 && x[n] == 0); return n + 1; }; var curve25519_egcd32 = function (x, y, a, b) { var an = 0, bn = 32, qn = 0, i = 0; for (i = 0; i < 32; i++) { x[i] = y[i] = 0; } x[0] = 1; an = curve25519_numsize(a, 32); if (an == 0) { return y; // division by zero } temp = new Int8Array(32); while (true) { qn = bn - an + 1; curve25519_divmod(temp, b, bn, a, an); bn = curve25519_numsize(b, bn); if (bn == 0) { return x; } curve25519_mula32(y, x, temp, qn, -1); qn = an - bn + 1; curve25519_divmod(temp, a, an, b, bn); an = curve25519_numsize(a, an); if (an == 0) { return y; } curve25519_mula32(x, y, temp, qn, -1); } }; var curve25519_compare = function (a, b) { var c; for (c = 15; c >= 0; c--) { var x = a[c]; var y = b[c]; if (x > y) { return 1; } if (x < y) { return -1; } } return 0; }; var curve25519_cpy16 = function (a) { var r = new Array(16); var i; for (i = 0; i < 16; i++) { r[i] = a[i]; } return r; }; /*** * BloodyRookie: odd numbers are negativ */ var curve25519_isNegative = function (x) { return x[0] & 1; }; var curve25519_isOverflow = function (x) { if (x[15] >= 0x8000) return 1; if (x[0] >= 0x10000) { var i; for (i = 1; i < 15; i++) { if (x[i] < 0xffff) { return 0; } } return 1; } else { return 0; } }; var curve25519_sqr8h = function (r, a7, a6, a5, a4, a3, a2, a1, a0) { var v = 0; r[0] = (v = a0 * a0) & 0xffff; r[1] = (v = ~~(v / 0x10000) + 2 * a0 * a1) & 0xffff; r[2] = (v = ~~(v / 0x10000) + 2 * a0 * a2 + a1 * a1) & 0xffff; r[3] = (v = ~~(v / 0x10000) + 2 * a0 * a3 + 2 * a1 * a2) & 0xffff; r[4] = (v = ~~(v / 0x10000) + 2 * a0 * a4 + 2 * a1 * a3 + a2 * a2) & 0xffff; r[5] = (v = ~~(v / 0x10000) + 2 * a0 * a5 + 2 * a1 * a4 + 2 * a2 * a3) & 0xffff; r[6] = (v = ~~(v / 0x10000) + 2 * a0 * a6 + 2 * a1 * a5 + 2 * a2 * a4 + a3 * a3) & 0xffff; r[7] = (v = ~~(v / 0x10000) + 2 * a0 * a7 + 2 * a1 * a6 + 2 * a2 * a5 + 2 * a3 * a4) & 0xffff; r[8] = (v = ~~(v / 0x10000) + 2 * a1 * a7 + 2 * a2 * a6 + 2 * a3 * a5 + a4 * a4) & 0xffff; r[9] = (v = ~~(v / 0x10000) + 2 * a2 * a7 + 2 * a3 * a6 + 2 * a4 * a5) & 0xffff; r[10] = (v = ~~(v / 0x10000) + 2 * a3 * a7 + 2 * a4 * a6 + a5 * a5) & 0xffff; r[11] = (v = ~~(v / 0x10000) + 2 * a4 * a7 + 2 * a5 * a6) & 0xffff; r[12] = (v = ~~(v / 0x10000) + 2 * a5 * a7 + a6 * a6) & 0xffff; r[13] = (v = ~~(v / 0x10000) + 2 * a6 * a7) & 0xffff; r[14] = (v = ~~(v / 0x10000) + a7 * a7) & 0xffff; r[15] = ~~(v / 0x10000); }; var curve25519_sqrmodp = function (r, a) { var x = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var y = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var z = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; curve25519_sqr8h(x, a[15], a[14], a[13], a[12], a[11], a[10], a[9], a[8]); curve25519_sqr8h(z, a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]); curve25519_sqr8h( y, a[15] + a[7], a[14] + a[6], a[13] + a[5], a[12] + a[4], a[11] + a[3], a[10] + a[2], a[9] + a[1], a[8] + a[0] ); var v = 0; r[0] = (v = 0x800000 + z[0] + (y[8] - x[8] - z[8] + x[0] - 0x80) * 38) & 0xffff; r[1] = (v = 0x7fff80 + ~~(v / 0x10000) + z[1] + (y[9] - x[9] - z[9] + x[1]) * 38) & 0xffff; r[2] = (v = 0x7fff80 + ~~(v / 0x10000) + z[2] + (y[10] - x[10] - z[10] + x[2]) * 38) & 0xffff; r[3] = (v = 0x7fff80 + ~~(v / 0x10000) + z[3] + (y[11] - x[11] - z[11] + x[3]) * 38) & 0xffff; r[4] = (v = 0x7fff80 + ~~(v / 0x10000) + z[4] + (y[12] - x[12] - z[12] + x[4]) * 38) & 0xffff; r[5] = (v = 0x7fff80 + ~~(v / 0x10000) + z[5] + (y[13] - x[13] - z[13] + x[5]) * 38) & 0xffff; r[6] = (v = 0x7fff80 + ~~(v / 0x10000) + z[6] + (y[14] - x[14] - z[14] + x[6]) * 38) & 0xffff; r[7] = (v = 0x7fff80 + ~~(v / 0x10000) + z[7] + (y[15] - x[15] - z[15] + x[7]) * 38) & 0xffff; r[8] = (v = 0x7fff80 + ~~(v / 0x10000) + z[8] + y[0] - x[0] - z[0] + x[8] * 38) & 0xffff; r[9] = (v = 0x7fff80 + ~~(v / 0x10000) + z[9] + y[1] - x[1] - z[1] + x[9] * 38) & 0xffff; r[10] = (v = 0x7fff80 + ~~(v / 0x10000) + z[10] + y[2] - x[2] - z[2] + x[10] * 38) & 0xffff; r[11] = (v = 0x7fff80 + ~~(v / 0x10000) + z[11] + y[3] - x[3] - z[3] + x[11] * 38) & 0xffff; r[12] = (v = 0x7fff80 + ~~(v / 0x10000) + z[12] + y[4] - x[4] - z[4] + x[12] * 38) & 0xffff; r[13] = (v = 0x7fff80 + ~~(v / 0x10000) + z[13] + y[5] - x[5] - z[5] + x[13] * 38) & 0xffff; r[14] = (v = 0x7fff80 + ~~(v / 0x10000) + z[14] + y[6] - x[6] - z[6] + x[14] * 38) & 0xffff; r[15] = 0x7fff80 + ~~(v / 0x10000) + z[15] + y[7] - x[7] - z[7] + x[15] * 38; curve25519_reduce(r); }; var curve25519_mul8h = function ( r, a7, a6, a5, a4, a3, a2, a1, a0, b7, b6, b5, b4, b3, b2, b1, b0 ) { var v = 0; r[0] = (v = a0 * b0) & 0xffff; r[1] = (v = ~~(v / 0x10000) + a0 * b1 + a1 * b0) & 0xffff; r[2] = (v = ~~(v / 0x10000) + a0 * b2 + a1 * b1 + a2 * b0) & 0xffff; r[3] = (v = ~~(v / 0x10000) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0) & 0xffff; r[4] = (v = ~~(v / 0x10000) + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0) & 0xffff; r[5] = (v = ~~(v / 0x10000) + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0) & 0xffff; r[6] = (v = ~~(v / 0x10000) + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0) & 0xffff; r[7] = (v = ~~(v / 0x10000) + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0) & 0xffff; r[8] = (v = ~~(v / 0x10000) + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1) & 0xffff; r[9] = (v = ~~(v / 0x10000) + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2) & 0xffff; r[10] = (v = ~~(v / 0x10000) + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3) & 0xffff; r[11] = (v = ~~(v / 0x10000) + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4) & 0xffff; r[12] = (v = ~~(v / 0x10000) + a5 * b7 + a6 * b6 + a7 * b5) & 0xffff; r[13] = (v = ~~(v / 0x10000) + a6 * b7 + a7 * b6) & 0xffff; r[14] = (v = ~~(v / 0x10000) + a7 * b7) & 0xffff; r[15] = ~~(v / 0x10000); }; var curve25519_mulmodp = function (r, a, b) { var x = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var y = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var z = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; curve25519_mul8h( x, a[15], a[14], a[13], a[12], a[11], a[10], a[9], a[8], b[15], b[14], b[13], b[12], b[11], b[10], b[9], b[8] ); curve25519_mul8h( z, a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0], b[7], b[6], b[5], b[4], b[3], b[2], b[1], b[0] ); curve25519_mul8h( y, a[15] + a[7], a[14] + a[6], a[13] + a[5], a[12] + a[4], a[11] + a[3], a[10] + a[2], a[9] + a[1], a[8] + a[0], b[15] + b[7], b[14] + b[6], b[13] + b[5], b[12] + b[4], b[11] + b[3], b[10] + b[2], b[9] + b[1], b[8] + b[0] ); var v = 0; r[0] = (v = 0x800000 + z[0] + (y[8] - x[8] - z[8] + x[0] - 0x80) * 38) & 0xffff; r[1] = (v = 0x7fff80 + ~~(v / 0x10000) + z[1] + (y[9] - x[9] - z[9] + x[1]) * 38) & 0xffff; r[2] = (v = 0x7fff80 + ~~(v / 0x10000) + z[2] + (y[10] - x[10] - z[10] + x[2]) * 38) & 0xffff; r[3] = (v = 0x7fff80 + ~~(v / 0x10000) + z[3] + (y[11] - x[11] - z[11] + x[3]) * 38) & 0xffff; r[4] = (v = 0x7fff80 + ~~(v / 0x10000) + z[4] + (y[12] - x[12] - z[12] + x[4]) * 38) & 0xffff; r[5] = (v = 0x7fff80 + ~~(v / 0x10000) + z[5] + (y[13] - x[13] - z[13] + x[5]) * 38) & 0xffff; r[6] = (v = 0x7fff80 + ~~(v / 0x10000) + z[6] + (y[14] - x[14] - z[14] + x[6]) * 38) & 0xffff; r[7] = (v = 0x7fff80 + ~~(v / 0x10000) + z[7] + (y[15] - x[15] - z[15] + x[7]) * 38) & 0xffff; r[8] = (v = 0x7fff80 + ~~(v / 0x10000) + z[8] + y[0] - x[0] - z[0] + x[8] * 38) & 0xffff; r[9] = (v = 0x7fff80 + ~~(v / 0x10000) + z[9] + y[1] - x[1] - z[1] + x[9] * 38) & 0xffff; r[10] = (v = 0x7fff80 + ~~(v / 0x10000) + z[10] + y[2] - x[2] - z[2] + x[10] * 38) & 0xffff; r[11] = (v = 0x7fff80 + ~~(v / 0x10000) + z[11] + y[3] - x[3] - z[3] + x[11] * 38) & 0xffff; r[12] = (v = 0x7fff80 + ~~(v / 0x10000) + z[12] + y[4] - x[4] - z[4] + x[12] * 38) & 0xffff; r[13] = (v = 0x7fff80 + ~~(v / 0x10000) + z[13] + y[5] - x[5] - z[5] + x[13] * 38) & 0xffff; r[14] = (v = 0x7fff80 + ~~(v / 0x10000) + z[14] + y[6] - x[6] - z[6] + x[14] * 38) & 0xffff; r[15] = 0x7fff80 + ~~(v / 0x10000) + z[15] + y[7] - x[7] - z[7] + x[15] * 38; curve25519_reduce(r); }; var curve25519_mulasmall = function (r, a, m) { var v = 0; r[0] = (v = a[0] * m) & 0xffff; r[1] = (v = ~~(v / 0x10000) + a[1] * m) & 0xffff; r[2] = (v = ~~(v / 0x10000) + a[2] * m) & 0xffff; r[3] = (v = ~~(v / 0x10000) + a[3] * m) & 0xffff; r[4] = (v = ~~(v / 0x10000) + a[4] * m) & 0xffff; r[5] = (v = ~~(v / 0x10000) + a[5] * m) & 0xffff; r[6] = (v = ~~(v / 0x10000) + a[6] * m) & 0xffff; r[7] = (v = ~~(v / 0x10000) + a[7] * m) & 0xffff; r[8] = (v = ~~(v / 0x10000) + a[8] * m) & 0xffff; r[9] = (v = ~~(v / 0x10000) + a[9] * m) & 0xffff; r[10] = (v = ~~(v / 0x10000) + a[10] * m) & 0xffff; r[11] = (v = ~~(v / 0x10000) + a[11] * m) & 0xffff; r[12] = (v = ~~(v / 0x10000) + a[12] * m) & 0xffff; r[13] = (v = ~~(v / 0x10000) + a[13] * m) & 0xffff; r[14] = (v = ~~(v / 0x10000) + a[14] * m) & 0xffff; r[15] = ~~(v / 0x10000) + a[15] * m; curve25519_reduce(r); }; var curve25519_addmodp = function (r, a, b) { var v = 0; r[0] = (v = (~~(a[15] / 0x8000) + ~~(b[15] / 0x8000)) * 19 + a[0] + b[0]) & 0xffff; r[1] = (v = ~~(v / 0x10000) + a[1] + b[1]) & 0xffff; r[2] = (v = ~~(v / 0x10000) + a[2] + b[2]) & 0xffff; r[3] = (v = ~~(v / 0x10000) + a[3] + b[3]) & 0xffff; r[4] = (v = ~~(v / 0x10000) + a[4] + b[4]) & 0xffff; r[5] = (v = ~~(v / 0x10000) + a[5] + b[5]) & 0xffff; r[6] = (v = ~~(v / 0x10000) + a[6] + b[6]) & 0xffff; r[7] = (v = ~~(v / 0x10000) + a[7] + b[7]) & 0xffff; r[8] = (v = ~~(v / 0x10000) + a[8] + b[8]) & 0xffff; r[9] = (v = ~~(v / 0x10000) + a[9] + b[9]) & 0xffff; r[10] = (v = ~~(v / 0x10000) + a[10] + b[10]) & 0xffff; r[11] = (v = ~~(v / 0x10000) + a[11] + b[11]) & 0xffff; r[12] = (v = ~~(v / 0x10000) + a[12] + b[12]) & 0xffff; r[13] = (v = ~~(v / 0x10000) + a[13] + b[13]) & 0xffff; r[14] = (v = ~~(v / 0x10000) + a[14] + b[14]) & 0xffff; r[15] = ~~(v / 0x10000) + (a[15] % 0x8000) + (b[15] % 0x8000); }; var curve25519_submodp = function (r, a, b) { var v = 0; r[0] = (v = 0x80000 + (~~(a[15] / 0x8000) - ~~(b[15] / 0x8000) - 1) * 19 + a[0] - b[0]) & 0xffff; r[1] = (v = ~~(v / 0x10000) + 0x7fff8 + a[1] - b[1]) & 0xffff; r[2] = (v = ~~(v / 0x10000) + 0x7fff8 + a[2] - b[2]) & 0xffff; r[3] = (v = ~~(v / 0x10000) + 0x7fff8 + a[3] - b[3]) & 0xffff; r[4] = (v = ~~(v / 0x10000) + 0x7fff8 + a[4] - b[4]) & 0xffff; r[5] = (v = ~~(v / 0x10000) + 0x7fff8 + a[5] - b[5]) & 0xffff; r[6] = (v = ~~(v / 0x10000) + 0x7fff8 + a[6] - b[6]) & 0xffff; r[7] = (v = ~~(v / 0x10000) + 0x7fff8 + a[7] - b[7]) & 0xffff; r[8] = (v = ~~(v / 0x10000) + 0x7fff8 + a[8] - b[8]) & 0xffff; r[9] = (v = ~~(v / 0x10000) + 0x7fff8 + a[9] - b[9]) & 0xffff; r[10] = (v = ~~(v / 0x10000) + 0x7fff8 + a[10] - b[10]) & 0xffff; r[11] = (v = ~~(v / 0x10000) + 0x7fff8 + a[11] - b[11]) & 0xffff; r[12] = (v = ~~(v / 0x10000) + 0x7fff8 + a[12] - b[12]) & 0xffff; r[13] = (v = ~~(v / 0x10000) + 0x7fff8 + a[13] - b[13]) & 0xffff; r[14] = (v = ~~(v / 0x10000) + 0x7fff8 + a[14] - b[14]) & 0xffff; r[15] = ~~(v / 0x10000) + 0x7ff8 + (a[15] % 0x8000) - (b[15] % 0x8000); }; /**** * BloodyRookie: a^-1 is found via Fermats little theorem: * a^p congruent a mod p and therefore a^(p-2) congruent a^-1 mod p */ var curve25519_invmodp = function (r, a, sqrtassist) { var r1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r3 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r5 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var i = 0; curve25519_sqrmodp(r2, a); // 2 == 2 * 1 curve25519_sqrmodp(r3, r2); // 4 == 2 * 2 curve25519_sqrmodp(r1, r3); // 8 == 2 * 4 curve25519_mulmodp(r3, r1, a); // 9 == 8 + 1 curve25519_mulmodp(r1, r3, r2); // 11 == 9 + 2 curve25519_sqrmodp(r2, r1); // 22 == 2 * 11 curve25519_mulmodp(r4, r2, r3); // 31 == 22 + 9 // == 2^5 - 2^0 curve25519_sqrmodp(r2, r4); // 2^6 - 2^1 curve25519_sqrmodp(r3, r2); // 2^7 - 2^2 curve25519_sqrmodp(r2, r3); // 2^8 - 2^3 curve25519_sqrmodp(r3, r2); // 2^9 - 2^4 curve25519_sqrmodp(r2, r3); // 2^10 - 2^5 curve25519_mulmodp(r3, r2, r4); // 2^10 - 2^0 curve25519_sqrmodp(r2, r3); // 2^11 - 2^1 curve25519_sqrmodp(r4, r2); // 2^12 - 2^2 for (i = 1; i < 5; i++) { curve25519_sqrmodp(r2, r4); curve25519_sqrmodp(r4, r2); } // 2^20 - 2^10 curve25519_mulmodp(r2, r4, r3); // 2^20 - 2^0 curve25519_sqrmodp(r4, r2); // 2^21 - 2^1 curve25519_sqrmodp(r5, r4); // 2^22 - 2^2 for (i = 1; i < 10; i++) { curve25519_sqrmodp(r4, r5); curve25519_sqrmodp(r5, r4); } // 2^40 - 2^20 curve25519_mulmodp(r4, r5, r2); // 2^40 - 2^0 for (i = 0; i < 5; i++) { curve25519_sqrmodp(r2, r4); curve25519_sqrmodp(r4, r2); } // 2^50 - 2^10 curve25519_mulmodp(r2, r4, r3); // 2^50 - 2^0 curve25519_sqrmodp(r3, r2); // 2^51 - 2^1 curve25519_sqrmodp(r4, r3); // 2^52 - 2^2 for (i = 1; i < 25; i++) { curve25519_sqrmodp(r3, r4); curve25519_sqrmodp(r4, r3); } // 2^100 - 2^50 curve25519_mulmodp(r3, r4, r2); // 2^100 - 2^0 curve25519_sqrmodp(r4, r3); // 2^101 - 2^1 curve25519_sqrmodp(r5, r4); // 2^102 - 2^2 for (i = 1; i < 50; i++) { curve25519_sqrmodp(r4, r5); curve25519_sqrmodp(r5, r4); } // 2^200 - 2^100 curve25519_mulmodp(r4, r5, r3); // 2^200 - 2^0 for (i = 0; i < 25; i++) { curve25519_sqrmodp(r5, r4); curve25519_sqrmodp(r4, r5); } // 2^250 - 2^50 curve25519_mulmodp(r3, r4, r2); // 2^250 - 2^0 curve25519_sqrmodp(r2, r3); // 2^251 - 2^1 curve25519_sqrmodp(r3, r2); // 2^252 - 2^2 if (sqrtassist == 1) { curve25519_mulmodp(r, a, r3); // 2^252 - 3 } else { curve25519_sqrmodp(r2, r3); // 2^253 - 2^3 curve25519_sqrmodp(r3, r2); // 2^254 - 2^4 curve25519_sqrmodp(r2, r3); // 2^255 - 2^5 curve25519_mulmodp(r, r2, r1); // 2^255 - 21 } }; /****** * BloodyRookie: Finding a square root mod p of x if we already know it exists and p congruent 3 mod 8. * Using x^((p-1)/2) congruent 1 mod p and 2^((p-1)/2) congruent -1 mod p * because of Eulers criterium we see that when we set v=(2x)^((p-5)/8) then * i:=2xv^2 is a square root of -1 and thus r=+xv(i-1) and r=-xv(i-1) are the square roots of x. */ var curve25519_sqrtmodp = function (r, x) { var r1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r3 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; curve25519_addmodp(r1, x, x); // r1 = 2x curve25519_invmodp(r2, r1, 1); // r2 = (2x)^((p-5)/8) =: v curve25519_sqrmodp(r3, r2); // r3 = v^2 curve25519_mulmodp(r4, r1, r3); // r4 = 2xv^2 =: i curve25519_submodp(r, r4, curve25519_one()); // r = i-1 curve25519_mulmodp(r1, r2, r); // r1 = v(i-1) curve25519_mulmodp(r, x, r1); // r = xv(i-1) }; var curve25519_reduce = function (a) { curve25519_reduce2(a); /** * BloodyRookie: special case for p <= a < 2^255 */ if ( a[15] != 0x7fff || a[14] != 0xffff || a[13] != 0xffff || a[12] != 0xffff || a[11] != 0xffff || a[10] != 0xffff || a[9] != 0xffff || a[8] != 0xffff || a[7] != 0xffff || a[6] != 0xffff || a[5] != 0xffff || a[4] != 0xffff || a[3] != 0xffff || a[2] != 0xffff || a[1] != 0xffff || a[0] < 0xffed ) { return; } var i; for (i = 1; i < 16; i++) { a[i] = 0; } a[0] = a[0] - 0xffed; }; var curve25519_reduce2 = function (a) { var v = a[15]; if (v < 0x8000) return; a[15] = v % 0x8000; v = ~~(v / 0x8000) * 19; a[0] = (v += a[0]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[1] = (v += a[1]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[2] = (v += a[2]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[3] = (v += a[3]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[4] = (v += a[4]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[5] = (v += a[5]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[6] = (v += a[6]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[7] = (v += a[7]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[8] = (v += a[8]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[9] = (v += a[9]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[10] = (v += a[10]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[11] = (v += a[11]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[12] = (v += a[12]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[13] = (v += a[13]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[14] = (v += a[14]) & 0xffff; if ((v = ~~(v / 0x10000)) < 1) return; a[15] += v; }; /** * Montgomery curve with A=486662 and B=1 */ var curve25519_x_to_y2 = function (r, x) { var r1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; curve25519_sqrmodp(r1, x); // r1 = x^2 curve25519_mulasmall(r2, x, 486662); // r2 = Ax curve25519_addmodp(r, r1, r2); // r = x^2 + Ax curve25519_addmodp(r1, r, curve25519_one()); // r1 = x^2 + Ax + 1 curve25519_mulmodp(r, r1, x); // r = x^3 + Ax^2 + x }; var curve25519_prep = function (r, s, a, b) { curve25519_addmodp(r, a, b); curve25519_submodp(s, a, b); }; /**** * BloodyRookie: Doubling a point on a Montgomery curve: * Point is given in projective coordinates p=x/z * 2*P = r/s, * r = (x+z)^2 * (x-z)^2 * s = ((((x+z)^2 - (x-z)^2) * 121665) + (x+z)^2) * ((x+z)^2 - (x-z)^2) * = 4*x*z * (x^2 + 486662*x*z + z^2) * = 4*x*z * ((x-z)^2 + ((486662+2)/4)(4*x*z)) */ var curve25519_dbl = function (r, s, t1, t2) { var r1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r3 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; curve25519_sqrmodp(r1, t1); // r1 = t1^2 curve25519_sqrmodp(r2, t2); // r2 = t2^2 curve25519_submodp(r3, r1, r2); // r3 = t1^2 - t2^2 curve25519_mulmodp(r, r2, r1); // r = t1^2 * t2^2 curve25519_mulasmall(r2, r3, 121665); // r2 = (t1^2 - t2^2) * 121665 curve25519_addmodp(r4, r2, r1); // r4 = (t1^2 - t2^2) * 121665 + t1^2 curve25519_mulmodp(s, r4, r3); // s = ((t1^2 - t2^2) * 121665 + t1^2) * (t1^2 - t2^2) }; /**** * BloodyRookie: Adding 2 points on a Montgomery curve: * R = Q + P = r/s when given * Q = x/z, P = x_p/z_p, P-Q = x_1/1 * r = ((x-z)*(x_p+z_p) + (x+z)*(x_p-z_p))^2 * s = x_1*((x-z)*(x_p+z_p) - (x+z)*(x_p-z_p))^2 */ function curve25519_sum(r, s, t1, t2, t3, t4, x_1) { var r1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r3 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var r4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; curve25519_mulmodp(r1, t2, t3); // r1 = t2 * t3 curve25519_mulmodp(r2, t1, t4); // r2 = t1 * t4 curve25519_addmodp(r3, r1, r2); // r3 = t2 * t3 + t1 * t4 curve25519_submodp(r4, r1, r2); // r4 = t2 * t3 - t1 * t4 curve25519_sqrmodp(r, r3); // r = (t2 * t3 + t1 * t4)^2 curve25519_sqrmodp(r1, r4); // r1 = (t2 * t3 - t1 * t4)^2 curve25519_mulmodp(s, r1, x_1); // s = (t2 * t3 - t1 * t4)^2 * x_1 } function curve25519_(f, c, s) { var j, a, x_1, q, fb, counter = 0; var t = new Array(16), t1 = new Array(16), t2 = new Array(16), t3 = new Array(16), t4 = new Array(16); var sb = new Int8Array(32); var temp1 = new Int8Array(32); var temp2 = new Int8Array(64); var temp3 = new Int8Array(64); x_1 = c; q = [curve25519_one(), curve25519_zero()]; a = [x_1, curve25519_one()]; var n = 255; /********************************************************************** * BloodyRookie: * * Given f = f0*2^0 + f1*2^1 + ... + f255*2^255 and Basepoint a=9/1 * * calculate f*a by applying the Montgomery ladder (const time algo): * * r0 := 0 (point at infinity) * * r1 := a * * for i from 255 to 0 do * * if fi = 0 then * * r1 := r0 + r1 * * r0 := 2r0 * * else * * r0 := r0 + r1 * * r1 := 2r1 * * * * Result: r0 = x-coordinate of f*a * **********************************************************************/ var r0 = new Array(new Array(16), new Array(16)); var r1 = new Array(new Array(16), new Array(16)); var t1 = new Array(16), t2 = new Array(16); var t3 = new Array(16), t4 = new Array(16); var fi; while (n >= 0) { fi = curve25519_getbit(f, n); if (fi == 0) { curve25519_prep(t1, t2, a[0], a[1]); curve25519_prep(t3, t4, q[0], q[1]); curve25519_sum(r1[0], r1[1], t1, t2, t3, t4, x_1); curve25519_dbl(r0[0], r0[1], t3, t4); } else { curve25519_prep(t1, t2, q[0], q[1]); curve25519_prep(t3, t4, a[0], a[1]); curve25519_sum(r0[0], r0[1], t1, t2, t3, t4, x_1); curve25519_dbl(r1[0], r1[1], t3, t4); } q = r0; a = r1; n--; } curve25519_invmodp(t, q[1], 0); curve25519_mulmodp(t1, q[0], t); q[0] = curve25519_cpy16(t1); // q[0]=x-coordinate of k*G=:Px // q[1]=z-coordinate of k*G=:Pz // a = q + G = P + G if (s != null) { /************************************************************************* * BloodyRookie: Recovery of the y-coordinate of point P: * * * * If P=(x,y), P1=(x1, y1), P2=(x2,y2) and P2 = P1 + P then * * * * y1 = ((x1 * x + 1)(x1 + x + 2A) - 2A - (x1 - x)^2 * x2)/2y * * * * Setting P2=Q, P1=P and P=G in the above formula we get * * * * Py = ((Px * Gx + 1) * (Px + Gx + 2A) - 2A - (Px - Gx)^2 * Qx)/(2*Gy) * * = -((Qx + Px + Gx + A) * (Px - Gx)^2 - Py^2 - Gy^2)/(2*Gy) * *************************************************************************/ t = curve25519_cpy16(q[0]); curve25519_x_to_y2(t1, t); // t1 = Py^2 curve25519_invmodp(t3, a[1], 0); curve25519_mulmodp(t2, a[0], t3); // t2 = (P+G)x = Qx curve25519_addmodp(t4, t2, t); // t4 = Qx + Px curve25519_addmodp(t2, t4, curve25519_486671()); // t2 = Qx + Px + Gx + A curve25519_submodp(t4, t, curve25519_nine()); // t4 = Px - Gx curve25519_sqrmodp(t3, t4); // t3 = (Px - Gx)^2 curve25519_mulmodp(t4, t2, t3); // t4 = (Qx + Px + Gx + A) * (Px - Gx)^2 curve25519_submodp(t, t4, t1); // t = (Qx + Px + Gx + A) * (Px - Gx)^2 - Py^2 curve25519_submodp(t4, t, curve25519_39420360()); // t4 = (Qx + Px + Gx + A) * (Px - Gx)^2 - Py^2 - Gy^2 curve25519_mulmodp(t1, t4, curve25519_r2y()); // t1 = ((Qx + Px + Gx + A) * (Px - Gx)^2 - Py^2 - Gy^2)/(2Gy) = -Py fb = curve25519_convertToByteArray(f); j = curve25519_isNegative(t1); if (j != 0) { /*** * Py is positiv, so just copy */ sb = curve25519_cpy32(fb); } else { /*** * Py is negative: * We will take s = -f^-1 mod q instead of s=f^-1 mod q */ curve25519_mula_small(sb, curve25519_order_times_8, 0, fb, 32, -1); } temp1 = curve25519_cpy32(curve25519_order); temp1 = curve25519_egcd32(temp2, temp3, sb, temp1); sb = curve25519_cpy32(temp1); if ((sb[31] & 0x80) != 0) { curve25519_mula_small(sb, sb, 0, curve25519_order, 32, 1); } var stmp = curve25519_convertToShortArray(sb); curve25519_fillShortArray(stmp, s); } return q[0]; } var curve25519_keygen = function (s, curve) { curve25519_clamp(curve); return curve25519_(curve, curve25519_nine(), s); }; /* Signature generation primitive, calculates (x-h)s mod q * v [out] signature value * h [in] signature hash (of message, signature pub key, and context data) * x [in] signature private key * s [in] private key for signing * returns true on success, false on failure (use different x or h) */ var curve25519_sign = function (v, h, x, s) { tmp1 = new Int8Array(65); tmp2 = new Int8Array(33); for (i = 0; i < 32; i++) { v[i] = 0; } curve25519_mula_small(v, x, 0, h, 32, -1); curve25519_mula_small( v, v, 0, curve25519_order, 32, parseInt((15 - v[31]) / 16) ); curve25519_mula32(tmp1, v, s, 32, 1); curve25519_divmod(tmp2, tmp1, 64, curve25519_order, 32); w = 0; for (k = 0; k < 32; k++) { v[k] = tmp1[k]; w |= v[k]; } return w != 0; }; var curve25519_verify = function (Y, v, h, P) { d = new Int8Array(32); yx = new Array(new Array(16), new Array(16), new Array(16)); yz = new Array(new Array(16), new Array(16), new Array(16)); var s = new Array(new Array(16), new Array(16)); var q = new Array(new Array(16), new Array(16)); var t1 = new Array(new Array(16), new Array(16), new Array(16)); var t2 = new Array(new Array(16), new Array(16), new Array(16)); var vi = 0, hi = 0, di = 0, nvh = 0, i = 0, j = 0, k = 0, counter = 1; /****************************************************************** * Set s[0] to P+G and s[1] to P-G. * * If sqrt(Py^2) is negativ we switch s[0] and s[1] * * * * s[0] = (Py^2 + Gy^2 - 2 Py Gy)/(Px - Gx)^2 - Px - Gx - 486662 * * s[1] = (Py^2 + Gy^2 + 2 Py Gy)/(Px - Gx)^2 - Px - Gx - 486662 * ******************************************************************/ var p = [curve25519_nine(), curve25519_convertToShortArray(P)]; curve25519_x_to_y2(q[0], p[1]); // q[0] = Py^2 curve25519_sqrtmodp(t1[0], q[0]); // t1[0] = +-Py j = curve25519_isNegative(t1[0]); curve25519_addmodp(t2[0], q[0], curve25519_39420360()); // t2[0] = Py^2 + Gy^2 curve25519_mulmodp(t2[1], curve25519_2y(), t1[0]); // t2[1] = +-Py * 2Gy curve25519_submodp(t1[j], t2[0], t2[1]); // t1[j] = Py^2 + Gy^2 - +-Py * 2Gy curve25519_addmodp(t1[1 - j], t2[0], t2[1]); // t1[1-j] = Py^2 + Gy^2 + +-Py * 2Gy q[0] = curve25519_cpy16(p[1]); // q[0] = Px curve25519_submodp(t2[0], q[0], curve25519_nine()); // t2[0] = Px-Gx curve25519_sqrmodp(t2[1], t2[0]); // t2[1] = (Px-Gx)^2 curve25519_invmodp(t2[0], t2[1], 0); // t2[0] = 1/(Px-Gx)^2 curve25519_mulmodp(q[0], t1[0], t2[0]); // q[0] = (Py^2 + Gy^2 - Py * 2Gy)/(Px-Gx)^2 curve25519_submodp(q[1], q[0], p[1]); // q[1] = (Py^2 + Gy^2 - Py * 2Gy)/(Px-Gx)^2 - Px curve25519_submodp(s[0], q[1], curve25519_486671()); // s[0] = (Py^2 + Gy^2 - Py * 2Gy)/(Px-Gx)^2 - Px - Gx - A = P+Q curve25519_mulmodp(q[0], t1[1], t2[0]); // q[0] = (Py^2 + Gy^2 + Py * 2Gy)/(Px-Gx)^2 curve25519_submodp(q[1], q[0], p[1]); // q[1] = (Py^2 + Gy^2 + Py * 2Gy)/(Px-Gx)^2 - Px curve25519_submodp(s[1], q[1], curve25519_486671()); // s[1] = (Py^2 + Gy^2 + Py * 2Gy)/(Px-Gx)^2 - Px - Gx - A = P-Q /** * Fast algorithm for computing vP+hG */ for (i = 0; i < 32; i++) { vi = (vi >> 8) ^ (v[i] & 0xff) ^ ((v[i] & 0xff) << 1); hi = (hi >> 8) ^ (h[i] & 0xff) ^ ((h[i] & 0xff) << 1); nvh = ~(vi ^ hi); di = (nvh & ((di & 0x80) >> 7)) ^ vi; di ^= nvh & ((di & 0x01) << 1); di ^= nvh & ((di & 0x02) << 1); di ^= nvh & ((di & 0x04) << 1); di ^= nvh & ((di & 0x08) << 1); di ^= nvh & ((di & 0x10) << 1); di ^= nvh & ((di & 0x20) << 1); di ^= nvh & ((di & 0x40) << 1); d[i] = di & 0xff; } di = ((nvh & ((di & 0x80) << 1)) ^ vi) >> 8; /** * yx[0]/yz[0] = point at infinity */ yx[0] = curve25519_cpy16(curve25519_one()); yx[1] = curve25519_cpy16(p[di]); yx[2] = curve25519_cpy16(s[0]); yz[0] = curve25519_cpy16(curve25519_zero()); yz[1] = curve25519_cpy16(curve25519_one()); yz[2] = curve25519_cpy16(curve25519_one()); vi = 0; hi = 0; for (i = 32; i-- != 0; i = i) { vi = (vi << 8) | (v[i] & 0xff); hi = (hi << 8) | (h[i] & 0xff); di = (di << 8) | (d[i] & 0xff); for (j = 8; j-- != 0; j = j) { k = (((vi ^ (vi >> 1)) >> j) & 1) + (((hi ^ (hi >> 1)) >> j) & 1); curve25519_prep(t1[0], t2[0], yx[0], yz[0]); curve25519_prep(t1[1], t2[1], yx[1], yz[1]); curve25519_prep(t1[2], t2[2], yx[2], yz[2]); curve25519_dbl(yx[0], yz[0], t1[k], t2[k]); k = ((di >> j) & 2) ^ (((di >> j) & 1) << 1); curve25519_sum( yx[1], yz[1], t1[1], t2[1], t1[k], t2[k], p[(di >> j) & 1] ); curve25519_sum( yx[2], yz[2], t1[2], t2[2], t1[0], t2[0], s[(((vi ^ hi) >> j) & 2) >> 1] ); } } k = (vi & 1) + (hi & 1); curve25519_invmodp(t1[0], yz[k], 0); curve25519_mulmodp(t1[1], yx[k], t1[0]); var YY = curve25519_convertToByteArray(t1[1]); curve25519_fillByteArray(YY, Y); }; export default curve25519_ ;