// Copyright (c) 2007, 2013 Michele Bini // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is furnished // to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. var c255lbase32chars = "abcdefghijklmnopqrstuvwxyz234567"; var c255lbase32values = {"a":0, "b":1, "c":2, "d":3, "e":4, "f":5, "g":6, "h":7, "i":8, "j":9, "k":10, "l":11, "m":12, "n":13, "o":14, "p":15, "q":16, "r":17, "s":18, "t":19, "u":20, "v":21, "w":22, "x":23, "y":24, "z":25, "2":26, "3":27, "4":28, "5":29, "6":30, "7":31 }; function c255lbase32encode(n) { var c; var r = ""; for (c = 0; c < 255; c+=5) { r = c255lbase32chars.substr(c255lgetbit(n, c) + c255lgetbit(n, c+1)*2 + c255lgetbit(n, c+2)*4 + c255lgetbit(n, c+3)*8 + c255lgetbit(n, c+4)*16, 1) + r; } return r; } function c255lbase32decode(n) { var c = 0; var r = c255lzero(); var l = n.length; for (c = 0; (l > 0) && (c < 255); c+=5) { l--; var v = c255lbase32values[n.substr(l, 1)]; c255lsetbit(r, c, v%2); v = v >> 1; c255lsetbit(r, c+1, v%2); v = v >> 1; c255lsetbit(r, c+2, v%2); v = v >> 1; c255lsetbit(r, c+3, v%2); v = v >> 1; c255lsetbit(r, c+4, v%2); } return r; } var c255lhexchars = "0123456789abcdef"; var c255lhexvalues = {"0":0, "1":1, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "a":10, "b":11, "c":12, "d":13, "e":14, "f":15 }; function c255lhexencode(n) { var c; var r = ""; for (c = 0; c < 255; c+=4) { r = c255lhexchars.substr(c255lgetbit(n, c) + c255lgetbit(n, c+1)*2 + c255lgetbit(n, c+2)*4 + c255lgetbit(n, c+3)*8, 1) + r; } return r; } function c255lhexdecode(n) { var c = 0; var r = c255lzero(); var l = n.length; for (c = 0; (l > 0) && (c < 255); c+=4) { l--; var v = c255lhexvalues[n.substr(l, 1)]; c255lsetbit(r, c, v%2); v = v >> 1; c255lsetbit(r, c+1, v%2); v = v >> 1; c255lsetbit(r, c+2, v%2); v = v >> 1; c255lsetbit(r, c+3, v%2); } return r; } var c255lprime = [0xffff-18, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x7fff]; function c255lsetbit(n, c, v) { var i = Math.floor(c / 16); var a = n[i]; a = a + Math.pow(2, c % 16) * v; n[i] = a; } function c255lgetbit(n, c) { return Math.floor(n[Math.floor(c / 16)] / Math.pow(2, c % 16)) % 2; } function c255lzero() { return [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; } function c255lone() { return [1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; } function c255lbase() { // Basepoint return [9,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; } // return -1, 0, +1 when a is less than, equal, or greater than b function c255lbigintcmp(a, b) { // The following code is a bit tricky to avoid code branching var c; var r = 0; for (c = 15; c >= 0; c--) { var x = a[c]; var y = b[c]; r = r + (x - y)*(1 - r*r); r = Math.round(2 * r / (Math.abs(r) + 1)); } r = Math.round(2 * r / (Math.abs(r) + 1)); return r; } function c255lbigintadd(a, b) { var r = []; var v; r[0] = (v = a[0] + b[0]) % 0x10000; r[1] = (v = Math.floor(v / 0x10000) + a[1] + b[1]) % 0x10000; r[2] = (v = Math.floor(v / 0x10000) + a[2] + b[2]) % 0x10000; r[3] = (v = Math.floor(v / 0x10000) + a[3] + b[3]) % 0x10000; r[4] = (v = Math.floor(v / 0x10000) + a[4] + b[4]) % 0x10000; r[5] = (v = Math.floor(v / 0x10000) + a[5] + b[5]) % 0x10000; r[6] = (v = Math.floor(v / 0x10000) + a[6] + b[6]) % 0x10000; r[7] = (v = Math.floor(v / 0x10000) + a[7] + b[7]) % 0x10000; r[8] = (v = Math.floor(v / 0x10000) + a[8] + b[8]) % 0x10000; r[9] = (v = Math.floor(v / 0x10000) + a[9] + b[9]) % 0x10000; r[10] = (v = Math.floor(v / 0x10000) + a[10] + b[10]) % 0x10000; r[11] = (v = Math.floor(v / 0x10000) + a[11] + b[11]) % 0x10000; r[12] = (v = Math.floor(v / 0x10000) + a[12] + b[12]) % 0x10000; r[13] = (v = Math.floor(v / 0x10000) + a[13] + b[13]) % 0x10000; r[14] = (v = Math.floor(v / 0x10000) + a[14] + b[14]) % 0x10000; r[15] = Math.floor(v / 0x10000) + a[15] + b[15]; return r; } function c255lbigintsub(a, b) { var r = []; var v; r[0] = (v = 0x80000 + a[0] - b[0]) % 0x10000; r[1] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[1] - b[1]) % 0x10000; r[2] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[2] - b[2]) % 0x10000; r[3] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[3] - b[3]) % 0x10000; r[4] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[4] - b[4]) % 0x10000; r[5] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[5] - b[5]) % 0x10000; r[6] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[6] - b[6]) % 0x10000; r[7] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[7] - b[7]) % 0x10000; r[8] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[8] - b[8]) % 0x10000; r[9] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[9] - b[9]) % 0x10000; r[10] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[10] - b[10]) % 0x10000; r[11] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[11] - b[11]) % 0x10000; r[12] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[12] - b[12]) % 0x10000; r[13] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[13] - b[13]) % 0x10000; r[14] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[14] - b[14]) % 0x10000; r[15] = Math.floor(v / 0x10000) - 8 + a[15] - b[15]; return r; } function c255lsqr8h(a7, a6, a5, a4, a3, a2, a1, a0) { var r = []; var v; r[0] = (v = a0*a0) % 0x10000; r[1] = (v = Math.floor(v / 0x10000) + 2*a0*a1) % 0x10000; r[2] = (v = Math.floor(v / 0x10000) + 2*a0*a2 + a1*a1) % 0x10000; r[3] = (v = Math.floor(v / 0x10000) + 2*a0*a3 + 2*a1*a2) % 0x10000; r[4] = (v = Math.floor(v / 0x10000) + 2*a0*a4 + 2*a1*a3 + a2*a2) % 0x10000; r[5] = (v = Math.floor(v / 0x10000) + 2*a0*a5 + 2*a1*a4 + 2*a2*a3) % 0x10000; r[6] = (v = Math.floor(v / 0x10000) + 2*a0*a6 + 2*a1*a5 + 2*a2*a4 + a3*a3) % 0x10000; r[7] = (v = Math.floor(v / 0x10000) + 2*a0*a7 + 2*a1*a6 + 2*a2*a5 + 2*a3*a4) % 0x10000; r[8] = (v = Math.floor(v / 0x10000) + 2*a1*a7 + 2*a2*a6 + 2*a3*a5 + a4*a4) % 0x10000; r[9] = (v = Math.floor(v / 0x10000) + 2*a2*a7 + 2*a3*a6 + 2*a4*a5) % 0x10000; r[10] = (v = Math.floor(v / 0x10000) + 2*a3*a7 + 2*a4*a6 + a5*a5) % 0x10000; r[11] = (v = Math.floor(v / 0x10000) + 2*a4*a7 + 2*a5*a6) % 0x10000; r[12] = (v = Math.floor(v / 0x10000) + 2*a5*a7 + a6*a6) % 0x10000; r[13] = (v = Math.floor(v / 0x10000) + 2*a6*a7) % 0x10000; r[14] = (v = Math.floor(v / 0x10000) + a7*a7) % 0x10000; r[15] = Math.floor(v / 0x10000); return r; } function c255lsqrmodp(a) { var x = c255lsqr8h(a[15], a[14], a[13], a[12], a[11], a[10], a[9], a[8]); var z = c255lsqr8h(a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]); var y = c255lsqr8h(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 r = []; var v; r[0] = (v = 0x800000 + z[0] + (y[8] -x[8] -z[8] + x[0] -0x80) * 38) % 0x10000; r[1] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[1] + (y[9] -x[9] -z[9] + x[1]) * 38) % 0x10000; r[2] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[2] + (y[10] -x[10] -z[10] + x[2]) * 38) % 0x10000; r[3] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[3] + (y[11] -x[11] -z[11] + x[3]) * 38) % 0x10000; r[4] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[4] + (y[12] -x[12] -z[12] + x[4]) * 38) % 0x10000; r[5] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[5] + (y[13] -x[13] -z[13] + x[5]) * 38) % 0x10000; r[6] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[6] + (y[14] -x[14] -z[14] + x[6]) * 38) % 0x10000; r[7] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[7] + (y[15] -x[15] -z[15] + x[7]) * 38) % 0x10000; r[8] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[8] + y[0] -x[0] -z[0] + x[8] * 38) % 0x10000; r[9] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[9] + y[1] -x[1] -z[1] + x[9] * 38) % 0x10000; r[10] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[10] + y[2] -x[2] -z[2] + x[10] * 38) % 0x10000; r[11] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[11] + y[3] -x[3] -z[3] + x[11] * 38) % 0x10000; r[12] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[12] + y[4] -x[4] -z[4] + x[12] * 38) % 0x10000; r[13] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[13] + y[5] -x[5] -z[5] + x[13] * 38) % 0x10000; r[14] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[14] + y[6] -x[6] -z[6] + x[14] * 38) % 0x10000; r[15] = 0x7fff80 + Math.floor(v / 0x10000) + z[15] + y[7] -x[7] -z[7] + x[15] * 38; c255lreduce(r); return r; } function c255lmul8h(a7, a6, a5, a4, a3, a2, a1, a0, b7, b6, b5, b4, b3, b2, b1, b0) { var r = []; var v; r[0] = (v = a0*b0) % 0x10000; r[1] = (v = Math.floor(v / 0x10000) + a0*b1 + a1*b0) % 0x10000; r[2] = (v = Math.floor(v / 0x10000) + a0*b2 + a1*b1 + a2*b0) % 0x10000; r[3] = (v = Math.floor(v / 0x10000) + a0*b3 + a1*b2 + a2*b1 + a3*b0) % 0x10000; r[4] = (v = Math.floor(v / 0x10000) + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0) % 0x10000; r[5] = (v = Math.floor(v / 0x10000) + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0) % 0x10000; r[6] = (v = Math.floor(v / 0x10000) + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0) % 0x10000; r[7] = (v = Math.floor(v / 0x10000) + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0) % 0x10000; r[8] = (v = Math.floor(v / 0x10000) + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1) % 0x10000; r[9] = (v = Math.floor(v / 0x10000) + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2) % 0x10000; r[10] = (v = Math.floor(v / 0x10000) + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3) % 0x10000; r[11] = (v = Math.floor(v / 0x10000) + a4*b7 + a5*b6 + a6*b5 + a7*b4) % 0x10000; r[12] = (v = Math.floor(v / 0x10000) + a5*b7 + a6*b6 + a7*b5) % 0x10000; r[13] = (v = Math.floor(v / 0x10000) + a6*b7 + a7*b6) % 0x10000; r[14] = (v = Math.floor(v / 0x10000) + a7*b7) % 0x10000; r[15] = Math.floor(v / 0x10000); return r; } function c255lmulmodp(a, b) { // Karatsuba multiplication scheme: x*y = (b^2+b)*x1*y1 - b*(x1-x0)*(y1-y0) + (b+1)*x0*y0 var x = c255lmul8h(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]); var z = c255lmul8h(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]); var y = c255lmul8h(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 r = []; var v; r[0] = (v = 0x800000 + z[0] + (y[8] -x[8] -z[8] + x[0] -0x80) * 38) % 0x10000; r[1] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[1] + (y[9] -x[9] -z[9] + x[1]) * 38) % 0x10000; r[2] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[2] + (y[10] -x[10] -z[10] + x[2]) * 38) % 0x10000; r[3] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[3] + (y[11] -x[11] -z[11] + x[3]) * 38) % 0x10000; r[4] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[4] + (y[12] -x[12] -z[12] + x[4]) * 38) % 0x10000; r[5] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[5] + (y[13] -x[13] -z[13] + x[5]) * 38) % 0x10000; r[6] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[6] + (y[14] -x[14] -z[14] + x[6]) * 38) % 0x10000; r[7] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[7] + (y[15] -x[15] -z[15] + x[7]) * 38) % 0x10000; r[8] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[8] + y[0] -x[0] -z[0] + x[8] * 38) % 0x10000; r[9] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[9] + y[1] -x[1] -z[1] + x[9] * 38) % 0x10000; r[10] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[10] + y[2] -x[2] -z[2] + x[10] * 38) % 0x10000; r[11] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[11] + y[3] -x[3] -z[3] + x[11] * 38) % 0x10000; r[12] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[12] + y[4] -x[4] -z[4] + x[12] * 38) % 0x10000; r[13] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[13] + y[5] -x[5] -z[5] + x[13] * 38) % 0x10000; r[14] = (v = 0x7fff80 + Math.floor(v / 0x10000) + z[14] + y[6] -x[6] -z[6] + x[14] * 38) % 0x10000; r[15] = 0x7fff80 + Math.floor(v / 0x10000) + z[15] + y[7] -x[7] -z[7] + x[15] * 38; c255lreduce(r); return r; } function c255lreduce(a) { var v = a[15]; a[15] = v % 0x8000; v = Math.floor(v / 0x8000) * 19; a[0] = (v += a[0]) % 0x10000; v = Math.floor(v / 0x10000); a[1] = (v += a[1]) % 0x10000; v = Math.floor(v / 0x10000); a[2] = (v += a[2]) % 0x10000; v = Math.floor(v / 0x10000); a[3] = (v += a[3]) % 0x10000; v = Math.floor(v / 0x10000); a[4] = (v += a[4]) % 0x10000; v = Math.floor(v / 0x10000); a[5] = (v += a[5]) % 0x10000; v = Math.floor(v / 0x10000); a[6] = (v += a[6]) % 0x10000; v = Math.floor(v / 0x10000); a[7] = (v += a[7]) % 0x10000; v = Math.floor(v / 0x10000); a[8] = (v += a[8]) % 0x10000; v = Math.floor(v / 0x10000); a[9] = (v += a[9]) % 0x10000; v = Math.floor(v / 0x10000); a[10] = (v += a[10]) % 0x10000; v = Math.floor(v / 0x10000); a[11] = (v += a[11]) % 0x10000; v = Math.floor(v / 0x10000); a[12] = (v += a[12]) % 0x10000; v = Math.floor(v / 0x10000); a[13] = (v += a[13]) % 0x10000; v = Math.floor(v / 0x10000); a[14] = (v += a[14]) % 0x10000; v = Math.floor(v / 0x10000); a[15] += v; } function c255laddmodp(a, b) { var r = []; var v; r[0] = (v = (Math.floor(a[15] / 0x8000) + Math.floor(b[15] / 0x8000)) * 19 + a[0] + b[0]) % 0x10000; r[1] = (v = Math.floor(v / 0x10000) + a[1] + b[1]) % 0x10000; r[2] = (v = Math.floor(v / 0x10000) + a[2] + b[2]) % 0x10000; r[3] = (v = Math.floor(v / 0x10000) + a[3] + b[3]) % 0x10000; r[4] = (v = Math.floor(v / 0x10000) + a[4] + b[4]) % 0x10000; r[5] = (v = Math.floor(v / 0x10000) + a[5] + b[5]) % 0x10000; r[6] = (v = Math.floor(v / 0x10000) + a[6] + b[6]) % 0x10000; r[7] = (v = Math.floor(v / 0x10000) + a[7] + b[7]) % 0x10000; r[8] = (v = Math.floor(v / 0x10000) + a[8] + b[8]) % 0x10000; r[9] = (v = Math.floor(v / 0x10000) + a[9] + b[9]) % 0x10000; r[10] = (v = Math.floor(v / 0x10000) + a[10] + b[10]) % 0x10000; r[11] = (v = Math.floor(v / 0x10000) + a[11] + b[11]) % 0x10000; r[12] = (v = Math.floor(v / 0x10000) + a[12] + b[12]) % 0x10000; r[13] = (v = Math.floor(v / 0x10000) + a[13] + b[13]) % 0x10000; r[14] = (v = Math.floor(v / 0x10000) + a[14] + b[14]) % 0x10000; r[15] = Math.floor(v / 0x10000) + a[15] % 0x8000 + b[15] % 0x8000; return r; } function c255lsubmodp(a, b) { var r = []; var v; r[0] = (v = 0x80000 + (Math.floor(a[15] / 0x8000) - Math.floor(b[15] / 0x8000) - 1) * 19 + a[0] - b[0]) % 0x10000; r[1] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[1] - b[1]) % 0x10000; r[2] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[2] - b[2]) % 0x10000; r[3] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[3] - b[3]) % 0x10000; r[4] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[4] - b[4]) % 0x10000; r[5] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[5] - b[5]) % 0x10000; r[6] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[6] - b[6]) % 0x10000; r[7] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[7] - b[7]) % 0x10000; r[8] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[8] - b[8]) % 0x10000; r[9] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[9] - b[9]) % 0x10000; r[10] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[10] - b[10]) % 0x10000; r[11] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[11] - b[11]) % 0x10000; r[12] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[12] - b[12]) % 0x10000; r[13] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[13] - b[13]) % 0x10000; r[14] = (v = Math.floor(v / 0x10000) + 0x7fff8 + a[14] - b[14]) % 0x10000; r[15] = Math.floor(v / 0x10000) + 0x7ff8 + a[15]%0x8000 - b[15]%0x8000; return r; } function c255linvmodp(a) { var c = a; var i = 250; while (--i) { a = c255lsqrmodp(a); //if (i > 240) { tracev("invmodp a", a); } a = c255lmulmodp(a, c); //if (i > 240) { tracev("invmodp a 2", a); } } a = c255lsqrmodp(a); a = c255lsqrmodp(a); a = c255lmulmodp(a, c); a = c255lsqrmodp(a); a = c255lsqrmodp(a); a = c255lmulmodp(a, c); a = c255lsqrmodp(a); a = c255lmulmodp(a, c); return a; } function c255lmulasmall(a) { var m = 121665; var r = []; var v; r[0] = (v = a[0] * m) % 0x10000; r[1] = (v = Math.floor(v / 0x10000) + a[1]*m) % 0x10000; r[2] = (v = Math.floor(v / 0x10000) + a[2]*m) % 0x10000; r[3] = (v = Math.floor(v / 0x10000) + a[3]*m) % 0x10000; r[4] = (v = Math.floor(v / 0x10000) + a[4]*m) % 0x10000; r[5] = (v = Math.floor(v / 0x10000) + a[5]*m) % 0x10000; r[6] = (v = Math.floor(v / 0x10000) + a[6]*m) % 0x10000; r[7] = (v = Math.floor(v / 0x10000) + a[7]*m) % 0x10000; r[8] = (v = Math.floor(v / 0x10000) + a[8]*m) % 0x10000; r[9] = (v = Math.floor(v / 0x10000) + a[9]*m) % 0x10000; r[10] = (v = Math.floor(v / 0x10000) + a[10]*m) % 0x10000; r[11] = (v = Math.floor(v / 0x10000) + a[11]*m) % 0x10000; r[12] = (v = Math.floor(v / 0x10000) + a[12]*m) % 0x10000; r[13] = (v = Math.floor(v / 0x10000) + a[13]*m) % 0x10000; r[14] = (v = Math.floor(v / 0x10000) + a[14]*m) % 0x10000; r[15] = Math.floor(v / 0x10000) + a[15]*m; c255lreduce(r); return r; } function c255ldbl(x, z) { var x_2, z_2, m, n, o; ///tracev("dbl x", x); ///tracev("dbl z", z); m = c255lsqrmodp(c255laddmodp(x, z)); //tracev("dbl m", c255laddmodp(x, z)); n = c255lsqrmodp(c255lsubmodp(x, z)); ///tracev("dbl n", n); o = c255lsubmodp(m, n); ///tracev("dbl o", o); x_2 = c255lmulmodp(n, m); //tracev("dbl x_2", x_2); z_2 = c255lmulmodp(c255laddmodp(c255lmulasmall(o), m), o); //tracev("dbl z_2", z_2); return [x_2, z_2]; } function c255lsum(x, z, x_p, z_p, x_1) { var x_3, z_3, k, l, p, q; //tracev("sum x", x); //tracev("sum z", z); p = c255lmulmodp(c255lsubmodp(x, z), c255laddmodp(x_p, z_p)); q = c255lmulmodp(c255laddmodp(x, z), c255lsubmodp(x_p, z_p)); //tracev("sum p", p); //tracev("sum q", q); x_3 = c255lsqrmodp(c255laddmodp(p, q)); z_3 = c255lmulmodp(c255lsqrmodp(c255lsubmodp(p, q)), x_1); return [x_3, z_3]; } function curve25519_raw(f, c) { var a, x_1, q; x_1 = c; //tracev("c", c); //tracev("x_1", x_1); a = c255ldbl(x_1, c255lone()); //tracev("x_a", a[0]); //tracev("z_a", a[1]); q = [ x_1, c255lone() ]; var n = 255; while (c255lgetbit(f, n) == 0) { n--; // For correct constant-time operation, bit 255 should always be set to 1 so the following 'while' loop is never entered if (n < 0) { return c255lzero(); } } n--; var aq = [ a, q ]; while (n >= 0) { var r, s; var b = c255lgetbit(f, n); r = c255lsum(aq[0][0], aq[0][1], aq[1][0], aq[1][1], x_1); s = c255ldbl(aq[1-b][0], aq[1-b][1]); aq[1-b] = s; aq[b] = r; n--; } q = aq[1]; //tracev("x", q[0]); //tracev("z", q[1]); q[1] = c255linvmodp(q[1]); //tracev("1/z", q[1]); q[0] = c255lmulmodp(q[0], q[1]); c255lreduce(q[0]); return q[0]; } function curve25519b32(a, b) { return c255lbase32encode(curve25519(c255lbase32decode(a), b && c255lbase32decode(b))); } function curve25519(f, c) { if (!c) { c = c255lbase(); } // The masking is done upstream (and not always done) //f[0] &= 0xFFF8; //f[15] = (f[15] & 0x7FFF) | 0x4000; return curve25519_raw(f, c); }