@tkey/core
Version:
TKey Core library
162 lines (158 loc) • 6.37 kB
JavaScript
'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;