@ethereumjs/evm
Version:
JavaScript Ethereum Virtual Machine (EVM) implementation
124 lines • 5.28 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NobleBN254 = void 0;
const util_1 = require("@ethereumjs/util");
const bn254_js_1 = require("@noble/curves/bn254.js");
const errors_ts_1 = require("../../errors.js");
const G1_INFINITY_POINT_BYTES = new Uint8Array(64);
const G2_INFINITY_POINT_BYTES = new Uint8Array(128);
const G1_POINT_BYTE_LENGTH = 64;
const G1_ELEMENT_BYTE_LENGTH = 32;
const G2_POINT_BYTE_LENGTH = 128;
const ZERO_BUFFER = new Uint8Array(32);
const ONE_BUFFER = (0, util_1.concatBytes)(new Uint8Array(31), (0, util_1.hexToBytes)('0x01'));
/**
* Converts an Uint8Array to a Noble G1 point.
* @param input Input Uint8Array. Should be 64 bytes
* @returns Noble G1 point
*/
function toG1Point(input) {
if ((0, util_1.equalsBytes)(input, G1_INFINITY_POINT_BYTES) === true) {
return bn254_js_1.bn254.G1.Point.ZERO;
}
const x = (0, util_1.bytesToBigInt)(input.subarray(0, G1_ELEMENT_BYTE_LENGTH));
const y = (0, util_1.bytesToBigInt)(input.subarray(G1_ELEMENT_BYTE_LENGTH, G1_POINT_BYTE_LENGTH));
const G1 = bn254_js_1.bn254.G1.Point.fromAffine({
x,
y,
});
G1.assertValidity();
return G1;
}
function fromG1Point(input) {
const xBytes = (0, util_1.setLengthLeft)((0, util_1.bigIntToBytes)(input.x), G1_ELEMENT_BYTE_LENGTH);
const yBytes = (0, util_1.setLengthLeft)((0, util_1.bigIntToBytes)(input.y), G1_ELEMENT_BYTE_LENGTH);
return (0, util_1.concatBytes)(xBytes, yBytes);
}
function toFp2Point(fpXCoordinate, fpYCoordinate) {
if ((0, util_1.bytesToBigInt)(fpXCoordinate) >= bn254_js_1.bn254.fields.Fp2.ORDER) {
throw new errors_ts_1.EVMError(errors_ts_1.EVMError.errorMessages.BN254_FP_NOT_IN_FIELD);
}
if ((0, util_1.bytesToBigInt)(fpYCoordinate) >= bn254_js_1.bn254.fields.Fp2.ORDER) {
throw new errors_ts_1.EVMError(errors_ts_1.EVMError.errorMessages.BN254_FP_NOT_IN_FIELD);
}
const fpBytes = (0, util_1.concatBytes)(fpXCoordinate, fpYCoordinate);
const FP = bn254_js_1.bn254.fields.Fp2.fromBytes(fpBytes);
return FP;
}
/**
* Converts an Uint8Array to a Noble G2 point. Raises errors if the point is not on the curve
* and (if activated) if the point is in the subgroup / order check.
* @param input Input Uint8Array. Should be 256 bytes
* @returns Noble G2 point
*/
function toG2Point(input) {
if ((0, util_1.equalsBytes)(input, G2_INFINITY_POINT_BYTES) === true) {
return bn254_js_1.bn254.G2.Point.ZERO;
}
const p_x_2 = input.subarray(0, G1_ELEMENT_BYTE_LENGTH);
const p_x_1 = input.subarray(G1_ELEMENT_BYTE_LENGTH, G1_ELEMENT_BYTE_LENGTH * 2);
const start2 = G1_ELEMENT_BYTE_LENGTH * 2;
const p_y_2 = input.subarray(start2, start2 + G1_ELEMENT_BYTE_LENGTH);
const p_y_1 = input.subarray(start2 + G1_ELEMENT_BYTE_LENGTH, start2 + G1_ELEMENT_BYTE_LENGTH * 2);
for (const p of [p_x_1, p_x_2, p_y_1, p_y_2]) {
const pB = (0, util_1.bytesToBigInt)(p);
if (bn254_js_1.bn254.fields.Fp.create(pB) !== pB) {
throw new errors_ts_1.EVMError(errors_ts_1.EVMError.errorMessages.BN254_FP_NOT_IN_FIELD);
}
}
const Fp2X = toFp2Point(p_x_1, p_x_2);
const Fp2Y = toFp2Point(p_y_1, p_y_2);
const pG2 = bn254_js_1.bn254.G2.Point.fromAffine({
x: Fp2X,
y: Fp2Y,
});
pG2.assertValidity();
return pG2;
}
/**
* Implementation of the `EVMBN254Interface` using the `ethereum-cryptography (`@noble/curves`)
* JS library, see https://github.com/ethereum/js-ethereum-cryptography.
*
* This is the EVM default implementation.
*/
class NobleBN254 {
add(input) {
const p1 = toG1Point(input.slice(0, G1_POINT_BYTE_LENGTH));
const p2 = toG1Point(input.slice(G1_POINT_BYTE_LENGTH, G1_POINT_BYTE_LENGTH * 2));
const result = fromG1Point(p1.add(p2).toAffine());
return result;
}
mul(input) {
const p1 = toG1Point(input.slice(0, G1_POINT_BYTE_LENGTH));
const scalar = bn254_js_1.bn254.fields.Fr.create((0, util_1.bytesToBigInt)(input.slice(G1_POINT_BYTE_LENGTH, 96)));
if (scalar === util_1.BIGINT_0) {
return G1_INFINITY_POINT_BYTES;
}
const result = fromG1Point(p1.multiply(scalar).toAffine());
return result;
}
pairing(input) {
// Extract the pairs from the input
const pairLength = 192;
const pairs = [];
for (let k = 0; k < input.length / pairLength; k++) {
const pairStart = pairLength * k;
const G1 = toG1Point(input.subarray(pairStart, pairStart + G1_POINT_BYTE_LENGTH));
const g2start = pairStart + G1_POINT_BYTE_LENGTH;
const G2 = toG2Point(input.subarray(g2start, g2start + G2_POINT_BYTE_LENGTH));
if (G1 === bn254_js_1.bn254.G1.Point.ZERO || G2 === bn254_js_1.bn254.G2.Point.ZERO) {
continue;
}
pairs.push({ g1: G1, g2: G2 });
}
const res = bn254_js_1.bn254.pairingBatch(pairs);
if (bn254_js_1.bn254.fields.Fp12.eql(res, bn254_js_1.bn254.fields.Fp12.ONE) === true) {
return ONE_BUFFER;
}
else {
return ZERO_BUFFER;
}
}
}
exports.NobleBN254 = NobleBN254;
//# sourceMappingURL=noble.js.map