arnaucube
arnaucube/circomlibPublic Self-hosted repository
circomlib/circuit/escalarmulfix.circom
circuit/escalarmulfix.circomRaw
  1include "mux3.circom";
  2include "montgomery.circom";
  3include "babyjub.circom";
  4
  5/*
  6    Window of 3 elements, it calculates
  7        out = base + base*in[0] + 2*base*in[1] + 4*base*in[2]
  8        out4 = 4*base
  9
 10    The result should be compensated.
 11 */
 12template WindowMulFix() {
 13    signal input in[3];
 14    signal input base[2];
 15    signal output out[2];
 16    signal output out8[2];   // Returns 8*Base (To be linked)
 17
 18    component mux = MultiMux3(2);
 19
 20    mux.s[0] <== in[0];
 21    mux.s[1] <== in[1];
 22    mux.s[2] <== in[2];
 23
 24    component dbl2 = MontgomeryDouble();
 25    component adr3 = MontgomeryAdd();
 26    component adr4 = MontgomeryAdd();
 27    component adr5 = MontgomeryAdd();
 28    component adr6 = MontgomeryAdd();
 29    component adr7 = MontgomeryAdd();
 30    component adr8 = MontgomeryAdd();
 31
 32// in[0]  -> 1*BASE
 33
 34    mux.c[0][0] <== base[0];
 35    mux.c[1][0] <== base[1];
 36
 37// in[1] -> 2*BASE
 38    dbl2.in[0] <== base[0];
 39    dbl2.in[1] <== base[1];
 40    mux.c[0][1] <== dbl2.out[0];
 41    mux.c[1][1] <== dbl2.out[1];
 42
 43// in[2] -> 3*BASE
 44    adr3.in1[0] <== base[0];
 45    adr3.in1[1] <== base[1];
 46    adr3.in2[0] <== dbl2.out[0];
 47    adr3.in2[1] <== dbl2.out[1];
 48    mux.c[0][2] <== adr3.out[0];
 49    mux.c[1][2] <== adr3.out[1];
 50
 51// in[3] -> 4*BASE
 52    adr4.in1[0] <== base[0];
 53    adr4.in1[1] <== base[1];
 54    adr4.in2[0] <== adr3.out[0];
 55    adr4.in2[1] <== adr3.out[1];
 56    mux.c[0][3] <== adr4.out[0];
 57    mux.c[1][3] <== adr4.out[1];
 58
 59// in[4] -> 5*BASE
 60    adr5.in1[0] <== base[0];
 61    adr5.in1[1] <== base[1];
 62    adr5.in2[0] <== adr4.out[0];
 63    adr5.in2[1] <== adr4.out[1];
 64    mux.c[0][4] <== adr5.out[0];
 65    mux.c[1][4] <== adr5.out[1];
 66
 67// in[5] -> 6*BASE
 68    adr6.in1[0] <== base[0];
 69    adr6.in1[1] <== base[1];
 70    adr6.in2[0] <== adr5.out[0];
 71    adr6.in2[1] <== adr5.out[1];
 72    mux.c[0][5] <== adr6.out[0];
 73    mux.c[1][5] <== adr6.out[1];
 74
 75// in[6] -> 7*BASE
 76    adr7.in1[0] <== base[0];
 77    adr7.in1[1] <== base[1];
 78    adr7.in2[0] <== adr6.out[0];
 79    adr7.in2[1] <== adr6.out[1];
 80    mux.c[0][6] <== adr7.out[0];
 81    mux.c[1][6] <== adr7.out[1];
 82
 83// in[7] -> 8*BASE
 84    adr8.in1[0] <== base[0];
 85    adr8.in1[1] <== base[1];
 86    adr8.in2[0] <== adr7.out[0];
 87    adr8.in2[1] <== adr7.out[1];
 88    mux.c[0][7] <== adr8.out[0];
 89    mux.c[1][7] <== adr8.out[1];
 90
 91    out8[0] <== adr8.out[0];
 92    out8[1] <== adr8.out[1];
 93
 94    out[0] <== mux.out[0];
 95    out[1] <== mux.out[1];
 96}
 97
 98
 99/*
100    This component does a multiplication of a escalar times a fix base
101    Signals:
102        e: The scalar in bits
103        base: the base point in edwards format
104        out:  The result
105        dbl: Point in Edwards to be linked to the next segment.
106 */
107
108template SegmentMulFix(nWindows) {
109    signal input e[nWindows*3];
110    signal input base[2];
111    signal output out[2];
112    signal output dbl[2];
113
114    var i;
115    var j;
116
117    // Convert the base to montgomery
118
119    component e2m = Edwards2Montgomery();
120    e2m.in[0] <== base[0];
121    e2m.in[1] <== base[1];
122
123    component windows[nWindows];
124    component adders[nWindows-1];
125    component cadders[nWindows-1];
126    for (i=0; i<nWindows; i++) {
127        windows[i] = WindowMulFix();
128        if (i==0) {
129            windows[i].base[0] <== e2m.out[0];
130            windows[i].base[1] <== e2m.out[1];
131        } else {
132            windows[i].base[0] <== windows[i-1].out8[0];
133            windows[i].base[1] <== windows[i-1].out8[1];
134
135            adders[i-1] = MontgomeryAdd();
136            cadders[i-1] = MontgomeryAdd();
137            if (i==1) {
138                adders[i-1].in1[0] <== windows[0].out[0];
139                adders[i-1].in1[1] <== windows[0].out[1];
140                cadders[i-1].in1[0] <== e2m.out[0];
141                cadders[i-1].in1[1] <== e2m.out[1];
142            } else {
143                adders[i-1].in1[0] <== adders[i-2].out[0];
144                adders[i-1].in1[1] <== adders[i-2].out[1];
145                cadders[i-1].in1[0] <== cadders[i-2].out[0];
146                cadders[i-1].in1[1] <== cadders[i-2].out[1];
147            }
148            adders[i-1].in2[0] <== windows[i].out[0];
149            adders[i-1].in2[1] <== windows[i].out[1];
150            cadders[i-1].in2[0] <== windows[i-1].out8[0];
151            cadders[i-1].in2[1] <== windows[i-1].out8[1];
152        }
153        for (j=0; j<3; j++) {
154            windows[i].in[j] <== e[3*i+j];
155        }
156    }
157
158    component m2e = Montgomery2Edwards();
159    component cm2e = Montgomery2Edwards();
160
161    if (nWindows > 1) {
162        m2e.in[0] <== adders[nWindows-2].out[0];
163        m2e.in[1] <== adders[nWindows-2].out[1];
164        cm2e.in[0] <== cadders[nWindows-2].out[0];
165        cm2e.in[1] <== cadders[nWindows-2].out[1];
166    } else {
167        m2e.in[0] <== windows[0].out[0];
168        m2e.in[1] <== windows[0].out[1];
169        cm2e.in[0] <== e2m.out[0];
170        cm2e.in[1] <== e2m.out[1];
171    }
172
173    component cAdd = BabyAdd();
174    cAdd.x1 <== m2e.out[0];
175    cAdd.y1 <== m2e.out[1];
176    cAdd.x2 <== -cm2e.out[0];
177    cAdd.y2 <== cm2e.out[1];
178
179
180    cAdd.xout ==> out[0];
181    cAdd.yout ==> out[1];
182
183    windows[nWindows-1].out8[0] ==> dbl[0];
184    windows[nWindows-1].out8[1] ==> dbl[1];
185}
186
187
188/*
189This component multiplies a escalar times a fixed point BASE (twisted edwards format)
190    Signals
191        e: The escalar in binary format
192        out: The output point in twisted edwards
193 */
194template EscalarMulFix(n, BASE) {
195    signal input e[n];              // Input in binary format
196    signal output out[2];           // Point (Twisted format)
197
198    var nsegments = (n-1)\249 +1;
199    var nlastsegment = n - (nsegments-1)*249;
200
201    component segments[nsegments];
202
203    component m2e[nsegments-1];
204    component adders[nsegments-1];
205
206    var s;
207    var i;
208    var nseg;
209    var nWindows
210
211    for (s=0; s<nsegments; s++) {
212
213        nseg = (s < nsegments-1) ? 249 : nlastsegment;
214        nWindows = ((nseg - 1)\3)+1;
215
216        segments[s] = SegmentMulFix(nWindows);
217
218        for (i=0; i<nseg; i++) {
219            segments[s].e[i] <== e[s*249+i];
220        }
221
222        for (i = nseg; i<nWindows*3; i++) {
223            segments[s].e[i] <== 0;
224        }
225
226        if (s==0) {
227            segments[s].base[0] <== BASE[0];
228            segments[s].base[1] <== BASE[1];
229        } else {
230            m2e[s-1] = Montgomery2Edwards();
231            adders[s-1] = BabyAdd();
232
233            segments[s-1].dbl[0] ==> m2e[s-1].in[0];
234            segments[s-1].dbl[1] ==> m2e[s-1].in[1];
235
236            m2e[s-1].out[0] ==> segments[s].base[0];
237            m2e[s-1].out[1] ==> segments[s].base[1];
238
239            if (s==1) {
240                segments[s-1].out[0] ==> adders[s-1].x1;
241                segments[s-1].out[1] ==> adders[s-1].y1;
242            } else {
243                adders[s-2].xout ==> adders[s-1].x1;
244                adders[s-2].yout ==> adders[s-1].y1;
245            }
246            segments[s].out[0] ==> adders[s-1].x2;
247            segments[s].out[1] ==> adders[s-1].y2;
248        }
249    }
250
251    if (nsegments == 1) {
252        segments[0].out[0] ==> out[0];
253        segments[0].out[1] ==> out[1];
254    } else {
255        adders[nsegments-2].xout ==> out[0];
256        adders[nsegments-2].yout ==> out[1];
257    }
258}