arnaucube
arnaucube/grapevine-sonobePublic Self-hosted repository
grapevine-sonobe/circom/node_modules/circomlib/circuits/escalarmulfix.circom
circom/node_modules/circomlib/circuits/escalarmulfix.circomRaw
  1/*
  2    Copyright 2018 0KIMS association.
  3
  4    This file is part of circom (Zero Knowledge Circuit Compiler).
  5
  6    circom is a free software: you can redistribute it and/or modify it
  7    under the terms of the GNU General Public License as published by
  8    the Free Software Foundation, either version 3 of the License, or
  9    (at your option) any later version.
 10
 11    circom is distributed in the hope that it will be useful, but WITHOUT
 12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 13    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
 14    License for more details.
 15
 16    You should have received a copy of the GNU General Public License
 17    along with circom. If not, see <https://www.gnu.org/licenses/>.
 18*/
 19pragma circom 2.0.0;
 20
 21include "mux3.circom";
 22include "montgomery.circom";
 23include "babyjub.circom";
 24
 25/*
 26    Window of 3 elements, it calculates
 27        out = base + base*in[0] + 2*base*in[1] + 4*base*in[2]
 28        out4 = 4*base
 29
 30    The result should be compensated.
 31 */
 32
 33/*
 34
 35    The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243
 36    First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B
 37
 38    Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B
 39
 40    And Finaly we compute the result: RES = SQ - Q
 41
 42    As you can see the input of the adders cannot be equal nor zero, except for the last
 43    substraction that it's done in montgomery.
 44
 45    A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
 46    is the output of the windows that it's going to be <= 2^246*B
 47 */
 48template WindowMulFix() {
 49    signal input in[3];
 50    signal input base[2];
 51    signal output out[2];
 52    signal output out8[2];   // Returns 8*Base (To be linked)
 53
 54    component mux = MultiMux3(2);
 55
 56    mux.s[0] <== in[0];
 57    mux.s[1] <== in[1];
 58    mux.s[2] <== in[2];
 59
 60    component dbl2 = MontgomeryDouble();
 61    component adr3 = MontgomeryAdd();
 62    component adr4 = MontgomeryAdd();
 63    component adr5 = MontgomeryAdd();
 64    component adr6 = MontgomeryAdd();
 65    component adr7 = MontgomeryAdd();
 66    component adr8 = MontgomeryAdd();
 67
 68// in[0]  -> 1*BASE
 69
 70    mux.c[0][0] <== base[0];
 71    mux.c[1][0] <== base[1];
 72
 73// in[1] -> 2*BASE
 74    dbl2.in[0] <== base[0];
 75    dbl2.in[1] <== base[1];
 76    mux.c[0][1] <== dbl2.out[0];
 77    mux.c[1][1] <== dbl2.out[1];
 78
 79// in[2] -> 3*BASE
 80    adr3.in1[0] <== base[0];
 81    adr3.in1[1] <== base[1];
 82    adr3.in2[0] <== dbl2.out[0];
 83    adr3.in2[1] <== dbl2.out[1];
 84    mux.c[0][2] <== adr3.out[0];
 85    mux.c[1][2] <== adr3.out[1];
 86
 87// in[3] -> 4*BASE
 88    adr4.in1[0] <== base[0];
 89    adr4.in1[1] <== base[1];
 90    adr4.in2[0] <== adr3.out[0];
 91    adr4.in2[1] <== adr3.out[1];
 92    mux.c[0][3] <== adr4.out[0];
 93    mux.c[1][3] <== adr4.out[1];
 94
 95// in[4] -> 5*BASE
 96    adr5.in1[0] <== base[0];
 97    adr5.in1[1] <== base[1];
 98    adr5.in2[0] <== adr4.out[0];
 99    adr5.in2[1] <== adr4.out[1];
100    mux.c[0][4] <== adr5.out[0];
101    mux.c[1][4] <== adr5.out[1];
102
103// in[5] -> 6*BASE
104    adr6.in1[0] <== base[0];
105    adr6.in1[1] <== base[1];
106    adr6.in2[0] <== adr5.out[0];
107    adr6.in2[1] <== adr5.out[1];
108    mux.c[0][5] <== adr6.out[0];
109    mux.c[1][5] <== adr6.out[1];
110
111// in[6] -> 7*BASE
112    adr7.in1[0] <== base[0];
113    adr7.in1[1] <== base[1];
114    adr7.in2[0] <== adr6.out[0];
115    adr7.in2[1] <== adr6.out[1];
116    mux.c[0][6] <== adr7.out[0];
117    mux.c[1][6] <== adr7.out[1];
118
119// in[7] -> 8*BASE
120    adr8.in1[0] <== base[0];
121    adr8.in1[1] <== base[1];
122    adr8.in2[0] <== adr7.out[0];
123    adr8.in2[1] <== adr7.out[1];
124    mux.c[0][7] <== adr8.out[0];
125    mux.c[1][7] <== adr8.out[1];
126
127    out8[0] <== adr8.out[0];
128    out8[1] <== adr8.out[1];
129
130    out[0] <== mux.out[0];
131    out[1] <== mux.out[1];
132}
133
134
135/*
136    This component does a multiplication of a escalar times a fix base
137    Signals:
138        e: The scalar in bits
139        base: the base point in edwards format
140        out:  The result
141        dbl: Point in Edwards to be linked to the next segment.
142 */
143
144template SegmentMulFix(nWindows) {
145    signal input e[nWindows*3];
146    signal input base[2];
147    signal output out[2];
148    signal output dbl[2];
149
150    var i;
151    var j;
152
153    // Convert the base to montgomery
154
155    component e2m = Edwards2Montgomery();
156    e2m.in[0] <== base[0];
157    e2m.in[1] <== base[1];
158
159    component windows[nWindows];
160    component adders[nWindows];
161    component cadders[nWindows];
162
163    // In the last step we add an extra doubler so that numbers do not match.
164    component dblLast = MontgomeryDouble();
165
166    for (i=0; i<nWindows; i++) {
167        windows[i] = WindowMulFix();
168        cadders[i] = MontgomeryAdd();
169        if (i==0) {
170            windows[i].base[0] <== e2m.out[0];
171            windows[i].base[1] <== e2m.out[1];
172            cadders[i].in1[0] <== e2m.out[0];
173            cadders[i].in1[1] <== e2m.out[1];
174        } else {
175            windows[i].base[0] <== windows[i-1].out8[0];
176            windows[i].base[1] <== windows[i-1].out8[1];
177            cadders[i].in1[0] <== cadders[i-1].out[0];
178            cadders[i].in1[1] <== cadders[i-1].out[1];
179        }
180        for (j=0; j<3; j++) {
181            windows[i].in[j] <== e[3*i+j];
182        }
183        if (i<nWindows-1) {
184            cadders[i].in2[0] <== windows[i].out8[0];
185            cadders[i].in2[1] <== windows[i].out8[1];
186        } else {
187            dblLast.in[0] <== windows[i].out8[0];
188            dblLast.in[1] <== windows[i].out8[1];
189            cadders[i].in2[0] <== dblLast.out[0];
190            cadders[i].in2[1] <== dblLast.out[1];
191        }
192    }
193
194    for (i=0; i<nWindows; i++) {
195        adders[i] = MontgomeryAdd();
196        if (i==0) {
197            adders[i].in1[0] <== dblLast.out[0];
198            adders[i].in1[1] <== dblLast.out[1];
199        } else {
200            adders[i].in1[0] <== adders[i-1].out[0];
201            adders[i].in1[1] <== adders[i-1].out[1];
202        }
203        adders[i].in2[0] <== windows[i].out[0];
204        adders[i].in2[1] <== windows[i].out[1];
205    }
206
207    component m2e = Montgomery2Edwards();
208    component cm2e = Montgomery2Edwards();
209
210    m2e.in[0] <== adders[nWindows-1].out[0];
211    m2e.in[1] <== adders[nWindows-1].out[1];
212    cm2e.in[0] <== cadders[nWindows-1].out[0];
213    cm2e.in[1] <== cadders[nWindows-1].out[1];
214
215    component cAdd = BabyAdd();
216    cAdd.x1 <== m2e.out[0];
217    cAdd.y1 <== m2e.out[1];
218    cAdd.x2 <== -cm2e.out[0];
219    cAdd.y2 <== cm2e.out[1];
220
221    cAdd.xout ==> out[0];
222    cAdd.yout ==> out[1];
223
224    windows[nWindows-1].out8[0] ==> dbl[0];
225    windows[nWindows-1].out8[1] ==> dbl[1];
226}
227
228
229/*
230This component multiplies a escalar times a fixed point BASE (twisted edwards format)
231    Signals
232        e: The escalar in binary format
233        out: The output point in twisted edwards
234 */
235template EscalarMulFix(n, BASE) {
236    signal input e[n];              // Input in binary format
237    signal output out[2];           // Point (Twisted format)
238
239    var nsegments = (n-1)\246 +1;       // 249 probably would work. But I'm not sure and for security I keep 246
240    var nlastsegment = n - (nsegments-1)*249;
241
242    component segments[nsegments];
243
244    component m2e[nsegments-1];
245    component adders[nsegments-1];
246
247    var s;
248    var i;
249    var nseg;
250    var nWindows;
251
252    for (s=0; s<nsegments; s++) {
253
254        nseg = (s < nsegments-1) ? 249 : nlastsegment;
255        nWindows = ((nseg - 1)\3)+1;
256
257        segments[s] = SegmentMulFix(nWindows);
258
259        for (i=0; i<nseg; i++) {
260            segments[s].e[i] <== e[s*249+i];
261        }
262
263        for (i = nseg; i<nWindows*3; i++) {
264            segments[s].e[i] <== 0;
265        }
266
267        if (s==0) {
268            segments[s].base[0] <== BASE[0];
269            segments[s].base[1] <== BASE[1];
270        } else {
271            m2e[s-1] = Montgomery2Edwards();
272            adders[s-1] = BabyAdd();
273
274            segments[s-1].dbl[0] ==> m2e[s-1].in[0];
275            segments[s-1].dbl[1] ==> m2e[s-1].in[1];
276
277            m2e[s-1].out[0] ==> segments[s].base[0];
278            m2e[s-1].out[1] ==> segments[s].base[1];
279
280            if (s==1) {
281                segments[s-1].out[0] ==> adders[s-1].x1;
282                segments[s-1].out[1] ==> adders[s-1].y1;
283            } else {
284                adders[s-2].xout ==> adders[s-1].x1;
285                adders[s-2].yout ==> adders[s-1].y1;
286            }
287            segments[s].out[0] ==> adders[s-1].x2;
288            segments[s].out[1] ==> adders[s-1].y2;
289        }
290    }
291
292    if (nsegments == 1) {
293        segments[0].out[0] ==> out[0];
294        segments[0].out[1] ==> out[1];
295    } else {
296        adders[nsegments-2].xout ==> out[0];
297        adders[nsegments-2].yout ==> out[1];
298    }
299}