forked from tornado-packages/archive-monorepo
301 lines
8.5 KiB
Plaintext
301 lines
8.5 KiB
Plaintext
|
/*
|
||
|
Copyright 2018 0KIMS association.
|
||
|
|
||
|
This file is part of circom (Zero Knowledge Circuit Compiler).
|
||
|
|
||
|
circom is a 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.
|
||
|
|
||
|
circom 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 circom. If not, see <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
include "mux3.circom";
|
||
|
include "montgomery.circom";
|
||
|
include "babyjub.circom";
|
||
|
|
||
|
/*
|
||
|
Window of 3 elements, it calculates
|
||
|
out = base + base*in[0] + 2*base*in[1] + 4*base*in[2]
|
||
|
out4 = 4*base
|
||
|
|
||
|
The result should be compensated.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
|
||
|
The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243
|
||
|
First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B
|
||
|
|
||
|
Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B
|
||
|
|
||
|
And Finaly we compute the result: RES = SQ - Q
|
||
|
|
||
|
As you can see the input of the adders cannot be equal nor zero, except for the last
|
||
|
substraction that it's done in montgomery.
|
||
|
|
||
|
A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
|
||
|
is the output of the windows that it's going to be <= 2^246*B
|
||
|
*/
|
||
|
/* base must not be the neutral element nor points of small order */
|
||
|
template WindowMulFix() {
|
||
|
signal input in[3];
|
||
|
signal input base[2];
|
||
|
signal output out[2];
|
||
|
signal output out8[2]; // Returns 8*Base (To be linked)
|
||
|
|
||
|
component mux = MultiMux3(2);
|
||
|
|
||
|
mux.s[0] <== in[0];
|
||
|
mux.s[1] <== in[1];
|
||
|
mux.s[2] <== in[2];
|
||
|
|
||
|
component dbl2 = MontgomeryDouble();
|
||
|
component adr3 = MontgomeryAdd();
|
||
|
component adr4 = MontgomeryAdd();
|
||
|
component adr5 = MontgomeryAdd();
|
||
|
component adr6 = MontgomeryAdd();
|
||
|
component adr7 = MontgomeryAdd();
|
||
|
component adr8 = MontgomeryAdd();
|
||
|
|
||
|
// in[0] -> 1*BASE
|
||
|
|
||
|
mux.c[0][0] <== base[0];
|
||
|
mux.c[1][0] <== base[1];
|
||
|
|
||
|
// in[1] -> 2*BASE
|
||
|
dbl2.in[0] <== base[0];
|
||
|
dbl2.in[1] <== base[1];
|
||
|
mux.c[0][1] <== dbl2.out[0];
|
||
|
mux.c[1][1] <== dbl2.out[1];
|
||
|
|
||
|
// in[2] -> 3*BASE
|
||
|
adr3.in1[0] <== base[0];
|
||
|
adr3.in1[1] <== base[1];
|
||
|
adr3.in2[0] <== dbl2.out[0];
|
||
|
adr3.in2[1] <== dbl2.out[1];
|
||
|
mux.c[0][2] <== adr3.out[0];
|
||
|
mux.c[1][2] <== adr3.out[1];
|
||
|
|
||
|
// in[3] -> 4*BASE
|
||
|
adr4.in1[0] <== base[0];
|
||
|
adr4.in1[1] <== base[1];
|
||
|
adr4.in2[0] <== adr3.out[0];
|
||
|
adr4.in2[1] <== adr3.out[1];
|
||
|
mux.c[0][3] <== adr4.out[0];
|
||
|
mux.c[1][3] <== adr4.out[1];
|
||
|
|
||
|
// in[4] -> 5*BASE
|
||
|
adr5.in1[0] <== base[0];
|
||
|
adr5.in1[1] <== base[1];
|
||
|
adr5.in2[0] <== adr4.out[0];
|
||
|
adr5.in2[1] <== adr4.out[1];
|
||
|
mux.c[0][4] <== adr5.out[0];
|
||
|
mux.c[1][4] <== adr5.out[1];
|
||
|
|
||
|
// in[5] -> 6*BASE
|
||
|
adr6.in1[0] <== base[0];
|
||
|
adr6.in1[1] <== base[1];
|
||
|
adr6.in2[0] <== adr5.out[0];
|
||
|
adr6.in2[1] <== adr5.out[1];
|
||
|
mux.c[0][5] <== adr6.out[0];
|
||
|
mux.c[1][5] <== adr6.out[1];
|
||
|
|
||
|
// in[6] -> 7*BASE
|
||
|
adr7.in1[0] <== base[0];
|
||
|
adr7.in1[1] <== base[1];
|
||
|
adr7.in2[0] <== adr6.out[0];
|
||
|
adr7.in2[1] <== adr6.out[1];
|
||
|
mux.c[0][6] <== adr7.out[0];
|
||
|
mux.c[1][6] <== adr7.out[1];
|
||
|
|
||
|
// in[7] -> 8*BASE
|
||
|
adr8.in1[0] <== base[0];
|
||
|
adr8.in1[1] <== base[1];
|
||
|
adr8.in2[0] <== adr7.out[0];
|
||
|
adr8.in2[1] <== adr7.out[1];
|
||
|
mux.c[0][7] <== adr8.out[0];
|
||
|
mux.c[1][7] <== adr8.out[1];
|
||
|
|
||
|
out8[0] <== adr8.out[0];
|
||
|
out8[1] <== adr8.out[1];
|
||
|
|
||
|
out[0] <== mux.out[0];
|
||
|
out[1] <== mux.out[1];
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
This component does a multiplication of a escalar times a fix base
|
||
|
nWindows must not exceed 82
|
||
|
Signals:
|
||
|
e: The scalar in bits
|
||
|
base: the base point in edwards format
|
||
|
out: The result
|
||
|
dbl: Point in Montgomery to be linked to the next segment.
|
||
|
*/
|
||
|
|
||
|
template SegmentMulFix(nWindows) {
|
||
|
signal input e[nWindows*3];
|
||
|
signal input base[2];
|
||
|
signal output out[2];
|
||
|
signal output dbl[2];
|
||
|
|
||
|
var i;
|
||
|
var j;
|
||
|
|
||
|
// Convert the base to montgomery
|
||
|
|
||
|
component e2m = Edwards2Montgomery();
|
||
|
e2m.in[0] <== base[0];
|
||
|
e2m.in[1] <== base[1];
|
||
|
|
||
|
component windows[nWindows];
|
||
|
component adders[nWindows];
|
||
|
component cadders[nWindows];
|
||
|
|
||
|
// In the last step we add an extra doubler so that numbers do not match.
|
||
|
component dblLast = MontgomeryDouble();
|
||
|
|
||
|
for (i=0; i<nWindows; i++) {
|
||
|
windows[i] = WindowMulFix();
|
||
|
cadders[i] = MontgomeryAdd();
|
||
|
if (i==0) {
|
||
|
windows[i].base[0] <== e2m.out[0];
|
||
|
windows[i].base[1] <== e2m.out[1];
|
||
|
cadders[i].in1[0] <== e2m.out[0];
|
||
|
cadders[i].in1[1] <== e2m.out[1];
|
||
|
} else {
|
||
|
windows[i].base[0] <== windows[i-1].out8[0];
|
||
|
windows[i].base[1] <== windows[i-1].out8[1];
|
||
|
cadders[i].in1[0] <== cadders[i-1].out[0];
|
||
|
cadders[i].in1[1] <== cadders[i-1].out[1];
|
||
|
}
|
||
|
if (i<nWindows-1) {
|
||
|
cadders[i].in2[0] <== windows[i].out8[0];
|
||
|
cadders[i].in2[1] <== windows[i].out8[1];
|
||
|
} else {
|
||
|
dblLast.in[0] <== windows[i].out8[0];
|
||
|
dblLast.in[1] <== windows[i].out8[1];
|
||
|
cadders[i].in2[0] <== dblLast.out[0];
|
||
|
cadders[i].in2[1] <== dblLast.out[1];
|
||
|
}
|
||
|
for (j=0; j<3; j++) {
|
||
|
windows[i].in[j] <== e[3*i+j];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i=0; i<nWindows; i++) {
|
||
|
adders[i] = MontgomeryAdd();
|
||
|
if (i==0) {
|
||
|
adders[i].in1[0] <== dblLast.out[0];
|
||
|
adders[i].in1[1] <== dblLast.out[1];
|
||
|
} else {
|
||
|
adders[i].in1[0] <== adders[i-1].out[0];
|
||
|
adders[i].in1[1] <== adders[i-1].out[1];
|
||
|
}
|
||
|
adders[i].in2[0] <== windows[i].out[0];
|
||
|
adders[i].in2[1] <== windows[i].out[1];
|
||
|
}
|
||
|
|
||
|
component m2e = Montgomery2Edwards();
|
||
|
component cm2e = Montgomery2Edwards();
|
||
|
|
||
|
m2e.in[0] <== adders[nWindows-1].out[0];
|
||
|
m2e.in[1] <== adders[nWindows-1].out[1];
|
||
|
cm2e.in[0] <== cadders[nWindows-1].out[0];
|
||
|
cm2e.in[1] <== cadders[nWindows-1].out[1];
|
||
|
|
||
|
component cAdd = BabyAdd();
|
||
|
cAdd.x1 <== m2e.out[0];
|
||
|
cAdd.y1 <== m2e.out[1];
|
||
|
cAdd.x2 <== -cm2e.out[0];
|
||
|
cAdd.y2 <== cm2e.out[1];
|
||
|
|
||
|
cAdd.xout ==> out[0];
|
||
|
cAdd.yout ==> out[1];
|
||
|
|
||
|
windows[nWindows-1].out8[0] ==> dbl[0];
|
||
|
windows[nWindows-1].out8[1] ==> dbl[1];
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
This component multiplies a escalar times a fixed point BASE (twisted edwards format)
|
||
|
Signals
|
||
|
e: The escalar in binary format
|
||
|
out: The output point in twisted edwards
|
||
|
*/
|
||
|
template EscalarMulFix(n, BASE) {
|
||
|
signal input e[n]; // Input in binary format
|
||
|
signal output out[2]; // Point (Twisted format)
|
||
|
|
||
|
var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
|
||
|
var nlastsegment = n - (nsegments-1)*246;
|
||
|
|
||
|
component segments[nsegments];
|
||
|
|
||
|
component m2e[nsegments-1];
|
||
|
component adders[nsegments-1];
|
||
|
|
||
|
var s;
|
||
|
var i;
|
||
|
var nseg;
|
||
|
var nWindows;
|
||
|
|
||
|
for (s=0; s<nsegments; s++) {
|
||
|
|
||
|
nseg = (s < nsegments-1) ? 246 : nlastsegment;
|
||
|
nWindows = ((nseg - 1)\3)+1;
|
||
|
|
||
|
segments[s] = SegmentMulFix(nWindows);
|
||
|
|
||
|
for (i=0; i<nseg; i++) {
|
||
|
segments[s].e[i] <== e[s*246+i];
|
||
|
}
|
||
|
|
||
|
for (i = nseg; i<nWindows*3; i++) {
|
||
|
segments[s].e[i] <== 0;
|
||
|
}
|
||
|
|
||
|
if (s==0) {
|
||
|
segments[s].base[0] <== BASE[0];
|
||
|
segments[s].base[1] <== BASE[1];
|
||
|
} else {
|
||
|
m2e[s-1] = Montgomery2Edwards();
|
||
|
adders[s-1] = BabyAdd();
|
||
|
|
||
|
segments[s-1].dbl[0] ==> m2e[s-1].in[0];
|
||
|
segments[s-1].dbl[1] ==> m2e[s-1].in[1];
|
||
|
|
||
|
m2e[s-1].out[0] ==> segments[s].base[0];
|
||
|
m2e[s-1].out[1] ==> segments[s].base[1];
|
||
|
|
||
|
if (s==1) {
|
||
|
segments[s-1].out[0] ==> adders[s-1].x1;
|
||
|
segments[s-1].out[1] ==> adders[s-1].y1;
|
||
|
} else {
|
||
|
adders[s-2].xout ==> adders[s-1].x1;
|
||
|
adders[s-2].yout ==> adders[s-1].y1;
|
||
|
}
|
||
|
segments[s].out[0] ==> adders[s-1].x2;
|
||
|
segments[s].out[1] ==> adders[s-1].y2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (nsegments == 1) {
|
||
|
segments[0].out[0] ==> out[0];
|
||
|
segments[0].out[1] ==> out[1];
|
||
|
} else {
|
||
|
adders[nsegments-2].xout ==> out[0];
|
||
|
adders[nsegments-2].yout ==> out[1];
|
||
|
}
|
||
|
}
|