@polygon-hermez/vm
Version:
An Ethereum VM implementation
156 lines • 6.85 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BLS12_381_ToFp2Point = exports.BLS12_381_ToFpPoint = exports.BLS12_381_ToFrPoint = exports.BLS12_381_FromG2Point = exports.BLS12_381_ToG2Point = exports.BLS12_381_FromG1Point = exports.BLS12_381_ToG1Point = void 0;
const ethereumjs_util_1 = require("ethereumjs-util");
const exceptions_1 = require("../../../exceptions");
// base field modulus as described in the EIP
const fieldModulus = new ethereumjs_util_1.BN('1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab', 16);
// convert an input Buffer to a mcl G1 point
// this does /NOT/ do any input checks. the input Buffer needs to be of length 128
// it does raise an error if the point is not on the curve.
function BLS12_381_ToG1Point(input, mcl) {
const p_x = input.slice(16, 64).toString('hex');
const p_y = input.slice(80, 128).toString('hex');
const ZeroString48Bytes = '0'.repeat(96);
if (p_x == p_y && p_x == ZeroString48Bytes) {
return new mcl.G1();
}
const Fp_X = new mcl.Fp();
const Fp_Y = new mcl.Fp();
const One = new mcl.Fp();
Fp_X.setStr(p_x, 16);
Fp_Y.setStr(p_y, 16);
One.setStr('1', 16);
const G1 = new mcl.G1();
G1.setX(Fp_X);
G1.setY(Fp_Y);
G1.setZ(One);
if (!G1.isValidOrder()) {
throw new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_POINT_NOT_ON_CURVE);
}
// Check if these coordinates are actually on the curve.
if (!G1.isValid()) {
throw new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_POINT_NOT_ON_CURVE);
}
return G1;
}
exports.BLS12_381_ToG1Point = BLS12_381_ToG1Point;
// input: a mcl G1 point
// output: a 128-byte Buffer
function BLS12_381_FromG1Point(input) {
// TODO: figure out if there is a better way to decode these values.
const decodeStr = input.getStr(16); //return a string of pattern "1 <x_coord> <y_coord>"
const decoded = decodeStr.match(/"?[0-9a-f]+"?/g); // match above pattern.
if (decodeStr == '0') {
return Buffer.alloc(128, 0);
}
// note: decoded[0] == 1
const xval = (0, ethereumjs_util_1.padToEven)(decoded[1]);
const yval = (0, ethereumjs_util_1.padToEven)(decoded[2]);
// convert to buffers.
const xBuffer = Buffer.concat([Buffer.alloc(64 - xval.length / 2, 0), Buffer.from(xval, 'hex')]);
const yBuffer = Buffer.concat([Buffer.alloc(64 - yval.length / 2, 0), Buffer.from(yval, 'hex')]);
return Buffer.concat([xBuffer, yBuffer]);
}
exports.BLS12_381_FromG1Point = BLS12_381_FromG1Point;
// convert an input Buffer to a mcl G2 point
// this does /NOT/ do any input checks. the input Buffer needs to be of length 256
function BLS12_381_ToG2Point(input, mcl) {
const p_x_1 = input.slice(0, 64);
const p_x_2 = input.slice(64, 128);
const p_y_1 = input.slice(128, 192);
const p_y_2 = input.slice(192, 256);
const ZeroBytes64 = Buffer.alloc(64, 0);
// check if we have to do with a zero point
if (p_x_1.equals(p_x_2) &&
p_x_1.equals(p_y_1) &&
p_x_1.equals(p_y_2) &&
p_x_1.equals(ZeroBytes64)) {
return new mcl.G2();
}
const Fp2X = BLS12_381_ToFp2Point(p_x_1, p_x_2, mcl);
const Fp2Y = BLS12_381_ToFp2Point(p_y_1, p_y_2, mcl);
const FpOne = new mcl.Fp();
FpOne.setStr('1', 16);
const FpZero = new mcl.Fp();
FpZero.setStr('0', 16);
const Fp2One = new mcl.Fp2();
Fp2One.set_a(FpOne);
Fp2One.set_b(FpZero);
const mclPoint = new mcl.G2();
mclPoint.setX(Fp2X);
mclPoint.setY(Fp2Y);
mclPoint.setZ(Fp2One);
if (!mclPoint.isValidOrder()) {
throw new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_POINT_NOT_ON_CURVE);
}
if (!mclPoint.isValid()) {
throw new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_POINT_NOT_ON_CURVE);
}
return mclPoint;
}
exports.BLS12_381_ToG2Point = BLS12_381_ToG2Point;
// input: a mcl G2 point
// output: a 256-byte Buffer
function BLS12_381_FromG2Point(input) {
// TODO: figure out if there is a better way to decode these values.
const decodeStr = input.getStr(16); //return a string of pattern "1 <x_coord_1> <x_coord_2> <y_coord_1> <y_coord_2>"
if (decodeStr == '0') {
return Buffer.alloc(256, 0);
}
const decoded = decodeStr.match(/"?[0-9a-f]+"?/g); // match above pattern.
// note: decoded[0] == 1
const x_1 = (0, ethereumjs_util_1.padToEven)(decoded[1]);
const x_2 = (0, ethereumjs_util_1.padToEven)(decoded[2]);
const y_1 = (0, ethereumjs_util_1.padToEven)(decoded[3]);
const y_2 = (0, ethereumjs_util_1.padToEven)(decoded[4]);
// convert to buffers.
const xBuffer1 = Buffer.concat([Buffer.alloc(64 - x_1.length / 2, 0), Buffer.from(x_1, 'hex')]);
const xBuffer2 = Buffer.concat([Buffer.alloc(64 - x_2.length / 2, 0), Buffer.from(x_2, 'hex')]);
const yBuffer1 = Buffer.concat([Buffer.alloc(64 - y_1.length / 2, 0), Buffer.from(y_1, 'hex')]);
const yBuffer2 = Buffer.concat([Buffer.alloc(64 - y_2.length / 2, 0), Buffer.from(y_2, 'hex')]);
return Buffer.concat([xBuffer1, xBuffer2, yBuffer1, yBuffer2]);
}
exports.BLS12_381_FromG2Point = BLS12_381_FromG2Point;
// input: a 32-byte hex scalar Buffer
// output: a mcl Fr point
function BLS12_381_ToFrPoint(input, mcl) {
const mclHex = mcl.fromHexStr(input.toString('hex'));
const Fr = new mcl.Fr();
Fr.setBigEndianMod(mclHex);
return Fr;
}
exports.BLS12_381_ToFrPoint = BLS12_381_ToFrPoint;
// input: a 64-byte buffer
// output: a mcl Fp point
function BLS12_381_ToFpPoint(fpCoordinate, mcl) {
// check if point is in field
if (new ethereumjs_util_1.BN(fpCoordinate).gte(fieldModulus)) {
throw new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_FP_NOT_IN_FIELD);
}
const fp = new mcl.Fp();
fp.setBigEndianMod(mcl.fromHexStr(fpCoordinate.toString('hex')));
return fp;
}
exports.BLS12_381_ToFpPoint = BLS12_381_ToFpPoint;
// input: two 64-byte buffers
// output: a mcl Fp2 point
function BLS12_381_ToFp2Point(fpXCoordinate, fpYCoordinate, mcl) {
// check if the coordinates are in the field
if (new ethereumjs_util_1.BN(fpXCoordinate).gte(fieldModulus)) {
throw new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_FP_NOT_IN_FIELD);
}
if (new ethereumjs_util_1.BN(fpYCoordinate).gte(fieldModulus)) {
throw new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_FP_NOT_IN_FIELD);
}
const fp_x = new mcl.Fp();
const fp_y = new mcl.Fp();
const fp2 = new mcl.Fp2();
fp_x.setStr(fpXCoordinate.slice(16).toString('hex'), 16);
fp_y.setStr(fpYCoordinate.slice(16).toString('hex'), 16);
fp2.set_a(fp_x);
fp2.set_b(fp_y);
return fp2;
}
exports.BLS12_381_ToFp2Point = BLS12_381_ToFp2Point;
//# sourceMappingURL=bls12_381.js.map