Cable-Desktop/js-deps/curve255.js

453 lines
20 KiB
JavaScript

// 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);
}