@dedis/kyber
Version:
A typescript implementation of Kyber interfaces
166 lines (165 loc) • 5.64 kB
JavaScript
;
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));
}