UNPKG

@kotevode/ffjavascript

Version:

Finite Field Library in Javascript

241 lines (193 loc) 5.52 kB
/* 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; } }