UNPKG

@signumjs/crypto

Version:

Cryptographic functions for building Signum Network apps.

632 lines 26.4 kB
"use strict"; /** @ignore */ /** @internal */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Curve25519 = void 0; /* tslint:disable */ /* * Ported to TypeScript 2.4.2 (https://github.com/Microsoft/TypeScript/issues/18158) 09/02/17. * Ported to JavaScript from Java 07/01/14. * Ported from C to Java by Dmitry Skiba [sahn0], 23/02/08. * Original: http://cds.xs4all.nl:8081/ecdh/ */ /* * Generic 64-bit integer implementation of Curve25519 ECDH * Written by Matthijs van Duin, 200608242056 * Public domain. * * Based on work by Daniel J Bernstein, http://cr.yp.to/ecdh.html */ class Curve25519 { //region Constants static KEY_SIZE = 32; /* array length */ static UNPACKED_SIZE = 16; /* group order (a prime near 2^252+2^124) */ static 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 ]; /* smallest multiple of the order that's >= 2^255 */ static 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 ]; /* constants 2Gy and 1/(2Gy) */ static BASE_2Y = [ 22587, 610, 29883, 44076, 15515, 9479, 25859, 56197, 23910, 4462, 17831, 16322, 62102, 36542, 52412, 16035 ]; static BASE_R2Y = [ 5744, 16384, 61977, 54121, 8776, 18501, 26522, 34893, 23833, 5823, 55924, 58749, 24147, 14085, 13606, 6080 ]; static C1 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; static C9 = [9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; static C486671 = [0x6D0F, 0x0007, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; static C39420360 = [0x81C8, 0x0259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; static P25 = 33554431; /* (1 << 25) - 1 */ static P26 = 67108863; /* (1 << 26) - 1 */ //#endregion //region Key Agreement /* Private key clamping * k [out] your private key for key agreement * k [in] 32 random bytes */ static clamp(k) { k[31] &= 0x7F; k[31] |= 0x40; k[0] &= 0xF8; } //endregion //region radix 2^8 math static cpy32(d, s) { for (let i = 0; i < 32; i++) d[i] = s[i]; } /* p[m..n+m-1] = q[m..n+m-1] + z * x */ /* n is the size of x */ /* n+m is the size of p and q */ static mula_small(p, q, m, x, n, z) { m = m | 0; n = n | 0; z = z | 0; let v = 0; for (let i = 0; i < n; ++i) { v += (q[i + m] & 0xFF) + z * (x[i] & 0xFF); p[i + m] = (v & 0xFF); v >>= 8; } return v; } /* p += x * y * z where z is a small integer * x is size 32, y is size t, p is size 32+t * y is allowed to overlap with p+32 if you don't care about the upper half */ static mula32(p, x, y, t, z) { t = t | 0; z = z | 0; let n = 31; let w = 0; let i = 0; for (; i < t; i++) { let 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; } /* divide r (size n) by d (size t), returning quotient q and remainder r * quotient is size n-t+1, remainder is size t * requires t > 0 && d[t-1] !== 0 * requires that r[-1] and d[-1] are valid memory locations * q may overlap with r+t */ static divmod(q, r, n, d, t) { n = n | 0; t = t | 0; let rn = 0; let dt = (d[t - 1] & 0xFF) << 8; if (t > 1) dt |= (d[t - 2] & 0xFF); while (n-- >= t) { let z = (rn << 16) | ((r[n] & 0xFF) << 8); if (n > 0) z |= (r[n - 1] & 0xFF); let i = n - t + 1; z /= dt; rn += Curve25519.mula_small(r, r, i, d, t, -z); q[i] = (z + rn) & 0xFF; /* rn is 0 or -1 (underflow) */ Curve25519.mula_small(r, r, i, d, t, -rn); rn = r[n] & 0xFF; r[n] = 0; } r[t - 1] = rn & 0xFF; } static numsize(x, n) { while (n-- !== 0 && x[n] === 0) { } return n + 1; } /* Returns x if a contains the gcd, y if b. * Also, the returned buffer contains the inverse of a mod b, * as 32-byte signed. * x and y must have 64 bytes space for temporary use. * requires that a[-1] and b[-1] are valid memory locations */ static egcd32(x, y, a, b) { let an, bn = 32, qn, i; 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 */ let temp = new Array(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); } } //endregion //region radix 2^25.5 GF(2^255-19) math //region pack / unpack /* Convert to internal format from little-endian byte format */ static unpack(x, m) { for (let i = 0; i < Curve25519.KEY_SIZE; i += 2) x[i / 2] = m[i] & 0xFF | ((m[i + 1] & 0xFF) << 8); } /* Check if reduced-form input >= 2^255-19 */ static is_overflow(x) { return (((x[0] > Curve25519.P26 - 19)) && ((x[1] & x[3] & x[5] & x[7] & x[9]) === Curve25519.P25) && ((x[2] & x[4] & x[6] & x[8]) === Curve25519.P26)) || (x[9] > Curve25519.P25); } /* Convert from internal format to little-endian byte format. The * number must be in a reduced form which is output by the following ops: * unpack, mul, sqr * set -- if input in range 0 .. P25 * If you're unsure if the number is reduced, first multiply it by 1. */ static pack(x, m) { for (let i = 0; i < Curve25519.UNPACKED_SIZE; ++i) { m[2 * i] = x[i] & 0x00FF; m[2 * i + 1] = (x[i] & 0xFF00) >> 8; } } //endregion static createUnpackedArray() { return new Uint16Array(Curve25519.UNPACKED_SIZE); } /* Copy a number */ static cpy(d, s) { for (let i = 0; i < Curve25519.UNPACKED_SIZE; ++i) d[i] = s[i]; } /* Set a number to value, which must be in range -185861411 .. 185861411 */ static set(d, s) { d[0] = s; for (let i = 1; i < Curve25519.UNPACKED_SIZE; ++i) d[i] = 0; } /* Calculates a reciprocal. The output is in reduced form, the inputs need not * be. Simply calculates y = x^(p-2) so it's not too fast. */ /* When sqrtassist is true, it instead calculates y = x^((p-5)/8) */ static recip(y, x, sqrtassist) { let t0 = Curve25519.createUnpackedArray(); let t1 = Curve25519.createUnpackedArray(); let t2 = Curve25519.createUnpackedArray(); let t3 = Curve25519.createUnpackedArray(); let t4 = Curve25519.createUnpackedArray(); /* the chain for x^(2^255-21) is straight from djb's implementation */ let i; Curve25519.sqr(t1, x); /* 2 === 2 * 1 */ Curve25519.sqr(t2, t1); /* 4 === 2 * 2 */ Curve25519.sqr(t0, t2); /* 8 === 2 * 4 */ Curve25519.mul(t2, t0, x); /* 9 === 8 + 1 */ Curve25519.mul(t0, t2, t1); /* 11 === 9 + 2 */ Curve25519.sqr(t1, t0); /* 22 === 2 * 11 */ Curve25519.mul(t3, t1, t2); /* 31 === 22 + 9 === 2^5 - 2^0 */ Curve25519.sqr(t1, t3); /* 2^6 - 2^1 */ Curve25519.sqr(t2, t1); /* 2^7 - 2^2 */ Curve25519.sqr(t1, t2); /* 2^8 - 2^3 */ Curve25519.sqr(t2, t1); /* 2^9 - 2^4 */ Curve25519.sqr(t1, t2); /* 2^10 - 2^5 */ Curve25519.mul(t2, t1, t3); /* 2^10 - 2^0 */ Curve25519.sqr(t1, t2); /* 2^11 - 2^1 */ Curve25519.sqr(t3, t1); /* 2^12 - 2^2 */ for (i = 1; i < 5; i++) { Curve25519.sqr(t1, t3); Curve25519.sqr(t3, t1); } /* t3 */ /* 2^20 - 2^10 */ Curve25519.mul(t1, t3, t2); /* 2^20 - 2^0 */ Curve25519.sqr(t3, t1); /* 2^21 - 2^1 */ Curve25519.sqr(t4, t3); /* 2^22 - 2^2 */ for (i = 1; i < 10; i++) { Curve25519.sqr(t3, t4); Curve25519.sqr(t4, t3); } /* t4 */ /* 2^40 - 2^20 */ Curve25519.mul(t3, t4, t1); /* 2^40 - 2^0 */ for (i = 0; i < 5; i++) { Curve25519.sqr(t1, t3); Curve25519.sqr(t3, t1); } /* t3 */ /* 2^50 - 2^10 */ Curve25519.mul(t1, t3, t2); /* 2^50 - 2^0 */ Curve25519.sqr(t2, t1); /* 2^51 - 2^1 */ Curve25519.sqr(t3, t2); /* 2^52 - 2^2 */ for (i = 1; i < 25; i++) { Curve25519.sqr(t2, t3); Curve25519.sqr(t3, t2); } /* t3 */ /* 2^100 - 2^50 */ Curve25519.mul(t2, t3, t1); /* 2^100 - 2^0 */ Curve25519.sqr(t3, t2); /* 2^101 - 2^1 */ Curve25519.sqr(t4, t3); /* 2^102 - 2^2 */ for (i = 1; i < 50; i++) { Curve25519.sqr(t3, t4); Curve25519.sqr(t4, t3); } /* t4 */ /* 2^200 - 2^100 */ Curve25519.mul(t3, t4, t2); /* 2^200 - 2^0 */ for (i = 0; i < 25; i++) { Curve25519.sqr(t4, t3); Curve25519.sqr(t3, t4); } /* t3 */ /* 2^250 - 2^50 */ Curve25519.mul(t2, t3, t1); /* 2^250 - 2^0 */ Curve25519.sqr(t1, t2); /* 2^251 - 2^1 */ Curve25519.sqr(t2, t1); /* 2^252 - 2^2 */ if (sqrtassist !== 0) { Curve25519.mul(y, x, t2); /* 2^252 - 3 */ } else { Curve25519.sqr(t1, t2); /* 2^253 - 2^3 */ Curve25519.sqr(t2, t1); /* 2^254 - 2^4 */ Curve25519.sqr(t1, t2); /* 2^255 - 2^5 */ Curve25519.mul(y, t1, t0); /* 2^255 - 21 */ } } /* checks if x is "negative", requires reduced input */ static is_negative(x) { let isOverflowOrNegative = Curve25519.is_overflow(x) || x[9] < 0; let leastSignificantBit = x[0] & 1; return ((isOverflowOrNegative ? 1 : 0) ^ leastSignificantBit) & 0xFFFFFFFF; } /* a square root */ static sqrt(x, u) { let v = Curve25519.createUnpackedArray(); let t1 = Curve25519.createUnpackedArray(); let t2 = Curve25519.createUnpackedArray(); Curve25519.add(t1, u, u); /* t1 = 2u */ Curve25519.recip(v, t1, 1); /* v = (2u)^((p-5)/8) */ Curve25519.sqr(x, v); /* x = v^2 */ Curve25519.mul(t2, t1, x); /* t2 = 2uv^2 */ Curve25519.sub(t2, t2, Curve25519.C1); /* t2 = 2uv^2-1 */ Curve25519.mul(t1, v, t2); /* t1 = v(2uv^2-1) */ Curve25519.mul(x, u, t1); /* x = uv(2uv^2-1) */ } //endregion //region JavaScript Fast Math static c255lsqr8h(a7, a6, a5, a4, a3, a2, a1, a0) { let r = []; let v; v = a0 * a0; r[0] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a0 * a1; r[1] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a0 * a2 + a1 * a1; r[2] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a0 * a3 + 2 * a1 * a2; r[3] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a0 * a4 + 2 * a1 * a3 + a2 * a2; r[4] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a0 * a5 + 2 * a1 * a4 + 2 * a2 * a3; r[5] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a0 * a6 + 2 * a1 * a5 + 2 * a2 * a4 + a3 * a3; r[6] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a0 * a7 + 2 * a1 * a6 + 2 * a2 * a5 + 2 * a3 * a4; r[7] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a1 * a7 + 2 * a2 * a6 + 2 * a3 * a5 + a4 * a4; r[8] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a2 * a7 + 2 * a3 * a6 + 2 * a4 * a5; r[9] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a3 * a7 + 2 * a4 * a6 + a5 * a5; r[10] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a4 * a7 + 2 * a5 * a6; r[11] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a5 * a7 + a6 * a6; r[12] = v & 0xFFFF; v = ((v / 0x10000) | 0) + 2 * a6 * a7; r[13] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a7 * a7; r[14] = v & 0xFFFF; r[15] = ((v / 0x10000) | 0); return r; } /* Square a number. Optimization of mul25519(x2, x, x) c255lsqrmodp*/ static sqr(r, a) { let x = Curve25519.c255lsqr8h(a[15], a[14], a[13], a[12], a[11], a[10], a[9], a[8]); let z = Curve25519.c255lsqr8h(a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]); let y = Curve25519.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]); let v; v = 0x800000 + z[0] + (y[8] - x[8] - z[8] + x[0] - 0x80) * 38; r[0] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[1] + (y[9] - x[9] - z[9] + x[1]) * 38; r[1] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[2] + (y[10] - x[10] - z[10] + x[2]) * 38; r[2] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[3] + (y[11] - x[11] - z[11] + x[3]) * 38; r[3] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[4] + (y[12] - x[12] - z[12] + x[4]) * 38; r[4] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[5] + (y[13] - x[13] - z[13] + x[5]) * 38; r[5] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[6] + (y[14] - x[14] - z[14] + x[6]) * 38; r[6] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[7] + (y[15] - x[15] - z[15] + x[7]) * 38; r[7] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[8] + y[0] - x[0] - z[0] + x[8] * 38; r[8] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[9] + y[1] - x[1] - z[1] + x[9] * 38; r[9] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[10] + y[2] - x[2] - z[2] + x[10] * 38; r[10] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[11] + y[3] - x[3] - z[3] + x[11] * 38; r[11] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[12] + y[4] - x[4] - z[4] + x[12] * 38; r[12] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[13] + y[5] - x[5] - z[5] + x[13] * 38; r[13] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[14] + y[6] - x[6] - z[6] + x[14] * 38; r[14] = v & 0xFFFF; let r15 = 0x7fff80 + ((v / 0x10000) | 0) + z[15] + y[7] - x[7] - z[7] + x[15] * 38; Curve25519.c255lreduce(r, r15); } static c255lmul8h(a7, a6, a5, a4, a3, a2, a1, a0, b7, b6, b5, b4, b3, b2, b1, b0) { let r = []; let v; v = a0 * b0; r[0] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a0 * b1 + a1 * b0; r[1] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a0 * b2 + a1 * b1 + a2 * b0; r[2] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; r[3] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; r[4] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; r[5] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0; r[6] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0; r[7] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1; r[8] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2; r[9] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3; r[10] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4; r[11] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a5 * b7 + a6 * b6 + a7 * b5; r[12] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a6 * b7 + a7 * b6; r[13] = v & 0xFFFF; v = ((v / 0x10000) | 0) + a7 * b7; r[14] = v & 0xFFFF; r[15] = ((v / 0x10000) | 0); return r; } /* Multiply two numbers. The output is in reduced form, the inputs need not be. c255lmulmodp*/ static mul(r, a, b) { // Karatsuba multiplication scheme: x*y = (b^2+b)*x1*y1 - b*(x1-x0)*(y1-y0) + (b+1)*x0*y0 let x = Curve25519.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]); let z = Curve25519.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]); let y = Curve25519.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]); let v; v = 0x800000 + z[0] + (y[8] - x[8] - z[8] + x[0] - 0x80) * 38; r[0] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[1] + (y[9] - x[9] - z[9] + x[1]) * 38; r[1] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[2] + (y[10] - x[10] - z[10] + x[2]) * 38; r[2] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[3] + (y[11] - x[11] - z[11] + x[3]) * 38; r[3] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[4] + (y[12] - x[12] - z[12] + x[4]) * 38; r[4] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[5] + (y[13] - x[13] - z[13] + x[5]) * 38; r[5] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[6] + (y[14] - x[14] - z[14] + x[6]) * 38; r[6] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[7] + (y[15] - x[15] - z[15] + x[7]) * 38; r[7] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[8] + y[0] - x[0] - z[0] + x[8] * 38; r[8] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[9] + y[1] - x[1] - z[1] + x[9] * 38; r[9] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[10] + y[2] - x[2] - z[2] + x[10] * 38; r[10] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[11] + y[3] - x[3] - z[3] + x[11] * 38; r[11] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[12] + y[4] - x[4] - z[4] + x[12] * 38; r[12] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[13] + y[5] - x[5] - z[5] + x[13] * 38; r[13] = v & 0xFFFF; v = 0x7fff80 + ((v / 0x10000) | 0) + z[14] + y[6] - x[6] - z[6] + x[14] * 38; r[14] = v & 0xFFFF; let r15 = 0x7fff80 + ((v / 0x10000) | 0) + z[15] + y[7] - x[7] - z[7] + x[15] * 38; Curve25519.c255lreduce(r, r15); } static c255lreduce(a, a15) { let v = a15; a[15] = v & 0x7FFF; v = ((v / 0x8000) | 0) * 19; for (let i = 0; i <= 14; ++i) { v += a[i]; a[i] = v & 0xFFFF; v = ((v / 0x10000) | 0); } a[15] += v; } /* Add/subtract two numbers. The inputs must be in reduced form, and the * output isn't, so to do another addition or subtraction on the output, * first multiply it by one to reduce it. c255laddmodp*/ static add(r, a, b) { let v; v = (((a[15] / 0x8000) | 0) + ((b[15] / 0x8000) | 0)) * 19 + a[0] + b[0]; r[0] = v & 0xFFFF; for (let i = 1; i <= 14; ++i) { v = ((v / 0x10000) | 0) + a[i] + b[i]; r[i] = v & 0xFFFF; } r[15] = ((v / 0x10000) | 0) + (a[15] & 0x7FFF) + (b[15] & 0x7FFF); } /* Add/subtract two numbers. The inputs must be in reduced form, and the * output isn't, so to do another addition or subtraction on the output, * first multiply it by one to reduce it. c255lsubmodp*/ static sub(r, a, b) { let v; v = 0x80000 + (((a[15] / 0x8000) | 0) - ((b[15] / 0x8000) | 0) - 1) * 19 + a[0] - b[0]; r[0] = v & 0xFFFF; for (let i = 1; i <= 14; ++i) { v = ((v / 0x10000) | 0) + 0x7fff8 + a[i] - b[i]; r[i] = v & 0xFFFF; } r[15] = ((v / 0x10000) | 0) + 0x7ff8 + (a[15] & 0x7FFF) - (b[15] & 0x7FFF); } /* Multiply a number by a small integer in range -185861411 .. 185861411. * The output is in reduced form, the input x need not be. x and xy may point * to the same buffer. c255lmulasmall*/ static mul_small(r, a, m) { let v; v = a[0] * m; r[0] = v & 0xFFFF; for (let i = 1; i <= 14; ++i) { v = ((v / 0x10000) | 0) + a[i] * m; r[i] = v & 0xFFFF; } let r15 = ((v / 0x10000) | 0) + a[15] * m; Curve25519.c255lreduce(r, r15); } //endregion /********************* Elliptic curve *********************/ /* y^2 = x^3 + 486662 x^2 + x over GF(2^255-19) */ /* t1 = ax + az * t2 = ax - az */ static mont_prep(t1, t2, ax, az) { Curve25519.add(t1, ax, az); Curve25519.sub(t2, ax, az); } /* A = P + Q where * X(A) = ax/az * X(P) = (t1+t2)/(t1-t2) * X(Q) = (t3+t4)/(t3-t4) * X(P-Q) = dx * clobbers t1 and t2, preserves t3 and t4 */ static mont_add(t1, t2, t3, t4, ax, az, dx) { Curve25519.mul(ax, t2, t3); Curve25519.mul(az, t1, t4); Curve25519.add(t1, ax, az); Curve25519.sub(t2, ax, az); Curve25519.sqr(ax, t1); Curve25519.sqr(t1, t2); Curve25519.mul(az, t1, dx); } /* B = 2 * Q where * X(B) = bx/bz * X(Q) = (t3+t4)/(t3-t4) * clobbers t1 and t2, preserves t3 and t4 */ static mont_dbl(t1, t2, t3, t4, bx, bz) { Curve25519.sqr(t1, t3); Curve25519.sqr(t2, t4); Curve25519.mul(bx, t1, t2); Curve25519.sub(t2, t1, t2); Curve25519.mul_small(bz, t2, 121665); Curve25519.add(t1, t1, bz); Curve25519.mul(bz, t1, t2); } /* Y^2 = X^3 + 486662 X^2 + X * t is a temporary */ static x_to_y2(t, y2, x) { Curve25519.sqr(t, x); Curve25519.mul_small(y2, x, 486662); Curve25519.add(t, t, y2); Curve25519.add(t, t, Curve25519.C1); Curve25519.mul(y2, t, x); } /* P = kG and s = sign(P)/k */ static core(Px, s, k, Gx) { let dx = Curve25519.createUnpackedArray(); let t1 = Curve25519.createUnpackedArray(); let t2 = Curve25519.createUnpackedArray(); let t3 = Curve25519.createUnpackedArray(); let t4 = Curve25519.createUnpackedArray(); let x = [Curve25519.createUnpackedArray(), Curve25519.createUnpackedArray()]; let z = [Curve25519.createUnpackedArray(), Curve25519.createUnpackedArray()]; let i, j; /* unpack the base */ if (Gx !== null) Curve25519.unpack(dx, Gx); else Curve25519.set(dx, 9); /* 0G = point-at-infinity */ Curve25519.set(x[0], 1); Curve25519.set(z[0], 0); /* 1G = G */ Curve25519.cpy(x[1], dx); Curve25519.set(z[1], 1); for (i = 32; i-- !== 0;) { for (j = 8; j-- !== 0;) { /* swap arguments depending on bit */ let bit1 = (k[i] & 0xFF) >> j & 1; let bit0 = ~(k[i] & 0xFF) >> j & 1; let ax = x[bit0]; let az = z[bit0]; let bx = x[bit1]; let bz = z[bit1]; /* a' = a + b */ /* b' = 2 b */ Curve25519.mont_prep(t1, t2, ax, az); Curve25519.mont_prep(t3, t4, bx, bz); Curve25519.mont_add(t1, t2, t3, t4, ax, az, dx); Curve25519.mont_dbl(t1, t2, t3, t4, bx, bz); } } Curve25519.recip(t1, z[0], 0); Curve25519.mul(dx, x[0], t1); Curve25519.pack(dx, Px); /* calculate s such that s abs(P) = G .. assumes G is std base point */ if (s !== null) { Curve25519.x_to_y2(t2, t1, dx); /* t1 = Py^2 */ Curve25519.recip(t3, z[1], 0); /* where Q=P+G ... */ Curve25519.mul(t2, x[1], t3); /* t2 = Qx */ Curve25519.add(t2, t2, dx); /* t2 = Qx + Px */ Curve25519.add(t2, t2, Curve25519.C486671); /* t2 = Qx + Px + Gx + 486662 */ Curve25519.sub(dx, dx, Curve25519.C9); /* dx = Px - Gx */ Curve25519.sqr(t3, dx); /* t3 = (Px - Gx)^2 */ Curve25519.mul(dx, t2, t3); /* dx = t2 (Px - Gx)^2 */ Curve25519.sub(dx, dx, t1); /* dx = t2 (Px - Gx)^2 - Py^2 */ Curve25519.sub(dx, dx, Curve25519.C39420360); /* dx = t2 (Px - Gx)^2 - Py^2 - Gy^2 */ Curve25519.mul(t1, dx, Curve25519.BASE_R2Y); /* t1 = -Py */ if (Curve25519.is_negative(t1) !== 0) /* sign is 1, so just copy */ Curve25519.cpy32(s, k); else /* sign is -1, so negate */ Curve25519.mula_small(s, Curve25519.ORDER_TIMES_8, 0, k, 32, -1); /* reduce s mod q * (is this needed? do it just in case, it's fast anyway) */ //divmod((dstptr) t1, s, 32, order25519, 32); /* take reciprocal of s mod q */ let temp1 = new Array(32); let temp2 = new Array(64); let temp3 = new Array(64); Curve25519.cpy32(temp1, Curve25519.ORDER); Curve25519.cpy32(s, Curve25519.egcd32(temp2, temp3, s, temp1)); if ((s[31] & 0x80) !== 0) Curve25519.mula_small(s, s, 0, Curve25519.ORDER, 32, 1); } } } exports.Curve25519 = Curve25519; //# sourceMappingURL=curve25519.js.map