UNPKG

@tkey/core

Version:
162 lines (158 loc) 6.37 kB
'use strict'; var commonTypes = require('@tkey/common-types'); var BN = require('bn.js'); var errors = require('./errors.js'); function generatePrivateBN() { return commonTypes.secp256k1.genKeyPair().getPrivate(); } const generateEmptyBNArray = length => Array.from({ length }, () => new BN(0)); const denominator = (i, innerPoints) => { let result = new BN(1); const xi = innerPoints[i].x; for (let j = innerPoints.length - 1; j >= 0; j -= 1) { if (i !== j) { let tmp = new BN(xi); tmp = tmp.sub(innerPoints[j].x); tmp = tmp.umod(commonTypes.secp256k1.curve.n); result = result.mul(tmp); result = result.umod(commonTypes.secp256k1.curve.n); } } return result; }; const interpolationPoly = (i, innerPoints) => { let coefficients = generateEmptyBNArray(innerPoints.length); const d = denominator(i, innerPoints); if (d.cmp(new BN(0)) === 0) { throw errors.default("Denominator for interpolationPoly is 0"); } coefficients[0] = d.invm(commonTypes.secp256k1.curve.n); for (let k = 0; k < innerPoints.length; k += 1) { const newCoefficients = generateEmptyBNArray(innerPoints.length); if (k !== i) { let j; if (k < i) { j = k + 1; } else { j = k; } j -= 1; for (; j >= 0; j -= 1) { newCoefficients[j + 1] = newCoefficients[j + 1].add(coefficients[j]); newCoefficients[j + 1] = newCoefficients[j + 1].umod(commonTypes.secp256k1.curve.n); let tmp = new BN(innerPoints[k].x); tmp = tmp.mul(coefficients[j]); tmp = tmp.umod(commonTypes.secp256k1.curve.n); newCoefficients[j] = newCoefficients[j].sub(tmp); newCoefficients[j] = newCoefficients[j].umod(commonTypes.secp256k1.curve.n); } coefficients = newCoefficients; } } return coefficients; }; const pointSort = innerPoints => { const pointArrClone = [...innerPoints]; pointArrClone.sort((a, b) => a.x.cmp(b.x)); return pointArrClone; }; const lagrange = unsortedPoints => { const sortedPoints = pointSort(unsortedPoints); const polynomial = generateEmptyBNArray(sortedPoints.length); for (let i = 0; i < sortedPoints.length; i += 1) { const coefficients = interpolationPoly(i, sortedPoints); for (let k = 0; k < sortedPoints.length; k += 1) { let tmp = new BN(sortedPoints[i].y); tmp = tmp.mul(coefficients[k]); polynomial[k] = polynomial[k].add(tmp); polynomial[k] = polynomial[k].umod(commonTypes.secp256k1.curve.n); } } return new commonTypes.Polynomial(polynomial); }; function lagrangeInterpolatePolynomial(points) { return lagrange(points); } function lagrangeInterpolation(shares, nodeIndex) { if (shares.length !== nodeIndex.length) { throw errors.default("shares not equal to nodeIndex length in lagrangeInterpolation"); } let secret = new BN(0); for (let i = 0; i < shares.length; i += 1) { let upper = new BN(1); let lower = new BN(1); for (let j = 0; j < shares.length; j += 1) { if (i !== j) { upper = upper.mul(nodeIndex[j].neg()); upper = upper.umod(commonTypes.secp256k1.curve.n); let temp = nodeIndex[i].sub(nodeIndex[j]); temp = temp.umod(commonTypes.secp256k1.curve.n); lower = lower.mul(temp).umod(commonTypes.secp256k1.curve.n); } } let delta = upper.mul(lower.invm(commonTypes.secp256k1.curve.n)).umod(commonTypes.secp256k1.curve.n); delta = delta.mul(shares[i]).umod(commonTypes.secp256k1.curve.n); secret = secret.add(delta); } return secret.umod(commonTypes.secp256k1.curve.n); } // generateRandomPolynomial - determinisiticShares are assumed random function generateRandomPolynomial(degree, secret, deterministicShares) { let actualS = secret; if (!secret) { actualS = commonTypes.generatePrivateExcludingIndexes([new BN(0)]); } if (!deterministicShares) { const poly = [actualS]; for (let i = 0; i < degree; i += 1) { const share = commonTypes.generatePrivateExcludingIndexes(poly); poly.push(share); } return new commonTypes.Polynomial(poly); } if (!Array.isArray(deterministicShares)) { throw errors.default("deterministic shares in generateRandomPolynomial should be an array"); } if (deterministicShares.length > degree) { throw errors.default("deterministicShares in generateRandomPolynomial should be less or equal than degree to ensure an element of randomness"); } const points = {}; deterministicShares.forEach(share => { points[share.shareIndex.toString("hex")] = new commonTypes.Point(share.shareIndex, share.share); }); for (let i = 0; i < degree - deterministicShares.length; i += 1) { let shareIndex = commonTypes.generatePrivateExcludingIndexes([new BN(0)]); while (points[shareIndex.toString("hex")] !== undefined) { shareIndex = commonTypes.generatePrivateExcludingIndexes([new BN(0)]); } points[shareIndex.toString("hex")] = new commonTypes.Point(shareIndex, generatePrivateBN()); } points["0"] = new commonTypes.Point(new BN(0), actualS); return lagrangeInterpolatePolynomial(Object.values(points)); } // 2 + 3x = y | secret for index 1 is 5 >>> g^5 is the commitment | now we have g^2, g^3 and 1, | function polyCommitmentEval(polyCommitments, index) { // convert to base points, this is badly written, its the only way to access the point rn zzz TODO: refactor const basePtPolyCommitments = []; for (let i = 0; i < polyCommitments.length; i += 1) { const key = commonTypes.secp256k1.keyFromPublic({ x: polyCommitments[i].x.toString("hex"), y: polyCommitments[i].y.toString("hex") }, ""); basePtPolyCommitments.push(key.getPublic()); } let shareCommitment = basePtPolyCommitments[0]; for (let i = 1; i < basePtPolyCommitments.length; i += 1) { const factor = index.pow(new BN(i)).umod(commonTypes.secp256k1.n); const e = basePtPolyCommitments[i].mul(factor); shareCommitment = shareCommitment.add(e); } return new commonTypes.Point(shareCommitment.getX(), shareCommitment.getY()); } exports.generatePrivateBN = generatePrivateBN; exports.generateRandomPolynomial = generateRandomPolynomial; exports.lagrangeInterpolatePolynomial = lagrangeInterpolatePolynomial; exports.lagrangeInterpolation = lagrangeInterpolation; exports.polyCommitmentEval = polyCommitmentEval;