arnaucube
arnaucube/snarkjsPublic Self-hosted repository
snarkjs/src/f3field.js
src/f3field.jsRaw
  1const fUtils = require("./futils.js");
  2
  3class F3Field {
  4    constructor(F, nonResidue) {
  5        this.F = F;
  6        this.zero = [this.F.zero, this.F.zero, this.F.zero];
  7        this.one = [this.F.one, this.F.zero, this.F.zero];
  8        this.nonResidue = nonResidue;
  9    }
 10
 11    _mulByNonResidue(a) {
 12        return this.F.mul(this.nonResidue, a);
 13    }
 14
 15    copy(a) {
 16        return [this.F.copy(a[0]), this.F.copy(a[1]), this.F.copy(a[2])];
 17    }
 18
 19    add(a, b) {
 20        return [
 21            this.F.add(a[0], b[0]),
 22            this.F.add(a[1], b[1]),
 23            this.F.add(a[2], b[2])
 24        ];
 25    }
 26
 27    double(a) {
 28        return this.add(a,a);
 29    }
 30
 31    sub(a, b) {
 32        return [
 33            this.F.sub(a[0], b[0]),
 34            this.F.sub(a[1], b[1]),
 35            this.F.sub(a[2], b[2])
 36        ];
 37    }
 38
 39    neg(a) {
 40        return this.sub(this.zero, a);
 41    }
 42
 43    mul(a, b) {
 44
 45        const aA = this.F.mul(a[0] , b[0]);
 46        const bB = this.F.mul(a[1] , b[1]);
 47        const cC = this.F.mul(a[2] , b[2]);
 48
 49        return [
 50            this.F.add(
 51                aA,
 52                this._mulByNonResidue(
 53                    this.F.sub(
 54                        this.F.mul(
 55                            this.F.add(a[1], a[2]),
 56                            this.F.add(b[1], b[2])),
 57                        this.F.add(bB, cC)))),    // aA + non_residue*((b+c)*(B+C)-bB-cC),
 58
 59            this.F.add(
 60                this.F.sub(
 61                    this.F.mul(
 62                        this.F.add(a[0], a[1]),
 63                        this.F.add(b[0], b[1])),
 64                    this.F.add(aA, bB)),
 65                this._mulByNonResidue( cC)),   // (a+b)*(A+B)-aA-bB+non_residue*cC
 66
 67            this.F.add(
 68                this.F.sub(
 69                    this.F.mul(
 70                        this.F.add(a[0], a[2]),
 71                        this.F.add(b[0], b[2])),
 72                    this.F.add(aA, cC)),
 73                bB)];                           // (a+c)*(A+C)-aA+bB-cC)
 74    }
 75
 76    inverse(a) {
 77        const t0 = this.F.square(a[0]);             // t0 = a^2 ;
 78        const t1 = this.F.square(a[1]);             // t1 = b^2 ;
 79        const t2 = this.F.square(a[2]);             // t2 = c^2;
 80        const t3 = this.F.mul(a[0],a[1]);           // t3 = ab
 81        const t4 = this.F.mul(a[0],a[2]);           // t4 = ac
 82        const t5 = this.F.mul(a[1],a[2]);           // t5 = bc;
 83        // c0 = t0 - non_residue * t5;
 84        const c0 = this.F.sub(t0, this._mulByNonResidue(t5));
 85        // c1 = non_residue * t2 - t3;
 86        const c1 = this.F.sub(this._mulByNonResidue(t2), t3);
 87        const c2 = this.F.sub(t1, t4);              // c2 = t1-t4
 88
 89        // t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse();
 90        const t6 =
 91            this.F.inverse(
 92                this.F.add(
 93                    this.F.mul(a[0], c0),
 94                    this._mulByNonResidue(
 95                        this.F.add(
 96                            this.F.mul(a[2], c1),
 97                            this.F.mul(a[1], c2)))));
 98
 99        return [
100            this.F.mul(t6, c0),         // t6*c0
101            this.F.mul(t6, c1),         // t6*c1
102            this.F.mul(t6, c2)];        // t6*c2
103    }
104
105    div(a, b) {
106        return this.mul(a, this.inverse(b));
107    }
108
109    square(a) {
110        const s0 = this.F.square(a[0]);                   // s0 = a^2
111        const ab = this.F.mul(a[0], a[1]);                // ab = a*b
112        const s1 = this.F.add(ab, ab);                    // s1 = 2ab;
113        const s2 = this.F.square(
114            this.F.add(this.F.sub(a[0],a[1]), a[2]));     // s2 = (a - b + c)^2;
115        const bc = this.F.mul(a[1],a[2]);                 // bc = b*c
116        const s3 = this.F.add(bc, bc);                    // s3 = 2*bc
117        const s4 = this.F.square(a[2]);                   // s4 = c^2
118
119
120        return [
121            this.F.add(
122                s0,
123                this._mulByNonResidue(s3)),           // s0 + non_residue * s3,
124            this.F.add(
125                s1,
126                this._mulByNonResidue(s4)),           // s1 + non_residue * s4,
127            this.F.sub(
128                this.F.add( this.F.add(s1, s2) , s3 ),
129                this.F.add(s0, s4))];                      // s1 + s2 + s3 - s0 - s4
130    }
131
132    isZero(a) {
133        return this.F.isZero(a[0]) && this.F.isZero(a[1]) && this.F.isZero(a[2]);
134    }
135
136    equals(a, b) {
137        return this.F.equals(a[0], b[0]) && this.F.equals(a[1], b[1]) && this.F.equals(a[2], b[2]);
138    }
139
140    affine(a) {
141        return [this.F.affine(a[0]), this.F.affine(a[1]), this.F.affine(a[2])];
142    }
143
144    mulEscalar(base, e) {
145        return fUtils.mulEscalar(this, base, e);
146    }
147
148    exp(base, e) {
149        return fUtils.exp(this, base, e);
150    }
151
152    toString(a) {
153        const cp = this.affine(a);
154        return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])}, ${this.F.toString(cp[2])} ]`;
155    }
156}
157
158module.exports = F3Field;