@kotevode/ffjavascript
Version:
Finite Field Library in Javascript
241 lines (193 loc) • 5.52 kB
JavaScript
/*
Copyright 2018 0kims association.
This file is part of snarkjs.
snarkjs is a free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
any later version.
snarkjs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
import * as fUtils from "./futils.js";
import buildSqrt from "./fsqrt.js";
export default class F2Field {
constructor(F, nonResidue) {
this.type="F2";
this.F = F;
this.zero = [this.F.zero, this.F.zero];
this.one = [this.F.one, this.F.zero];
this.negone = this.neg(this.one);
this.nonResidue = nonResidue;
this.m = F.m*2;
this.p = F.p;
this.n64 = F.n64*2;
this.n32 = this.n64*2;
this.n8 = this.n64*8;
buildSqrt(this);
}
_mulByNonResidue(a) {
return this.F.mul(this.nonResidue, a);
}
copy(a) {
return [this.F.copy(a[0]), this.F.copy(a[1])];
}
add(a, b) {
return [
this.F.add(a[0], b[0]),
this.F.add(a[1], b[1])
];
}
double(a) {
return this.add(a,a);
}
sub(a, b) {
return [
this.F.sub(a[0], b[0]),
this.F.sub(a[1], b[1])
];
}
neg(a) {
return this.sub(this.zero, a);
}
conjugate(a) {
return [
a[0],
this.F.neg(a[1])
];
}
mul(a, b) {
const aA = this.F.mul(a[0] , b[0]);
const bB = this.F.mul(a[1] , b[1]);
return [
this.F.add( aA , this._mulByNonResidue(bB)),
this.F.sub(
this.F.mul(
this.F.add(a[0], a[1]),
this.F.add(b[0], b[1])),
this.F.add(aA, bB))];
}
inv(a) {
const t0 = this.F.square(a[0]);
const t1 = this.F.square(a[1]);
const t2 = this.F.sub(t0, this._mulByNonResidue(t1));
const t3 = this.F.inv(t2);
return [
this.F.mul(a[0], t3),
this.F.neg(this.F.mul( a[1], t3)) ];
}
div(a, b) {
return this.mul(a, this.inv(b));
}
square(a) {
const ab = this.F.mul(a[0] , a[1]);
/*
[
(a + b) * (a + non_residue * b) - ab - non_residue * ab,
ab + ab
];
*/
return [
this.F.sub(
this.F.mul(
this.F.add(a[0], a[1]) ,
this.F.add(
a[0] ,
this._mulByNonResidue(a[1]))),
this.F.add(
ab,
this._mulByNonResidue(ab))),
this.F.add(ab, ab)
];
}
isZero(a) {
return this.F.isZero(a[0]) && this.F.isZero(a[1]);
}
eq(a, b) {
return this.F.eq(a[0], b[0]) && this.F.eq(a[1], b[1]);
}
mulScalar(base, e) {
return fUtils.mulScalar(this, base, e);
}
pow(base, e) {
return fUtils.exp(this, base, e);
}
exp(base, e) {
return fUtils.exp(this, base, e);
}
toString(a) {
return `[ ${this.F.toString(a[0])} , ${this.F.toString(a[1])} ]`;
}
fromRng(rng) {
const c0 = this.F.fromRng(rng);
const c1 = this.F.fromRng(rng);
return [c0, c1];
}
gt(a, b) {
if (this.F.gt(a[0], b[0])) return true;
if (this.F.gt(b[0], a[0])) return false;
if (this.F.gt(a[1], b[1])) return true;
return false;
}
geq(a, b) {
return this.gt(a, b) || this.eq(a, b);
}
lt(a, b) {
return !this.geq(a,b);
}
leq(a, b) {
return !this.gt(a,b);
}
neq(a, b) {
return !this.eq(a,b);
}
random() {
return [this.F.random(), this.F.random()];
}
toRprLE(buff, o, e) {
this.F.toRprLE(buff, o, e[0]);
this.F.toRprLE(buff, o+this.F.n8, e[1]);
}
toRprBE(buff, o, e) {
this.F.toRprBE(buff, o, e[1]);
this.F.toRprBE(buff, o+this.F.n8, e[0]);
}
toRprLEM(buff, o, e) {
this.F.toRprLEM(buff, o, e[0]);
this.F.toRprLEM(buff, o+this.F.n8, e[1]);
}
toRprBEM(buff, o, e) {
this.F.toRprBEM(buff, o, e[1]);
this.F.toRprBEM(buff, o+this.F.n8, e[0]);
}
fromRprLE(buff, o) {
o = o || 0;
const c0 = this.F.fromRprLE(buff, o);
const c1 = this.F.fromRprLE(buff, o+this.F.n8);
return [c0, c1];
}
fromRprBE(buff, o) {
o = o || 0;
const c1 = this.F.fromRprBE(buff, o);
const c0 = this.F.fromRprBE(buff, o+this.F.n8);
return [c0, c1];
}
fromRprLEM(buff, o) {
o = o || 0;
const c0 = this.F.fromRprLEM(buff, o);
const c1 = this.F.fromRprLEM(buff, o+this.F.n8);
return [c0, c1];
}
fromRprBEM(buff, o) {
o = o || 0;
const c1 = this.F.fromRprBEM(buff, o);
const c0 = this.F.fromRprBEM(buff, o+this.F.n8);
return [c0, c1];
}
toObject(a) {
return a;
}
}