@nikkolasg/noble-bls12-381
Version:
Noble BLS12-381 pairing-friendly curve. High-security, easily auditable, 0-dep aggregated signatures & pubkey.
179 lines (178 loc) • 6.27 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
const fp_1 = require("./fp");
const group_1 = require("./group");
const FP12_DEFAULT = [
0n, 1n, 0n, 1n,
0n, 1n, 0n, 1n,
0n, 1n, 0n, 1n
];
class Fp12 {
constructor(...args) {
this.coefficients = FP12_DEFAULT.map(a => new fp_1.Fp(a));
args =
args.length === 0 ? FP12_DEFAULT : args.slice(0, 12);
this.coefficients = args[0] instanceof fp_1.Fp ? args : args.map(a => new fp_1.Fp(a));
}
get value() {
return this.coefficients.map(c => c.value);
}
get zero() {
return new Fp12(0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n);
}
get one() {
return new Fp12(1n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n);
}
normalize(v) {
if (typeof v === "bigint") {
return v;
}
return v instanceof Fp12 ? v : new Fp12(...v);
}
isEmpty() {
return this.coefficients.every(a => a.isEmpty());
}
equals(rhs) {
return this.coefficients.every((a, i) => a.equals(rhs.coefficients[i]));
}
negative() {
return new Fp12(...this.coefficients.map(a => a.negative()));
}
add(rhs) {
return new Fp12(...this.coefficients.map((a, i) => a.add(rhs.coefficients[i])));
}
subtract(rhs) {
return new Fp12(...this.coefficients.map((a, i) => a.subtract(rhs.coefficients[i])));
}
multiply(otherValue) {
if (typeof otherValue === "bigint") {
return new Fp12(...this.coefficients.map(a => a.multiply(otherValue)));
}
const LENGTH = this.coefficients.length;
const filler = Array(LENGTH * 2 - 1)
.fill(null)
.map(() => new fp_1.Fp());
for (let i = 0; i < LENGTH; i++) {
for (let j = 0; j < LENGTH; j++) {
filler[i + j] = filler[i + j].add(this.coefficients[i].multiply(otherValue.coefficients[j]));
}
}
for (let exp = LENGTH - 2; exp >= 0; exp--) {
const top = filler.pop();
if (top === undefined) {
break;
}
for (const [i, value] of Fp12.ENTRY_COEFFICIENTS) {
filler[exp + i] = filler[exp + i].subtract(top.multiply(value));
}
}
return new Fp12(...filler);
}
square() {
return this.multiply(this);
}
pow(n) {
if (n === 1n) {
return this;
}
let result = new Fp12(1n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n);
let value = this;
while (n > 0n) {
if ((n & 1n) === 1n) {
result = result.multiply(value);
}
n >>= 1n;
value = value.square();
}
return result;
}
degree(nums) {
let degree = nums.length - 1;
while (nums[degree] === 0n && degree !== 0) {
degree--;
}
return degree;
}
primeNumberInvariant(num) {
return new fp_1.Fp(num).invert().value;
}
optimizedRoundedDiv(coefficients, others) {
const tmp = [...coefficients];
const degreeThis = this.degree(tmp);
const degreeOthers = this.degree(others);
const zeros = Array.from(tmp).fill(0n);
const edgeInvariant = this.primeNumberInvariant(others[degreeOthers]);
for (let i = degreeThis - degreeOthers; i >= 0; i--) {
zeros[i] = zeros[i] + tmp[degreeOthers + i] * edgeInvariant;
for (let c = 0; c < degreeOthers; c++) {
tmp[c + i] = tmp[c + i] - zeros[c];
}
}
return new Fp12(...zeros.slice(0, this.degree(zeros) + 1));
}
invert() {
const LENGTH = this.coefficients.length;
let lm = [...this.one.coefficients.map(a => a.value), 0n];
let hm = [...this.zero.coefficients.map(a => a.value), 0n];
let low = [...this.coefficients.map(a => a.value), 0n];
let high = [...Fp12.MODULE_COEFFICIENTS, 1n];
while (this.degree(low) !== 0) {
const { coefficients } = this.optimizedRoundedDiv(high, low);
const zeros = Array(LENGTH + 1 - coefficients.length)
.fill(null)
.map(() => new fp_1.Fp());
const roundedDiv = coefficients.concat(zeros);
let nm = [...hm];
let nw = [...high];
for (let i = 0; i <= LENGTH; i++) {
for (let j = 0; j <= LENGTH - i; j++) {
nm[i + j] -= lm[i] * roundedDiv[j].value;
nw[i + j] -= low[i] * roundedDiv[j].value;
}
}
nm = nm.map(a => new fp_1.Fp(a).value);
nw = nw.map(a => new fp_1.Fp(a).value);
hm = lm;
lm = nm;
high = low;
low = nw;
}
const result = new Fp12(...lm);
return result.div(low[0]);
}
div(otherValue) {
if (typeof otherValue === "bigint") {
return new Fp12(...this.coefficients.map(a => a.div(otherValue)));
}
return this.multiply(otherValue.invert());
}
}
Fp12.MODULE_COEFFICIENTS = [
2n, 0n, 0n, 0n, 0n, 0n, -2n, 0n, 0n, 0n, 0n, 0n
];
Fp12.ENTRY_COEFFICIENTS = [
[0, 2n],
[6, -2n]
];
__decorate([
group_1.normalized
], Fp12.prototype, "equals", null);
__decorate([
group_1.normalized
], Fp12.prototype, "add", null);
__decorate([
group_1.normalized
], Fp12.prototype, "subtract", null);
__decorate([
group_1.normalized
], Fp12.prototype, "multiply", null);
__decorate([
group_1.normalized
], Fp12.prototype, "div", null);
exports.Fp12 = Fp12;