You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

176 lines
5.6 KiB

/*
Copyright 2018 0kims association
This file is part of zksnark javascript library.
zksnark javascript library is 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.
zksnark javascript library 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 zksnark javascript library. If not, see <https://www.gnu.org/licenses/>.
*/
const fUtils = require("./futils.js");
class F3Field {
constructor(F, nonResidue) {
this.F = F;
this.zero = [this.F.zero, this.F.zero, this.F.zero];
this.one = [this.F.one, this.F.zero, this.F.zero];
this.nonResidue = nonResidue;
}
_mulByNonResidue(a) {
return this.F.mul(this.nonResidue, a);
}
copy(a) {
return [this.F.copy(a[0]), this.F.copy(a[1]), this.F.copy(a[2])];
}
add(a, b) {
return [
this.F.add(a[0], b[0]),
this.F.add(a[1], b[1]),
this.F.add(a[2], b[2])
];
}
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]),
this.F.sub(a[2], b[2])
];
}
neg(a) {
return this.sub(this.zero, a);
}
mul(a, b) {
const aA = this.F.mul(a[0] , b[0]);
const bB = this.F.mul(a[1] , b[1]);
const cC = this.F.mul(a[2] , b[2]);
return [
this.F.add(
aA,
this._mulByNonResidue(
this.F.sub(
this.F.mul(
this.F.add(a[1], a[2]),
this.F.add(b[1], b[2])),
this.F.add(bB, cC)))), // aA + non_residue*((b+c)*(B+C)-bB-cC),
this.F.add(
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)),
this._mulByNonResidue( cC)), // (a+b)*(A+B)-aA-bB+non_residue*cC
this.F.add(
this.F.sub(
this.F.mul(
this.F.add(a[0], a[2]),
this.F.add(b[0], b[2])),
this.F.add(aA, cC)),
bB)]; // (a+c)*(A+C)-aA+bB-cC)
}
inverse(a) {
const t0 = this.F.square(a[0]); // t0 = a^2 ;
const t1 = this.F.square(a[1]); // t1 = b^2 ;
const t2 = this.F.square(a[2]); // t2 = c^2;
const t3 = this.F.mul(a[0],a[1]); // t3 = ab
const t4 = this.F.mul(a[0],a[2]); // t4 = ac
const t5 = this.F.mul(a[1],a[2]); // t5 = bc;
// c0 = t0 - non_residue * t5;
const c0 = this.F.sub(t0, this._mulByNonResidue(t5));
// c1 = non_residue * t2 - t3;
const c1 = this.F.sub(this._mulByNonResidue(t2), t3);
const c2 = this.F.sub(t1, t4); // c2 = t1-t4
// t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse();
const t6 =
this.F.inverse(
this.F.add(
this.F.mul(a[0], c0),
this._mulByNonResidue(
this.F.add(
this.F.mul(a[2], c1),
this.F.mul(a[1], c2)))));
return [
this.F.mul(t6, c0), // t6*c0
this.F.mul(t6, c1), // t6*c1
this.F.mul(t6, c2)]; // t6*c2
}
div(a, b) {
return this.mul(a, this.inverse(b));
}
square(a) {
const s0 = this.F.square(a[0]); // s0 = a^2
const ab = this.F.mul(a[0], a[1]); // ab = a*b
const s1 = this.F.add(ab, ab); // s1 = 2ab;
const s2 = this.F.square(
this.F.add(this.F.sub(a[0],a[1]), a[2])); // s2 = (a - b + c)^2;
const bc = this.F.mul(a[1],a[2]); // bc = b*c
const s3 = this.F.add(bc, bc); // s3 = 2*bc
const s4 = this.F.square(a[2]); // s4 = c^2
return [
this.F.add(
s0,
this._mulByNonResidue(s3)), // s0 + non_residue * s3,
this.F.add(
s1,
this._mulByNonResidue(s4)), // s1 + non_residue * s4,
this.F.sub(
this.F.add( this.F.add(s1, s2) , s3 ),
this.F.add(s0, s4))]; // s1 + s2 + s3 - s0 - s4
}
isZero(a) {
return this.F.isZero(a[0]) && this.F.isZero(a[1]) && this.F.isZero(a[2]);
}
equals(a, b) {
return this.F.equals(a[0], b[0]) && this.F.equals(a[1], b[1]) && this.F.equals(a[2], b[2]);
}
affine(a) {
return [this.F.affine(a[0]), this.F.affine(a[1]), this.F.affine(a[2])];
}
mulScalar(base, e) {
return fUtils.mulScalar(this, base, e);
}
exp(base, e) {
return fUtils.exp(this, base, e);
}
toString(a) {
const cp = this.affine(a);
return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])}, ${this.F.toString(cp[2])} ]`;
}
}
module.exports = F3Field;