@polygon-hermez/vm
Version:
An Ethereum VM implementation
91 lines • 3.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const ethereumjs_util_1 = require("ethereumjs-util");
const evm_1 = require("../evm");
const exceptions_1 = require("../../exceptions");
const assert = require('assert');
const { BLS12_381_ToG1Point, BLS12_381_ToG2Point } = require('./util/bls12_381');
const zeroBuffer = Buffer.alloc(32, 0);
const oneBuffer = Buffer.concat([Buffer.alloc(31, 0), Buffer.from('01', 'hex')]);
async function default_1(opts) {
assert(opts.data);
const mcl = opts._VM._mcl;
const inputData = opts.data;
const baseGas = new ethereumjs_util_1.BN(opts._common.paramByEIP('gasPrices', 'Bls12381PairingBaseGas', 2537));
if (inputData.length == 0) {
return (0, evm_1.VmErrorResult)(new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_INPUT_EMPTY), opts.gasLimit);
}
const gasUsedPerPair = new ethereumjs_util_1.BN(opts._common.paramByEIP('gasPrices', 'Bls12381PairingPerPairGas', 2537));
const gasUsed = baseGas.iadd(gasUsedPerPair.imul(new ethereumjs_util_1.BN(Math.floor(inputData.length / 384))));
if (inputData.length % 384 != 0) {
return (0, evm_1.VmErrorResult)(new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_INVALID_INPUT_LENGTH), opts.gasLimit);
}
if (opts.gasLimit.lt(gasUsed)) {
return (0, evm_1.OOGResult)(opts.gasLimit);
}
// prepare pairing list and check for mandatory zero bytes
const pairs = [];
const zeroBytes16 = Buffer.alloc(16, 0);
const zeroByteCheck = [
[0, 16],
[64, 80],
[128, 144],
[192, 208],
[256, 272],
[320, 336],
];
for (let k = 0; k < inputData.length / 384; k++) {
// zero bytes check
const pairStart = 384 * k;
for (const index in zeroByteCheck) {
const slicedBuffer = opts.data.slice(zeroByteCheck[index][0] + pairStart, zeroByteCheck[index][1] + pairStart);
if (!slicedBuffer.equals(zeroBytes16)) {
return (0, evm_1.VmErrorResult)(new exceptions_1.VmError(exceptions_1.ERROR.BLS_12_381_POINT_NOT_ON_CURVE), opts.gasLimit);
}
}
let G1;
try {
G1 = BLS12_381_ToG1Point(opts.data.slice(pairStart, pairStart + 128), mcl);
}
catch (e) {
return (0, evm_1.VmErrorResult)(e, opts.gasLimit);
}
const g2start = pairStart + 128;
let G2;
try {
G2 = BLS12_381_ToG2Point(opts.data.slice(g2start, g2start + 256), mcl);
}
catch (e) {
return (0, evm_1.VmErrorResult)(e, opts.gasLimit);
}
pairs.push([G1, G2]);
}
// run the pairing check
// reference (Nethermind): https://github.com/NethermindEth/nethermind/blob/374b036414722b9c8ad27e93d64840b8f63931b9/src/Nethermind/Nethermind.Evm/Precompiles/Bls/Mcl/PairingPrecompile.cs#L93
let GT;
for (let index = 0; index < pairs.length; index++) {
const pair = pairs[index];
const G1 = pair[0];
const G2 = pair[1];
if (index == 0) {
GT = mcl.millerLoop(G1, G2);
}
else {
GT = mcl.mul(GT, mcl.millerLoop(G1, G2));
}
}
GT = mcl.finalExp(GT);
let returnValue;
if (GT.isOne()) {
returnValue = oneBuffer;
}
else {
returnValue = zeroBuffer;
}
return {
gasUsed,
returnValue: returnValue,
};
}
exports.default = default_1;
//# sourceMappingURL=10-bls12-pairing.js.map