UNPKG

@dedis/kyber

Version:

A typescript implementation of Kyber interfaces

220 lines (219 loc) 7.26 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); // tslint:disable:no-bitwise const bn_js_1 = __importDefault(require("bn.js")); const crypto_browserify_1 = require("crypto-browserify"); const constants_1 = require("../../constants"); /** * Represents a Point on the nist curve * * The value of the parameters is expected in little endian form if being * passed as a buffer */ class NistPoint { constructor(curve, x, y) { if (x instanceof Buffer) { x = new bn_js_1.default(x, 16, "le"); } if (y instanceof Buffer) { y = new bn_js_1.default(y, 16, "le"); } // the point reference is stored in an object to make set() // consistent. this.ref = { curve, point: curve.curve.point(x, y), }; } /** @inheritdoc */ set(p2) { this.ref = p2.ref; return this; } /** @inheritdoc */ clone() { const point = this.ref.point; return new NistPoint(this.ref.curve, point.x, point.y); } /** @inheritdoc */ null() { this.ref.point = this.ref.curve.curve.point(null, null); return this; } /** @inheritdoc */ base() { const g = this.ref.curve.curve.g; this.ref.point = this.ref.curve.curve.point(g.x, g.y); return this; } /** @inheritdoc */ embedLen() { // Reserve the most-significant 8 bits for pseudo-randomness. // Reserve the least-significant 8 bits for embedded data length. // (Hopefully it's unlikely we'll need >=2048-bit curves soon.) return (this.ref.curve.curve.p.bitLength() - 8 - 8) >> 3; } /** @inheritdoc */ embed(data, callback) { const l = this.ref.curve.coordLen(); let dl = this.embedLen(); if (data.length > dl) { throw new Error("data.length > dl"); } if (dl > data.length) { dl = data.length; } callback = callback || crypto_browserify_1.randomBytes; while (true) { const bitLen = this.ref.curve.curve.p.bitLength(); const buffLen = bitLen >> 3; const buff = callback(buffLen); const highbits = bitLen & 7; if (highbits !== 0) { buff[0] &= ~(0xff << highbits); } if (dl > 0) { buff[l - 1] = dl; // encode length in lower 8 bits data.copy(buff, l - dl - 1); } // console.log(bytes); const x = new bn_js_1.default(buff, 16, "be"); if (x.cmp(this.ref.curve.curve.p) > 0) { continue; } const xRed = x.toRed(this.ref.curve.curve.red); // @ts-ignore const aX = xRed.redMul(new bn_js_1.default(this.ref.curve.curve.a)); // y^2 = x^3 + ax + b const y2 = xRed.redSqr() .redMul(xRed) .redAdd(aX) // @ts-ignore .redAdd(new bn_js_1.default(this.ref.curve.curve.b)); let y = y2.redSqrt(); const b = callback(1); if ((b[0] & 0x80) !== 0) { y = this.ref.curve.curve.p.sub(y).toRed(this.ref.curve.curve.red); } // check if it is a valid point const y2t = y.redSqr(); if (y2t.cmp(y2) === 0) { return new NistPoint(this.ref.curve, xRed, y); } } } /** @inheritdoc */ data() { const l = this.ref.curve.coordLen(); const b = Buffer.from(this.ref.point.x.fromRed().toArray("be", l)); const dl = b[l - 1]; if (dl > this.embedLen()) { throw new Error("invalid embed data length"); } return b.slice(l - dl - 1, l - 1); } /** @inheritdoc */ add(p1, p2) { const point = p1.ref.point; this.ref.point = this.ref.curve.curve .point(point.x, point.y) .add(p2.ref.point); return this; } /** @inheritdoc */ sub(p1, p2) { const point = p1.ref.point; this.ref.point = this.ref.curve.curve .point(point.x, point.y) .add(p2.ref.point.neg()); return this; } /** @inheritdoc */ neg(p) { this.ref.point = p.ref.point.neg(); return this; } /** @inheritdoc */ mul(s, p) { p = p || null; const arr = s.ref.arr.fromRed(); this.ref.point = p !== null ? p.ref.point.mul(arr) : this.ref.curve.curve.g.mul(arr); return this; } /** @inheritdoc */ pick(callback) { callback = callback || null; return this.embed(Buffer.from([]), callback); } /** @inheritdoc */ marshalSize() { // uncompressed ANSI X9.62 representation return this.ref.curve.pointLen(); } /** @inheritdoc */ marshalBinary() { const byteLen = this.ref.curve.coordLen(); const buf = Buffer.alloc(this.ref.curve.pointLen(), 0); buf[0] = 4; // uncompressed point const xBytes = Buffer.from(this.ref.point.x.fromRed().toArray("be")); xBytes.copy(buf, 1 + byteLen - xBytes.length); const yBytes = Buffer.from(this.ref.point.y.fromRed().toArray("be")); yBytes.copy(buf, 1 + 2 * byteLen - yBytes.length); return buf; } /** @inheritdoc */ unmarshalBinary(bytes) { const byteLen = this.ref.curve.coordLen(); if (bytes.length !== 1 + 2 * byteLen) { throw new Error(); } // not an uncompressed point if (bytes[0] !== 4) { throw new Error("unmarshalBinary only accepts uncompressed point"); } const x = new bn_js_1.default(bytes.slice(1, 1 + byteLen), 16); const y = new bn_js_1.default(bytes.slice(1 + byteLen), 16); if (x.cmp(constants_1.zeroBN) === 0 && y.cmp(constants_1.zeroBN) === 0) { this.ref.point = this.ref.curve.curve.point(null, null); return; } this.ref.point = this.ref.curve.curve.point(x, y); if (!this.ref.curve.curve.validate(this.ref.point)) { throw new Error("point is not on curve"); } } /** @inheritdoc */ equals(p2) { if (this.ref.point.isInfinity() ^ p2.ref.point.isInfinity()) { return false; } if (this.ref.point.isInfinity() & p2.ref.point.isInfinity()) { return true; } return (this.ref.point.x.cmp(p2.ref.point.x) === 0 && this.ref.point.y.cmp(p2.ref.point.y) === 0); } inspect() { return this.toString(); } /** @inheritdoc */ toString() { if (this.ref.point.inf) { return "(0,0)"; } return ("(" + this.ref.point.x.fromRed().toString(10) + "," + this.ref.point.y.fromRed().toString(10) + ")"); } /** @inheritdoc */ toProto() { throw new Error("not implemented"); } } exports.default = NistPoint;