UNPKG

@beraji/wallet-sdk

Version:

Beraji: Distributed Secret Sharing.

132 lines 6.55 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SecretSharing = void 0; const utils_1 = require("@noble/hashes/utils"); const utils_2 = require("./utils"); const bn_js_1 = __importDefault(require("bn.js")); class SecretSharing { constructor(ff) { this.ff = ff; this.validateShares = (shares) => { shares.forEach((share) => { if (share.length !== SecretSharing.shareLength) throw new Error('Invalid share length'); }); const indice = shares.map((share) => SecretSharing.extract(share).index); const ts = shares.map((share) => SecretSharing.extract(share).t); const ns = shares.map((share) => SecretSharing.extract(share).n); const ids = shares.map((share) => SecretSharing.extract(share).id); if (!(0, utils_2.equal)(ts) || !(0, utils_2.equal)(ns) || !(0, utils_2.equal)(ids)) throw new Error('The shares are not in a same group'); const t = ts[0]; if (this.ff.numberToRedBN(indice.length).lt(this.ff.encode(t))) throw new Error('Not enough required number of shares'); return { indice, t, n: ns[0], id: ids[0] }; }; this.pi = (indice, index = this.ff.decode(this.ff.ZERO, 8)) => { const _indice = indice.map((i) => this.ff.encode(i)); const _index = this.ff.encode(index); const involved = _indice.findIndex((i) => i.eq(_index)); if (involved >= 0) return _indice .map((_, i) => (i === involved ? this.ff.ONE : this.ff.ZERO)) .map((prod) => this.ff.decode(prod)); const _shared = _indice.reduce((prod, e) => e.redSub(_index).redMul(prod), this.ff.ONE); return _indice .map((_anchor, i) => _indice .reduce((prod, e, j) => (i !== j ? e.redSub(_anchor).redMul(prod) : prod), this.ff.ONE) .redMul(_anchor.redSub(_index)) .redInvm() .redMul(_shared)) .map((prod) => this.ff.decode(prod)); }; this.yl = (y, l) => this.ff.mul(y, l); this.ft1 = (shares) => { const { indice, t } = this.validateShares(shares); const _t = this.ff.encode(t).toNumber(); const xs = indice.map(this.ff.encode).slice(0, _t); const ys = shares.map((share) => share.subarray(32, 64)).slice(0, _t); const ls = xs .map((x, i) => xs .reduce((prod, o, j) => (i !== j ? x.redSub(o).redMul(prod) : prod), this.ff.ONE) .redInvm()) .map((l) => this.ff.decode(l, 32)); return ys.reduce((sum, y, i) => this.ff.add(this.yl(y, ls[i]), sum), this.ff.decode(this.ff.ZERO)); }; this.interpolate = (index, shares) => { const { indice } = this.validateShares(shares); const ls = this.pi(indice, index); const ys = shares.map((share) => share.subarray(32, 64)); return ys.reduce((sum, y, i) => this.ff.add(this.yl(y, ls[i]), sum), this.ff.decode(this.ff.ZERO)); }; this.construct = (shares) => { return this.interpolate(this.ff.decode(this.ff.ZERO, 8), shares); }; this.share = (key, t, n, { indice = [], id = (0, utils_1.randomBytes)(8), ec, } = {}) => { if (t < 1 || n < 1 || t > n) throw new Error('Invalid t-out-of-n format.'); if (id && id.length !== 8) throw new Error('Id must be an 8-length bytes-like array.'); const T = this.ff.decode(this.ff.numberToRedBN(t), 8); const N = this.ff.decode(this.ff.numberToRedBN(n), 8); const ID = id; const coefficients = [key]; while (coefficients.length < t) coefficients.push(this.ff.rand()); const xs = [...indice]; while (xs.length < n) xs.push((0, utils_1.randomBytes)(8)); const shares = xs .map((x) => (0, utils_2.calcPolynomial)(x, coefficients, this.ff)) .map((s, i) => (0, utils_1.concatBytes)(xs[i], T, N, ID, s)); if (!ec) return { shares }; const zkp = coefficients.map((co) => ec.baseMul(co)); return { shares, zkp }; }; this.proactivate = (t, n, indice, { id = (0, utils_1.randomBytes)(8), ec, } = {}) => { if (n !== indice.length) throw new Error('Not enough number of indexes.'); const zero = this.ff.decode(this.ff.ZERO, 32); const updates = this.share(zero, t, n, { indice, id, ec }); return updates; }; this.merge = (prev, next) => { if (prev.length !== SecretSharing.shareLength || next.length !== SecretSharing.shareLength) throw new Error('Invalid share length.'); if (!(0, utils_2.equal)([prev.subarray(0, 8), next.subarray(0, 8)])) throw new Error('Cannot merge irrelevant shares.'); const i = next.subarray(0, 8); const t = next.subarray(8, 16); const n = next.subarray(16, 24); const id = next.subarray(24, 32); const a = this.ff.add(prev.subarray(32), next.subarray(32)); return (0, utils_1.concatBytes)(i, t, n, id, a); }; } } exports.SecretSharing = SecretSharing; SecretSharing.shareLength = 64; SecretSharing.extract = (share) => ({ index: share.subarray(0, 8), t: share.subarray(8, 16), n: share.subarray(16, 24), id: share.subarray(24, 32), share: share.subarray(32, 64), }); SecretSharing.compress = ({ index, t, n, id, share }) => (0, utils_1.concatBytes)(index, t, n, id, share); SecretSharing.verify = (z, index, pzkp, rzkp, ec) => { const zkp = []; const n = Math.max(pzkp.length, rzkp.length); for (let i = 0; i < n; i++) zkp.push(ec.addPoint(pzkp[i] || ec.ZERO, rzkp[i] || ec.ZERO)); const x = ec.ff.decode(new bn_js_1.default(index, 8, ec.ff.en)); const zG = ec.baseMul(z); const _zG = zkp.reduce((sum, co, i) => ec.addPoint(sum, ec.mulScalar(co, ec.ff.pow(x, i))), ec.ZERO); return (0, utils_2.equal)([zG, _zG]); }; //# sourceMappingURL=sss.js.map