UNPKG

@cdottori/ecdsa-node

Version:

fast openSSL-compatible implementation of the Elliptic Curve Digital Signature Algorithm (ECDSA)

185 lines (142 loc) 5.96 kB
var Point = require("./point").Point; var modulo = require("./utils/integer").modulo; var BigInt = require("big-integer"); var multiply = function (p, n, N, A, P) { // Fast way to multily point and scalar in elliptic curves // :param p: First Point to mutiply // :param n: Scalar to mutiply // :param N: Order of the elliptic curve // :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) // :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) // :return: Point that represents the sum of First and Second Point return fromJacobian(jacobianMultiply(toJacobian(p), n, N, A, P), P); }; var add = function (p, q, A, P) { // Fast way to add two points in elliptic curves // :param p: First Point you want to add // :param q: Second Point you want to add // :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) // :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) // :return: Point that represents the sum of First and Second Point return fromJacobian(jacobianAdd(toJacobian(p), toJacobian(q), A, P), P); }; var inv = function (x, n) { // Extended Euclidean Algorithm. It's the 'division' in elliptic curves // :param x: Divisor // :param n: Mod for division // :return: Value representing the division if (x.eq(0)) { return BigInt(0); }; let lm = BigInt(1); let hm = BigInt(0); let low = modulo(x, n); let high = n; let r, nm, newLow; while (low.greater(1)) { r = high.over(low); // bigint division floors result automaticaly nm = hm.minus(lm.multiply(r)); newLow = high.minus(low.multiply(r)); high = low; hm = lm; low = newLow; lm = nm; }; return modulo(lm, n); }; var toJacobian = function (p) { // Convert point to Jacobian coordinates // :param p: First Point you want to add // :return: Point in Jacobian coordinates return new Point(p.x, p.y, BigInt(1)); }; var fromJacobian = function (p, P) { // Convert point back from Jacobian coordinates // :param p: First Point you want to add // :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) // :return: Point in default coordinates z = inv(p.z, P); var point = new Point( modulo(p.x.multiply(z.pow(2)), P), modulo(p.y.multiply(z.pow(3)), P) ); return point; }; var jacobianDouble = function (p, A, P) { // Double a point in elliptic curves // :param p: Point you want to double // :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) // :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) // :return: Point that represents the sum of First and Second Point if (!p.y.value) { return new Point(BigInt(0), BigInt(0), BigInt(0)); }; let ysq = modulo((p.y.pow(2)), P); let S = modulo((p.x.multiply(ysq).multiply(4)), P); let M = modulo((((p.x.pow(2)).multiply(3)).add(A.multiply(p.z.pow(4)))), P); let nx = modulo(((M.pow(2)).minus(S.multiply(2))), P); let ny = modulo((M.multiply(S.minus(nx)).minus((ysq.pow(2)).multiply(8))), P); let nz = modulo((p.y.multiply(p.z).multiply(2)), P); return new Point(nx, ny, nz); }; var jacobianAdd = function (p, q, A, P) { // Add two points in elliptic curves // :param p: First Point you want to add // :param q: Second Point you want to add // :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) // :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) // :return: Point that represents the sum of First and Second Point if (!p.y.value) { return q; }; if (!q.y.value) { return p; }; U1 = modulo(p.x.multiply(q.z.pow(2)), P); U2 = modulo(q.x.multiply(p.z.pow(2)), P); S1 = modulo(p.y.multiply(q.z.pow(3)), P); S2 = modulo(q.y.multiply(p.z.pow(3)), P); if (U1.eq(U2)) { if (S1.neq(S2)) { return Point(BigInt(0), BigInt(0), BigInt(1)); }; return jacobianDouble(p, A, P); }; H = U2.minus(U1); R = S2.minus(S1); H2 = modulo((H.multiply(H)), P); H3 = modulo((H.multiply(H2)), P); U1H2 = modulo((U1.multiply(H2)), P); nx = modulo(((R.pow(2)).minus(H3).minus(U1H2.multiply(2))), P); ny = modulo((R.multiply(U1H2.minus(nx)).minus(S1.multiply(H3))), P); nz = modulo((H.multiply(p.z).multiply(q.z)), P); return new Point(nx, ny, nz); }; var jacobianMultiply = function (p, n, N, A, P) { // Multily point and scalar in elliptic curves // :param p: First Point to mutiply // :param n: Scalar to mutiply // :param N: Order of the elliptic curve // :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) // :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) // :return: Point that represents the sum of First and Second Point if (p.y.eq(0) | n.eq(0)) { return new Point(BigInt(0), BigInt(0), BigInt(1)); }; if (n.eq(1)) { return p; }; if (n.lesser(0) | n.greaterOrEquals(N)) { return jacobianMultiply(p, modulo(n, N), N, A, P); }; if (modulo(n, 2).eq(0)) { return jacobianDouble(jacobianMultiply(p, n.over(2), N, A, P), A, P); // bigint division floors result automaticaly }; if (modulo(n, 2).eq(1)) { return jacobianAdd(jacobianDouble(jacobianMultiply(p, n.over(2), N, A, P), A, P), p, A, P); // bigint division floors result automaticaly }; throw new Error("logical failure: p: " + p + ", n: " + n + ", N: " + N + ", A: " + A + ", P: " + P); }; exports.multiply = multiply; exports.add = add; exports.inv = inv;