UNPKG

@dedis/kyber

Version:

A typescript implementation of Kyber interfaces

166 lines (165 loc) 5.64 kB
"use strict"; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); // tslint:disable:variable-name const blake2xs_1 = require("@stablelib/blake2xs"); const lodash_1 = require("lodash"); const curve = __importStar(require("../../curve")); // tslint:disable-next-line exports.Suite = curve.newCurve("edwards25519"); class RingSig { static fromBytes(signatureBuffer, isLinkableSig) { const scalarMarshalSize = exports.Suite.scalarLen(); const pointMarshalSize = exports.Suite.pointLen(); const c0 = exports.Suite.scalar(); c0.unmarshalBinary(signatureBuffer.slice(0, pointMarshalSize)); const S = []; const endIndex = isLinkableSig ? signatureBuffer.length - pointMarshalSize : signatureBuffer.length; for (let i = pointMarshalSize; i < endIndex; i += scalarMarshalSize) { const t = exports.Suite.scalar(); t.unmarshalBinary(signatureBuffer.slice(i, i + scalarMarshalSize)); S.push(t); } if (isLinkableSig) { const tag = exports.Suite.point(); tag.unmarshalBinary(signatureBuffer.slice(endIndex)); return new RingSig(c0, S, tag); } return new RingSig(c0, S); } constructor(c0, s, tag) { this.c0 = c0; this.s = s; this.tag = tag; } encode() { const bufs = []; bufs.push(this.c0.marshalBinary()); for (const scalar of this.s) { bufs.push(scalar.marshalBinary()); } if (this.tag) { bufs.push(this.tag.marshalBinary()); } return Buffer.concat(bufs); } } exports.RingSig = RingSig; function sign(message, anonymitySet, secret, linkScope) { const hasLS = linkScope && (linkScope !== null); const pi = findSecretIndex(anonymitySet, secret); const n = anonymitySet.length; const L = anonymitySet.slice(0); let linkBase; let linkTag; if (hasLS) { const linkStream = new blake2xs_1.BLAKE2Xs(undefined, { key: linkScope }); linkBase = exports.Suite.point().pick(createStreamFromBlake(linkStream)); linkTag = exports.Suite.point().mul(secret, linkBase); } const H1pre = signH1pre(linkScope, linkTag, message); const u = exports.Suite.scalar().pick(); const UB = exports.Suite.point().mul(u); let UL; if (hasLS) { UL = exports.Suite.point().mul(u, linkBase); } const s = []; const c = []; c[(pi + 1) % n] = signH1(H1pre, UB, UL); const P = exports.Suite.point(); const PG = exports.Suite.point(); let PH; if (hasLS) { PH = exports.Suite.point(); } for (let i = (pi + 1) % n; i !== pi; i = (i + 1) % n) { s[i] = exports.Suite.scalar().pick(); PG.add(PG.mul(s[i]), P.mul(c[i], L[i])); if (hasLS) { PH.add(PH.mul(s[i], linkBase), P.mul(c[i], linkTag)); } c[(i + 1) % n] = signH1(H1pre, PG, PH); } s[pi] = exports.Suite.scalar(); s[pi].mul(secret, c[pi]).sub(u, s[pi]); return new RingSig(c[0], s, linkTag); } exports.sign = sign; function verify(message, anonymitySet, signatureBuffer, linkScope) { const n = anonymitySet.length; const L = anonymitySet.slice(0); let linkBase; let linkTag; const sig = RingSig.fromBytes(signatureBuffer, !!linkScope); if (anonymitySet.length !== sig.s.length) { throw new Error("given anonymity set and signature anonymity set not of equal length"); } if (linkScope) { const linkStream = new blake2xs_1.BLAKE2Xs(undefined, { key: linkScope }); linkBase = exports.Suite.point().pick(createStreamFromBlake(linkStream)); linkTag = sig.tag; } const H1pre = signH1pre(linkScope, linkTag, message); let PH; const P = exports.Suite.point(); const PG = exports.Suite.point(); if (linkScope) { PH = exports.Suite.point(); } const s = sig.s; let ci = sig.c0; for (let i = 0; i < n; i++) { PG.add(PG.mul(s[i]), P.mul(ci, L[i])); if (linkScope) { PH.add(PH.mul(s[i], linkBase), P.mul(ci, linkTag)); } ci = signH1(H1pre, PG, PH); } if (!ci.equals(sig.c0)) { return false; } return true; } exports.verify = verify; function findSecretIndex(keys, privateKey) { const pubKey = exports.Suite.point().base().mul(privateKey); const pi = keys.findIndex((pub) => pub.equals(pubKey)); if (pi < 0) { throw new Error("didn't find public key in anonymity set"); } return pi; } function createStreamFromBlake(blakeInstance) { function getNextBytes(count) { const array = new Uint8Array(count); blakeInstance.stream(array); return Buffer.from(array); } return getNextBytes; } function signH1pre(linkScope, linkTag, message) { const H1pre = new blake2xs_1.BLAKE2Xs(undefined, { key: message }); if (linkScope) { H1pre.update(linkScope); const tag = linkTag.marshalBinary(); H1pre.update(tag); } return H1pre; } function signH1(H1pre, PG, PH) { const H1 = lodash_1.cloneDeep(H1pre); const PGb = PG.marshalBinary(); H1.update(PGb); if (PH) { const PHb = PH.marshalBinary(); H1.update(PHb); } return exports.Suite.scalar().pick(createStreamFromBlake(H1)); }