@dedis/kyber
Version:
A typescript implementation of Kyber interfaces
431 lines (430 loc) • 12.3 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const bn_js_1 = __importDefault(require("bn.js"));
const curve_point_1 = __importDefault(require("./curve-point"));
const gfp12_1 = __importDefault(require("./gfp12"));
const gfp2_1 = __importDefault(require("./gfp2"));
const gfp6_1 = __importDefault(require("./gfp6"));
const opt_ate_1 = require("./opt-ate");
const twist_point_1 = __importDefault(require("./twist-point"));
/**
* Wrapper around the basic curve point. It acts as a mutable object and
* then every modification is done in-place.
*/
class G1 {
constructor(k) {
this.p = new curve_point_1.default();
if (k) {
this.scalarBaseMul(new bn_js_1.default(k));
}
}
/**
* Hash the message to a point
* @param msg The message to hash
* @returns a valid point
*/
static hashToPoint(msg) {
const g1 = new G1();
g1.p = curve_point_1.default.hashToPoint(msg);
return g1;
}
/**
* Get the curve point
* @returns the point
*/
getPoint() {
return this.p;
}
/**
* Set the point to the generator of the curve
*/
setBase() {
this.p = curve_point_1.default.generator.clone();
}
/**
* Set the point to infinity
*/
setInfinity() {
this.p.setInfinity();
}
/**
* Check if the point is the infinity
* @returns true when infinity, false otherwise
*/
isInfinity() {
return this.p.isInfinity();
}
/**
* Multiply the generator by the scalar k and set the value
* @param k the scalar
*/
scalarBaseMul(k) {
this.p.mul(curve_point_1.default.generator, k);
}
/**
* Multiply a by the scalar k and set the value
* @param a the point
* @param k the scalar
*/
scalarMul(a, k) {
this.p.mul(a.p, k);
}
/**
* Add a to b and set the value
* @param a the first point
* @param b the second point
*/
add(a, b) {
this.p.add(a.p, b.p);
}
/**
* Compute the negative of a and set the value
* @param the point to negate
*/
neg(a) {
this.p.negative(a.p);
}
/**
* Get the buffer size after marshaling
* @returns the length
*/
marshalSize() {
return G1.MARSHAL_SIZE;
}
/**
* Serialize the point into bytes
* @returns the buffer
*/
marshal() {
const p = this.p.clone();
const buf = Buffer.alloc(G1.MARSHAL_SIZE, 0);
if (p.isInfinity()) {
return buf;
}
p.makeAffine();
const xBytes = p.getX().toBytes();
const yBytes = p.getY().toBytes();
return Buffer.concat([xBytes, yBytes]);
}
/**
* Take a buffer to deserialize a point
* @param bytes the buffer
*/
unmarshal(bytes) {
if (bytes.length !== G1.MARSHAL_SIZE) {
throw new Error("wrong buffer size for a G1 point");
}
this.p = new curve_point_1.default(bytes.slice(0, G1.ELEM_SIZE), bytes.slice(G1.ELEM_SIZE), 1, 1);
if (this.p.getX().isZero() && this.p.getY().isZero()) {
this.p.setInfinity();
return;
}
if (!this.p.isOnCurve()) {
throw new Error("malformed G1 point");
}
}
/**
* Check the equality between the point and the object
* @param o the object
* @returns true when both are equal, false otherwise
*/
equals(o) {
if (!(o instanceof G1)) {
return false;
}
return this.p.equals(o.p);
}
/**
* Get a clone of the element
* @returns the new element
*/
clone() {
const g = new G1();
g.p = this.p.clone();
return g;
}
/**
* Get the string representation of the point
* @returns the string representation
*/
toString() {
return `bn256.G1${this.p.toString()}`;
}
}
G1.ELEM_SIZE = 256 / 8;
G1.MARSHAL_SIZE = G1.ELEM_SIZE * 2;
exports.G1 = G1;
/**
* Wrapper around the twist point. It acts as a mutable object and
* then every modification is done in-place.
*/
class G2 {
constructor(k) {
this.p = new twist_point_1.default();
if (k) {
this.scalarBaseMul(new bn_js_1.default(k));
}
}
/**
* Get the twist point
* @returns the point
*/
getPoint() {
return this.p;
}
/**
* Set to the generator of the curve
*/
setBase() {
this.p = twist_point_1.default.generator.clone();
}
/**
* Set the point to the infinity
*/
setInfinity() {
this.p.setInfinity();
}
/**
* Check if the point is the infinity
* @returns true when infinity, false otherwise
*/
isInfinity() {
return this.p.isInfinity();
}
/**
* Mutliply the generator by a scalar k and set the value
* @param k the scalar
*/
scalarBaseMul(k) {
this.p.mul(twist_point_1.default.generator, k);
}
/**
* Multiply a by a scalar k and set the value
* @param a the point
* @param k the scalar
*/
scalarMul(a, k) {
this.p.mul(a.p, k);
}
/**
* Add a to b and set the value
* @param a the first point
* @param b the second point
*/
add(a, b) {
this.p.add(a.p, b.p);
}
/**
* Compute the negative of a and set the value
* @param a the point
*/
neg(a) {
this.p.neg(a.p);
}
/**
* Get the size of the buffer after marshaling
* @returns the size
*/
marshalSize() {
return G2.MARSHAL_SIZE;
}
/**
* Serialize the point into bytes
* @returns the buffer
*/
marshal() {
if (this.isInfinity()) {
return Buffer.alloc(G2.MARSHAL_SIZE, 0);
}
const t = this.clone();
t.p.makeAffine();
const xxBytes = t.p.getX().getX().toBytes();
const xyBytes = t.p.getX().getY().toBytes();
const yxBytes = t.p.getY().getX().toBytes();
const yyBytes = t.p.getY().getY().toBytes();
return Buffer.concat([xxBytes, xyBytes, yxBytes, yyBytes]);
}
/**
* Take a buffer and deserialize a point
* @param bytes the buffer
*/
unmarshal(bytes) {
if (bytes.length !== G2.MARSHAL_SIZE) {
throw new Error("wrong buffer size for G2 point");
}
const xxBytes = bytes.slice(0, G2.ELEM_SIZE);
const xyBytes = bytes.slice(G2.ELEM_SIZE, G2.ELEM_SIZE * 2);
const yxBytes = bytes.slice(G2.ELEM_SIZE * 2, G2.ELEM_SIZE * 3);
const yyBytes = bytes.slice(G2.ELEM_SIZE * 3);
this.p = new twist_point_1.default(new gfp2_1.default(xxBytes, xyBytes), new gfp2_1.default(yxBytes, yyBytes), gfp2_1.default.one(), gfp2_1.default.one());
if (this.p.getX().isZero() && this.p.getY().isZero()) {
this.p.setInfinity();
return;
}
if (!this.p.isOnCurve()) {
throw new Error("malformed G2 point");
}
}
/**
* Get a clone of G2
* @returns the clone
*/
clone() {
const t = new G2();
t.p = this.p.clone();
return t;
}
/**
* Check the equality of the current point and the object
* @param o the object
* @returns true when both are equal, false otherwise
*/
equals(o) {
if (!(o instanceof G2)) {
return false;
}
return this.p.equals(o.p);
}
/**
* Get the string representation of the point
* @returns the string representation
*/
toString() {
return `bn256.G2${this.p.toString()}`;
}
}
G2.ELEM_SIZE = 256 / 8;
G2.MARSHAL_SIZE = G2.ELEM_SIZE * 4;
exports.G2 = G2;
/**
* Wrapper around the result of pairing of G1 and G2. It acts as a mutable
* object and then every modification is done in-place.
*/
class GT {
constructor(g) {
this.g = g || new gfp12_1.default();
}
static pair(g1, g2) {
return optimalAte(g1, g2);
}
static one() {
return new GT(gfp12_1.default.one());
}
/**
* Check if the point is one
* @returns true when one, false otherwise
*/
isOne() {
return this.g.isOne();
}
/**
* Multiply the point a by a scalar k and set the value
* @param a the point
* @param k the scalar
*/
scalarMul(a, k) {
this.g = a.g.exp(k);
}
/**
* Add two points a and b and set the value
* @param a the first point
* @param b the second point
*/
add(a, b) {
this.g = a.g.mul(b.g);
}
/**
* Compute the negative of a and set the value
* @param a the point
*/
neg(a) {
this.g = a.g.invert();
}
/**
* Serialize the point into bytes
* @returns the buffer
*/
marshal() {
const xxxBytes = this.g.getX().getX().getX().toBytes();
const xxyBytes = this.g.getX().getX().getY().toBytes();
const xyxBytes = this.g.getX().getY().getX().toBytes();
const xyyBytes = this.g.getX().getY().getY().toBytes();
const xzxBytes = this.g.getX().getZ().getX().toBytes();
const xzyBytes = this.g.getX().getZ().getY().toBytes();
const yxxBytes = this.g.getY().getX().getX().toBytes();
const yxyBytes = this.g.getY().getX().getY().toBytes();
const yyxBytes = this.g.getY().getY().getX().toBytes();
const yyyBytes = this.g.getY().getY().getY().toBytes();
const yzxBytes = this.g.getY().getZ().getX().toBytes();
const yzyBytes = this.g.getY().getZ().getY().toBytes();
return Buffer.concat([
xxxBytes, xxyBytes, xyxBytes,
xyyBytes, xzxBytes, xzyBytes,
yxxBytes, yxyBytes, yyxBytes,
yyyBytes, yzxBytes, yzyBytes,
]);
}
/**
* Take a buffer and deserialize a point
* @param bytes the buffer
*/
unmarshal(bytes) {
if (bytes.length !== GT.MARSHAL_SIZE) {
throw new Error("wrong buffer size for a GT point");
}
const n = GT.ELEM_SIZE;
const xxxBytes = bytes.slice(0, n);
const xxyBytes = bytes.slice(n, n * 2);
const xyxBytes = bytes.slice(n * 2, n * 3);
const xyyBytes = bytes.slice(n * 3, n * 4);
const xzxBytes = bytes.slice(n * 4, n * 5);
const xzyBytes = bytes.slice(n * 5, n * 6);
const yxxBytes = bytes.slice(n * 6, n * 7);
const yxyBytes = bytes.slice(n * 7, n * 8);
const yyxBytes = bytes.slice(n * 8, n * 9);
const yyyBytes = bytes.slice(n * 9, n * 10);
const yzxBytes = bytes.slice(n * 10, n * 11);
const yzyBytes = bytes.slice(n * 11);
this.g = new gfp12_1.default(new gfp6_1.default(new gfp2_1.default(xxxBytes, xxyBytes), new gfp2_1.default(xyxBytes, xyyBytes), new gfp2_1.default(xzxBytes, xzyBytes)), new gfp6_1.default(new gfp2_1.default(yxxBytes, yxyBytes), new gfp2_1.default(yyxBytes, yyyBytes), new gfp2_1.default(yzxBytes, yzyBytes)));
}
/**
* Check the equality of the point and an object
* @param o the object
* @returns true when both are equal, false otherwise
*/
equals(o) {
if (!(o instanceof GT)) {
return false;
}
return this.g.equals(o.g);
}
/**
* Get the string representation of the point
* @returns the string representation
*/
toString() {
return `bn256.GT${this.g.toString()}`;
}
}
GT.ELEM_SIZE = 256 / 8;
GT.MARSHAL_SIZE = GT.ELEM_SIZE * 12;
exports.GT = GT;
/**
* Compute the pairing between a point in G1 and a point in G2
* using the Optimal Ate algorithm
* @param g1 the point in G1
* @param g2 the point in G2
* @returns the resulting point in GT
*/
function optimalAte(g1, g2) {
const e = opt_ate_1.miller(g2.getPoint(), g1.getPoint());
const ret = opt_ate_1.finalExponentiation(e);
if (g1.isInfinity() || g2.isInfinity()) {
return new GT(gfp12_1.default.one());
}
return new GT(ret);
}
exports.optimalAte = optimalAte;