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;