diff --git a/circuits/circomlib/babyjub.circom b/circuits/circomlib/babyjub.circom
new file mode 100644
index 0000000..36810fe
--- /dev/null
+++ b/circuits/circomlib/babyjub.circom
@@ -0,0 +1,107 @@
+/*
+ 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 .
+*/
+pragma circom 2.0.0;
+
+include "bitify.circom";
+include "escalarmulfix.circom";
+
+template BabyAdd() {
+ signal input x1;
+ signal input y1;
+ signal input x2;
+ signal input y2;
+ signal output xout;
+ signal output yout;
+
+ signal beta;
+ signal gamma;
+ signal delta;
+ signal tau;
+
+ var a = 168700;
+ var d = 168696;
+
+ beta <== x1*y2;
+ gamma <== y1*x2;
+ delta <== (-a*x1+y1)*(x2 + y2);
+ tau <== beta * gamma;
+
+ xout <-- (beta + gamma) / (1+ d*tau);
+ (1+ d*tau) * xout === (beta + gamma);
+
+ yout <-- (delta + a*beta - gamma) / (1-d*tau);
+ (1-d*tau)*yout === (delta + a*beta - gamma);
+}
+
+template BabyDbl() {
+ signal input x;
+ signal input y;
+ signal output xout;
+ signal output yout;
+
+ component adder = BabyAdd();
+ adder.x1 <== x;
+ adder.y1 <== y;
+ adder.x2 <== x;
+ adder.y2 <== y;
+
+ adder.xout ==> xout;
+ adder.yout ==> yout;
+}
+
+
+template BabyCheck() {
+ signal input x;
+ signal input y;
+
+ signal x2;
+ signal y2;
+
+ var a = 168700;
+ var d = 168696;
+
+ x2 <== x*x;
+ y2 <== y*y;
+
+ a*x2 + y2 === 1 + d*x2*y2;
+}
+
+// Extracts the public key from private key
+template BabyPbk() {
+ signal input in;
+ signal output Ax;
+ signal output Ay;
+
+ var BASE8[2] = [
+ 5299619240641551281634865583518297030282874472190772894086521144482721001553,
+ 16950150798460657717958625567821834550301663161624707787222815936182638968203
+ ];
+
+ component pvkBits = Num2Bits(253);
+ pvkBits.in <== in;
+
+ component mulFix = EscalarMulFix(253, BASE8);
+
+ var i;
+ for (i=0; i<253; i++) {
+ mulFix.e[i] <== pvkBits.out[i];
+ }
+ Ax <== mulFix.out[0];
+ Ay <== mulFix.out[1];
+}
diff --git a/circuits/circomlib/escalarmulany.circom b/circuits/circomlib/escalarmulany.circom
new file mode 100644
index 0000000..f07fe7d
--- /dev/null
+++ b/circuits/circomlib/escalarmulany.circom
@@ -0,0 +1,197 @@
+/*
+ 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 .
+*/
+pragma circom 2.0.0;
+
+include "montgomery.circom";
+include "babyjub.circom";
+include "comparators.circom";
+
+template Multiplexor2() {
+ signal input sel;
+ signal input in[2][2];
+ signal output out[2];
+
+ out[0] <== (in[1][0] - in[0][0])*sel + in[0][0];
+ out[1] <== (in[1][1] - in[0][1])*sel + in[0][1];
+}
+
+template BitElementMulAny() {
+ signal input sel;
+ signal input dblIn[2];
+ signal input addIn[2];
+ signal output dblOut[2];
+ signal output addOut[2];
+
+ component doubler = MontgomeryDouble();
+ component adder = MontgomeryAdd();
+ component selector = Multiplexor2();
+
+
+ sel ==> selector.sel;
+
+ dblIn[0] ==> doubler.in[0];
+ dblIn[1] ==> doubler.in[1];
+ doubler.out[0] ==> adder.in1[0];
+ doubler.out[1] ==> adder.in1[1];
+ addIn[0] ==> adder.in2[0];
+ addIn[1] ==> adder.in2[1];
+ addIn[0] ==> selector.in[0][0];
+ addIn[1] ==> selector.in[0][1];
+ adder.out[0] ==> selector.in[1][0];
+ adder.out[1] ==> selector.in[1][1];
+
+ doubler.out[0] ==> dblOut[0];
+ doubler.out[1] ==> dblOut[1];
+ selector.out[0] ==> addOut[0];
+ selector.out[1] ==> addOut[1];
+}
+
+// p is montgomery point
+// n must be <= 248
+// returns out in twisted edwards
+// Double is in montgomery to be linked;
+
+template SegmentMulAny(n) {
+ signal input e[n];
+ signal input p[2];
+ signal output out[2];
+ signal output dbl[2];
+
+ component bits[n-1];
+
+ component e2m = Edwards2Montgomery();
+
+ p[0] ==> e2m.in[0];
+ p[1] ==> e2m.in[1];
+
+ var i;
+
+ bits[0] = BitElementMulAny();
+ e2m.out[0] ==> bits[0].dblIn[0];
+ e2m.out[1] ==> bits[0].dblIn[1];
+ e2m.out[0] ==> bits[0].addIn[0];
+ e2m.out[1] ==> bits[0].addIn[1];
+ e[1] ==> bits[0].sel;
+
+ for (i=1; i bits[i].dblIn[0];
+ bits[i-1].dblOut[1] ==> bits[i].dblIn[1];
+ bits[i-1].addOut[0] ==> bits[i].addIn[0];
+ bits[i-1].addOut[1] ==> bits[i].addIn[1];
+ e[i+1] ==> bits[i].sel;
+ }
+
+ bits[n-2].dblOut[0] ==> dbl[0];
+ bits[n-2].dblOut[1] ==> dbl[1];
+
+ component m2e = Montgomery2Edwards();
+
+ bits[n-2].addOut[0] ==> m2e.in[0];
+ bits[n-2].addOut[1] ==> m2e.in[1];
+
+ component eadder = BabyAdd();
+
+ m2e.out[0] ==> eadder.x1;
+ m2e.out[1] ==> eadder.y1;
+ -p[0] ==> eadder.x2;
+ p[1] ==> eadder.y2;
+
+ component lastSel = Multiplexor2();
+
+ e[0] ==> lastSel.sel;
+ eadder.xout ==> lastSel.in[0][0];
+ eadder.yout ==> lastSel.in[0][1];
+ m2e.out[0] ==> lastSel.in[1][0];
+ m2e.out[1] ==> lastSel.in[1][1];
+
+ lastSel.out[0] ==> out[0];
+ lastSel.out[1] ==> out[1];
+}
+
+// This function assumes that p is in the subgroup and it is different to 0
+
+template EscalarMulAny(n) {
+ signal input e[n]; // Input in binary format
+ signal input p[2]; // Point (Twisted format)
+ signal output out[2]; // Point (Twisted format)
+
+ var nsegments = (n-1)\148 +1;
+ var nlastsegment = n - (nsegments-1)*148;
+
+ component segments[nsegments];
+ component doublers[nsegments-1];
+ component m2e[nsegments-1];
+ component adders[nsegments-1];
+ component zeropoint = IsZero();
+ zeropoint.in <== p[0];
+
+ var s;
+ var i;
+ var nseg;
+
+ for (s=0; s segments[s].e[i];
+ }
+
+ if (s==0) {
+ // force G8 point if input point is zero
+ segments[s].p[0] <== p[0] + (5299619240641551281634865583518297030282874472190772894086521144482721001553 - p[0])*zeropoint.out;
+ segments[s].p[1] <== p[1] + (16950150798460657717958625567821834550301663161624707787222815936182638968203 - p[1])*zeropoint.out;
+ } else {
+ doublers[s-1] = MontgomeryDouble();
+ m2e[s-1] = Montgomery2Edwards();
+ adders[s-1] = BabyAdd();
+
+ segments[s-1].dbl[0] ==> doublers[s-1].in[0];
+ segments[s-1].dbl[1] ==> doublers[s-1].in[1];
+
+ doublers[s-1].out[0] ==> m2e[s-1].in[0];
+ doublers[s-1].out[1] ==> m2e[s-1].in[1];
+
+ m2e[s-1].out[0] ==> segments[s].p[0];
+ m2e[s-1].out[1] ==> segments[s].p[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]*(1-zeropoint.out) ==> out[0];
+ segments[0].out[1]+(1-segments[0].out[1])*zeropoint.out ==> out[1];
+ } else {
+ adders[nsegments-2].xout*(1-zeropoint.out) ==> out[0];
+ adders[nsegments-2].yout+(1-adders[nsegments-2].yout)*zeropoint.out ==> out[1];
+ }
+}
diff --git a/circuits/circomlib/escalarmulfix.circom b/circuits/circomlib/escalarmulfix.circom
new file mode 100644
index 0000000..4669d36
--- /dev/null
+++ b/circuits/circomlib/escalarmulfix.circom
@@ -0,0 +1,299 @@
+/*
+ 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 .
+*/
+pragma circom 2.0.0;
+
+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
+ */
+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
+ Signals:
+ e: The scalar in bits
+ base: the base point in edwards format
+ out: The result
+ dbl: Point in Edwards 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 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)*249;
+
+ component segments[nsegments];
+
+ component m2e[nsegments-1];
+ component adders[nsegments-1];
+
+ var s;
+ var i;
+ var nseg;
+ var nWindows;
+
+ for (s=0; s 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];
+ }
+}
diff --git a/circuits/circomlib/mimc.circom b/circuits/circomlib/mimc.circom
new file mode 100644
index 0000000..1f963a9
--- /dev/null
+++ b/circuits/circomlib/mimc.circom
@@ -0,0 +1,156 @@
+/*
+ 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 .
+*/
+pragma circom 2.0.0;
+
+template MiMC7(nrounds) {
+ signal input x_in;
+ signal input k;
+ signal output out;
+
+ var c[91] = [
+ 0,
+ 20888961410941983456478427210666206549300505294776164667214940546594746570981,
+ 15265126113435022738560151911929040668591755459209400716467504685752745317193,
+ 8334177627492981984476504167502758309043212251641796197711684499645635709656,
+ 1374324219480165500871639364801692115397519265181803854177629327624133579404,
+ 11442588683664344394633565859260176446561886575962616332903193988751292992472,
+ 2558901189096558760448896669327086721003508630712968559048179091037845349145,
+ 11189978595292752354820141775598510151189959177917284797737745690127318076389,
+ 3262966573163560839685415914157855077211340576201936620532175028036746741754,
+ 17029914891543225301403832095880481731551830725367286980611178737703889171730,
+ 4614037031668406927330683909387957156531244689520944789503628527855167665518,
+ 19647356996769918391113967168615123299113119185942498194367262335168397100658,
+ 5040699236106090655289931820723926657076483236860546282406111821875672148900,
+ 2632385916954580941368956176626336146806721642583847728103570779270161510514,
+ 17691411851977575435597871505860208507285462834710151833948561098560743654671,
+ 11482807709115676646560379017491661435505951727793345550942389701970904563183,
+ 8360838254132998143349158726141014535383109403565779450210746881879715734773,
+ 12663821244032248511491386323242575231591777785787269938928497649288048289525,
+ 3067001377342968891237590775929219083706800062321980129409398033259904188058,
+ 8536471869378957766675292398190944925664113548202769136103887479787957959589,
+ 19825444354178182240559170937204690272111734703605805530888940813160705385792,
+ 16703465144013840124940690347975638755097486902749048533167980887413919317592,
+ 13061236261277650370863439564453267964462486225679643020432589226741411380501,
+ 10864774797625152707517901967943775867717907803542223029967000416969007792571,
+ 10035653564014594269791753415727486340557376923045841607746250017541686319774,
+ 3446968588058668564420958894889124905706353937375068998436129414772610003289,
+ 4653317306466493184743870159523234588955994456998076243468148492375236846006,
+ 8486711143589723036499933521576871883500223198263343024003617825616410932026,
+ 250710584458582618659378487568129931785810765264752039738223488321597070280,
+ 2104159799604932521291371026105311735948154964200596636974609406977292675173,
+ 16313562605837709339799839901240652934758303521543693857533755376563489378839,
+ 6032365105133504724925793806318578936233045029919447519826248813478479197288,
+ 14025118133847866722315446277964222215118620050302054655768867040006542798474,
+ 7400123822125662712777833064081316757896757785777291653271747396958201309118,
+ 1744432620323851751204287974553233986555641872755053103823939564833813704825,
+ 8316378125659383262515151597439205374263247719876250938893842106722210729522,
+ 6739722627047123650704294650168547689199576889424317598327664349670094847386,
+ 21211457866117465531949733809706514799713333930924902519246949506964470524162,
+ 13718112532745211817410303291774369209520657938741992779396229864894885156527,
+ 5264534817993325015357427094323255342713527811596856940387954546330728068658,
+ 18884137497114307927425084003812022333609937761793387700010402412840002189451,
+ 5148596049900083984813839872929010525572543381981952060869301611018636120248,
+ 19799686398774806587970184652860783461860993790013219899147141137827718662674,
+ 19240878651604412704364448729659032944342952609050243268894572835672205984837,
+ 10546185249390392695582524554167530669949955276893453512788278945742408153192,
+ 5507959600969845538113649209272736011390582494851145043668969080335346810411,
+ 18177751737739153338153217698774510185696788019377850245260475034576050820091,
+ 19603444733183990109492724100282114612026332366576932662794133334264283907557,
+ 10548274686824425401349248282213580046351514091431715597441736281987273193140,
+ 1823201861560942974198127384034483127920205835821334101215923769688644479957,
+ 11867589662193422187545516240823411225342068709600734253659804646934346124945,
+ 18718569356736340558616379408444812528964066420519677106145092918482774343613,
+ 10530777752259630125564678480897857853807637120039176813174150229243735996839,
+ 20486583726592018813337145844457018474256372770211860618687961310422228379031,
+ 12690713110714036569415168795200156516217175005650145422920562694422306200486,
+ 17386427286863519095301372413760745749282643730629659997153085139065756667205,
+ 2216432659854733047132347621569505613620980842043977268828076165669557467682,
+ 6309765381643925252238633914530877025934201680691496500372265330505506717193,
+ 20806323192073945401862788605803131761175139076694468214027227878952047793390,
+ 4037040458505567977365391535756875199663510397600316887746139396052445718861,
+ 19948974083684238245321361840704327952464170097132407924861169241740046562673,
+ 845322671528508199439318170916419179535949348988022948153107378280175750024,
+ 16222384601744433420585982239113457177459602187868460608565289920306145389382,
+ 10232118865851112229330353999139005145127746617219324244541194256766741433339,
+ 6699067738555349409504843460654299019000594109597429103342076743347235369120,
+ 6220784880752427143725783746407285094967584864656399181815603544365010379208,
+ 6129250029437675212264306655559561251995722990149771051304736001195288083309,
+ 10773245783118750721454994239248013870822765715268323522295722350908043393604,
+ 4490242021765793917495398271905043433053432245571325177153467194570741607167,
+ 19596995117319480189066041930051006586888908165330319666010398892494684778526,
+ 837850695495734270707668553360118467905109360511302468085569220634750561083,
+ 11803922811376367215191737026157445294481406304781326649717082177394185903907,
+ 10201298324909697255105265958780781450978049256931478989759448189112393506592,
+ 13564695482314888817576351063608519127702411536552857463682060761575100923924,
+ 9262808208636973454201420823766139682381973240743541030659775288508921362724,
+ 173271062536305557219323722062711383294158572562695717740068656098441040230,
+ 18120430890549410286417591505529104700901943324772175772035648111937818237369,
+ 20484495168135072493552514219686101965206843697794133766912991150184337935627,
+ 19155651295705203459475805213866664350848604323501251939850063308319753686505,
+ 11971299749478202793661982361798418342615500543489781306376058267926437157297,
+ 18285310723116790056148596536349375622245669010373674803854111592441823052978,
+ 7069216248902547653615508023941692395371990416048967468982099270925308100727,
+ 6465151453746412132599596984628739550147379072443683076388208843341824127379,
+ 16143532858389170960690347742477978826830511669766530042104134302796355145785,
+ 19362583304414853660976404410208489566967618125972377176980367224623492419647,
+ 1702213613534733786921602839210290505213503664731919006932367875629005980493,
+ 10781825404476535814285389902565833897646945212027592373510689209734812292327,
+ 4212716923652881254737947578600828255798948993302968210248673545442808456151,
+ 7594017890037021425366623750593200398174488805473151513558919864633711506220,
+ 18979889247746272055963929241596362599320706910852082477600815822482192194401,
+ 13602139229813231349386885113156901793661719180900395818909719758150455500533
+ ];
+
+ var t;
+ signal t2[nrounds];
+ signal t4[nrounds];
+ signal t6[nrounds];
+ signal t7[nrounds-1];
+
+ for (var i=0; i.
+*/
+
+/*
+ Source: https://en.wikipedia.org/wiki/Montgomery_curve
+
+ 1 + y 1 + y
+ [u, v] = [ ------- , ---------- ]
+ 1 - y (1 - y)x
+
+ */
+ pragma circom 2.0.0;
+
+template Edwards2Montgomery() {
+ signal input in[2];
+ signal output out[2];
+
+ out[0] <-- (1 + in[1]) / (1 - in[1]);
+ out[1] <-- out[0] / in[0];
+
+
+ out[0] * (1-in[1]) === (1 + in[1]);
+ out[1] * in[0] === out[0];
+}
+
+/*
+
+ u u - 1
+ [x, y] = [ ---, ------- ]
+ v u + 1
+
+ */
+template Montgomery2Edwards() {
+ signal input in[2];
+ signal output out[2];
+
+ out[0] <-- in[0] / in[1];
+ out[1] <-- (in[0] - 1) / (in[0] + 1);
+
+ out[0] * in[1] === in[0];
+ out[1] * (in[0] + 1) === in[0] - 1;
+}
+
+
+/*
+ x2 - x1
+ lamda = ---------
+ y2 - y1
+
+ x3 + A + x1 + x2
+ x3 = B * lamda^2 - A - x1 -x2 => lamda^2 = ------------------
+ B
+
+ y3 = (2*x1 + x2 + A)*lamda - B*lamda^3 - y1 =>
+
+
+ => y3 = lamda * ( 2*x1 + x2 + A - x3 - A - x1 - x2) - y1 =>
+
+ => y3 = lamda * ( x1 - x3 ) - y1
+
+----------
+
+ y2 - y1
+ lamda = ---------
+ x2 - x1
+
+ x3 = B * lamda^2 - A - x1 -x2
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+
+template MontgomeryAdd() {
+ signal input in1[2];
+ signal input in2[2];
+ signal output out[2];
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+
+ lamda <-- (in2[1] - in1[1]) / (in2[0] - in1[0]);
+ lamda * (in2[0] - in1[0]) === (in2[1] - in1[1]);
+
+ out[0] <== B*lamda*lamda - A - in1[0] -in2[0];
+ out[1] <== lamda * (in1[0] - out[0]) - in1[1];
+}
+
+/*
+
+ x1_2 = x1*x1
+
+ 3*x1_2 + 2*A*x1 + 1
+ lamda = ---------------------
+ 2*B*y1
+
+ x3 = B * lamda^2 - A - x1 -x1
+
+ y3 = lamda * ( x1 - x3 ) - y1
+
+ */
+template MontgomeryDouble() {
+ signal input in[2];
+ signal output out[2];
+
+ var a = 168700;
+ var d = 168696;
+
+ var A = (2 * (a + d)) / (a - d);
+ var B = 4 / (a - d);
+
+ signal lamda;
+ signal x1_2;
+
+ x1_2 <== in[0] * in[0];
+
+ lamda <-- (3*x1_2 + 2*A*in[0] + 1 ) / (2*B*in[1]);
+ lamda * (2*B*in[1]) === (3*x1_2 + 2*A*in[0] + 1 );
+
+ out[0] <== B*lamda*lamda - A - 2*in[0];
+ out[1] <== lamda * (in[0] - out[0]) - in[1];
+}
diff --git a/circuits/circomlib/mux3.circom b/circuits/circomlib/mux3.circom
new file mode 100644
index 0000000..4be5f7c
--- /dev/null
+++ b/circuits/circomlib/mux3.circom
@@ -0,0 +1,75 @@
+/*
+ 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 .
+*/
+pragma circom 2.0.0;
+
+template MultiMux3(n) {
+ signal input c[n][8]; // Constants
+ signal input s[3]; // Selector
+ signal output out[n];
+
+ signal a210[n];
+ signal a21[n];
+ signal a20[n];
+ signal a2[n];
+
+ signal a10[n];
+ signal a1[n];
+ signal a0[n];
+ signal a[n];
+
+ // 4 constrains for the intermediary variables
+ signal s10;
+ s10 <== s[1] * s[0];
+
+ for (var i=0; i mux.s[i];
+ }
+
+ mux.out[0] ==> out;
+}
diff --git a/circuits/crypto/ecdh.circom b/circuits/crypto/ecdh.circom
new file mode 100644
index 0000000..69983a5
--- /dev/null
+++ b/circuits/crypto/ecdh.circom
@@ -0,0 +1,29 @@
+// from privacy-scaling-explorations/maci
+
+pragma circom 2.0.0;
+
+include "../circomlib/bitify.circom";
+include "../circomlib/escalarmulany.circom";
+
+template Ecdh() {
+ // Note: private key
+ // Needs to be hashed, and then pruned before
+ // supplying it to the circuit
+ signal input private_key;
+ signal input public_key[2];
+
+ signal output shared_key;
+
+ component privBits = Num2Bits(253);
+ privBits.in <== private_key;
+
+ component mulFix = EscalarMulAny(253);
+ mulFix.p[0] <== public_key[0];
+ mulFix.p[1] <== public_key[1];
+
+ for (var i = 0; i < 253; i++) {
+ mulFix.e[i] <== privBits.out[i];
+ }
+
+ shared_key <== mulFix.out[0];
+}
\ No newline at end of file
diff --git a/circuits/crypto/encrypt.circom b/circuits/crypto/encrypt.circom
new file mode 100644
index 0000000..382325e
--- /dev/null
+++ b/circuits/crypto/encrypt.circom
@@ -0,0 +1,74 @@
+//from zk-ml/linear-regression-demo
+
+pragma circom 2.0.0;
+
+include "../circomlib/mimc.circom";
+
+template EncryptBits(N) {
+ signal input plaintext[N];
+ signal input shared_key;
+ signal output out[N+1];
+
+ component mimc = MultiMiMC7(N, 91);
+ for (var i=0; i=10.0.0"
+ }
+ },
+ "node_modules/ethereumjs-util/node_modules/bn.js": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+ "dev": true
+ },
+ "node_modules/ethers": {
+ "version": "4.0.45",
+ "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.45.tgz",
+ "integrity": "sha512-N/Wmc6Mw4pQO+Sss1HnKDCSS6KSCx0luoBMiPNq+1GbOaO3YaZOyplBEhj+NEoYsizZYODtkITg2oecPeNnidQ==",
+ "dev": true,
+ "dependencies": {
+ "aes-js": "3.0.0",
+ "bn.js": "^4.4.0",
+ "elliptic": "6.5.2",
+ "hash.js": "1.1.3",
+ "js-sha3": "0.5.7",
+ "scrypt-js": "2.0.4",
+ "setimmediate": "1.0.4",
+ "uuid": "2.0.1",
+ "xmlhttprequest": "1.8.0"
+ }
+ },
+ "node_modules/ethers/node_modules/elliptic": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
+ "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^4.4.0",
+ "brorand": "^1.0.1",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.0"
+ }
+ },
+ "node_modules/ethers/node_modules/hash.js": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
+ "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "node_modules/ethers/node_modules/js-sha3": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz",
+ "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==",
+ "dev": true
+ },
+ "node_modules/ethers/node_modules/scrypt-js": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz",
+ "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==",
+ "dev": true
+ },
+ "node_modules/ethers/node_modules/setimmediate": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz",
+ "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==",
+ "dev": true
+ },
+ "node_modules/ethjs-unit": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz",
+ "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "4.11.6",
+ "number-to-bn": "1.7.0"
+ },
+ "engines": {
+ "node": ">=6.5.0",
+ "npm": ">=3"
+ }
+ },
+ "node_modules/ethjs-unit/node_modules/bn.js": {
+ "version": "4.11.6",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz",
+ "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==",
+ "dev": true
+ },
+ "node_modules/evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "dev": true,
+ "dependencies": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
}
},
"node_modules/fastfile": {
@@ -1572,6 +1852,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/hash-base": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+ "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/hash.js": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
@@ -1760,6 +2054,16 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-hex-prefixed": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz",
+ "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.5.0",
+ "npm": ">=3"
+ }
+ },
"node_modules/is-negative-zero": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
@@ -1927,6 +2231,27 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/keccak": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz",
+ "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "node-addon-api": "^2.0.0",
+ "node-gyp-build": "^4.2.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/keccak/node_modules/node-addon-api": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
+ "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==",
+ "dev": true
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -1967,6 +2292,17 @@
"get-func-name": "^2.0.0"
}
},
+ "node_modules/md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
+ "dependencies": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
"node_modules/minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@@ -2084,6 +2420,26 @@
"node": ">=0.10.0"
}
},
+ "node_modules/number-to-bn": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz",
+ "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "4.11.6",
+ "strip-hex-prefix": "1.0.0"
+ },
+ "engines": {
+ "node": ">=6.5.0",
+ "npm": ">=3"
+ }
+ },
+ "node_modules/number-to-bn/node_modules/bn.js": {
+ "version": "4.11.6",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz",
+ "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==",
+ "dev": true
+ },
"node_modules/object-inspect": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
@@ -2186,6 +2542,22 @@
"node": "*"
}
},
+ "node_modules/pbkdf2": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+ "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
+ "dev": true,
+ "dependencies": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -2289,6 +2661,34 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
+ "dependencies": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "node_modules/rlp": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz",
+ "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^5.2.0"
+ },
+ "bin": {
+ "rlp": "bin/rlp"
+ }
+ },
+ "node_modules/rlp/node_modules/bn.js": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+ "dev": true
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -2315,6 +2715,27 @@
"integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==",
"dev": true
},
+ "node_modules/secp256k1": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
+ "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "elliptic": "^6.5.4",
+ "node-addon-api": "^2.0.0",
+ "node-gyp-build": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/secp256k1/node_modules/node-addon-api": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
+ "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==",
+ "dev": true
+ },
"node_modules/serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
@@ -2324,6 +2745,25 @@
"randombytes": "^2.1.0"
}
},
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+ "dev": true
+ },
+ "node_modules/sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ },
+ "bin": {
+ "sha.js": "bin.js"
+ }
+ },
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -2399,6 +2839,19 @@
"node": ">=8"
}
},
+ "node_modules/strip-hex-prefix": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz",
+ "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==",
+ "dev": true,
+ "dependencies": {
+ "is-hex-prefixed": "1.0.0"
+ },
+ "engines": {
+ "node": ">=6.5.0",
+ "npm": ">=3"
+ }
+ },
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -2483,6 +2936,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/utf8": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
+ "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==",
+ "dev": true
+ },
"node_modules/util": {
"version": "0.12.4",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz",
@@ -2503,6 +2962,13 @@
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
+ "node_modules/uuid": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz",
+ "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==",
+ "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
+ "dev": true
+ },
"node_modules/wasmbuilder": {
"version": "0.0.12",
"resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.12.tgz",
@@ -2528,6 +2994,30 @@
"integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==",
"dev": true
},
+ "node_modules/web3-utils": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.1.tgz",
+ "integrity": "sha512-LgnM9p6V7rHHUGfpMZod+NST8cRfGzJ1BTXAyNo7A9cJX9LczBfSRxJp+U/GInYe9mby40t3v22AJdlELibnsQ==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^5.2.1",
+ "ethereum-bloom-filters": "^1.0.6",
+ "ethereumjs-util": "^7.1.0",
+ "ethjs-unit": "0.1.6",
+ "number-to-bn": "1.7.0",
+ "randombytes": "^2.1.0",
+ "utf8": "3.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/web3-utils/node_modules/bn.js": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+ "dev": true
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -2635,6 +3125,15 @@
}
}
},
+ "node_modules/xmlhttprequest": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
+ "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@@ -2701,402 +3200,420 @@
},
"dependencies": {
"@ethersproject/abi": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.0.tgz",
- "integrity": "sha512-AhVByTwdXCc2YQ20v300w6KVHle9g2OFc28ZAFCPnJyEpkv1xKXjZcSTgWOlv1i+0dqlgF8RCF2Rn2KC1t+1Vg==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz",
+ "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==",
"dev": true,
"requires": {
- "@ethersproject/address": "^5.6.0",
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/constants": "^5.6.0",
- "@ethersproject/hash": "^5.6.0",
- "@ethersproject/keccak256": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/strings": "^5.6.0"
+ "@ethersproject/address": "^5.7.0",
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/constants": "^5.7.0",
+ "@ethersproject/hash": "^5.7.0",
+ "@ethersproject/keccak256": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/strings": "^5.7.0"
}
},
"@ethersproject/abstract-provider": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz",
- "integrity": "sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz",
+ "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==",
"dev": true,
"requires": {
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/networks": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/transactions": "^5.6.0",
- "@ethersproject/web": "^5.6.0"
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/networks": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/transactions": "^5.7.0",
+ "@ethersproject/web": "^5.7.0"
}
},
"@ethersproject/abstract-signer": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz",
- "integrity": "sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz",
+ "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==",
"dev": true,
"requires": {
- "@ethersproject/abstract-provider": "^5.6.0",
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/properties": "^5.6.0"
+ "@ethersproject/abstract-provider": "^5.7.0",
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0"
}
},
"@ethersproject/address": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.0.tgz",
- "integrity": "sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz",
+ "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==",
"dev": true,
"requires": {
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/keccak256": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/rlp": "^5.6.0"
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/keccak256": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/rlp": "^5.7.0"
}
},
"@ethersproject/base64": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.0.tgz",
- "integrity": "sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz",
+ "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0"
+ "@ethersproject/bytes": "^5.7.0"
}
},
"@ethersproject/basex": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.6.0.tgz",
- "integrity": "sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz",
+ "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/properties": "^5.6.0"
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0"
}
},
"@ethersproject/bignumber": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.0.tgz",
- "integrity": "sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz",
+ "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "bn.js": "^4.11.9"
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "bn.js": "^5.2.1"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+ "dev": true
+ }
}
},
"@ethersproject/bytes": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.0.tgz",
- "integrity": "sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz",
+ "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==",
"dev": true,
"requires": {
- "@ethersproject/logger": "^5.6.0"
+ "@ethersproject/logger": "^5.7.0"
}
},
"@ethersproject/constants": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.0.tgz",
- "integrity": "sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz",
+ "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==",
"dev": true,
"requires": {
- "@ethersproject/bignumber": "^5.6.0"
+ "@ethersproject/bignumber": "^5.7.0"
}
},
"@ethersproject/contracts": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.6.0.tgz",
- "integrity": "sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz",
+ "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==",
"dev": true,
"requires": {
- "@ethersproject/abi": "^5.6.0",
- "@ethersproject/abstract-provider": "^5.6.0",
- "@ethersproject/abstract-signer": "^5.6.0",
- "@ethersproject/address": "^5.6.0",
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/constants": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/transactions": "^5.6.0"
+ "@ethersproject/abi": "^5.7.0",
+ "@ethersproject/abstract-provider": "^5.7.0",
+ "@ethersproject/abstract-signer": "^5.7.0",
+ "@ethersproject/address": "^5.7.0",
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/constants": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/transactions": "^5.7.0"
}
},
"@ethersproject/hash": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.0.tgz",
- "integrity": "sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz",
+ "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==",
"dev": true,
"requires": {
- "@ethersproject/abstract-signer": "^5.6.0",
- "@ethersproject/address": "^5.6.0",
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/keccak256": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/strings": "^5.6.0"
+ "@ethersproject/abstract-signer": "^5.7.0",
+ "@ethersproject/address": "^5.7.0",
+ "@ethersproject/base64": "^5.7.0",
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/keccak256": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/strings": "^5.7.0"
}
},
"@ethersproject/hdnode": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.6.0.tgz",
- "integrity": "sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz",
+ "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==",
"dev": true,
"requires": {
- "@ethersproject/abstract-signer": "^5.6.0",
- "@ethersproject/basex": "^5.6.0",
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/pbkdf2": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/sha2": "^5.6.0",
- "@ethersproject/signing-key": "^5.6.0",
- "@ethersproject/strings": "^5.6.0",
- "@ethersproject/transactions": "^5.6.0",
- "@ethersproject/wordlists": "^5.6.0"
+ "@ethersproject/abstract-signer": "^5.7.0",
+ "@ethersproject/basex": "^5.7.0",
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/pbkdf2": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/sha2": "^5.7.0",
+ "@ethersproject/signing-key": "^5.7.0",
+ "@ethersproject/strings": "^5.7.0",
+ "@ethersproject/transactions": "^5.7.0",
+ "@ethersproject/wordlists": "^5.7.0"
}
},
"@ethersproject/json-wallets": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.6.0.tgz",
- "integrity": "sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz",
+ "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==",
"dev": true,
"requires": {
- "@ethersproject/abstract-signer": "^5.6.0",
- "@ethersproject/address": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/hdnode": "^5.6.0",
- "@ethersproject/keccak256": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/pbkdf2": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/random": "^5.6.0",
- "@ethersproject/strings": "^5.6.0",
- "@ethersproject/transactions": "^5.6.0",
+ "@ethersproject/abstract-signer": "^5.7.0",
+ "@ethersproject/address": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/hdnode": "^5.7.0",
+ "@ethersproject/keccak256": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/pbkdf2": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/random": "^5.7.0",
+ "@ethersproject/strings": "^5.7.0",
+ "@ethersproject/transactions": "^5.7.0",
"aes-js": "3.0.0",
"scrypt-js": "3.0.1"
}
},
"@ethersproject/keccak256": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.0.tgz",
- "integrity": "sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz",
+ "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
+ "@ethersproject/bytes": "^5.7.0",
"js-sha3": "0.8.0"
}
},
"@ethersproject/logger": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz",
- "integrity": "sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz",
+ "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==",
"dev": true
},
"@ethersproject/networks": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.0.tgz",
- "integrity": "sha512-DaVzgyThzHgSDLuURhvkp4oviGoGe9iTZW4jMEORHDRCgSZ9K9THGFKqL+qGXqPAYLEgZTf5z2w56mRrPR1MjQ==",
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz",
+ "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==",
"dev": true,
"requires": {
- "@ethersproject/logger": "^5.6.0"
+ "@ethersproject/logger": "^5.7.0"
}
},
"@ethersproject/pbkdf2": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.6.0.tgz",
- "integrity": "sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz",
+ "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/sha2": "^5.6.0"
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/sha2": "^5.7.0"
}
},
"@ethersproject/properties": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.6.0.tgz",
- "integrity": "sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz",
+ "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==",
"dev": true,
"requires": {
- "@ethersproject/logger": "^5.6.0"
+ "@ethersproject/logger": "^5.7.0"
}
},
"@ethersproject/providers": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.6.0.tgz",
- "integrity": "sha512-6+5PKXTWAttJWFWF8+xCDTCa2/dtq9BNrdKQHGl0IyIOwj99vM6OeThmIRcsIAzIOb8m0XS6w+1KFZwrf3j9nw==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz",
+ "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==",
"dev": true,
"requires": {
- "@ethersproject/abstract-provider": "^5.6.0",
- "@ethersproject/abstract-signer": "^5.6.0",
- "@ethersproject/address": "^5.6.0",
- "@ethersproject/basex": "^5.6.0",
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/constants": "^5.6.0",
- "@ethersproject/hash": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/networks": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/random": "^5.6.0",
- "@ethersproject/rlp": "^5.6.0",
- "@ethersproject/sha2": "^5.6.0",
- "@ethersproject/strings": "^5.6.0",
- "@ethersproject/transactions": "^5.6.0",
- "@ethersproject/web": "^5.6.0",
+ "@ethersproject/abstract-provider": "^5.7.0",
+ "@ethersproject/abstract-signer": "^5.7.0",
+ "@ethersproject/address": "^5.7.0",
+ "@ethersproject/base64": "^5.7.0",
+ "@ethersproject/basex": "^5.7.0",
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/constants": "^5.7.0",
+ "@ethersproject/hash": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/networks": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/random": "^5.7.0",
+ "@ethersproject/rlp": "^5.7.0",
+ "@ethersproject/sha2": "^5.7.0",
+ "@ethersproject/strings": "^5.7.0",
+ "@ethersproject/transactions": "^5.7.0",
+ "@ethersproject/web": "^5.7.0",
"bech32": "1.1.4",
"ws": "7.4.6"
}
},
"@ethersproject/random": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.6.0.tgz",
- "integrity": "sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz",
+ "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/logger": "^5.6.0"
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0"
}
},
"@ethersproject/rlp": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.0.tgz",
- "integrity": "sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz",
+ "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/logger": "^5.6.0"
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0"
}
},
"@ethersproject/sha2": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.0.tgz",
- "integrity": "sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz",
+ "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
"hash.js": "1.1.7"
}
},
"@ethersproject/signing-key": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.0.tgz",
- "integrity": "sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz",
+ "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "bn.js": "^4.11.9",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "bn.js": "^5.2.1",
"elliptic": "6.5.4",
"hash.js": "1.1.7"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+ "dev": true
+ }
}
},
"@ethersproject/solidity": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.6.0.tgz",
- "integrity": "sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz",
+ "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==",
"dev": true,
"requires": {
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/keccak256": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/sha2": "^5.6.0",
- "@ethersproject/strings": "^5.6.0"
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/keccak256": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/sha2": "^5.7.0",
+ "@ethersproject/strings": "^5.7.0"
}
},
"@ethersproject/strings": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.0.tgz",
- "integrity": "sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz",
+ "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/constants": "^5.6.0",
- "@ethersproject/logger": "^5.6.0"
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/constants": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0"
}
},
"@ethersproject/transactions": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.0.tgz",
- "integrity": "sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz",
+ "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==",
"dev": true,
"requires": {
- "@ethersproject/address": "^5.6.0",
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/constants": "^5.6.0",
- "@ethersproject/keccak256": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/rlp": "^5.6.0",
- "@ethersproject/signing-key": "^5.6.0"
+ "@ethersproject/address": "^5.7.0",
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/constants": "^5.7.0",
+ "@ethersproject/keccak256": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/rlp": "^5.7.0",
+ "@ethersproject/signing-key": "^5.7.0"
}
},
"@ethersproject/units": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.6.0.tgz",
- "integrity": "sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz",
+ "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==",
"dev": true,
"requires": {
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/constants": "^5.6.0",
- "@ethersproject/logger": "^5.6.0"
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/constants": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0"
}
},
"@ethersproject/wallet": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.6.0.tgz",
- "integrity": "sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz",
+ "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==",
"dev": true,
"requires": {
- "@ethersproject/abstract-provider": "^5.6.0",
- "@ethersproject/abstract-signer": "^5.6.0",
- "@ethersproject/address": "^5.6.0",
- "@ethersproject/bignumber": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/hash": "^5.6.0",
- "@ethersproject/hdnode": "^5.6.0",
- "@ethersproject/json-wallets": "^5.6.0",
- "@ethersproject/keccak256": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/random": "^5.6.0",
- "@ethersproject/signing-key": "^5.6.0",
- "@ethersproject/transactions": "^5.6.0",
- "@ethersproject/wordlists": "^5.6.0"
+ "@ethersproject/abstract-provider": "^5.7.0",
+ "@ethersproject/abstract-signer": "^5.7.0",
+ "@ethersproject/address": "^5.7.0",
+ "@ethersproject/bignumber": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/hash": "^5.7.0",
+ "@ethersproject/hdnode": "^5.7.0",
+ "@ethersproject/json-wallets": "^5.7.0",
+ "@ethersproject/keccak256": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/random": "^5.7.0",
+ "@ethersproject/signing-key": "^5.7.0",
+ "@ethersproject/transactions": "^5.7.0",
+ "@ethersproject/wordlists": "^5.7.0"
}
},
"@ethersproject/web": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.0.tgz",
- "integrity": "sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==",
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz",
+ "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==",
"dev": true,
"requires": {
- "@ethersproject/base64": "^5.6.0",
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/strings": "^5.6.0"
+ "@ethersproject/base64": "^5.7.0",
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/strings": "^5.7.0"
}
},
"@ethersproject/wordlists": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.6.0.tgz",
- "integrity": "sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q==",
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz",
+ "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==",
"dev": true,
"requires": {
- "@ethersproject/bytes": "^5.6.0",
- "@ethersproject/hash": "^5.6.0",
- "@ethersproject/logger": "^5.6.0",
- "@ethersproject/properties": "^5.6.0",
- "@ethersproject/strings": "^5.6.0"
+ "@ethersproject/bytes": "^5.7.0",
+ "@ethersproject/hash": "^5.7.0",
+ "@ethersproject/logger": "^5.7.0",
+ "@ethersproject/properties": "^5.7.0",
+ "@ethersproject/strings": "^5.7.0"
}
},
"@iden3/bigarray": {
@@ -3105,6 +3622,39 @@
"integrity": "sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==",
"dev": true
},
+ "@types/bn.js": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz",
+ "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/node": {
+ "version": "18.11.9",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
+ "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
+ "dev": true
+ },
+ "@types/pbkdf2": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz",
+ "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/secp256k1": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz",
+ "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@ungap/promise-all-settled": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
@@ -3114,7 +3664,7 @@
"aes-js": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz",
- "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=",
+ "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==",
"dev": true
},
"ansi-colors": {
@@ -3178,6 +3728,15 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
+ "base-x": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
+ "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"bech32": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
@@ -3270,6 +3829,46 @@
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
"dev": true
},
+ "browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "dev": true,
+ "requires": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "bs58": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
+ "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
+ "dev": true,
+ "requires": {
+ "base-x": "^3.0.2"
+ }
+ },
+ "bs58check": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
+ "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+ "dev": true,
+ "requires": {
+ "bs58": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
+ "dev": true
+ },
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -3350,6 +3949,16 @@
"readdirp": "~3.6.0"
}
},
+ "cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"circom_tester": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/circom_tester/-/circom_tester-0.0.5.tgz",
@@ -3387,6 +3996,46 @@
"blake2b": "^2.1.3",
"ethers": "^5.5.1",
"ffjavascript": "^0.2.45"
+ },
+ "dependencies": {
+ "ethers": {
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz",
+ "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==",
+ "dev": true,
+ "requires": {
+ "@ethersproject/abi": "5.7.0",
+ "@ethersproject/abstract-provider": "5.7.0",
+ "@ethersproject/abstract-signer": "5.7.0",
+ "@ethersproject/address": "5.7.0",
+ "@ethersproject/base64": "5.7.0",
+ "@ethersproject/basex": "5.7.0",
+ "@ethersproject/bignumber": "5.7.0",
+ "@ethersproject/bytes": "5.7.0",
+ "@ethersproject/constants": "5.7.0",
+ "@ethersproject/contracts": "5.7.0",
+ "@ethersproject/hash": "5.7.0",
+ "@ethersproject/hdnode": "5.7.0",
+ "@ethersproject/json-wallets": "5.7.0",
+ "@ethersproject/keccak256": "5.7.0",
+ "@ethersproject/logger": "5.7.0",
+ "@ethersproject/networks": "5.7.1",
+ "@ethersproject/pbkdf2": "5.7.0",
+ "@ethersproject/properties": "5.7.0",
+ "@ethersproject/providers": "5.7.2",
+ "@ethersproject/random": "5.7.0",
+ "@ethersproject/rlp": "5.7.0",
+ "@ethersproject/sha2": "5.7.0",
+ "@ethersproject/signing-key": "5.7.0",
+ "@ethersproject/solidity": "5.7.0",
+ "@ethersproject/strings": "5.7.0",
+ "@ethersproject/transactions": "5.7.0",
+ "@ethersproject/units": "5.7.0",
+ "@ethersproject/wallet": "5.7.0",
+ "@ethersproject/web": "5.7.1",
+ "@ethersproject/wordlists": "5.7.0"
+ }
+ }
}
},
"cliui": {
@@ -3421,6 +4070,33 @@
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
+ "create-hash": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "create-hmac": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
"debug": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
@@ -3540,42 +4216,147 @@
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
},
- "ethers": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.6.0.tgz",
- "integrity": "sha512-00FP71jt6bW3ndO5DhgH9mLIZhoCGnAKFLu8qig5KmV03ubEChKf2ilB3g6fX512tTYo+tSMDJ5WpCJWdBHkBQ==",
+ "ethereum-bloom-filters": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz",
+ "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==",
"dev": true,
"requires": {
- "@ethersproject/abi": "5.6.0",
- "@ethersproject/abstract-provider": "5.6.0",
- "@ethersproject/abstract-signer": "5.6.0",
- "@ethersproject/address": "5.6.0",
- "@ethersproject/base64": "5.6.0",
- "@ethersproject/basex": "5.6.0",
- "@ethersproject/bignumber": "5.6.0",
- "@ethersproject/bytes": "5.6.0",
- "@ethersproject/constants": "5.6.0",
- "@ethersproject/contracts": "5.6.0",
- "@ethersproject/hash": "5.6.0",
- "@ethersproject/hdnode": "5.6.0",
- "@ethersproject/json-wallets": "5.6.0",
- "@ethersproject/keccak256": "5.6.0",
- "@ethersproject/logger": "5.6.0",
- "@ethersproject/networks": "5.6.0",
- "@ethersproject/pbkdf2": "5.6.0",
- "@ethersproject/properties": "5.6.0",
- "@ethersproject/providers": "5.6.0",
- "@ethersproject/random": "5.6.0",
- "@ethersproject/rlp": "5.6.0",
- "@ethersproject/sha2": "5.6.0",
- "@ethersproject/signing-key": "5.6.0",
- "@ethersproject/solidity": "5.6.0",
- "@ethersproject/strings": "5.6.0",
- "@ethersproject/transactions": "5.6.0",
- "@ethersproject/units": "5.6.0",
- "@ethersproject/wallet": "5.6.0",
- "@ethersproject/web": "5.6.0",
- "@ethersproject/wordlists": "5.6.0"
+ "js-sha3": "^0.8.0"
+ }
+ },
+ "ethereum-cryptography": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz",
+ "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==",
+ "dev": true,
+ "requires": {
+ "@types/pbkdf2": "^3.0.0",
+ "@types/secp256k1": "^4.0.1",
+ "blakejs": "^1.1.0",
+ "browserify-aes": "^1.2.0",
+ "bs58check": "^2.1.2",
+ "create-hash": "^1.2.0",
+ "create-hmac": "^1.1.7",
+ "hash.js": "^1.1.7",
+ "keccak": "^3.0.0",
+ "pbkdf2": "^3.0.17",
+ "randombytes": "^2.1.0",
+ "safe-buffer": "^5.1.2",
+ "scrypt-js": "^3.0.0",
+ "secp256k1": "^4.0.1",
+ "setimmediate": "^1.0.5"
+ }
+ },
+ "ethereumjs-util": {
+ "version": "7.1.5",
+ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz",
+ "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==",
+ "dev": true,
+ "requires": {
+ "@types/bn.js": "^5.1.0",
+ "bn.js": "^5.1.2",
+ "create-hash": "^1.1.2",
+ "ethereum-cryptography": "^0.1.3",
+ "rlp": "^2.2.4"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+ "dev": true
+ }
+ }
+ },
+ "ethers": {
+ "version": "4.0.45",
+ "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.45.tgz",
+ "integrity": "sha512-N/Wmc6Mw4pQO+Sss1HnKDCSS6KSCx0luoBMiPNq+1GbOaO3YaZOyplBEhj+NEoYsizZYODtkITg2oecPeNnidQ==",
+ "dev": true,
+ "requires": {
+ "aes-js": "3.0.0",
+ "bn.js": "^4.4.0",
+ "elliptic": "6.5.2",
+ "hash.js": "1.1.3",
+ "js-sha3": "0.5.7",
+ "scrypt-js": "2.0.4",
+ "setimmediate": "1.0.4",
+ "uuid": "2.0.1",
+ "xmlhttprequest": "1.8.0"
+ },
+ "dependencies": {
+ "elliptic": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
+ "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.4.0",
+ "brorand": "^1.0.1",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.0"
+ }
+ },
+ "hash.js": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
+ "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "js-sha3": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz",
+ "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==",
+ "dev": true
+ },
+ "scrypt-js": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz",
+ "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==",
+ "dev": true
+ },
+ "setimmediate": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz",
+ "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==",
+ "dev": true
+ }
+ }
+ },
+ "ethjs-unit": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz",
+ "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==",
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.6",
+ "number-to-bn": "1.7.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.6",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz",
+ "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==",
+ "dev": true
+ }
+ }
+ },
+ "evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "dev": true,
+ "requires": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
}
},
"fastfile": {
@@ -3761,6 +4542,17 @@
"has-symbols": "^1.0.2"
}
},
+ "hash-base": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+ "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ }
+ },
"hash.js": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
@@ -3898,6 +4690,12 @@
"is-extglob": "^2.1.1"
}
},
+ "is-hex-prefixed": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz",
+ "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==",
+ "dev": true
+ },
"is-negative-zero": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
@@ -4008,6 +4806,25 @@
"argparse": "^2.0.1"
}
},
+ "keccak": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz",
+ "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==",
+ "dev": true,
+ "requires": {
+ "node-addon-api": "^2.0.0",
+ "node-gyp-build": "^4.2.0",
+ "readable-stream": "^3.6.0"
+ },
+ "dependencies": {
+ "node-addon-api": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
+ "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==",
+ "dev": true
+ }
+ }
+ },
"locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -4036,6 +4853,17 @@
"get-func-name": "^2.0.0"
}
},
+ "md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
"minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@@ -4125,6 +4953,24 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
+ "number-to-bn": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz",
+ "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==",
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.6",
+ "strip-hex-prefix": "1.0.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.6",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz",
+ "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==",
+ "dev": true
+ }
+ }
+ },
"object-inspect": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
@@ -4194,6 +5040,19 @@
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
"dev": true
},
+ "pbkdf2": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+ "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
+ "dev": true,
+ "requires": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -4278,6 +5137,33 @@
"glob": "^7.1.3"
}
},
+ "ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "rlp": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz",
+ "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^5.2.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+ "dev": true
+ }
+ }
+ },
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -4290,6 +5176,25 @@
"integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==",
"dev": true
},
+ "secp256k1": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
+ "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
+ "dev": true,
+ "requires": {
+ "elliptic": "^6.5.4",
+ "node-addon-api": "^2.0.0",
+ "node-gyp-build": "^4.2.0"
+ },
+ "dependencies": {
+ "node-addon-api": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
+ "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==",
+ "dev": true
+ }
+ }
+ },
"serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
@@ -4299,6 +5204,22 @@
"randombytes": "^2.1.0"
}
},
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+ "dev": true
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -4359,6 +5280,15 @@
"ansi-regex": "^5.0.1"
}
},
+ "strip-hex-prefix": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz",
+ "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==",
+ "dev": true,
+ "requires": {
+ "is-hex-prefixed": "1.0.0"
+ }
+ },
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -4419,6 +5349,12 @@
"which-boxed-primitive": "^1.0.2"
}
},
+ "utf8": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
+ "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==",
+ "dev": true
+ },
"util": {
"version": "0.12.4",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz",
@@ -4439,6 +5375,12 @@
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
+ "uuid": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz",
+ "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==",
+ "dev": true
+ },
"wasmbuilder": {
"version": "0.0.12",
"resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.12.tgz",
@@ -4464,6 +5406,29 @@
"integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==",
"dev": true
},
+ "web3-utils": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.1.tgz",
+ "integrity": "sha512-LgnM9p6V7rHHUGfpMZod+NST8cRfGzJ1BTXAyNo7A9cJX9LczBfSRxJp+U/GInYe9mby40t3v22AJdlELibnsQ==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^5.2.1",
+ "ethereum-bloom-filters": "^1.0.6",
+ "ethereumjs-util": "^7.1.0",
+ "ethjs-unit": "0.1.6",
+ "number-to-bn": "1.7.0",
+ "randombytes": "^2.1.0",
+ "utf8": "3.0.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
+ "dev": true
+ }
+ }
+ },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -4536,6 +5501,12 @@
"dev": true,
"requires": {}
},
+ "xmlhttprequest": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
+ "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==",
+ "dev": true
+ },
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/package.json b/package.json
index 2b3f33b..ed3cae6 100644
--- a/package.json
+++ b/package.json
@@ -23,12 +23,15 @@
"author": "Cathie So, PhD",
"license": "GPL-3.0",
"devDependencies": {
+ "@types/node": "^18.11.9",
"blake-hash": "^2.0.0",
"chai": "^4.3.4",
"circom_tester": "0.0.5",
"circomlib": "^2.0.3",
"circomlib-matrix": "^1.0.1",
"circomlibjs": "^0.1.0",
- "mocha": "^9.1.3"
+ "ethers": "^4.0.45",
+ "mocha": "^9.1.3",
+ "web3-utils": "^1.8.1"
}
}
diff --git a/test/circuits/ecdh_test.circom b/test/circuits/ecdh_test.circom
new file mode 100644
index 0000000..d6b1301
--- /dev/null
+++ b/test/circuits/ecdh_test.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.3;
+
+include "../../circuits/crypto/ecdh.circom";
+
+component main = Ecdh();
\ No newline at end of file
diff --git a/test/circuits/publicKey_test.circom b/test/circuits/publicKey_test.circom
new file mode 100644
index 0000000..00d7acb
--- /dev/null
+++ b/test/circuits/publicKey_test.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.3;
+
+include "../../circuits/crypto/publickey_derivation.circom";
+
+component main = PublicKey();
\ No newline at end of file
diff --git a/test/encryption.js b/test/encryption.js
new file mode 100644
index 0000000..6cf926e
--- /dev/null
+++ b/test/encryption.js
@@ -0,0 +1,34 @@
+const chai = require("chai");
+const path = require("path");
+
+const wasm_tester = require("circom_tester").wasm;
+
+const F1Field = require("ffjavascript").F1Field;
+const Scalar = require("ffjavascript").Scalar;
+exports.p = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
+const Fr = new F1Field(exports.p);
+
+const assert = chai.assert;
+const { Keypair } = require("./modules/maci-domainobjs");
+
+describe("crypto circuits test", function () {
+ this.timeout(100000000);
+
+ it("public key test", async () => {
+ const circuit = await wasm_tester(path.join(__dirname, "circuits", "publicKey_test.circom"));
+
+ const keypair = new Keypair();
+
+ const INPUT = {
+ 'private_key': keypair.privKey.asCircuitInputs(),
+ }
+
+ const witness = await circuit.calculateWitness(INPUT, true);
+
+ //console.log(witness);
+
+ assert(Fr.eq(Fr.e(witness[0]), Fr.e(1)));
+ assert(Fr.eq(Fr.e(witness[1]), Fr.e(keypair.pubKey.rawPubKey[0])));
+ assert(Fr.eq(Fr.e(witness[2]), Fr.e(keypair.pubKey.rawPubKey[1])));
+ });
+});
\ No newline at end of file
diff --git a/test/modules/circomlib-0.5.1.js b/test/modules/circomlib-0.5.1.js
new file mode 100644
index 0000000..a0293a9
--- /dev/null
+++ b/test/modules/circomlib-0.5.1.js
@@ -0,0 +1,12 @@
+exports.smt = require("./src/smt");
+exports.eddsa = require("./src/eddsa");
+exports.mimc7 = require("./src/mimc7");
+exports.mimcsponge = require("./src/mimcsponge");
+exports.babyJub = require("./src/babyjub");
+exports.pedersenHash = require("./src/pedersenHash");
+exports.SMT = require("./src/smt").SMT;
+exports.SMTMemDB = require("./src/smt_memdb");
+exports.poseidon = require("./src/poseidon");
+
+
+
diff --git a/test/modules/maci-crypto.js b/test/modules/maci-crypto.js
new file mode 100644
index 0000000..6b93fd1
--- /dev/null
+++ b/test/modules/maci-crypto.js
@@ -0,0 +1,238 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.unpackPubKey = exports.packPubKey = exports.bigInt2Buffer = exports.SNARK_FIELD_SIZE = exports.NOTHING_UP_MY_SLEEVE_PUBKEY = exports.NOTHING_UP_MY_SLEEVE = exports.formatPrivKeyForBabyJub = exports.unstringifyBigInts = exports.stringifyBigInts = exports.verifySignature = exports.hashLeftRight = exports.hash11 = exports.hash5 = exports.hashOne = exports.sign = exports.decrypt = exports.encrypt = exports.genEcdhSharedKey = exports.genKeypair = exports.genPubKey = exports.genPrivKey = exports.genRandomSalt = void 0;
+const assert = require('assert');
+const crypto = require("crypto");
+const ethers = require("ethers");
+const ff = require('ffjavascript');
+const createBlakeHash = require('blake-hash');
+const circomlib_0_5_1_1 = require("./circomlib-0.5.1");
+const stringifyBigInts = ff.utils.stringifyBigInts;
+exports.stringifyBigInts = stringifyBigInts;
+const unstringifyBigInts = ff.utils.unstringifyBigInts;
+exports.unstringifyBigInts = unstringifyBigInts;
+const SNARK_FIELD_SIZE = BigInt('21888242871839275222246405745257275088548364400416034343698204186575808495617');
+exports.SNARK_FIELD_SIZE = SNARK_FIELD_SIZE;
+// A nothing-up-my-sleeve zero value
+// Should be equal to 8370432830353022751713833565135785980866757267633941821328460903436894336785
+const NOTHING_UP_MY_SLEEVE = BigInt(ethers.utils.solidityKeccak256(['bytes'], [ethers.utils.toUtf8Bytes('Maci')])) % SNARK_FIELD_SIZE;
+exports.NOTHING_UP_MY_SLEEVE = NOTHING_UP_MY_SLEEVE;
+// The pubkey is the first Pedersen base point from iden3's circomlib
+// See https://github.com/iden3/circomlib/blob/d5ed1c3ce4ca137a6b3ca48bec4ac12c1b38957a/src/pedersen_printbases.js
+const NOTHING_UP_MY_SLEEVE_PUBKEY = [
+ BigInt('10457101036533406547632367118273992217979173478358440826365724437999023779287'),
+ BigInt('19824078218392094440610104313265183977899662750282163392862422243483260492317')
+];
+exports.NOTHING_UP_MY_SLEEVE_PUBKEY = NOTHING_UP_MY_SLEEVE_PUBKEY;
+/*
+ * Convert a BigInt to a Buffer
+ */
+const bigInt2Buffer = (i) => {
+ let hexStr = i.toString(16);
+ while (hexStr.length < 64) {
+ hexStr = '0' + hexStr;
+ }
+ return Buffer.from(hexStr, 'hex');
+};
+exports.bigInt2Buffer = bigInt2Buffer;
+// Hash up to 2 elements
+const poseidonT3 = (inputs) => {
+ assert(inputs.length === 2);
+ return (0, circomlib_0_5_1_1.poseidon)(inputs);
+};
+// Hash up to 5 elements
+const poseidonT6 = (inputs) => {
+ assert(inputs.length === 5);
+ return (0, circomlib_0_5_1_1.poseidon)(inputs);
+};
+const hash5 = (elements) => {
+ const elementLength = elements.length;
+ if (elements.length > 5) {
+ throw new Error(`elements length should not greater than 5, got ${elements.length}`);
+ }
+ const elementsPadded = elements.slice();
+ if (elementLength < 5) {
+ for (let i = elementLength; i < 5; i++) {
+ elementsPadded.push(BigInt(0));
+ }
+ }
+ return poseidonT6(elementsPadded);
+};
+exports.hash5 = hash5;
+/*
+ * A convenience function for to use Poseidon to hash a Plaintext with
+ * no more than 11 elements
+ */
+const hash11 = (elements) => {
+ const elementLength = elements.length;
+ if (elementLength > 11) {
+ throw new TypeError(`elements length should not greater than 11, got ${elementLength}`);
+ }
+ const elementsPadded = elements.slice();
+ if (elementLength < 11) {
+ for (let i = elementLength; i < 11; i++) {
+ elementsPadded.push(BigInt(0));
+ }
+ }
+ return poseidonT3([
+ poseidonT3([
+ poseidonT6(elementsPadded.slice(0, 5)),
+ poseidonT6(elementsPadded.slice(5, 10))
+ ]),
+ elementsPadded[10]
+ ]);
+};
+exports.hash11 = hash11;
+/*
+ * Hash a single BigInt with the Poseidon hash function
+ */
+const hashOne = (preImage) => {
+ return poseidonT3([preImage, BigInt(0)]);
+};
+exports.hashOne = hashOne;
+/*
+ * Hash two BigInts with the Poseidon hash function
+ */
+const hashLeftRight = (left, right) => {
+ return poseidonT3([left, right]);
+};
+exports.hashLeftRight = hashLeftRight;
+/*
+ * Returns a BabyJub-compatible random value. We create it by first generating
+ * a random value (initially 256 bits large) modulo the snark field size as
+ * described in EIP197. This results in a key size of roughly 253 bits and no
+ * more than 254 bits. To prevent modulo bias, we then use this efficient
+ * algorithm:
+ * http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/crypt/arc4random_uniform.c
+ * @return A BabyJub-compatible random value.
+ */
+const genRandomBabyJubValue = () => {
+ // Prevent modulo bias
+ //const lim = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000')
+ //const min = (lim - SNARK_FIELD_SIZE) % SNARK_FIELD_SIZE
+ const min = BigInt('6350874878119819312338956282401532410528162663560392320966563075034087161851');
+ let rand;
+ while (true) {
+ rand = BigInt('0x' + crypto.randomBytes(32).toString('hex'));
+ if (rand >= min) {
+ break;
+ }
+ }
+ const privKey = rand % SNARK_FIELD_SIZE;
+ assert(privKey < SNARK_FIELD_SIZE);
+ return privKey;
+};
+/*
+ * @return A BabyJub-compatible private key.
+ */
+const genPrivKey = () => {
+ return genRandomBabyJubValue();
+};
+exports.genPrivKey = genPrivKey;
+/*
+ * @return A BabyJub-compatible salt.
+ */
+const genRandomSalt = () => {
+ return genRandomBabyJubValue();
+};
+exports.genRandomSalt = genRandomSalt;
+/*
+ * An internal function which formats a random private key to be compatible
+ * with the BabyJub curve. This is the format which should be passed into the
+ * PublicKey and other circuits.
+ */
+const formatPrivKeyForBabyJub = (privKey) => {
+ const sBuff = circomlib_0_5_1_1.eddsa.pruneBuffer(createBlakeHash("blake512").update(bigInt2Buffer(privKey)).digest().slice(0, 32));
+ const s = ff.utils.leBuff2int(sBuff);
+ return ff.Scalar.shr(s, 3);
+};
+exports.formatPrivKeyForBabyJub = formatPrivKeyForBabyJub;
+/*
+ * Losslessly reduces the size of the representation of a public key
+ * @param pubKey The public key to pack
+ * @return A packed public key
+ */
+const packPubKey = (pubKey) => {
+ return circomlib_0_5_1_1.babyJub.packPoint(pubKey);
+};
+exports.packPubKey = packPubKey;
+/*
+ * Restores the original PubKey from its packed representation
+ * @param packed The value to unpack
+ * @return The unpacked public key
+ */
+const unpackPubKey = (packed) => {
+ return circomlib_0_5_1_1.babyJub.unpackPoint(packed);
+};
+exports.unpackPubKey = unpackPubKey;
+/*
+ * @param privKey A private key generated using genPrivKey()
+ * @return A public key associated with the private key
+ */
+const genPubKey = (privKey) => {
+ privKey = BigInt(privKey.toString());
+ assert(privKey < SNARK_FIELD_SIZE);
+ return circomlib_0_5_1_1.eddsa.prv2pub(bigInt2Buffer(privKey));
+};
+exports.genPubKey = genPubKey;
+const genKeypair = () => {
+ const privKey = genPrivKey();
+ const pubKey = genPubKey(privKey);
+ const Keypair = { privKey, pubKey };
+ return Keypair;
+};
+exports.genKeypair = genKeypair;
+/*
+ * Generates an Elliptic-curve Diffie–Hellman shared key given a private key
+ * and a public key.
+ * @return The ECDH shared key.
+ */
+const genEcdhSharedKey = (privKey, pubKey) => {
+ return circomlib_0_5_1_1.babyJub.mulPointEscalar(pubKey, formatPrivKeyForBabyJub(privKey))[0];
+};
+exports.genEcdhSharedKey = genEcdhSharedKey;
+/*
+ * Encrypts a plaintext using a given key.
+ * @return The ciphertext.
+ */
+const encrypt = (plaintext, sharedKey) => {
+ // Generate the IV
+ const iv = circomlib_0_5_1_1.mimc7.multiHash(plaintext, BigInt(0));
+ const ciphertext = {
+ iv,
+ data: plaintext.map((e, i) => {
+ return e + circomlib_0_5_1_1.mimc7.hash(sharedKey, iv + BigInt(i));
+ }),
+ };
+ // TODO: add asserts here
+ return ciphertext;
+};
+exports.encrypt = encrypt;
+/*
+ * Decrypts a ciphertext using a given key.
+ * @return The plaintext.
+ */
+const decrypt = (ciphertext, sharedKey) => {
+ const plaintext = ciphertext.data.map((e, i) => {
+ return BigInt(e) - BigInt(circomlib_0_5_1_1.mimc7.hash(sharedKey, BigInt(ciphertext.iv) + BigInt(i)));
+ });
+ return plaintext;
+};
+exports.decrypt = decrypt;
+/*
+ * Generates a signature given a private key and plaintext.
+ * @return The signature.
+ */
+const sign = (privKey, msg) => {
+ return circomlib_0_5_1_1.eddsa.signPoseidon(bigInt2Buffer(privKey), msg);
+};
+exports.sign = sign;
+/*
+ * Checks whether the signature of the given plaintext was created using the
+ * private key associated with the given public key.
+ * @return True if the signature is valid, and false otherwise.
+ */
+const verifySignature = (msg, signature, pubKey) => {
+ return circomlib_0_5_1_1.eddsa.verifyPoseidon(msg, signature, pubKey);
+};
+exports.verifySignature = verifySignature;
diff --git a/test/modules/maci-crypto.ts b/test/modules/maci-crypto.ts
new file mode 100644
index 0000000..df52116
--- /dev/null
+++ b/test/modules/maci-crypto.ts
@@ -0,0 +1,343 @@
+const assert = require('assert')
+const crypto = require("crypto")
+const ethers = require("ethers")
+const ff = require('ffjavascript')
+const createBlakeHash = require('blake-hash')
+import { babyJub, mimc7, poseidon, eddsa } from './circomlib-0.5.1'
+const stringifyBigInts: (obj: object) => any = ff.utils.stringifyBigInts
+const unstringifyBigInts: (obj: object) => any = ff.utils.unstringifyBigInts
+
+type SnarkBigInt = BigInt
+type PrivKey = BigInt
+type PubKey = BigInt[]
+type EcdhSharedKey = BigInt
+type Plaintext = BigInt[]
+
+interface Keypair {
+ privKey: PrivKey;
+ pubKey: PubKey;
+}
+
+interface Ciphertext {
+ // The initialisation vector
+ iv: BigInt;
+
+ // The encrypted data
+ data: BigInt[];
+}
+
+// An EdDSA signature.
+// TODO: document what R8 and S mean
+interface Signature {
+ R8: BigInt[];
+ S: BigInt;
+}
+
+const SNARK_FIELD_SIZE = BigInt(
+ '21888242871839275222246405745257275088548364400416034343698204186575808495617'
+)
+
+// A nothing-up-my-sleeve zero value
+// Should be equal to 8370432830353022751713833565135785980866757267633941821328460903436894336785
+const NOTHING_UP_MY_SLEEVE =
+ BigInt(ethers.utils.solidityKeccak256(['bytes'], [ethers.utils.toUtf8Bytes('Maci')])) % SNARK_FIELD_SIZE
+
+// The pubkey is the first Pedersen base point from iden3's circomlib
+// See https://github.com/iden3/circomlib/blob/d5ed1c3ce4ca137a6b3ca48bec4ac12c1b38957a/src/pedersen_printbases.js
+const NOTHING_UP_MY_SLEEVE_PUBKEY: PubKey = [
+ BigInt('10457101036533406547632367118273992217979173478358440826365724437999023779287'),
+ BigInt('19824078218392094440610104313265183977899662750282163392862422243483260492317')
+]
+
+/*
+ * Convert a BigInt to a Buffer
+ */
+const bigInt2Buffer = (i: BigInt): Buffer => {
+ let hexStr = i.toString(16)
+ while (hexStr.length < 64) {
+ hexStr = '0' + hexStr
+ }
+ return Buffer.from(hexStr, 'hex')
+}
+
+// Hash up to 2 elements
+const poseidonT3 = (inputs: BigInt[]) => {
+ assert(inputs.length === 2)
+ return poseidon(inputs)
+}
+
+// Hash up to 5 elements
+const poseidonT6 = (inputs: BigInt[]) => {
+ assert(inputs.length === 5)
+ return poseidon(inputs)
+}
+
+const hash5 = (elements: Plaintext): BigInt => {
+ const elementLength = elements.length
+ if (elements.length > 5) {
+ throw new Error(`elements length should not greater than 5, got ${elements.length}`)
+ }
+ const elementsPadded = elements.slice()
+ if (elementLength < 5) {
+ for (let i = elementLength; i < 5; i++) {
+ elementsPadded.push(BigInt(0))
+ }
+ }
+ return poseidonT6(elementsPadded)
+}
+
+/*
+ * A convenience function for to use Poseidon to hash a Plaintext with
+ * no more than 11 elements
+ */
+const hash11 = (elements: Plaintext): BigInt => {
+ const elementLength = elements.length
+ if (elementLength > 11) {
+ throw new TypeError(`elements length should not greater than 11, got ${elementLength}`)
+ }
+ const elementsPadded = elements.slice()
+ if (elementLength < 11) {
+ for (let i = elementLength; i < 11; i++) {
+ elementsPadded.push(BigInt(0))
+ }
+ }
+ return poseidonT3([
+ poseidonT3([
+ poseidonT6(elementsPadded.slice(0, 5)),
+ poseidonT6(elementsPadded.slice(5, 10))
+ ])
+ , elementsPadded[10]
+ ])
+}
+
+/*
+ * Hash a single BigInt with the Poseidon hash function
+ */
+const hashOne = (preImage: BigInt): BigInt => {
+
+ return poseidonT3([preImage, BigInt(0)])
+}
+
+/*
+ * Hash two BigInts with the Poseidon hash function
+ */
+const hashLeftRight = (left: BigInt, right: BigInt): BigInt => {
+ return poseidonT3([left, right])
+}
+
+/*
+ * Returns a BabyJub-compatible random value. We create it by first generating
+ * a random value (initially 256 bits large) modulo the snark field size as
+ * described in EIP197. This results in a key size of roughly 253 bits and no
+ * more than 254 bits. To prevent modulo bias, we then use this efficient
+ * algorithm:
+ * http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/crypt/arc4random_uniform.c
+ * @return A BabyJub-compatible random value.
+ */
+const genRandomBabyJubValue = (): BigInt => {
+
+ // Prevent modulo bias
+ //const lim = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000')
+ //const min = (lim - SNARK_FIELD_SIZE) % SNARK_FIELD_SIZE
+ const min = BigInt('6350874878119819312338956282401532410528162663560392320966563075034087161851')
+
+ let rand
+ while (true) {
+ rand = BigInt('0x' + crypto.randomBytes(32).toString('hex'))
+
+ if (rand >= min) {
+ break
+ }
+ }
+
+ const privKey: PrivKey = rand % SNARK_FIELD_SIZE
+ assert(privKey < SNARK_FIELD_SIZE)
+
+ return privKey
+}
+
+/*
+ * @return A BabyJub-compatible private key.
+ */
+const genPrivKey = (): PrivKey => {
+
+ return genRandomBabyJubValue()
+}
+
+/*
+ * @return A BabyJub-compatible salt.
+ */
+const genRandomSalt = (): PrivKey=> {
+
+ return genRandomBabyJubValue()
+}
+
+/*
+ * An internal function which formats a random private key to be compatible
+ * with the BabyJub curve. This is the format which should be passed into the
+ * PublicKey and other circuits.
+ */
+const formatPrivKeyForBabyJub = (privKey: PrivKey) => {
+ const sBuff = eddsa.pruneBuffer(
+ createBlakeHash("blake512").update(
+ bigInt2Buffer(privKey),
+ ).digest().slice(0,32)
+ )
+ const s = ff.utils.leBuff2int(sBuff)
+ return ff.Scalar.shr(s, 3)
+}
+
+/*
+ * Losslessly reduces the size of the representation of a public key
+ * @param pubKey The public key to pack
+ * @return A packed public key
+ */
+const packPubKey = (pubKey: PubKey): Buffer => {
+ return babyJub.packPoint(pubKey)
+}
+
+/*
+ * Restores the original PubKey from its packed representation
+ * @param packed The value to unpack
+ * @return The unpacked public key
+ */
+const unpackPubKey = (packed: Buffer): PubKey => {
+ return babyJub.unpackPoint(packed)
+}
+
+/*
+ * @param privKey A private key generated using genPrivKey()
+ * @return A public key associated with the private key
+ */
+const genPubKey = (privKey: PrivKey): PubKey => {
+ privKey = BigInt(privKey.toString())
+ assert(privKey < SNARK_FIELD_SIZE)
+ return eddsa.prv2pub(bigInt2Buffer(privKey))
+}
+
+const genKeypair = (): Keypair => {
+ const privKey = genPrivKey()
+ const pubKey = genPubKey(privKey)
+
+ const Keypair: Keypair = { privKey, pubKey }
+
+ return Keypair
+}
+
+/*
+ * Generates an Elliptic-curve Diffie–Hellman shared key given a private key
+ * and a public key.
+ * @return The ECDH shared key.
+ */
+const genEcdhSharedKey = (
+ privKey: PrivKey,
+ pubKey: PubKey,
+): EcdhSharedKey => {
+
+ return babyJub.mulPointEscalar(pubKey, formatPrivKeyForBabyJub(privKey))[0]
+}
+
+/*
+ * Encrypts a plaintext using a given key.
+ * @return The ciphertext.
+ */
+const encrypt = (
+ plaintext: Plaintext,
+ sharedKey: EcdhSharedKey,
+): Ciphertext => {
+
+ // Generate the IV
+ const iv = mimc7.multiHash(plaintext, BigInt(0))
+
+ const ciphertext: Ciphertext = {
+ iv,
+ data: plaintext.map((e: BigInt, i: number): BigInt => {
+ return e + mimc7.hash(
+ sharedKey,
+ iv + BigInt(i),
+ )
+ }),
+ }
+
+ // TODO: add asserts here
+ return ciphertext
+}
+
+/*
+ * Decrypts a ciphertext using a given key.
+ * @return The plaintext.
+ */
+const decrypt = (
+ ciphertext: Ciphertext,
+ sharedKey: EcdhSharedKey,
+): Plaintext => {
+
+ const plaintext: Plaintext = ciphertext.data.map(
+ (e: BigInt, i: number): BigInt => {
+ return BigInt(e) - BigInt(mimc7.hash(sharedKey, BigInt(ciphertext.iv) + BigInt(i)))
+ }
+ )
+
+ return plaintext
+}
+
+/*
+ * Generates a signature given a private key and plaintext.
+ * @return The signature.
+ */
+const sign = (
+ privKey: PrivKey,
+ msg: BigInt,
+): Signature => {
+ return eddsa.signPoseidon(
+ bigInt2Buffer(privKey),
+ msg,
+ )
+}
+
+/*
+ * Checks whether the signature of the given plaintext was created using the
+ * private key associated with the given public key.
+ * @return True if the signature is valid, and false otherwise.
+ */
+const verifySignature = (
+ msg: BigInt,
+ signature: Signature,
+ pubKey: PubKey,
+): boolean => {
+
+ return eddsa.verifyPoseidon(msg, signature, pubKey)
+}
+
+export {
+ genRandomSalt,
+ genPrivKey,
+ genPubKey,
+ genKeypair,
+ genEcdhSharedKey,
+ encrypt,
+ decrypt,
+ sign,
+ hashOne,
+ hash5,
+ hash11,
+ hashLeftRight,
+ verifySignature,
+ Signature,
+ PrivKey,
+ PubKey,
+ Keypair,
+ EcdhSharedKey,
+ Ciphertext,
+ Plaintext,
+ SnarkBigInt,
+ stringifyBigInts,
+ unstringifyBigInts,
+ formatPrivKeyForBabyJub,
+ NOTHING_UP_MY_SLEEVE,
+ NOTHING_UP_MY_SLEEVE_PUBKEY,
+ SNARK_FIELD_SIZE,
+ bigInt2Buffer,
+ packPubKey,
+ unpackPubKey,
+}
\ No newline at end of file
diff --git a/test/modules/maci-domainobjs.js b/test/modules/maci-domainobjs.js
new file mode 100644
index 0000000..5b73697
--- /dev/null
+++ b/test/modules/maci-domainobjs.js
@@ -0,0 +1,296 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.PrivKey = exports.PubKey = exports.Keypair = exports.Message = exports.Command = exports.StateLeaf = void 0;
+const assert = require('assert');
+const maci_crypto_1 = require("./maci-crypto");
+const SERIALIZED_PRIV_KEY_PREFIX = 'macisk.';
+class PrivKey {
+ constructor(rawPrivKey) {
+ this.copy = () => {
+ return new PrivKey(BigInt(this.rawPrivKey.toString()));
+ };
+ this.asCircuitInputs = () => {
+ return (0, maci_crypto_1.formatPrivKeyForBabyJub)(this.rawPrivKey).toString();
+ };
+ this.serialize = () => {
+ return SERIALIZED_PRIV_KEY_PREFIX + this.rawPrivKey.toString(16);
+ };
+ this.rawPrivKey = rawPrivKey;
+ }
+}
+exports.PrivKey = PrivKey;
+PrivKey.unserialize = (s) => {
+ const x = s.slice(SERIALIZED_PRIV_KEY_PREFIX.length);
+ return new PrivKey(BigInt('0x' + x));
+};
+PrivKey.isValidSerializedPrivKey = (s) => {
+ const correctPrefix = s.startsWith(SERIALIZED_PRIV_KEY_PREFIX);
+ const x = s.slice(SERIALIZED_PRIV_KEY_PREFIX.length);
+ let validValue = false;
+ try {
+ const value = BigInt('0x' + x);
+ validValue = value < maci_crypto_1.SNARK_FIELD_SIZE;
+ }
+ catch {
+ // comment to make linter happy
+ }
+ return correctPrefix && validValue;
+};
+const SERIALIZED_PUB_KEY_PREFIX = 'macipk.';
+class PubKey {
+ constructor(rawPubKey) {
+ this.copy = () => {
+ return new PubKey([
+ BigInt(this.rawPubKey[0].toString()),
+ BigInt(this.rawPubKey[1].toString()),
+ ]);
+ };
+ this.asContractParam = () => {
+ return {
+ x: this.rawPubKey[0].toString(),
+ y: this.rawPubKey[1].toString(),
+ };
+ };
+ this.asCircuitInputs = () => {
+ return this.rawPubKey.map((x) => x.toString());
+ };
+ this.asArray = () => {
+ return [
+ this.rawPubKey[0],
+ this.rawPubKey[1],
+ ];
+ };
+ this.serialize = () => {
+ // Blank leaves have pubkey [0, 0], which packPubKey does not support
+ if (BigInt(this.rawPubKey[0]) === BigInt(0) &&
+ BigInt(this.rawPubKey[1]) === BigInt(0)) {
+ return SERIALIZED_PUB_KEY_PREFIX + 'z';
+ }
+ const packed = (0, maci_crypto_1.packPubKey)(this.rawPubKey).toString('hex');
+ return SERIALIZED_PUB_KEY_PREFIX + packed.toString();
+ };
+ assert(rawPubKey.length === 2);
+ assert(rawPubKey[0] < maci_crypto_1.SNARK_FIELD_SIZE);
+ assert(rawPubKey[1] < maci_crypto_1.SNARK_FIELD_SIZE);
+ this.rawPubKey = rawPubKey;
+ }
+}
+exports.PubKey = PubKey;
+PubKey.unserialize = (s) => {
+ // Blank leaves have pubkey [0, 0], which packPubKey does not support
+ if (s === SERIALIZED_PUB_KEY_PREFIX + 'z') {
+ return new PubKey([BigInt(0), BigInt(0)]);
+ }
+ const len = SERIALIZED_PUB_KEY_PREFIX.length;
+ const packed = Buffer.from(s.slice(len), 'hex');
+ return new PubKey((0, maci_crypto_1.unpackPubKey)(packed));
+};
+PubKey.isValidSerializedPubKey = (s) => {
+ const correctPrefix = s.startsWith(SERIALIZED_PUB_KEY_PREFIX);
+ let validValue = false;
+ try {
+ PubKey.unserialize(s);
+ validValue = true;
+ }
+ catch {
+ // comment to make linter happy
+ }
+ return correctPrefix && validValue;
+};
+class Keypair {
+ constructor(privKey) {
+ this.copy = () => {
+ return new Keypair(this.privKey.copy());
+ };
+ if (privKey) {
+ this.privKey = privKey;
+ this.pubKey = new PubKey((0, maci_crypto_1.genPubKey)(privKey.rawPrivKey));
+ }
+ else {
+ const rawKeyPair = (0, maci_crypto_1.genKeypair)();
+ this.privKey = new PrivKey(rawKeyPair.privKey);
+ this.pubKey = new PubKey(rawKeyPair.pubKey);
+ }
+ }
+ static genEcdhSharedKey(privKey, pubKey) {
+ return (0, maci_crypto_1.genEcdhSharedKey)(privKey.rawPrivKey, pubKey.rawPubKey);
+ }
+ equals(keypair) {
+ const equalPrivKey = this.privKey.rawPrivKey === keypair.privKey.rawPrivKey;
+ const equalPubKey = this.pubKey.rawPubKey[0] === keypair.pubKey.rawPubKey[0] &&
+ this.pubKey.rawPubKey[1] === keypair.pubKey.rawPubKey[1];
+ // If this assertion fails, something is very wrong and this function
+ // should not return anything
+ // XOR is equivalent to: (x && !y) || (!x && y )
+ const x = (equalPrivKey && equalPubKey);
+ const y = (!equalPrivKey && !equalPubKey);
+ assert((x && !y) || (!x && y));
+ return equalPrivKey;
+ }
+}
+exports.Keypair = Keypair;
+/*
+ * An encrypted command and signature.
+ */
+class Message {
+ constructor(iv, data) {
+ this.asArray = () => {
+ return [
+ this.iv,
+ ...this.data,
+ ];
+ };
+ this.asContractParam = () => {
+ return {
+ iv: this.iv.toString(),
+ data: this.data.map((x) => x.toString()),
+ };
+ };
+ this.asCircuitInputs = () => {
+ return this.asArray();
+ };
+ this.hash = () => {
+ return (0, maci_crypto_1.hash11)(this.asArray());
+ };
+ this.copy = () => {
+ return new Message(BigInt(this.iv.toString()), this.data.map((x) => BigInt(x.toString())));
+ };
+ assert(data.length === 10);
+ this.iv = iv;
+ this.data = data;
+ }
+}
+exports.Message = Message;
+/*
+ * A leaf in the state tree, which maps public keys to votes
+ */
+class StateLeaf {
+ constructor(pubKey, voteOptionTreeRoot, voiceCreditBalance, nonce) {
+ this.asArray = () => {
+ return [
+ ...this.pubKey.asArray(),
+ this.voteOptionTreeRoot,
+ this.voiceCreditBalance,
+ this.nonce,
+ ];
+ };
+ this.asCircuitInputs = () => {
+ return this.asArray();
+ };
+ this.hash = () => {
+ return (0, maci_crypto_1.hash5)(this.asArray());
+ };
+ this.serialize = () => {
+ const j = {
+ pubKey: this.pubKey.serialize(),
+ voteOptionTreeRoot: this.voteOptionTreeRoot.toString(16),
+ voiceCreditBalance: this.voiceCreditBalance.toString(16),
+ nonce: this.nonce.toString(16),
+ };
+ return Buffer.from(JSON.stringify(j, null, 0), 'utf8').toString('base64');
+ };
+ this.pubKey = pubKey;
+ this.voteOptionTreeRoot = voteOptionTreeRoot;
+ this.voiceCreditBalance = voiceCreditBalance;
+ // The this is the current nonce. i.e. a user who has published 0 valid
+ // command should have this value at 0, and the first command should
+ // have a nonce of 1
+ this.nonce = nonce;
+ }
+ copy() {
+ return new StateLeaf(this.pubKey.copy(), BigInt(this.voteOptionTreeRoot.toString()), BigInt(this.voiceCreditBalance.toString()), BigInt(this.nonce.toString()));
+ }
+ static genBlankLeaf(emptyVoteOptionTreeRoot) {
+ return new StateLeaf(new PubKey(maci_crypto_1.NOTHING_UP_MY_SLEEVE_PUBKEY), emptyVoteOptionTreeRoot, BigInt(0), BigInt(0));
+ }
+ static genRandomLeaf() {
+ return new StateLeaf(new PubKey(maci_crypto_1.NOTHING_UP_MY_SLEEVE_PUBKEY), (0, maci_crypto_1.genRandomSalt)(), (0, maci_crypto_1.genRandomSalt)(), (0, maci_crypto_1.genRandomSalt)());
+ }
+}
+exports.StateLeaf = StateLeaf;
+StateLeaf.unserialize = (serialized) => {
+ const j = JSON.parse(Buffer.from(serialized, 'base64').toString('utf8'));
+ return new StateLeaf(PubKey.unserialize(j.pubKey), BigInt('0x' + j.voteOptionTreeRoot), BigInt('0x' + j.voiceCreditBalance), BigInt('0x' + j.nonce));
+};
+/*
+ * Unencrypted data whose fields include the user's public key, vote etc.
+ */
+class Command {
+ constructor(stateIndex, newPubKey, voteOptionIndex, newVoteWeight, nonce, salt = (0, maci_crypto_1.genRandomSalt)()) {
+ this.copy = () => {
+ return new Command(BigInt(this.stateIndex.toString()), this.newPubKey.copy(), BigInt(this.voteOptionIndex.toString()), BigInt(this.newVoteWeight.toString()), BigInt(this.nonce.toString()), BigInt(this.salt.toString()));
+ };
+ this.asArray = () => {
+ return [
+ this.stateIndex,
+ ...this.newPubKey.asArray(),
+ this.voteOptionIndex,
+ this.newVoteWeight,
+ this.nonce,
+ this.salt,
+ ];
+ };
+ /*
+ * Check whether this command has deep equivalence to another command
+ */
+ this.equals = (command) => {
+ return this.stateIndex == command.stateIndex &&
+ this.newPubKey[0] == command.newPubKey[0] &&
+ this.newPubKey[1] == command.newPubKey[1] &&
+ this.voteOptionIndex == command.voteOptionIndex &&
+ this.newVoteWeight == command.newVoteWeight &&
+ this.nonce == command.nonce &&
+ this.salt == command.salt;
+ };
+ this.hash = () => {
+ return (0, maci_crypto_1.hash11)(this.asArray());
+ };
+ /*
+ * Signs this command and returns a Signature.
+ */
+ this.sign = (privKey) => {
+ return (0, maci_crypto_1.sign)(privKey.rawPrivKey, this.hash());
+ };
+ /*
+ * Returns true if the given signature is a correct signature of this
+ * command and signed by the private key associated with the given public
+ * key.
+ */
+ this.verifySignature = (signature, pubKey) => {
+ return (0, maci_crypto_1.verifySignature)(this.hash(), signature, pubKey.rawPubKey);
+ };
+ /*
+ * Encrypts this command along with a signature to produce a Message.
+ */
+ this.encrypt = (signature, sharedKey) => {
+ const plaintext = [
+ ...this.asArray(),
+ signature.R8[0],
+ signature.R8[1],
+ signature.S,
+ ];
+ const ciphertext = (0, maci_crypto_1.encrypt)(plaintext, sharedKey);
+ const message = new Message(ciphertext.iv, ciphertext.data);
+ return message;
+ };
+ this.stateIndex = stateIndex;
+ this.newPubKey = newPubKey;
+ this.voteOptionIndex = voteOptionIndex;
+ this.newVoteWeight = newVoteWeight;
+ this.nonce = nonce;
+ this.salt = salt;
+ }
+}
+exports.Command = Command;
+/*
+ * Decrypts a Message to produce a Command.
+ */
+Command.decrypt = (message, sharedKey) => {
+ const decrypted = (0, maci_crypto_1.decrypt)(message, sharedKey);
+ const command = new Command(decrypted[0], new PubKey([decrypted[1], decrypted[2]]), decrypted[3], decrypted[4], decrypted[5], decrypted[6]);
+ const signature = {
+ R8: [decrypted[7], decrypted[8]],
+ S: decrypted[9],
+ };
+ return { command, signature };
+};
diff --git a/test/modules/maci-domainobjs.ts b/test/modules/maci-domainobjs.ts
new file mode 100644
index 0000000..0c91e9b
--- /dev/null
+++ b/test/modules/maci-domainobjs.ts
@@ -0,0 +1,514 @@
+const assert = require('assert');
+import {
+ Ciphertext,
+ Plaintext,
+ EcdhSharedKey,
+ Signature,
+ PubKey as RawPubKey,
+ PrivKey as RawPrivKey,
+ encrypt,
+ decrypt,
+ sign,
+ hash5,
+ hash11,
+ verifySignature,
+ genRandomSalt,
+ genKeypair,
+ genPubKey,
+ formatPrivKeyForBabyJub,
+ genEcdhSharedKey,
+ packPubKey,
+ unpackPubKey,
+ SNARK_FIELD_SIZE,
+ NOTHING_UP_MY_SLEEVE_PUBKEY,
+} from './maci-crypto'
+
+const SERIALIZED_PRIV_KEY_PREFIX = 'macisk.'
+
+class PrivKey {
+ public rawPrivKey: RawPrivKey
+
+ constructor (rawPrivKey: RawPrivKey) {
+ this.rawPrivKey = rawPrivKey
+ }
+
+ public copy = (): PrivKey => {
+ return new PrivKey(BigInt(this.rawPrivKey.toString()))
+ }
+
+ public asCircuitInputs = () => {
+ return formatPrivKeyForBabyJub(this.rawPrivKey).toString()
+ }
+
+ public serialize = (): string => {
+ return SERIALIZED_PRIV_KEY_PREFIX + this.rawPrivKey.toString(16)
+ }
+
+ public static unserialize = (s: string): PrivKey => {
+ const x = s.slice(SERIALIZED_PRIV_KEY_PREFIX.length)
+ return new PrivKey(BigInt('0x' + x))
+ }
+
+ public static isValidSerializedPrivKey = (s: string): boolean => {
+ const correctPrefix = s.startsWith(SERIALIZED_PRIV_KEY_PREFIX)
+ const x = s.slice(SERIALIZED_PRIV_KEY_PREFIX.length)
+
+ let validValue = false
+ try {
+ const value = BigInt('0x' + x)
+ validValue = value < SNARK_FIELD_SIZE
+ } catch {
+ // comment to make linter happy
+ }
+
+ return correctPrefix && validValue
+ }
+}
+
+const SERIALIZED_PUB_KEY_PREFIX = 'macipk.'
+
+class PubKey {
+ public rawPubKey: RawPubKey
+
+ constructor (rawPubKey: RawPubKey) {
+ assert(rawPubKey.length === 2)
+ assert(rawPubKey[0] < SNARK_FIELD_SIZE)
+ assert(rawPubKey[1] < SNARK_FIELD_SIZE)
+ this.rawPubKey = rawPubKey
+ }
+
+ public copy = (): PubKey => {
+
+ return new PubKey([
+ BigInt(this.rawPubKey[0].toString()),
+ BigInt(this.rawPubKey[1].toString()),
+ ])
+ }
+
+ public asContractParam = () => {
+ return {
+ x: this.rawPubKey[0].toString(),
+ y: this.rawPubKey[1].toString(),
+ }
+ }
+
+ public asCircuitInputs = () => {
+ return this.rawPubKey.map((x) => x.toString())
+ }
+
+ public asArray = (): BigInt[] => {
+ return [
+ this.rawPubKey[0],
+ this.rawPubKey[1],
+ ]
+ }
+
+ public serialize = (): string => {
+ // Blank leaves have pubkey [0, 0], which packPubKey does not support
+ if (
+ BigInt(this.rawPubKey[0]) === BigInt(0) &&
+ BigInt(this.rawPubKey[1]) === BigInt(0)
+ ) {
+ return SERIALIZED_PUB_KEY_PREFIX + 'z'
+ }
+ const packed = packPubKey(this.rawPubKey).toString('hex')
+ return SERIALIZED_PUB_KEY_PREFIX + packed.toString()
+ }
+
+ public static unserialize = (s: string): PubKey => {
+ // Blank leaves have pubkey [0, 0], which packPubKey does not support
+ if (s === SERIALIZED_PUB_KEY_PREFIX + 'z') {
+ return new PubKey([BigInt(0), BigInt(0)])
+ }
+
+ const len = SERIALIZED_PUB_KEY_PREFIX.length
+ const packed = Buffer.from(s.slice(len), 'hex')
+ return new PubKey(unpackPubKey(packed))
+ }
+
+ public static isValidSerializedPubKey = (s: string): boolean => {
+ const correctPrefix = s.startsWith(SERIALIZED_PUB_KEY_PREFIX)
+
+ let validValue = false
+ try {
+ PubKey.unserialize(s)
+ validValue = true
+ } catch {
+ // comment to make linter happy
+ }
+
+ return correctPrefix && validValue
+ }
+}
+
+class Keypair {
+ public privKey: PrivKey
+ public pubKey: PubKey
+
+ constructor (
+ privKey?: PrivKey,
+ ) {
+ if (privKey) {
+ this.privKey = privKey
+ this.pubKey = new PubKey(genPubKey(privKey.rawPrivKey))
+ } else {
+ const rawKeyPair = genKeypair()
+ this.privKey = new PrivKey(rawKeyPair.privKey)
+ this.pubKey = new PubKey(rawKeyPair.pubKey)
+ }
+ }
+
+ public copy = (): Keypair => {
+ return new Keypair(this.privKey.copy())
+ }
+
+ public static genEcdhSharedKey(
+ privKey: PrivKey,
+ pubKey: PubKey,
+ ) {
+ return genEcdhSharedKey(privKey.rawPrivKey, pubKey.rawPubKey)
+ }
+
+ public equals(
+ keypair: Keypair,
+ ): boolean {
+
+ const equalPrivKey = this.privKey.rawPrivKey === keypair.privKey.rawPrivKey
+ const equalPubKey =
+ this.pubKey.rawPubKey[0] === keypair.pubKey.rawPubKey[0] &&
+ this.pubKey.rawPubKey[1] === keypair.pubKey.rawPubKey[1]
+
+ // If this assertion fails, something is very wrong and this function
+ // should not return anything
+ // XOR is equivalent to: (x && !y) || (!x && y )
+ const x = (equalPrivKey && equalPubKey)
+ const y = (!equalPrivKey && !equalPubKey)
+
+ assert((x && !y) || (!x && y))
+
+ return equalPrivKey
+ }
+}
+
+
+interface IStateLeaf {
+ pubKey: PubKey;
+ voteOptionTreeRoot: BigInt;
+ voiceCreditBalance: BigInt;
+ nonce: BigInt;
+}
+
+interface VoteOptionTreeLeaf {
+ votes: BigInt;
+}
+
+/*
+ * An encrypted command and signature.
+ */
+class Message {
+ public iv: BigInt
+ public data: BigInt[]
+
+ constructor (
+ iv: BigInt,
+ data: BigInt[],
+ ) {
+ assert(data.length === 10)
+ this.iv = iv
+ this.data = data
+ }
+
+ private asArray = (): BigInt[] => {
+
+ return [
+ this.iv,
+ ...this.data,
+ ]
+ }
+
+ public asContractParam = () => {
+ return {
+ iv: this.iv.toString(),
+ data: this.data.map((x: BigInt) => x.toString()),
+ }
+ }
+
+ public asCircuitInputs = (): BigInt[] => {
+
+ return this.asArray()
+ }
+
+ public hash = (): BigInt => {
+
+ return hash11(this.asArray())
+ }
+
+ public copy = (): Message => {
+
+ return new Message(
+ BigInt(this.iv.toString()),
+ this.data.map((x: BigInt) => BigInt(x.toString())),
+ )
+ }
+}
+
+/*
+ * A leaf in the state tree, which maps public keys to votes
+ */
+class StateLeaf implements IStateLeaf {
+ public pubKey: PubKey
+ public voteOptionTreeRoot: BigInt
+ public voiceCreditBalance: BigInt
+ public nonce: BigInt
+
+ constructor (
+ pubKey: PubKey,
+ voteOptionTreeRoot: BigInt,
+ voiceCreditBalance: BigInt,
+ nonce: BigInt,
+ ) {
+ this.pubKey = pubKey
+ this.voteOptionTreeRoot = voteOptionTreeRoot
+ this.voiceCreditBalance = voiceCreditBalance
+ // The this is the current nonce. i.e. a user who has published 0 valid
+ // command should have this value at 0, and the first command should
+ // have a nonce of 1
+ this.nonce = nonce
+ }
+
+ public copy(): StateLeaf {
+ return new StateLeaf(
+ this.pubKey.copy(),
+ BigInt(this.voteOptionTreeRoot.toString()),
+ BigInt(this.voiceCreditBalance.toString()),
+ BigInt(this.nonce.toString()),
+ )
+ }
+
+ public static genBlankLeaf(
+ emptyVoteOptionTreeRoot: BigInt,
+ ): StateLeaf {
+ return new StateLeaf(
+ new PubKey(NOTHING_UP_MY_SLEEVE_PUBKEY),
+ emptyVoteOptionTreeRoot,
+ BigInt(0),
+ BigInt(0),
+ )
+ }
+
+ public static genRandomLeaf() {
+ return new StateLeaf(
+ new PubKey(NOTHING_UP_MY_SLEEVE_PUBKEY),
+ genRandomSalt(),
+ genRandomSalt(),
+ genRandomSalt(),
+ )
+ }
+
+ private asArray = (): BigInt[] => {
+
+ return [
+ ...this.pubKey.asArray(),
+ this.voteOptionTreeRoot,
+ this.voiceCreditBalance,
+ this.nonce,
+ ]
+ }
+
+ public asCircuitInputs = (): BigInt[] => {
+
+ return this.asArray()
+ }
+
+ public hash = (): BigInt => {
+
+ return hash5(this.asArray())
+ }
+
+ public serialize = (): string => {
+ const j = {
+ pubKey: this.pubKey.serialize(),
+ voteOptionTreeRoot: this.voteOptionTreeRoot.toString(16),
+ voiceCreditBalance: this.voiceCreditBalance.toString(16),
+ nonce: this.nonce.toString(16),
+ }
+
+ return Buffer.from(JSON.stringify(j, null, 0), 'utf8').toString('base64')
+ }
+
+ static unserialize = (serialized: string): StateLeaf => {
+ const j = JSON.parse(Buffer.from(serialized, 'base64').toString('utf8'))
+ return new StateLeaf(
+ PubKey.unserialize(j.pubKey),
+ BigInt('0x' + j.voteOptionTreeRoot),
+ BigInt('0x' + j.voiceCreditBalance),
+ BigInt('0x' + j.nonce),
+ )
+ }
+}
+
+interface ICommand {
+ stateIndex: BigInt;
+ newPubKey: PubKey;
+ voteOptionIndex: BigInt;
+ newVoteWeight: BigInt;
+ nonce: BigInt;
+
+ sign: (PrivKey) => Signature;
+ encrypt: (EcdhSharedKey, Signature) => Message;
+}
+
+/*
+ * Unencrypted data whose fields include the user's public key, vote etc.
+ */
+class Command implements ICommand {
+ public stateIndex: BigInt
+ public newPubKey: PubKey
+ public voteOptionIndex: BigInt
+ public newVoteWeight: BigInt
+ public nonce: BigInt
+ public salt: BigInt
+
+ constructor (
+ stateIndex: BigInt,
+ newPubKey: PubKey,
+ voteOptionIndex: BigInt,
+ newVoteWeight: BigInt,
+ nonce: BigInt,
+ salt: BigInt = genRandomSalt(),
+ ) {
+ this.stateIndex = stateIndex
+ this.newPubKey = newPubKey
+ this.voteOptionIndex = voteOptionIndex
+ this.newVoteWeight = newVoteWeight
+ this.nonce = nonce
+ this.salt = salt
+ }
+
+ public copy = (): Command => {
+
+ return new Command(
+ BigInt(this.stateIndex.toString()),
+ this.newPubKey.copy(),
+ BigInt(this.voteOptionIndex.toString()),
+ BigInt(this.newVoteWeight.toString()),
+ BigInt(this.nonce.toString()),
+ BigInt(this.salt.toString()),
+ )
+ }
+
+ public asArray = (): BigInt[] => {
+
+ return [
+ this.stateIndex,
+ ...this.newPubKey.asArray(),
+ this.voteOptionIndex,
+ this.newVoteWeight,
+ this.nonce,
+ this.salt,
+ ]
+ }
+
+ /*
+ * Check whether this command has deep equivalence to another command
+ */
+ public equals = (command: Command): boolean => {
+
+ return this.stateIndex == command.stateIndex &&
+ this.newPubKey[0] == command.newPubKey[0] &&
+ this.newPubKey[1] == command.newPubKey[1] &&
+ this.voteOptionIndex == command.voteOptionIndex &&
+ this.newVoteWeight == command.newVoteWeight &&
+ this.nonce == command.nonce &&
+ this.salt == command.salt
+ }
+
+ public hash = (): BigInt => {
+ return hash11(this.asArray())
+ }
+
+ /*
+ * Signs this command and returns a Signature.
+ */
+ public sign = (
+ privKey: PrivKey,
+ ): Signature => {
+
+ return sign(privKey.rawPrivKey, this.hash())
+ }
+
+ /*
+ * Returns true if the given signature is a correct signature of this
+ * command and signed by the private key associated with the given public
+ * key.
+ */
+ public verifySignature = (
+ signature: Signature,
+ pubKey: PubKey,
+ ): boolean => {
+
+ return verifySignature(
+ this.hash(),
+ signature,
+ pubKey.rawPubKey,
+ )
+ }
+
+ /*
+ * Encrypts this command along with a signature to produce a Message.
+ */
+ public encrypt = (
+ signature: Signature,
+ sharedKey: EcdhSharedKey,
+ ): Message => {
+
+ const plaintext: Plaintext = [
+ ...this.asArray(),
+ signature.R8[0],
+ signature.R8[1],
+ signature.S,
+ ]
+
+ const ciphertext: Ciphertext = encrypt(plaintext, sharedKey)
+ const message = new Message(ciphertext.iv, ciphertext.data)
+
+ return message
+ }
+
+ /*
+ * Decrypts a Message to produce a Command.
+ */
+ public static decrypt = (
+ message: Message,
+ sharedKey: EcdhSharedKey,
+ ) => {
+
+ const decrypted = decrypt(message, sharedKey)
+
+ const command = new Command(
+ decrypted[0],
+ new PubKey([decrypted[1], decrypted[2]]),
+ decrypted[3],
+ decrypted[4],
+ decrypted[5],
+ decrypted[6],
+ )
+
+ const signature = {
+ R8: [decrypted[7], decrypted[8]],
+ S: decrypted[9],
+ }
+
+ return { command, signature }
+ }
+}
+
+export {
+ StateLeaf,
+ VoteOptionTreeLeaf,
+ Command,
+ Message,
+ Keypair,
+ PubKey,
+ PrivKey,
+}
\ No newline at end of file
diff --git a/test/modules/src/babyjub.js b/test/modules/src/babyjub.js
new file mode 100644
index 0000000..6651571
--- /dev/null
+++ b/test/modules/src/babyjub.js
@@ -0,0 +1,128 @@
+const F1Field = require("ffjavascript").F1Field;
+const Scalar = require("ffjavascript").Scalar;
+const utils = require("ffjavascript").utils;
+
+exports.addPoint = addPoint;
+exports.mulPointEscalar = mulPointEscalar;
+exports.inCurve = inCurve;
+exports.inSubgroup = inSubgroup;
+exports.packPoint = packPoint;
+exports.unpackPoint = unpackPoint;
+
+
+exports.p = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
+const F = new F1Field(exports.p);
+exports.F = F;
+
+exports.Generator = [
+ F.e("995203441582195749578291179787384436505546430278305826713579947235728471134"),
+ F.e("5472060717959818805561601436314318772137091100104008585924551046643952123905")
+];
+exports.Base8 = [
+ F.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
+ F.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
+];
+exports.order = Scalar.fromString("21888242871839275222246405745257275088614511777268538073601725287587578984328");
+exports.subOrder = Scalar.shiftRight(exports.order, 3);
+exports.A = F.e("168700");
+exports.D = F.e("168696");
+
+
+function addPoint(a,b) {
+
+ const res = [];
+
+ /* does the equivalent of:
+ res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
+ res[1] = bigInt((a[1]*b[1] - cta*a[0]*b[0]) * bigInt(bigInt("1") - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
+ */
+
+ const beta = F.mul(a[0],b[1]);
+ const gamma = F.mul(a[1],b[0]);
+ const delta = F.mul(
+ F.sub(a[1], F.mul(exports.A, a[0])),
+ F.add(b[0], b[1])
+ );
+ const tau = F.mul(beta, gamma);
+ const dtau = F.mul(exports.D, tau);
+
+ res[0] = F.div(
+ F.add(beta, gamma),
+ F.add(F.one, dtau)
+ );
+
+ res[1] = F.div(
+ F.add(delta, F.sub(F.mul(exports.A,beta), gamma)),
+ F.sub(F.one, dtau)
+ );
+
+ return res;
+}
+
+function mulPointEscalar(base, e) {
+ let res = [F.e("0"),F.e("1")];
+ let rem = e;
+ let exp = base;
+
+ while (! Scalar.isZero(rem)) {
+ if (Scalar.isOdd(rem)) {
+ res = addPoint(res, exp);
+ }
+ exp = addPoint(exp, exp);
+ rem = Scalar.shiftRight(rem, 1);
+ }
+
+ return res;
+}
+
+function inSubgroup(P) {
+ if (!inCurve(P)) return false;
+ const res= mulPointEscalar(P, exports.subOrder);
+ return (F.isZero(res[0]) && F.eq(res[1], F.one));
+}
+
+function inCurve(P) {
+
+ const x2 = F.square(P[0]);
+ const y2 = F.square(P[1]);
+
+ if (!F.eq(
+ F.add(F.mul(exports.A, x2), y2),
+ F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false;
+
+ return true;
+}
+
+function packPoint(P) {
+ const buff = utils.leInt2Buff(P[1], 32);
+ if (F.lt(P[0], F.zero)) {
+ buff[31] = buff[31] | 0x80;
+ }
+ return buff;
+}
+
+function unpackPoint(_buff) {
+ const buff = Buffer.from(_buff);
+ let sign = false;
+ const P = new Array(2);
+ if (buff[31] & 0x80) {
+ sign = true;
+ buff[31] = buff[31] & 0x7F;
+ }
+ P[1] = utils.leBuff2int(buff);
+ if (Scalar.gt(P[1], exports.p)) return null;
+
+ const y2 = F.square(P[1]);
+
+ let x = F.sqrt(F.div(
+ F.sub(F.one, y2),
+ F.sub(exports.A, F.mul(exports.D, y2))));
+
+ if (x == null) return null;
+
+ if (sign) x = F.neg(x);
+
+ P[0] = x;
+
+ return P;
+}
diff --git a/test/modules/src/eddsa.js b/test/modules/src/eddsa.js
new file mode 100644
index 0000000..3edad47
--- /dev/null
+++ b/test/modules/src/eddsa.js
@@ -0,0 +1,228 @@
+const createBlakeHash = require("blake-hash");
+const Scalar = require("ffjavascript").Scalar;
+const F1Field = require("ffjavascript").F1Field;
+const babyJub = require("./babyjub");
+const utils = require("ffjavascript").utils;
+const pedersenHash = require("./pedersenHash").hash;
+const mimc7 = require("./mimc7");
+const poseidon = require("./poseidon.js");
+const mimcsponge = require("./mimcsponge");
+
+
+exports.prv2pub= prv2pub;
+exports.sign = sign;
+exports.signMiMC = signMiMC;
+exports.signPoseidon = signPoseidon;
+exports.signMiMCSponge = signMiMCSponge;
+exports.verify = verify;
+exports.verifyMiMC = verifyMiMC;
+exports.verifyPoseidon = verifyPoseidon;
+exports.verifyMiMCSponge = verifyMiMCSponge;
+exports.packSignature = packSignature;
+exports.unpackSignature = unpackSignature;
+exports.pruneBuffer = pruneBuffer;
+
+
+function pruneBuffer(_buff) {
+ const buff = Buffer.from(_buff);
+ buff[0] = buff[0] & 0xF8;
+ buff[31] = buff[31] & 0x7F;
+ buff[31] = buff[31] | 0x40;
+ return buff;
+}
+
+function prv2pub(prv) {
+ const sBuff = pruneBuffer(createBlakeHash("blake512").update(prv).digest().slice(0,32));
+ let s = utils.leBuff2int(sBuff);
+ const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s,3));
+ return A;
+}
+
+function sign(prv, msg) {
+ const h1 = createBlakeHash("blake512").update(prv).digest();
+ const sBuff = pruneBuffer(h1.slice(0,32));
+ const s = utils.leBuff2int(sBuff);
+ const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
+
+ const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msg])).digest();
+ let r = utils.leBuff2int(rBuff);
+ const Fr = new F1Field(babyJub.subOrder);
+ r = Fr.e(r);
+ const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
+ const R8p = babyJub.packPoint(R8);
+ const Ap = babyJub.packPoint(A);
+ const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
+ const hm = utils.leBuff2int(hmBuff);
+ const S = Fr.add(r , Fr.mul(hm, s));
+ return {
+ R8: R8,
+ S: S
+ };
+}
+
+function signMiMC(prv, msg) {
+ const h1 = createBlakeHash("blake512").update(prv).digest();
+ const sBuff = pruneBuffer(h1.slice(0,32));
+ const s = utils.leBuff2int(sBuff);
+ const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
+
+ const msgBuff = utils.leInt2Buff(msg, 32);
+ const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
+ let r = utils.leBuff2int(rBuff);
+ const Fr = new F1Field(babyJub.subOrder);
+ r = Fr.e(r);
+ const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
+ const hm = mimc7.multiHash([R8[0], R8[1], A[0], A[1], msg]);
+ const S = Fr.add(r , Fr.mul(hm, s));
+ return {
+ R8: R8,
+ S: S
+ };
+}
+
+function signMiMCSponge(prv, msg) {
+ const h1 = createBlakeHash("blake512").update(prv).digest();
+ const sBuff = pruneBuffer(h1.slice(0,32));
+ const s = utils.leBuff2int(sBuff);
+ const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
+
+ const msgBuff = utils.leInt2Buff(msg, 32);
+ const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
+ let r = utils.leBuff2int(rBuff);
+ const Fr = new F1Field(babyJub.subOrder);
+ r = Fr.e(r);
+ const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
+ const hm = mimcsponge.multiHash([R8[0], R8[1], A[0], A[1], msg]);
+ const S = Fr.add(r , Fr.mul(hm, s));
+ return {
+ R8: R8,
+ S: S
+ };
+}
+
+function signPoseidon(prv, msg) {
+ const h1 = createBlakeHash("blake512").update(prv).digest();
+ const sBuff = pruneBuffer(h1.slice(0,32));
+ const s = utils.leBuff2int(sBuff);
+ const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
+
+ const msgBuff = utils.leInt2Buff(msg, 32);
+ const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
+ let r = utils.leBuff2int(rBuff);
+ const Fr = new F1Field(babyJub.subOrder);
+ r = Fr.e(r);
+ const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
+ const hm = poseidon([R8[0], R8[1], A[0], A[1], msg]);
+ const S = Fr.add(r , Fr.mul(hm, s));
+ return {
+ R8: R8,
+ S: S
+ };
+}
+
+function verify(msg, sig, A) {
+ // Check parameters
+ if (typeof sig != "object") return false;
+ if (!Array.isArray(sig.R8)) return false;
+ if (sig.R8.length!= 2) return false;
+ if (!babyJub.inCurve(sig.R8)) return false;
+ if (!Array.isArray(A)) return false;
+ if (A.length!= 2) return false;
+ if (!babyJub.inCurve(A)) return false;
+ if (sig.S>= babyJub.subOrder) return false;
+
+ const R8p = babyJub.packPoint(sig.R8);
+ const Ap = babyJub.packPoint(A);
+ const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
+ const hm = utils.leBuff2int(hmBuff);
+
+ const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
+ let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm,8));
+ Pright = babyJub.addPoint(sig.R8, Pright);
+
+ if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
+ if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
+ return true;
+}
+
+function verifyMiMC(msg, sig, A) {
+ // Check parameters
+ if (typeof sig != "object") return false;
+ if (!Array.isArray(sig.R8)) return false;
+ if (sig.R8.length!= 2) return false;
+ if (!babyJub.inCurve(sig.R8)) return false;
+ if (!Array.isArray(A)) return false;
+ if (A.length!= 2) return false;
+ if (!babyJub.inCurve(A)) return false;
+ if (sig.S>= babyJub.subOrder) return false;
+
+ const hm = mimc7.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
+
+ const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
+ let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8));
+ Pright = babyJub.addPoint(sig.R8, Pright);
+
+ if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
+ if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
+ return true;
+}
+
+
+function verifyPoseidon(msg, sig, A) {
+ // Check parameters
+ if (typeof sig != "object") return false;
+ if (!Array.isArray(sig.R8)) return false;
+ if (sig.R8.length!= 2) return false;
+ if (!babyJub.inCurve(sig.R8)) return false;
+ if (!Array.isArray(A)) return false;
+ if (A.length!= 2) return false;
+ if (!babyJub.inCurve(A)) return false;
+ if (sig.S>= babyJub.subOrder) return false;
+
+ const hm = poseidon([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
+
+ const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
+ let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8));
+ Pright = babyJub.addPoint(sig.R8, Pright);
+
+ if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
+ if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
+ return true;
+}
+
+function verifyMiMCSponge(msg, sig, A) {
+ // Check parameters
+ if (typeof sig != "object") return false;
+ if (!Array.isArray(sig.R8)) return false;
+ if (sig.R8.length!= 2) return false;
+ if (!babyJub.inCurve(sig.R8)) return false;
+ if (!Array.isArray(A)) return false;
+ if (A.length!= 2) return false;
+ if (!babyJub.inCurve(A)) return false;
+ if (sig.S>= babyJub.subOrder) return false;
+
+ const hm = mimcsponge.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
+
+ const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
+ let Pright = babyJub.mulPointEscalar(A, hm.times(bigInt("8")));
+ Pright = babyJub.addPoint(sig.R8, Pright);
+
+ if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
+ if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
+ return true;
+}
+
+function packSignature(sig) {
+ const R8p = babyJub.packPoint(sig.R8);
+ const Sp = utils.leInt2Buff(sig.S, 32);
+ return Buffer.concat([R8p, Sp]);
+}
+
+function unpackSignature(sigBuff) {
+ return {
+ R8: babyJub.unpackPoint(sigBuff.slice(0,32)),
+ S: utils.leBuff2int(sigBuff.slice(32,64))
+ };
+}
+
+
diff --git a/test/modules/src/evmasm.js b/test/modules/src/evmasm.js
new file mode 100644
index 0000000..ab7f830
--- /dev/null
+++ b/test/modules/src/evmasm.js
@@ -0,0 +1,208 @@
+// Copyright (c) 2018 Jordi Baylina
+// License: LGPL-3.0+
+//
+
+
+const Web3Utils = require("web3-utils");
+
+class Contract {
+ constructor() {
+ this.code = [];
+ this.labels = {};
+ this.pendingLabels = {};
+ }
+
+ createTxData() {
+ let C;
+
+ // Check all labels are defined
+ const pendingLabels = Object.keys(this.pendingLabels);
+ if (pendingLabels.length>0) {
+ throw new Error("Lables not defined: "+ pendingLabels.join(", "));
+ }
+
+ let setLoaderLength = 0;
+ let genLoadedLength = -1;
+
+ while (genLoadedLength!=setLoaderLength) {
+ setLoaderLength = genLoadedLength;
+ C = new module.exports();
+ C.codesize();
+ C.push(setLoaderLength);
+ C.push(0);
+ C.codecopy();
+
+ C.push(this.code.length);
+ C.push(0);
+ C.return();
+ genLoadedLength = C.code.length;
+ }
+
+ return Web3Utils.bytesToHex(C.code.concat(this.code));
+ }
+
+ stop() { this.code.push(0x00); }
+ add() { this.code.push(0x01); }
+ mul() { this.code.push(0x02); }
+ sub() { this.code.push(0x03); }
+ div() { this.code.push(0x04); }
+ sdiv() { this.code.push(0x05); }
+ mod() { this.code.push(0x06); }
+ smod() { this.code.push(0x07); }
+ addmod() { this.code.push(0x08); }
+ mulmod() { this.code.push(0x09); }
+ exp() { this.code.push(0x0a); }
+ signextend() { this.code.push(0x0b); }
+
+ lt() { this.code.push(0x10); }
+ gt() { this.code.push(0x11); }
+ slt() { this.code.push(0x12); }
+ sgt() { this.code.push(0x13); }
+ eq() { this.code.push(0x14); }
+ iszero() { this.code.push(0x15); }
+ and() { this.code.push(0x16); }
+ or() { this.code.push(0x17); }
+ shor() { this.code.push(0x18); }
+ not() { this.code.push(0x19); }
+ byte() { this.code.push(0x1a); }
+
+ keccak() { this.code.push(0x20); }
+ sha3() { this.code.push(0x20); } // alias
+
+ address() { this.code.push(0x30); }
+ balance() { this.code.push(0x31); }
+ origin() { this.code.push(0x32); }
+ caller() { this.code.push(0x33); }
+ callvalue() { this.code.push(0x34); }
+ calldataload() { this.code.push(0x35); }
+ calldatasize() { this.code.push(0x36); }
+ calldatacopy() { this.code.push(0x37); }
+ codesize() { this.code.push(0x38); }
+ codecopy() { this.code.push(0x39); }
+ gasprice() { this.code.push(0x3a); }
+ extcodesize() { this.code.push(0x3b); }
+ extcodecopy() { this.code.push(0x3c); }
+ returndatasize() { this.code.push(0x3d); }
+ returndatacopy() { this.code.push(0x3e); }
+
+ blockhash() { this.code.push(0x40); }
+ coinbase() { this.code.push(0x41); }
+ timestamp() { this.code.push(0x42); }
+ number() { this.code.push(0x43); }
+ difficulty() { this.code.push(0x44); }
+ gaslimit() { this.code.push(0x45); }
+
+ pop() { this.code.push(0x50); }
+ mload() { this.code.push(0x51); }
+ mstore() { this.code.push(0x52); }
+ mstore8() { this.code.push(0x53); }
+ sload() { this.code.push(0x54); }
+ sstore() { this.code.push(0x55); }
+
+ _pushLabel(label) {
+ if (typeof this.labels[label] != "undefined") {
+ this.push(this.labels[label]);
+ } else {
+ this.pendingLabels[label] = this.pendingLabels[label] || [];
+ this.pendingLabels[label].push(this.code.length);
+ this.push("0x000000");
+ }
+ }
+
+ _fillLabel(label) {
+ if (!this.pendingLabels[label]) return;
+
+ let dst = this.labels[label];
+
+ const dst3 = [dst >> 16, (dst >> 8) & 0xFF, dst & 0xFF];
+
+ this.pendingLabels[label].forEach((p) => {
+ for (let i=0; i<3; i++) {
+ this.code[p+i+1] = dst3[i];
+ }
+ });
+
+ delete this.pendingLabels[label];
+ }
+
+
+ jmp(label) {
+ if (typeof label !== "undefined") {
+ this._pushLabel(label);
+ }
+ this.code.push(0x56);
+ }
+
+ jmpi(label) {
+ if (typeof label !== "undefined") {
+ this._pushLabel(label);
+ }
+ this.code.push(0x57);
+ }
+
+ pc() { this.code.push(0x58); }
+ msize() { this.code.push(0x59); }
+ gas() { this.code.push(0x5a); }
+ label(name) {
+ if (typeof this.labels[name] != "undefined") {
+ throw new Error("Label already defined");
+ }
+ this.labels[name] = this.code.length;
+ this.code.push(0x5b);
+
+ this._fillLabel(name);
+ }
+
+ push(data) {
+ if (typeof data === "number") {
+ let isNeg;
+ if (data<0) {
+ isNeg = true;
+ data = -data;
+ }
+ data = data.toString(16);
+ if (data.length % 2 == 1) data = "0" + data;
+ data = "0x" + data;
+ if (isNeg) data = "-"+data;
+ }
+ const d = Web3Utils.hexToBytes(Web3Utils.toHex(data));
+ if (d.length == 0 || d.length > 32) {
+ throw new Error("Assertion failed");
+ }
+ this.code = this.code.concat([0x5F + d.length], d);
+ }
+
+ dup(n) {
+ if (n < 0 || n >= 16) {
+ throw new Error("Assertion failed");
+ }
+ this.code.push(0x80 + n);
+ }
+
+ swap(n) {
+ if (n < 1 || n > 16) {
+ throw new Error("Assertion failed");
+ }
+ this.code.push(0x8f + n);
+ }
+
+ log0() { this.code.push(0xa0); }
+ log1() { this.code.push(0xa1); }
+ log2() { this.code.push(0xa2); }
+ log3() { this.code.push(0xa3); }
+ log4() { this.code.push(0xa4); }
+
+ create() { this.code.push(0xf0); }
+ call() { this.code.push(0xf1); }
+ callcode() { this.code.push(0xf2); }
+ return() { this.code.push(0xf3); }
+ delegatecall() { this.code.push(0xf4); }
+
+ staticcall() { this.code.push(0xfa); }
+ revert() { this.code.push(0xfd); }
+ invalid() { this.code.push(0xfe); }
+ selfdestruct() { this.code.push(0xff); }
+}
+
+module.exports = Contract;
+
diff --git a/test/modules/src/g2_gencontract.js b/test/modules/src/g2_gencontract.js
new file mode 100644
index 0000000..9ed1698
--- /dev/null
+++ b/test/modules/src/g2_gencontract.js
@@ -0,0 +1,582 @@
+// Copyright (c) 2018 Jordi Baylina
+// License: LGPL-3.0+
+//
+
+const Contract = require("./evmasm");
+const G2 = require("snarkjs").bn128.G2;
+
+
+function toHex256(a) {
+ let S = a.toString(16);
+ while (S.length < 64) S="0"+S;
+ return "0x" + S;
+}
+
+function createCode(P, w) {
+
+ const C = new Contract();
+
+ const NPOINTS = 1 << (w-1);
+
+ const VAR_POS = C.allocMem(32);
+ const VAR_POINTS = C.allocMem( (NPOINTS)*4*32);
+ const savedP = C.allocMem(32);
+ const savedZ3 = C.allocMem(32);
+
+ // Check selector
+ C.push("0x0100000000000000000000000000000000000000000000000000000000");
+ C.push(0);
+ C.calldataload();
+ C.div();
+ C.push("b65c7c74"); // mulexp(uint256)
+ C.eq();
+ C.jmpi("start");
+ C.invalid();
+
+ C.label("start");
+
+ storeVals();
+
+ C.push( Math.floor(255/w)*w ); // pos := 255
+ C.push(VAR_POS);
+ C.mstore();
+
+ C.push("21888242871839275222246405745257275088696311157297823662689037894645226208583");
+ C.push(0);
+ C.push(0);
+ C.push(0);
+ C.push(0);
+ C.push(0);
+ C.push(0);
+
+ C.label("begin_loop"); // ACC_X ACC_Y ACC_Z q
+
+ C.internalCall("double");
+
+ // g = (e>>pos)&MASK
+ C.push(4);
+ C.calldataload(); // e ACC_X ACC_Y ACC_Z q
+
+ C.push(VAR_POS);
+ C.mload(); // pos e ACC_X ACC_Y ACC_Z q
+ C.shr();
+
+ C.push(NPOINTS-1);
+ C.and(); // g ACC_X ACC_Y ACC_Z q
+
+ C.internalCall("add"); // acc_x acc_y acc_z
+
+ C.push(VAR_POS);
+ C.mload(); // pos acc_x acc_y acc_z
+ C.dup(0); // pos pos acc_x acc_y acc_z
+ C.push(0); // 0 pos pos acc_x acc_y acc_z
+ C.eq(); // eq pos acc_x acc_y acc_z
+ C.jmpi("after_loop"); // pos acc_x acc_y acc_z
+ C.push(w); // 5 pos acc_x acc_y acc_z
+ C.sub(); // pos acc_x acc_y acc_z
+ C.push(VAR_POS);
+ C.mstore(); // acc_x acc_y acc_z
+ C.jmp("begin_loop");
+ C.label("after_loop"); // pos acc_x acc_y acc_z
+ C.pop(); // acc_x acc_y acc_z
+
+ C.internalCall("affine"); // acc_x acc_y
+
+ C.push(0);
+ C.mstore();
+ C.push(20);
+ C.mstore();
+ C.push(40);
+ C.mstore();
+ C.push(60);
+ C.mstore();
+
+ C.push("0x80");
+ C.push("0x00");
+ C.return();
+
+
+ double();
+ addPoint();
+ affine();
+
+ return C.createTxData();
+
+ function add(a,b,q) {
+ C.dup(q);
+ C.dup(a+1 + 1);
+ C.dup(b+1 + 2);
+ C.addmod();
+ C.dup(q + 1);
+ C.dup(a + 2);
+ C.dup(b + 3);
+ C.addmod();
+ }
+
+ function sub(a,b,q) {
+ C.dup(q); // q
+ C.dup(a+1 + 1); // ai q
+ C.dub(q + 2); // q ai q
+ C.dup(b+1 + 3); // bi q ai q
+ C.sub(); // -bi ai q
+ C.addmod(); // ci
+ C.dup(q + 1); // q ci
+ C.dup(a + 2); // ar q ci
+ C.dup(q + 3); // q ar q ci
+ C.dup(b + 4); // br q ar q ci
+ C.sub(); // -br ar q ci
+ C.addmod(); // cr ci
+ }
+
+ function mul(a, b, q) {
+ C.dup(q); // q
+ C.dup(q + 1); // q q
+ C.dup(a + 2); // ar q q
+ C.dup(b+1 + 3); // bi ar q q
+ C.mulmod(); // ci1 q
+ C.dup(q + 2); // q ci1 q
+ C.dup(a+1 + 3); // ai q ci1 q
+ C.dup(b + 4); // ar ai q ci1 q
+ C.mulmod(); // ci2 ci1 q
+ C.addmod(); // ci
+ C.dup(q + 1); // q ci
+ C.dup(q + 2); // q q ci
+ C.dup(q + 3); // q q q ci
+ C.dup(a+1 + 4); // ai q q ci
+ C.dup(b+1 + 5); // bi ai q q ci
+ C.mulmod(); // cr2 q q ci
+ C.sub(); // -cr2 q ci
+ C.dup(q + 3); // q -cr2 q ci
+ C.dup(a + 4); // ar q -cr2 q ci
+ C.dup(b + 5); // br ar q -cr2 q ci
+ C.mulmod(); // cr1 -cr2 q ci
+ C.addmod(); // cr ci
+ }
+
+ function square(a, q) {
+ C.dup(q); // q
+ C.dup(q + 1); // q q
+ C.dup(a + 2); // ar q q
+ C.dup(a+1 + 3); // ai ar q q
+ C.mulmod(); // arai q
+ C.dup(0); // arai arai q
+ C.addmod(); // ci
+ C.dup(q + 1); // q ci
+ C.dup(q + 2); // q q ci
+ C.dup(q + 3); // q q q ci
+ C.dup(a+1 + 4); // ai q q ci
+ C.dup(a+1 + 5); // ai ai q q ci
+ C.mulmod(); // cr2 q q ci
+ C.sub(); // -cr2 q ci
+ C.dup(q + 3); // q -cr2 q ci
+ C.dup(a + 4); // ar q -cr2 q ci
+ C.dup(a + 5); // br ar q -cr2 q ci
+ C.mulmod(); // cr1 -cr2 q ci
+ C.addmod(); // cr ci
+ }
+
+ function add1(a, q) {
+ C.dup(a+1); // im
+ C.dup(1 + q); // q
+ C.dup(2 + a); // re q im
+ C.push(1); // 1 re q im
+ C.addmod();
+ }
+
+ function cmp(a, b) {
+ C.dup(a);
+ C.dup(b);
+ C.eq();
+ C.dup(a+1);
+ C.dup(a+1);
+ C.and();
+ }
+
+ function rm(a) {
+ if (a>0) C.swap(a);
+ C.pop();
+ if (a>0) C.swap(a);
+ C.pop();
+ }
+
+ function double() {
+ C.label("double"); // xR, xI, yR, yI, zR zI, q
+
+ C.dup(4);
+ C.iszero();
+ C.dup(6);
+ C.iszero();
+ C.and();
+ C.jumpi("enddouble"); // X Y Z q
+
+
+ // Z3 = 2*Y*Z // Remove Z
+ mul(2, 4, 6); // yz X Y Z q
+ rm(6); // X Y yz q
+
+ add(4, 4, 6); // 2yz X Y yz q
+ rm(6); // X Y Z3 q
+
+ // A = X^2
+ square(0,6); // A X Y Z3 q
+
+ // B = Y^2 // Remove Y
+ square(4,8); // B A X Y Z3 q
+ rm(6); // A X B Z3 q
+
+ // C = B^2
+ square(4,8); // C A X B Z3 q
+
+ // D = (X+B)^2-A-C // Remove X, Remove B
+ add(4,6, 10); // X+B C A X B Z3 q
+ rm(6); // C A X+B B Z3 q
+ rm(6); // A X+B C Z3 q
+ square(2,8); // (X+B)^2 A X+B C Z3 q
+ rm(4); // A (X+B)^2 C Z3 q
+ sub(2, 0, 8); // (X+B)^2-A A (X+B)^2 C Z3 q
+ rm(4); // A (X+B)^2-A C Z3 q
+ sub(2, 4, 8); // (X+B)^2-A-C A (X+B)^2-A C Z3 q
+ rm(4); // A D C Z3 q
+
+ // D = D+D
+ add(2,2, 8); // D+D A D C Z3 q
+ rm(4); // A D C Z3 q
+
+ // E=A+A+A
+ add(0, 0, 8); // 2A A D C Z3 q
+ add(0, 2, 10); // 3A 2A A D C Z3 q
+ rm(4); // 2A 3A D C Z3 q
+ rm(0); // E D C Z3 q
+
+ // F=E^2
+ square(0, 8); // F E D C Z3 q
+
+ // X3= F - 2*D // Remove F
+ add(4, 4, 10); // 2D F E D C Z3 q
+ sub(2, 0, 12); // F-2D 2D F E D C Z3 q
+ rm(4); // 2D X3 E D C Z3 q
+ rm(0); // X3 E D C Z3 q
+
+ // Y3 = E * (D - X3) - 8 * C // Remove D C E
+
+ sub(4, 0, 10); // D-X3 X3 E D C Z3 q
+ rm(6); // X3 E D-X3 C Z3 q
+ mul(2, 4, 10); // E*(D-X3) X3 E D-X3 C Z3 q
+ rm(6); // X3 E E*(D-X3) C Z3 q
+ rm(2); // X3 E*(D-X3) C Z3 q
+ add(4, 4, 8); // 2C X3 E*(D-X3) C Z3 q
+ rm(6); // X3 E*(D-X3) 2C Z3 q
+ add(4, 4, 8); // 4C X3 E*(D-X3) 2C Z3 q
+ rm(6); // X3 E*(D-X3) 4C Z3 q
+ add(4, 4, 8); // 8C X3 E*(D-X3) 4C Z3 q
+ rm(6); // X3 E*(D-X3) 8C Z3 q
+ sub(2, 4, 8); // E*(D-X3)-8C X3 E*(D-X3) 8C Z3 q
+ rm(6); // X3 E*(D-X3) Y3 Z3 q
+ rm(2); // X3 Y3 Z3 q
+
+ C.label("enddouble");
+ C.returnCall();
+ }
+
+ function addPoint() { // p, xR, xI, yR, yI, zR zI, q
+
+
+ C.dup(0); // p p X2 Y2 Z2 q
+
+ C.push(savedP);
+ C.mstore();
+
+ C.iszero(); // X2 Y2 Z2 q
+ C.jumpi("endpadd");
+
+
+ C.dup(4);
+ C.iszero();
+ C.dup(6);
+ C.iszero();
+ C.and();
+ C.jumpi("returnP"); // X2 Y2 Z2 q
+
+
+
+ // lastZ3 = (Z2+1)^2 - Z2^2
+ add1(4, 6); // Z2+1 X2 Y2 Z2 q
+ square(0, 8); // (Z2+1)^2 Z2+1 X2 Y2 Z2 q
+ rm(2); // (Z2+1)^2 X2 Y2 Z2 q
+ square(6, 8); // Z2^2 (Z2+1)^2 X2 Y2 Z2 q
+
+
+ sub(2, 0, 10); // (Z2+1)^2-Z2^2 Z2^2 (Z2+1)^2 X2 Y2 Z2 q
+
+ saveZ3(); // Z2^2 (Z2+1)^2 X2 Y2 Z2 q
+ rm(2); // Z2^2 X2 Y2 Z2 q
+
+ // U2 = X2
+ // S2 = Y2 // Z2^2 U2 S2 Z2 q
+
+
+ // U1 = X1 * Z2^2
+ loadX(); // X1 Z2^2 U2 S2 Z2 q
+ mul(0, 2, 10); // X1*Z2^2 X1 Z2^2 U2 S2 Z2 q
+ rm(2); // X1*Z2^2 Z2^2 U2 S2 Z2 q
+
+
+ mul(2, 8, 10); // Z2^3 U1 Z2^2 U2 S2 Z2 q
+ rm(4); // U1 Z2^3 U2 S2 Z2 q
+ rm(8); // Z2^3 U2 S2 U1 q
+
+ // S1 = Y1 * Z1^3
+ loadY(); // Y1 Z2^3 U2 S2 U1 q
+ mul(0, 2, 10); // S1 Y1 Z2^3 U2 S2 U1 q
+ rm(4); // Y1 S1 U2 S2 U1 q
+ rm(0); // S1 U2 S2 U1 q
+
+ cmp(0, 4); // c1 S1 U2 S2 U1 q
+ cmp(3, 7); // c2 c1 S1 U2 S2 U1 q
+ C.and(); // c2&c1 S1 U2 S2 U1 q
+ C.jumpi("double1"); // S1 U2 S2 U1 q
+
+
+ // Returns the double
+
+ // H = U2-U1 // Remove U2
+ C.sub(4, 8, 10); // H S1 U2 S2 U1 q
+ rm(4); // S1 H S2 U1 q
+
+ // // r = 2 * (S2-S1) // Remove S2
+ C.sub(4, 4, 8); // S1-S2 S1 H S2 U1 q
+ rm(6); // S1 H S1-S2 U1 q
+ C.add(4, 4, 8); // 2*(S1-S2) S1 H S1-S2 U1 q
+ rm(6); // S1 H r U1 q
+
+ // I = (2 * H)^2
+ C.add(2, 2, 8); // 2*H S1 H r U1 q
+ C.square(0, 10); // (2*H)^2 2*H S1 H r U1 q
+ rm(2); // I S1 H r U1 q
+
+ // V = U1 * I
+ mul(8, 0, 10); // V I S1 H r U1 q
+ rm(10); // I S1 H r V q
+
+ // J = H * I // Remove I
+ mul(4, 0, 10); // J I S1 H r V q
+ rm(2); // J S1 H r V q
+
+ // X3 = r^2 - J - 2 * V
+
+ // S1J2 = (S1*J)*2 // Remove S1
+ mul(2, 0, 10); // S1*J J S1 H r V q
+ rm(4); // J S1*J H r V q
+ add(2,2, 10); // (S1*J)*2 J S1*J H r V q
+ rm(4); // J S1J2 H r V q
+
+ // X3 = r^2 - J - 2 * V
+ square(6, 10); // r^2 J S1J2 H r V q
+ sub(0, 2, 12); // r^2-J r^2 J S1J2 H r V q
+ rm(2); // r^2-J J S1J2 H r V q
+ rm(2); // r^2-J S1J2 H r V q
+ add(8, 8, 10); // 2*V r^2-J S1J2 H r V q
+ sub(2, 0, 12); // r^2-J-2*V 2*V r^2-J S1J2 H r V q
+ rm(4); // 2*V X3 S1J2 H r V q
+ rm(0); // X3 S1J2 H r V q
+
+ // Y3 = r * (V-X3)-S1J2
+
+ sub(8, 0, 10); // V-X3 X3 S1J2 H r V q
+ rm(10); // X3 S1J2 H r V-X3 q
+ mul(6, 8, 10); // r*(V-X3) X3 S1J2 H r V-X3 q
+ rm(8); // X3 S1J2 H r*(V-X3) V-X3 q
+ rm(8); // S1J2 H r*(V-X3) X3 q
+ sub(4, 0, 8); // Y3 S1J2 H r*(V-X3) X3 q
+ rm(6); // S1J2 H Y3 X3 q
+ rm(0); // H Y3 X3 q
+
+ // Z3 = lastZ * H
+ loadZ3(); // lastZ3 H Y3 X3 q
+ mul(0, 2, 8); // Z3 lastZ3 H Y3 X3 q
+ rm(4); // lastZ3 Z3 Y3 X3 q
+ rm(0); // Z3 Y3 X3 q
+
+ C.swap(1);
+ C.swap(5);
+ C.swap(1);
+ C.swap(4); // X3 Y3 Z3 q
+
+ // returns the point in memory
+ C.label("returnP"); // X Y Z q
+ rm(0);
+ rm(0);
+ rm(0);
+ C.push(0);
+ C.push(1);
+ loadX();
+ loadY();
+ C.jump("endpadd");
+
+ C.label("double1"); // S1 U2 S2 U1 q
+ rm(0);
+ rm(0);
+ rm(0);
+ rm(0);
+ C.push(0);
+ C.push(1);
+ loadX();
+ loadY();
+ C.jump("double");
+
+ C.label("endpadd");
+ C.returnCall();
+
+ function loadX() {
+ C.push(savedP);
+ C.mload(); // p
+ C.push(32);
+ C.mul(); // P*32
+ C.push(VAR_POINTS+32);
+ C.add(); // P*32+32
+ C.dup(); // P*32+32 P*32+32
+ C.mload(); // im P*32+32
+ C.swap(1); // P*32+32 im
+ C.push(0x20); // 32 P*32+32 im
+ C.sub(); // P*32 im
+ C.mload(); // re im
+ }
+
+ function loadY() {
+ C.push(savedP);
+ C.mload(); // p
+ C.push(32);
+ C.mul(); // P*32
+ C.push(VAR_POINTS+32*3);
+ C.add(); // P*32+32
+ C.dup(); // P*32+32 P*32+32
+ C.mload(); // im P*32+32
+ C.swap(1); // P*32+32 im
+ C.push(0x20); // 32 P*32+32 im
+ C.sub(); // P*32 im
+ C.mload(); // re im
+ }
+
+ function loadZ3() {
+ C.push(savedZ3+32);
+ C.mload(); // p
+ C.push(savedZ3);
+ C.mload();
+ }
+
+ function saveZ3() {
+ C.push(savedZ3);
+ C.mstore();
+ C.push(savedZ3+32);
+ C.mstore();
+ }
+ }
+
+ function affine() { // X Y Z q
+ // If Z2=0 return 0
+ C.label("affine");
+ C.dup(4);
+ C.dup(5 + 1);
+ C.or();
+ C.jumpi("notZero"); // X Y Z q
+ rm(0);
+ rm(0);
+ C.push(0);
+ C.push(0);
+
+ C.jmp("endAffine");
+ C.label("notZero");
+
+ inverse2(4,6); // Z_inv X Y Z q
+ square(2, 8); // Z2_inv Z_inv X Y Z q
+ mul(0, 2, 10); // Z3_inv Z2_inv Z_inv X Y Z q
+ rm(4); // Z2_inv Z3_inv X Y Z q
+ C.push(1);
+ C.push(0); // 1 Z2_inv Z3_inv X Y Z q
+ rm(10); // Z2_inv Z3_inv X Y 1 q
+ mul(2, 6, 10); // YI Z2_inv Z3_inv X Y 1 q
+ rm(8); // Z2_inv Z3_inv X YI 1 q
+ mul(0, 4, 10); // XI Z2_inv Z3_inv X YI 1 q
+ rm(6); // Z2_inv Z3_inv XI YI 1 q
+ rm(0); // Z3_inv XI YI 1 q
+ rm(0); // XI YI 1 q
+ C.label("endAffine");
+ C.returnCall();
+ }
+
+ function inverse2(a, q) {
+ C.dup(q); // q
+ C.dup(q + 1); // q q
+ C.push(2); // 2 q q
+ C.sub(); // q-2 q
+ C.dup(q + 2); // q q-2 q
+ C.dup(q + 3); // q q q-2 q
+ C.dup(a + 4); // ar q q q-2 q
+ C.dup(a + 5); // ar ar q q q-2 q
+ C.mulmod(); // t0 q q-2 q
+
+ C.dup(q + 4); // q t0 q q-2 q
+ C.dup(a+1 + 5); // ai q t0 q q-2 q
+ C.dup(a+1 + 6); // ai ai q t0 q q-2 q
+ C.mulmod(); // t1 t0 q q-2 q
+
+ C.addmod(); // t2 q-2 q
+ C.expmod(); // t3
+
+ C.dup(q + 1); // q t3
+ C.dup(q + 2); // q q t3
+ C.dup(q + 3); // q q q t3
+ C.dup(1); // t3 q q q t3
+ C.sub(); // -t3 q q t3
+ C.dup(a+1 + 3); // ai -t3 q q t3
+ C.mulmod(); // ii q t3
+ C.swap(2); // t3 q ii
+ C.dup(a + 3); // ar t3 q ii
+ C.mulmod(); // ir ii
+ }
+
+ function storeVals() {
+ C.push(VAR_POINTS); // p
+ for (let i=0; i {
+ if (typeof seed === "undefined") seed = SEED;
+ const c = Web3Utils.keccak256(seed+"_iv");
+ const cn = Scalar.FromString(Web3Utils.toBN(c).toString());
+ const iv = cn.mod(F.p);
+ return iv;
+};
+
+exports.getConstants = (seed, nRounds) => {
+ if (typeof seed === "undefined") seed = SEED;
+ if (typeof nRounds === "undefined") nRounds = NROUNDS;
+ const cts = new Array(nRounds);
+ let c = Web3Utils.keccak256(SEED);
+ for (let i=1; i{
+ const x_in = F.e(_x_in);
+ const k = F.e(_k);
+ let r;
+ for (let i=0; i {
+ let r;
+ if (typeof(key) === "undefined") {
+ r = F.zero;
+ } else {
+ r = key;
+ }
+ for (let i=0; i {
+ if (typeof seed === "undefined") seed = SEED;
+ const c = Web3Utils.keccak256(seed+"_iv");
+ const cn = Scalar.fromString(Web3Utils.toBN(c).toString());
+ const iv = cn.mod(F.p);
+ return iv;
+};
+
+exports.getConstants = (seed, nRounds) => {
+ if (typeof seed === "undefined") seed = SEED;
+ if (typeof nRounds === "undefined") nRounds = NROUNDS;
+ const cts = new Array(nRounds);
+ let c = Web3Utils.keccak256(SEED);
+ for (let i=1; i{
+ let xL = F.e(_xL_in);
+ let xR = F.e(_xR_in);
+ const k = F.e(_k);
+ for (let i=0; i {
+ if (typeof(numOutputs) === "undefined") {
+ numOutputs = 1;
+ }
+ if (typeof(key) === "undefined") {
+ key = F.zero;
+ }
+
+ let R = F.zero;
+ let C = F.zero;
+
+ for (let i=0; i F.normalize(x));
+ }
+};
diff --git a/test/modules/src/mimcsponge_gencontract.js b/test/modules/src/mimcsponge_gencontract.js
new file mode 100644
index 0000000..eb7d27b
--- /dev/null
+++ b/test/modules/src/mimcsponge_gencontract.js
@@ -0,0 +1,128 @@
+// Copyright (c) 2018 Jordi Baylina
+// License: LGPL-3.0+
+//
+
+const Web3Utils = require("web3-utils");
+
+const Contract = require("./evmasm");
+
+function createCode(seed, n) {
+
+ let ci = Web3Utils.keccak256(seed);
+
+ const C = new Contract();
+
+ C.push(0x64);
+ C.push("0x00");
+ C.push("0x00");
+ C.calldatacopy();
+ C.push("0x0100000000000000000000000000000000000000000000000000000000");
+ C.push("0x00");
+ C.mload();
+ C.div();
+ C.push("0x3f1a1187"); // MiMCSponge(uint256,uint256,uint256)
+ C.eq();
+ C.jmpi("start");
+ C.invalid();
+
+ C.label("start");
+ C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
+ C.push("0x44");
+ C.mload(); // k q
+ C.push("0x04");
+ C.mload(); // xL k q
+ C.dup(2); // q xL k q
+ C.push("0x24");
+ C.mload(); // xR q xL k q
+ C.dup(1); // q xR q xL k q
+ C.dup(0); // q q xR q xL k q
+ C.dup(4); // xL q q xR q xL k q
+ C.dup(6); // k xL q q xR q xL k q
+ C.addmod(); // t=k+xL q xR q xL k q
+ C.dup(1); // q t q xR q xL k q
+ C.dup(0); // q q t q xR q xL k q
+ C.dup(2); // t q q t q xR q xL k q
+ C.dup(0); // t t q q t q xR q xL k q
+ C.mulmod(); // b=t^2 q t q xR q xL k q
+ C.dup(0); // b b q t q xR q xL k q
+ C.mulmod(); // c=t^4 t q xR q xL k q
+ C.mulmod(); // d=t^5 xR q xL k q
+ C.addmod(); // e=t^5+xR xL k q (for next round: xL xR k q)
+
+ for (let i=0; i F.mul(a, F.square(F.square(a, a)));
+
+function poseidon(inputs) {
+ assert(inputs.length > 0);
+ assert(inputs.length < N_ROUNDS_P.length - 1);
+
+ const t = inputs.length + 1;
+ const nRoundsF = N_ROUNDS_F;
+ const nRoundsP = N_ROUNDS_P[t - 2];
+
+ let state = [F.zero, ...inputs.map(a => F.e(a))];
+ for (let r = 0; r < nRoundsF + nRoundsP; r++) {
+ state = state.map((a, i) => F.add(a, C[t - 2][r * t + i]));
+
+ if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) {
+ state = state.map(a => pow5(a));
+ } else {
+ state[0] = pow5(state[0]);
+ }
+
+ state = state.map((_, i) =>
+ state.reduce((acc, a, j) => F.add(acc, F.mul(M[t - 2][i][j], a)), F.zero)
+ );
+ }
+ return F.normalize(state[0]);
+}
+
+module.exports = poseidon;
diff --git a/test/modules/src/poseidon_constants.json b/test/modules/src/poseidon_constants.json
new file mode 100644
index 0000000..b5b6196
--- /dev/null
+++ b/test/modules/src/poseidon_constants.json
@@ -0,0 +1,3449 @@
+{
+ "C": [
+ [
+ "4417881134626180770308697923359573201005643519861877412381846989312604493735",
+ "5433650512959517612316327474713065966758808864213826738576266661723522780033",
+ "13641176377184356099764086973022553863760045607496549923679278773208775739952",
+ "17949713444224994136330421782109149544629237834775211751417461773584374506783",
+ "13765628375339178273710281891027109699578766420463125835325926111705201856003",
+ "19179513468172002314585757290678967643352171735526887944518845346318719730387",
+ "5157412437176756884543472904098424903141745259452875378101256928559722612176",
+ "535160875740282236955320458485730000677124519901643397458212725410971557409",
+ "1050793453380762984940163090920066886770841063557081906093018330633089036729",
+ "10665495010329663932664894101216428400933984666065399374198502106997623173873",
+ "19965634623406616956648724894636666805991993496469370618546874926025059150737",
+ "13007250030070838431593222885902415182312449212965120303174723305710127422213",
+ "16877538715074991604507979123743768693428157847423939051086744213162455276374",
+ "18211747749504876135588847560312685184956239426147543810126553367063157141465",
+ "18151553319826126919739798892854572062191241985315767086020821632812331245635",
+ "19957033149976712666746140949846950406660099037474791840946955175819555930825",
+ "3469514863538261843186854830917934449567467100548474599735384052339577040841",
+ "989698510043911779243192466312362856042600749099921773896924315611668507708",
+ "12568377015646290945235387813564567111330046038050864455358059568128000172201",
+ "20856104135605479600325529349246932565148587186338606236677138505306779314172",
+ "8206918720503535523121349917159924938835810381723474192155637697065780938424",
+ "1309058477013932989380617265069188723120054926187607548493110334522527703566",
+ "14076116939332667074621703729512195584105250395163383769419390236426287710606",
+ "10153498892749751942204288991871286290442690932856658983589258153608012428674",
+ "18202499207234128286137597834010475797175973146805180988367589376893530181575",
+ "12739388830157083522877690211447248168864006284243907142044329113461613743052",
+ "15123358710467780770838026754240340042441262572309759635224051333176022613949",
+ "19925004701844594370904593774447343836015483888496504201331110250494635362184",
+ "10352416606816998476681131583320899030072315953910679608943150613208329645891",
+ "10567371822366244361703342347428230537114808440249611395507235283708966113221",
+ "5635498582763880627392290206431559361272660937399944184533035305989295959602",
+ "11866432933224219174041051738704352719163271639958083608224676028593315904909",
+ "5795020705294401441272215064554385591292330721703923167136157291459784140431",
+ "9482202378699252817564375087302794636287866584767523335624368774856230692758",
+ "4245237636894546151746468406560945873445548423466753843402086544922216329298",
+ "12000500941313982757584712677991730019124834399479314697467598397927435905133",
+ "7596790274058425558167520209857956363736666939016807569082239187494363541787",
+ "2484867918246116343205467273440098378820186751202461278013576281097918148877",
+ "18312645949449997391810445935615409295369169383463185688973803378104013950190",
+ "15320686572748723004980855263301182130424010735782762814513954166519592552733",
+ "12618438900597948888520621062416758747872180395546164387827245287017031303859",
+ "17438141672027706116733201008397064011774368832458707512367404736905021019585",
+ "6374197807230665998865688675365359100400438034755781666913068586172586548950",
+ "2189398913433273865510950346186699930188746169476472274335177556702504595264",
+ "6268495580028970231803791523870131137294646402347399003576649137450213034606",
+ "17896250365994900261202920044129628104272791547990619503076839618914047059275",
+ "13692156312448722528008862371944543449350293305158722920787736248435893008873",
+ "15234446864368744483209945022439268713300180233589581910497691316744177619376",
+ "1572426502623310766593681563281600503979671244997798691029595521622402217227",
+ "80103447810215150918585162168214870083573048458555897999822831203653996617",
+ "8228820324013669567851850635126713973797711779951230446503353812192849106342",
+ "5375851433746509614045812476958526065449377558695752132494533666370449415873",
+ "12115998939203497346386774317892338270561208357481805380546938146796257365018",
+ "9764067909645821279940531410531154041386008396840887338272986634350423466622",
+ "8538708244538850542384936174629541085495830544298260335345008245230827876882",
+ "7140127896620013355910287215441004676619168261422440177712039790284719613114",
+ "14297402962228458726038826185823085337698917275385741292940049024977027409762",
+ "6667115556431351074165934212337261254608231545257434281887966406956835140819",
+ "20226761165244293291042617464655196752671169026542832236139342122602741090001",
+ "12038289506489256655759141386763477208196694421666339040483042079632134429119",
+ "19027757334170818571203982241812412991528769934917288000224335655934473717551",
+ "16272152964456553579565580463468069884359929612321610357528838696790370074720",
+ "2500392889689246014710135696485946334448570271481948765283016105301740284071",
+ "8595254970528530312401637448610398388203855633951264114100575485022581946023",
+ "11635945688914011450976408058407206367914559009113158286982919675551688078198",
+ "614739068603482619581328040478536306925147663946742687395148680260956671871",
+ "18692271780377861570175282183255720350972693125537599213951106550953176268753",
+ "4987059230784976306647166378298632695585915319042844495357753339378260807164",
+ "21851403978498723616722415377430107676258664746210815234490134600998983955497",
+ "9830635451186415300891533983087800047564037813328875992115573428596207326204",
+ "4842706106434537116860242620706030229206345167233200482994958847436425185478",
+ "6422235064906823218421386871122109085799298052314922856340127798647926126490",
+ "4564364104986856861943331689105797031330091877115997069096365671501473357846",
+ "1944043894089780613038197112872830569538541856657037469098448708685350671343",
+ "21179865974855950600518216085229498748425990426231530451599322283119880194955",
+ "14296697761894107574369608843560006996183955751502547883167824879840894933162",
+ "12274619649702218570450581712439138337725246879938860735460378251639845671898",
+ "16371396450276899401411886674029075408418848209575273031725505038938314070356",
+ "3702561221750983937578095019779188631407216522704543451228773892695044653565",
+ "19721616877735564664624984774636557499099875603996426215495516594530838681980",
+ "6383350109027696789969911008057747025018308755462287526819231672217685282429",
+ "20860583956177367265984596617324237471765572961978977333122281041544719622905",
+ "5766390934595026947545001478457407504285452477687752470140790011329357286275",
+ "4043175758319898049344746138515323336207420888499903387536875603879441092484",
+ "15579382179133608217098622223834161692266188678101563820988612253342538956534",
+ "1864640783252634743892105383926602930909039567065240010338908865509831749824",
+ "15943719865023133586707144161652035291705809358178262514871056013754142625673",
+ "2326415993032390211558498780803238091925402878871059708106213703504162832999",
+ "19995326402773833553207196590622808505547443523750970375738981396588337910289",
+ "5143583711361588952673350526320181330406047695593201009385718506918735286622",
+ "15436006486881920976813738625999473183944244531070780793506388892313517319583",
+ "16660446760173633166698660166238066533278664023818938868110282615200613695857",
+ "4966065365695755376133119391352131079892396024584848298231004326013366253934",
+ "20683781957411705574951987677641476019618457561419278856689645563561076926702",
+ "17280836839165902792086432296371645107551519324565649849400948918605456875699",
+ "17045635513701208892073056357048619435743564064921155892004135325530808465371",
+ "17055032967194400710390142791334572297458033582458169295920670679093585707295",
+ "15727174639569115300068198908071514334002742825679221638729902577962862163505",
+ "1001755657610446661315902885492677747789366510875120894840818704741370398633",
+ "18638547332826171619311285502376343504539399518545103511265465604926625041234",
+ "6751954224763196429755298529194402870632445298969935050224267844020826420799",
+ "3526747115904224771452549517614107688674036840088422555827581348280834879405",
+ "15705897908180497062880001271426561999724005008972544196300715293701537574122",
+ "574386695213920937259007343820417029802510752426579750428758189312416867750",
+ "15973040855000600860816974646787367136127946402908768408978806375685439868553",
+ "20934130413948796333037139460875996342810005558806621330680156931816867321122",
+ "6918585327145564636398173845411579411526758237572034236476079610890705810764",
+ "14158163500813182062258176233162498241310167509137716527054939926126453647182",
+ "4164602626597695668474100217150111342272610479949122406544277384862187287433",
+ "12146526846507496913615390662823936206892812880963914267275606265272996025304",
+ "10153527926900017763244212043512822363696541810586522108597162891799345289938",
+ "13564663485965299104296214940873270349072051793008946663855767889066202733588",
+ "5612449256997576125867742696783020582952387615430650198777254717398552960096",
+ "12151885480032032868507892738683067544172874895736290365318623681886999930120",
+ "380452237704664384810613424095477896605414037288009963200982915188629772177",
+ "9067557551252570188533509616805287919563636482030947363841198066124642069518",
+ "21280306817619711661335268484199763923870315733198162896599997188206277056900",
+ "5567165819557297006750252582140767993422097822227408837378089569369734876257",
+ "10411936321072105429908396649383171465939606386380071222095155850987201580137",
+ "21338390051413922944780864872652000187403217966653363270851298678606449622266",
+ "12156296560457833712186127325312904760045212412680904475497938949653569234473",
+ "4271647814574748734312113971565139132510281260328947438246615707172526380757",
+ "9061738206062369647211128232833114177054715885442782773131292534862178874950",
+ "10134551893627587797380445583959894183158393780166496661696555422178052339133",
+ "8932270237664043612366044102088319242789325050842783721780970129656616386103",
+ "3339412934966886386194449782756711637636784424032779155216609410591712750636",
+ "9704903972004596791086522314847373103670545861209569267884026709445485704400",
+ "17467570179597572575614276429760169990940929887711661192333523245667228809456"
+ ],
+ [
+ "6745197990210204598374042828761989596302876299545964402857411729872131034734",
+ "426281677759936592021316809065178817848084678679510574715894138690250139748",
+ "4014188762916583598888942667424965430287497824629657219807941460227372577781",
+ "21328925083209914769191926116470334003273872494252651254811226518870906634704",
+ "19525217621804205041825319248827370085205895195618474548469181956339322154226",
+ "1402547928439424661186498190603111095981986484908825517071607587179649375482",
+ "18320863691943690091503704046057443633081959680694199244583676572077409194605",
+ "17709820605501892134371743295301255810542620360751268064484461849423726103416",
+ "15970119011175710804034336110979394557344217932580634635707518729185096681010",
+ "9818625905832534778628436765635714771300533913823445439412501514317783880744",
+ "6235167673500273618358172865171408902079591030551453531218774338170981503478",
+ "12575685815457815780909564540589853169226710664203625668068862277336357031324",
+ "7381963244739421891665696965695211188125933529845348367882277882370864309593",
+ "14214782117460029685087903971105962785460806586237411939435376993762368956406",
+ "13382692957873425730537487257409819532582973556007555550953772737680185788165",
+ "2203881792421502412097043743980777162333765109810562102330023625047867378813",
+ "2916799379096386059941979057020673941967403377243798575982519638429287573544",
+ "4341714036313630002881786446132415875360643644216758539961571543427269293497",
+ "2340590164268886572738332390117165591168622939528604352383836760095320678310",
+ "5222233506067684445011741833180208249846813936652202885155168684515636170204",
+ "7963328565263035669460582454204125526132426321764384712313576357234706922961",
+ "1394121618978136816716817287892553782094854454366447781505650417569234586889",
+ "20251767894547536128245030306810919879363877532719496013176573522769484883301",
+ "141695147295366035069589946372747683366709960920818122842195372849143476473",
+ "15919677773886738212551540894030218900525794162097204800782557234189587084981",
+ "2616624285043480955310772600732442182691089413248613225596630696960447611520",
+ "4740655602437503003625476760295930165628853341577914460831224100471301981787",
+ "19201590924623513311141753466125212569043677014481753075022686585593991810752",
+ "12116486795864712158501385780203500958268173542001460756053597574143933465696",
+ "8481222075475748672358154589993007112877289817336436741649507712124418867136",
+ "5181207870440376967537721398591028675236553829547043817076573656878024336014",
+ "1576305643467537308202593927724028147293702201461402534316403041563704263752",
+ "2555752030748925341265856133642532487884589978209403118872788051695546807407",
+ "18840924862590752659304250828416640310422888056457367520753407434927494649454",
+ "14593453114436356872569019099482380600010961031449147888385564231161572479535",
+ "20826991704411880672028799007667199259549645488279985687894219600551387252871",
+ "9159011389589751902277217485643457078922343616356921337993871236707687166408",
+ "5605846325255071220412087261490782205304876403716989785167758520729893194481",
+ "1148784255964739709393622058074925404369763692117037208398835319441214134867",
+ "20945896491956417459309978192328611958993484165135279604807006821513499894540",
+ "229312996389666104692157009189660162223783309871515463857687414818018508814",
+ "21184391300727296923488439338697060571987191396173649012875080956309403646776",
+ "21853424399738097885762888601689700621597911601971608617330124755808946442758",
+ "12776298811140222029408960445729157525018582422120161448937390282915768616621",
+ "7556638921712565671493830639474905252516049452878366640087648712509680826732",
+ "19042212131548710076857572964084011858520620377048961573689299061399932349935",
+ "12871359356889933725034558434803294882039795794349132643274844130484166679697",
+ "3313271555224009399457959221795880655466141771467177849716499564904543504032",
+ "15080780006046305940429266707255063673138269243146576829483541808378091931472",
+ "21300668809180077730195066774916591829321297484129506780637389508430384679582",
+ "20480395468049323836126447690964858840772494303543046543729776750771407319822",
+ "10034492246236387932307199011778078115444704411143703430822959320969550003883",
+ "19584962776865783763416938001503258436032522042569001300175637333222729790225",
+ "20155726818439649091211122042505326538030503429443841583127932647435472711802",
+ "13313554736139368941495919643765094930693458639277286513236143495391474916777",
+ "14606609055603079181113315307204024259649959674048912770003912154260692161833",
+ "5563317320536360357019805881367133322562055054443943486481491020841431450882",
+ "10535419877021741166931390532371024954143141727751832596925779759801808223060",
+ "12025323200952647772051708095132262602424463606315130667435888188024371598063",
+ "2906495834492762782415522961458044920178260121151056598901462871824771097354",
+ "19131970618309428864375891649512521128588657129006772405220584460225143887876",
+ "8896386073442729425831367074375892129571226824899294414632856215758860965449",
+ "7748212315898910829925509969895667732958278025359537472413515465768989125274",
+ "422974903473869924285294686399247660575841594104291551918957116218939002865",
+ "6398251826151191010634405259351528880538837895394722626439957170031528482771",
+ "18978082967849498068717608127246258727629855559346799025101476822814831852169",
+ "19150742296744826773994641927898928595714611370355487304294875666791554590142",
+ "12896891575271590393203506752066427004153880610948642373943666975402674068209",
+ "9546270356416926575977159110423162512143435321217584886616658624852959369669",
+ "2159256158967802519099187112783460402410585039950369442740637803310736339200",
+ "8911064487437952102278704807713767893452045491852457406400757953039127292263",
+ "745203718271072817124702263707270113474103371777640557877379939715613501668",
+ "19313999467876585876087962875809436559985619524211587308123441305315685710594",
+ "13254105126478921521101199309550428567648131468564858698707378705299481802310",
+ "1842081783060652110083740461228060164332599013503094142244413855982571335453",
+ "9630707582521938235113899367442877106957117302212260601089037887382200262598",
+ "5066637850921463603001689152130702510691309665971848984551789224031532240292",
+ "4222575506342961001052323857466868245596202202118237252286417317084494678062",
+ "2919565560395273474653456663643621058897649501626354982855207508310069954086",
+ "6828792324689892364977311977277548750189770865063718432946006481461319858171",
+ "2245543836264212411244499299744964607957732316191654500700776604707526766099",
+ "19602444885919216544870739287153239096493385668743835386720501338355679311704",
+ "8239538512351936341605373169291864076963368674911219628966947078336484944367",
+ "15053013456316196458870481299866861595818749671771356646798978105863499965417",
+ "7173615418515925804810790963571435428017065786053377450925733428353831789901",
+ "8239211677777829016346247446855147819062679124993100113886842075069166957042",
+ "15330855478780269194281285878526984092296288422420009233557393252489043181621",
+ "10014883178425964324400942419088813432808659204697623248101862794157084619079",
+ "14014440630268834826103915635277409547403899966106389064645466381170788813506",
+ "3580284508947993352601712737893796312152276667249521401778537893620670305946",
+ "2559754020964039399020874042785294258009596917335212876725104742182177996988",
+ "14898657953331064524657146359621913343900897440154577299309964768812788279359",
+ "2094037260225570753385567402013028115218264157081728958845544426054943497065",
+ "18051086536715129874440142649831636862614413764019212222493256578581754875930",
+ "21680659279808524976004872421382255670910633119979692059689680820959727969489",
+ "13950668739013333802529221454188102772764935019081479852094403697438884885176",
+ "9703845704528288130475698300068368924202959408694460208903346143576482802458",
+ "12064310080154762977097567536495874701200266107682637369509532768346427148165",
+ "16970760937630487134309762150133050221647250855182482010338640862111040175223",
+ "9790997389841527686594908620011261506072956332346095631818178387333642218087",
+ "16314772317774781682315680698375079500119933343877658265473913556101283387175",
+ "82044870826814863425230825851780076663078706675282523830353041968943811739",
+ "21696416499108261787701615667919260888528264686979598953977501999747075085778",
+ "327771579314982889069767086599893095509690747425186236545716715062234528958",
+ "4606746338794869835346679399457321301521448510419912225455957310754258695442",
+ "64499140292086295251085369317820027058256893294990556166497635237544139149",
+ "10455028514626281809317431738697215395754892241565963900707779591201786416553",
+ "10421411526406559029881814534127830959833724368842872558146891658647152404488",
+ "18848084335930758908929996602136129516563864917028006334090900573158639401697",
+ "13844582069112758573505569452838731733665881813247931940917033313637916625267",
+ "13488838454403536473492810836925746129625931018303120152441617863324950564617",
+ "15742141787658576773362201234656079648895020623294182888893044264221895077688",
+ "6756884846734501741323584200608866954194124526254904154220230538416015199997",
+ "7860026400080412708388991924996537435137213401947704476935669541906823414404",
+ "7871040688194276447149361970364037034145427598711982334898258974993423182255",
+ "20758972836260983284101736686981180669442461217558708348216227791678564394086",
+ "21723241881201839361054939276225528403036494340235482225557493179929400043949",
+ "19428469330241922173653014973246050805326196062205770999171646238586440011910",
+ "7969200143746252148180468265998213908636952110398450526104077406933642389443",
+ "10950417916542216146808986264475443189195561844878185034086477052349738113024",
+ "18149233917533571579549129116652755182249709970669448788972210488823719849654",
+ "3729796741814967444466779622727009306670204996071028061336690366291718751463",
+ "5172504399789702452458550583224415301790558941194337190035441508103183388987",
+ "6686473297578275808822003704722284278892335730899287687997898239052863590235",
+ "19426913098142877404613120616123695099909113097119499573837343516470853338513",
+ "5120337081764243150760446206763109494847464512045895114970710519826059751800",
+ "5055737465570446530938379301905385631528718027725177854815404507095601126720",
+ "14235578612970484492268974539959119923625505766550088220840324058885914976980",
+ "653592517890187950103239281291172267359747551606210609563961204572842639923",
+ "5507360526092411682502736946959369987101940689834541471605074817375175870579",
+ "7864202866011437199771472205361912625244234597659755013419363091895334445453",
+ "21294659996736305811805196472076519801392453844037698272479731199885739891648",
+ "13767183507040326119772335839274719411331242166231012705169069242737428254651",
+ "810181532076738148308457416289197585577119693706380535394811298325092337781",
+ "14232321930654703053193240133923161848171310212544136614525040874814292190478",
+ "16796904728299128263054838299534612533844352058851230375569421467352578781209",
+ "16256310366973209550759123431979563367001604350120872788217761535379268327259",
+ "19791658638819031543640174069980007021961272701723090073894685478509001321817",
+ "7046232469803978873754056165670086532908888046886780200907660308846356865119",
+ "16001732848952745747636754668380555263330934909183814105655567108556497219752",
+ "9737276123084413897604802930591512772593843242069849260396983774140735981896",
+ "11410895086919039954381533622971292904413121053792570364694836768885182251535",
+ "19098362474249267294548762387533474746422711206129028436248281690105483603471",
+ "11013788190750472643548844759298623898218957233582881400726340624764440203586",
+ "2206958256327295151076063922661677909471794458896944583339625762978736821035",
+ "7171889270225471948987523104033632910444398328090760036609063776968837717795",
+ "2510237900514902891152324520472140114359583819338640775472608119384714834368",
+ "8825275525296082671615660088137472022727508654813239986303576303490504107418",
+ "1481125575303576470988538039195271612778457110700618040436600537924912146613",
+ "16268684562967416784133317570130804847322980788316762518215429249893668424280",
+ "4681491452239189664806745521067158092729838954919425311759965958272644506354",
+ "3131438137839074317765338377823608627360421824842227925080193892542578675835",
+ "7930402370812046914611776451748034256998580373012248216998696754202474945793",
+ "8973151117361309058790078507956716669068786070949641445408234962176963060145",
+ "10223139291409280771165469989652431067575076252562753663259473331031932716923",
+ "2232089286698717316374057160056566551249777684520809735680538268209217819725",
+ "16930089744400890347392540468934821520000065594669279286854302439710657571308",
+ "21739597952486540111798430281275997558482064077591840966152905690279247146674",
+ "7508315029150148468008716674010060103310093296969466203204862163743615534994",
+ "11418894863682894988747041469969889669847284797234703818032750410328384432224",
+ "10895338268862022698088163806301557188640023613155321294365781481663489837917",
+ "18644184384117747990653304688839904082421784959872380449968500304556054962449",
+ "7414443845282852488299349772251184564170443662081877445177167932875038836497",
+ "5391299369598751507276083947272874512197023231529277107201098701900193273851",
+ "10329906873896253554985208009869159014028187242848161393978194008068001342262",
+ "4711719500416619550464783480084256452493890461073147512131129596065578741786",
+ "11943219201565014805519989716407790139241726526989183705078747065985453201504",
+ "4298705349772984837150885571712355513879480272326239023123910904259614053334",
+ "9999044003322463509208400801275356671266978396985433172455084837770460579627",
+ "4908416131442887573991189028182614782884545304889259793974797565686968097291",
+ "11963412684806827200577486696316210731159599844307091475104710684559519773777",
+ "20129916000261129180023520480843084814481184380399868943565043864970719708502",
+ "12884788430473747619080473633364244616344003003135883061507342348586143092592",
+ "20286808211545908191036106582330883564479538831989852602050135926112143921015",
+ "16282045180030846845043407450751207026423331632332114205316676731302016331498",
+ "4332932669439410887701725251009073017227450696965904037736403407953448682093",
+ "11105712698773407689561953778861118250080830258196150686012791790342360778288",
+ "21853934471586954540926699232107176721894655187276984175226220218852955976831",
+ "9807888223112768841912392164376763820266226276821186661925633831143729724792",
+ "13411808896854134882869416756427789378942943805153730705795307450368858622668",
+ "17906847067500673080192335286161014930416613104209700445088168479205894040011",
+ "14554387648466176616800733804942239711702169161888492380425023505790070369632",
+ "4264116751358967409634966292436919795665643055548061693088119780787376143967",
+ "2401104597023440271473786738539405349187326308074330930748109868990675625380",
+ "12251645483867233248963286274239998200789646392205783056343767189806123148785",
+ "15331181254680049984374210433775713530849624954688899814297733641575188164316",
+ "13108834590369183125338853868477110922788848506677889928217413952560148766472",
+ "6843160824078397950058285123048455551935389277899379615286104657075620692224",
+ "10151103286206275742153883485231683504642432930275602063393479013696349676320",
+ "7074320081443088514060123546121507442501369977071685257650287261047855962224",
+ "11413928794424774638606755585641504971720734248726394295158115188173278890938",
+ "7312756097842145322667451519888915975561412209738441762091369106604423801080",
+ "7181677521425162567568557182629489303281861794357882492140051324529826589361",
+ "15123155547166304758320442783720138372005699143801247333941013553002921430306",
+ "13409242754315411433193860530743374419854094495153957441316635981078068351329"
+ ],
+ [
+ "11633431549750490989983886834189948010834808234699737327785600195936805266405",
+ "17353750182810071758476407404624088842693631054828301270920107619055744005334",
+ "11575173631114898451293296430061690731976535592475236587664058405912382527658",
+ "9724643380371653925020965751082872123058642683375812487991079305063678725624",
+ "20936725237749945635418633443468987188819556232926135747685274666391889856770",
+ "6427758822462294912934022562310355233516927282963039741999349770315205779230",
+ "16782979953202249973699352594809882974187694538612412531558950864304931387798",
+ "8979171037234948998646722737761679613767384188475887657669871981433930833742",
+ "5428827536651017352121626533783677797977876323745420084354839999137145767736",
+ "507241738797493565802569310165979445570507129759637903167193063764556368390",
+ "6711578168107599474498163409443059675558516582274824463959700553865920673097",
+ "2197359304646916921018958991647650011119043556688567376178243393652789311643",
+ "4634703622846121403803831560584049007806112989824652272428991253572845447400",
+ "17008376818199175111793852447685303011746023680921106348278379453039148937791",
+ "18430784755956196942937899353653692286521408688385681805132578732731487278753",
+ "4573768376486344895797915946239137669624900197544620153250805961657870918727",
+ "5624865188680173294191042415227598609140934495743721047183803859030618890703",
+ "8228252753786907198149068514193371173033070694924002912950645971088002709521",
+ "17586714789554691446538331362711502394998837215506284064347036653995353304693",
+ "12985198716830497423350597750558817467658937953000235442251074063454897365701",
+ "13480076116139680784838493959937969792577589073830107110893279354229821035984",
+ "480609231761423388761863647137314056373740727639536352979673303078459561332",
+ "19503345496799249258956440299354839375920540225688429628121751361906635419276",
+ "16837818502122887883669221005435922946567532037624537243846974433811447595173",
+ "5492108497278641078569490709794391352213168666744080628008171695469579703581",
+ "11365311159988448419785032079155356000691294261495515880484003277443744617083",
+ "13876891705632851072613751905778242936713392247975808888614530203269491723653",
+ "10660388389107698747692475159023710744797290186015856503629656779989214850043",
+ "18876318870401623474401728758498150977988613254023317877612912724282285739292",
+ "15543349138237018307536452195922365893694804703361435879256942490123776892424",
+ "2839988449157209999638903652853828318645773519300826410959678570041742458201",
+ "7566039810305694135184226097163626060317478635973510706368412858136696413063",
+ "6344830340705033582410486810600848473125256338903726340728639711688240744220",
+ "12475357769019880256619207099578191648078162511547701737481203260317463892731",
+ "13337401254840718303633782478677852514218549070508887338718446132574012311307",
+ "21161869193849404954234950798647336336709035097706159414187214758702055364571",
+ "20671052961616073313397254362345395594858011165315285344464242404604146448678",
+ "2772189387845778213446441819361180378678387127454165972767013098872140927416",
+ "3339032002224218054945450150550795352855387702520990006196627537441898997147",
+ "14919705931281848425960108279746818433850049439186607267862213649460469542157",
+ "17056699976793486403099510941807022658662936611123286147276760381688934087770",
+ "16144580075268719403964467603213740327573316872987042261854346306108421013323",
+ "15582343953927413680541644067712456296539774919658221087452235772880573393376",
+ "17528510080741946423534916423363640132610906812668323263058626230135522155749",
+ "3190600034239022251529646836642735752388641846393941612827022280601486805721",
+ "8463814172152682468446984305780323150741498069701538916468821815030498611418",
+ "16533435971270903741871235576178437313873873358463959658178441562520661055273",
+ "11845696835505436397913764735273748291716405946246049903478361223369666046634",
+ "18391057370973634202531308463652130631065370546571735004701144829951670507215",
+ "262537877325812689820791215463881982531707709719292538608229687240243203710",
+ "2187234489894387585309965540987639130975753519805550941279098789852422770021",
+ "19189656350920455659006418422409390013967064310525314160026356916172976152967",
+ "15839474183930359560478122372067744245080413846070743460407578046890458719219",
+ "1805019124769763805045852541831585930225376844141668951787801647576910524592",
+ "323592203814803486950280155834638828455175703393817797003361354810251742052",
+ "9780393509796825017346015868945480913627956475147371732521398519483580624282",
+ "14009429785059642386335012561867511048847749030947687313594053997432177705759",
+ "13749550162460745037234826077137388777330401847577727796245150843898019635981",
+ "19497187499283431845443758879472819384797584633472792651343926414232528405311",
+ "3708428802547661961864524194762556064568867603968214870300574294082023305587",
+ "1339414413482882567499652761996854155383863472782829777976929310155400981782",
+ "6396261245879814100794661157306877072718690153118140891315137894471052482309",
+ "2069661495404347929962833138824526893650803079024564477269192079629046031674",
+ "15793521554502133342917616035884588152451122589545915605459159078589855944361",
+ "17053424498357819626596285492499512504457128907932827007302385782133229252374",
+ "13658536470391360399708067455536748955260723760813498481671323619545320978896",
+ "21546095668130239633971575351786704948662094117932406102037724221634677838565",
+ "21411726238386979516934941789127061362496195649331822900487557574597304399109",
+ "1944776378988765673004063363506638781964264107780425928778257145151172817981",
+ "15590719714223718537172639598316570285163081746016049278954513732528516468773",
+ "1351266421179051765004709939353170430290500926943038391678843253157009556309",
+ "6772476224477167317130064764757502335545080109882028900432703947986275397548",
+ "10670120969725161535937685539136065944959698664551200616467222887025111751992",
+ "4731853626374224678749618809759140702342195350742653173378450474772131006181",
+ "14473527495914528513885847341981310373531349450901830749157165104135412062812",
+ "16937191362061486658876740597821783333355021670608822932942683228741190786143",
+ "5656559696428674390125424316117443507583679061659043998559560535270557939546",
+ "8897648276515725841133578021896617755369443750194849587616503841335248902806",
+ "14938684446722672719637788054570691068799510611164812175626676768545923371470",
+ "15284149043690546115252102390417391226617211133644099356880071475803043461465",
+ "2623479025068612775740107497276979457946709347831661908218182874823658838107",
+ "6809791961761836061129379546794905411734858375517368211894790874813684813988",
+ "2417620338751920563196799065781703780495622795713803712576790485412779971775",
+ "4445143310792944321746901285176579692343442786777464604312772017806735512661",
+ "1429019233589939118995503267516676481141938536269008901607126781291273208629",
+ "19874283200702583165110559932895904979843482162236139561356679724680604144459",
+ "13426632171723830006915194799390005513190035492503509233177687891041405113055",
+ "10582332261829184460912611488470654685922576576939233092337240630493625631748",
+ "21233753931561918964692715735079738969202507286592442257083521969358109931739",
+ "15570526832729960536088203016939646235070527502823725736220985057263010426410",
+ "9379993197409194016084018867205217180276068758980710078281820842068357746159",
+ "20771047769547788232530761122022227554484215799917531852224053856574439035591",
+ "20468066117407230615347036860121267564735050776924839007390915936603720868039",
+ "5488458379783632930817704196671117722181776789793038046303454621235628350505",
+ "1394272944960494549436156060041871735938329188644910029274839018389507786995",
+ "5147716541319265558364686380685869814344975511061045836883803841066664401308",
+ "14583556014436264794011679557180458872925270147116325433110111823036572987256",
+ "11881598145635709076820802010238799308467020773223027240974808290357539410246",
+ "1566675577370566803714158020143436746360531503329117352692311127363508063658",
+ "212097210828847555076368799807292486212366234848453077606919035866276438405",
+ "7447795983723838393344606913699113402588250391491430720006009618589586043349",
+ "7626475329478847982857743246276194948757851985510858890691733676098590062312",
+ "148936322117705719734052984176402258788283488576388928671173547788498414614",
+ "15456385653678559339152734484033356164266089951521103188900320352052358038156",
+ "18207029603568083031075933940507782729612798852390383193518574746240484434885",
+ "2783356767974552799246444090988849933848968900471538294757665724820698962027",
+ "2721136724873145834448711197875719736776242904173494370334510875996324906822",
+ "2101139679159828164567502977338446902934095964116292264803779234163802308621",
+ "8995221857405946029753863203034191016106353727035116779995228902499254557482",
+ "502050382895618998241481591846956281507455925731652006822624065608151015665",
+ "4998642074447347292230083981705092465562944918178587362047610976950173759150",
+ "9349925422548495396957991080641322437286312278286826683803695584372829655908",
+ "11780347248050333407713097022607360765169543706092266937432199545936788840710",
+ "17875657248128792902343900636176628524337469245418171053476833541334867949063",
+ "10366707960411170224546487410133378396211437543372531210718212258701730218585",
+ "16918708725327525329474486073529093971911689155838787615544405646587858805834",
+ "18845394288827839099791436411179859406694814287249240544635770075956540806104",
+ "9838806160073701591447223014625214979004281138811495046618998465898136914308",
+ "10285680425916086863571101560978592912547567902925573205991454216988033815759",
+ "1292119286233210185026381033809498665433650491423040630240164455269575958565",
+ "2665524343601461489082054230426835550060387413710679950970616347092017688857",
+ "13502286133892103192305476866434484921895765252706158317341618311553476426306",
+ "686854655578191041672292972738875170071982317195092845673566320025160026512",
+ "9315942923163981372372434957632152754092082859001311184186702151150554806508",
+ "17166793131238158480636170455452575971861309825745828685724097210995239015581",
+ "4443784618760852757287735236046535266034706880634443644576653970979377878608",
+ "21470445782021672615018345703580059646973568891521510437236903770708690160080",
+ "6932852445473908850835611723958058203645654625170962537129706393570586565567",
+ "17078326120157725640173982185667969009350208542843294226397809921509565607842",
+ "19251873001736801921864956728611772738233338338726553113352118847732921831266",
+ "13062907978694932362695258750558734366820802962383346229947907261606619788585",
+ "16576609187793673559170206379939616900133457644695219057683704871664434872406",
+ "17140499059660867342372156843620845644831519603574612796639429147195776838516",
+ "16226688173010504218547945848523900236290532501559570164276462499487632388445",
+ "2806068123803905806401128967330263340459046260107112845068533446899070326517",
+ "17788735370835052317224182711467216134690146479710634688273650370951230404901",
+ "9840665370904113434661468973557421114403401847108482949465899631150766783733",
+ "17357287363046228581837055771327121704742940914150998420465281177406182088510",
+ "8956082469997974864521346025916496675956939495318858500685756691488425559998",
+ "10583741436561099911914917245130852199607666337956354910388730829023746895549",
+ "15241902639811607164983030447109332729761435946009172128089506810551693978973",
+ "10889882303914055687481932975789161945462141459528413507160087442461090813788",
+ "19789561133254944544821898921133697408237804586549835559829396563401674817160",
+ "20741336668287037026472434608739333171202674306575625457456116338034432647230",
+ "17864073449995977742930566850933082711031717858550870842712972350665650521079",
+ "6017691253505466300212182439349954426085752315661098358839308909771637792741",
+ "5209125836207196173669497054522582922896061838702136844305036341250990710540",
+ "8138726312837322624537330169363664364899441867118983214176695868443641051381",
+ "15491983986041746833254372934846748393213690608865689646440909282144232382678",
+ "5054332867608171303802774230688792431028169804536607979111644888500809938980",
+ "15427030776591294577308915282298854681562344215287630895931797573417982096417",
+ "21754057982677295571284116502193272661309010996970316384923307174180521790164",
+ "16265286590463120486705206231835953324076688991892805307349612983237844034032",
+ "17679791107777049796013011282788633179411040182820636236163074053597517790779",
+ "4281652562868629887097957174897458165728741859103571825874408386197225591996",
+ "9168010397863299719604788533602757515513214141450093775967322808686129400625",
+ "17584182367226175071087689123358883902969885218985589531538416263709138156515",
+ "15671512310414658663135385639435845966109237059155734764323312289873534719186",
+ "10536294659491685326297777845632759824567028904726211134518740400643540109527",
+ "13431319759608247201135260841651365578663315527795431484765940626659812285319",
+ "9584697124715190200241839387725546204368618031045071660911490086723434692561",
+ "5180327104839158483066851400960171505063442195966219343315555549982472660055",
+ "18888217223053385111625483360538133292128748730565502371803782424772027937822",
+ "19535732913737027522540340630296365525208404217634392013266346283017745945894",
+ "8577759627886344995887423695190093296190181539234301534326157005220006624466",
+ "16793670928407147476673650839110019799844249677846432113010280456483595763987",
+ "13926032620965299897272071104154310460519723329016284975305942957859374938463",
+ "4794697578055472890255676575927616606591024075768967985031137397587590174501",
+ "3529566190782060578446859853852791941913086545101307988176595267965876143250",
+ "3975008029239568933166738482470827494289192118694622729549964538823092192163",
+ "17739094873244464728483944474780943281491793683051033330476367597242349886622",
+ "7367136451127531266518046223598095299278392589059366687082785080179161005418",
+ "11175297939460631138047404082172242706491354303440776362693987984031241399771",
+ "21687543815463985355165197827968086406938428974327951792877419032069230058777",
+ "21156136641989461785420005321350884477682466566148802533375726181416623358719",
+ "17347558768803521970212188258074365309929638984714303299899732035040892048478",
+ "16293716234695956076322008955071091921491953458541407305955104663269677475740",
+ "4206144021605871396668976569508168522675546062304959729829228403361714668567",
+ "19988050626299122864942213847548542155670073758974734015174045163059179151544",
+ "747972634423324369570795147739377097591383105262743308036321386836856106229",
+ "4612470951309047869982067912468200581649949743307592869671537990797895413707",
+ "9630852913694079049153027193127278569487291430069466630362958024525616303220",
+ "17941539917430916523930519432495442476511211427972760202450248798031711471474",
+ "20332911350443969653703295317915788278109458962706923653715140186132935894113",
+ "21764801803055897327474057344100833670291402543384934706514147201527191846513",
+ "18792043166429470991157980448329308661526906138700725174612608941551872082876",
+ "12308177224490762720061048892842527800271687977085172836705858261595655154325",
+ "6234555076867437297776538521925679658360922070165740193866337972293380196151",
+ "4651047048822067434403056477377459986292934655827821636179452835839127581305",
+ "4762047093602693619418269784972874862577325737690375448572644958129932507374",
+ "12373514879531674477721132062882065826558811149582829246378921774344318418269",
+ "452512704634345955634014968317367844987135264395068376894497483188243356523",
+ "21642936370936057063268550589361090955573362743817395689260298777690935495218",
+ "16170209200627740434842090607802586195654207376087117044989637541681675086276",
+ "11682826760471401430136435257946377996085824742031456481961511737883954750045",
+ "20628055165039718158878805520495324869838279647796500565701893698896698211929",
+ "16438375313036818694140277721632185529697783132872683043559674569424388375143",
+ "4855690425141732729622202649174026736476144238882856677953515240716341676853",
+ "11680269552161854836013784579325442981497075865007420427279871128110023581360",
+ "7052688838948398479718163301866620773458411881591190572311273079833122884040",
+ "10339199500986679207942447430230758709198802637648680544816596214595887890122",
+ "16310974164366557619327768780809157500356605306298690718711623172209302167675",
+ "4572051236178600578566286373491186377601851723137133424312445102215267283375",
+ "20933392620931420860078756859763708025350478446661033451436796955762857910093",
+ "10145870387395991071594748880090507240612313913083518483680901820696866812598",
+ "11173854866888110108878560284050142518686158431744851782991510385755602063727",
+ "3895357290105797542988795070918100785105415165483657264407967118738833241858",
+ "16358886674154007883356717944805100413481233709808000948036974385803613296849",
+ "10544067501284177518983466437755150442726536257903869254459488412549270232123",
+ "10495171258604974589451578238018388630585794890815982293891430761424812600427",
+ "13820724103604550843562070971473423552484851063169471886037640613650155173554",
+ "2334954333435579600152488915208745055087482119087065911968347050969338669409",
+ "15100284614446277058846085121308897497066957549089629374506920751044105723791",
+ "8493821960754696376711287628276980042183127459347650448500304251148421115590",
+ "18612435536889941393944858783110719304584209891406420832295898519317994950798",
+ "362101794940079733974215941991047456600874474038781578925062694203564740952",
+ "11020033081956343850903875701444955317664141075326494650405276926536449284939",
+ "9396289482656518627529185765935649373549564165735162258912975312413185691167",
+ "6879055176150676925438486069371149089824290576271090206945130252868108043422",
+ "12466610601804566637227883322591924115458766539177061670432424956205788935144",
+ "6570302110526154075173287644133038486970998888099669190857256824048085590052",
+ "20997862990590350605775941983360263378441519274215787225587679916056749626824",
+ "2642485040919927233352421501444361753154137311893617974318977215281720542724",
+ "18832940311494549247524002614969382413324906834787422940144532352384742506504",
+ "18751288968473015103659806087408412890105261892140397690496125593160830694164",
+ "13938622158186434739533995447553824444480420613323252752005511269934155122652",
+ "12878982657080117316101160964182202074759312554860119090514406868768962707099",
+ "13757859113119127982418426758782225628393556023865807897214601826218702003247",
+ "11817871682869491875135867072669251115204978941736982465520516648114811792373",
+ "11336448548896065624515261709306933490181794458266726453198857687608284871020",
+ "194970717714150352477887371297168267861902418496792228400198694925721020795",
+ "4999282817977533227652305360183045040853565298259070645110453061034932285549",
+ "17094174197873140035316532568922652294881600587639905417701074492648767414173",
+ "8484251464872873032022789624790167173458682056313339863651348894878144808746",
+ "10260366716129057466862964875306868898686918428814373470382979997177852668590",
+ "549263552864476084904464374701167884060947403076520259964592729731619317724",
+ "10052714818439832487575851829190658679562445501271745818931448693381812170889",
+ "1735373362835209096342827192021124337509188507323448903608623506589963950966",
+ "7998373949540733111485892137806629484517602009122941425332571732658301689428",
+ "9035170288660659483243066011612158174896974797912618405030929911180945246244",
+ "6458619567307414386633203375143968061892762498463026121155477954682976784731",
+ "12314261817227551876673777186352972884847144237148169773300066404053441924532",
+ "19869454329688183813243851218196625862680921049019496233616575272637276975230",
+ "20326917073492686652690019138603910654692396590122884746951129061818467704300",
+ "20403270805536666081472738304916561119325397964511536801752236086414818653063",
+ "2865941730880218719188224311916978807415673142487507504983320505748719154068",
+ "20614246027521726470902405957496110178017768563127335842405314212897493119848",
+ "12060194341463088508348622863463208827312128863463014006529428845777217660299",
+ "1128906798719793375274166820235650701301189774851381709919492584451845983197",
+ "19670876372911656158743764425809421400123168087389888660308456184201759209723",
+ "5647230694522866559497222129254930524469944430191328619422533907417776118543",
+ "318629082509194371490189248876734616088516535434806492900653650176451776632",
+ "13685970881538585172319228162662520285656571966985351768743970447782846353365",
+ "8283840607829148567836919316142994745766280854211662326632930274668867638198",
+ "8968895518159422029900464138741638511289476298837958524156654785428413265371",
+ "10061801991000917366002570579819627134666386452411986168205986791283562415829"
+ ],
+ [
+ "6652655389322448471317061533546982911992554640679550674058582942754771150993",
+ "2411464732857349694082092299330329691469354396507353145272547491824343787723",
+ "21491443688002139478732659842894153142870918973450440713149176834049574486740",
+ "20196926676989483530222124573030747187074792043523478381149800153065505592963",
+ "12986278951352369831003505493892366673723882190521699331613883287145355738793",
+ "21126146258242782643168619000295062005037298340836817770565977031890883232034",
+ "15509665795506578582538177431401381655815033647735781734613703976071034655246",
+ "6989769181472743404364681671283889685042701491627165526899522083327752110839",
+ "7062179885254277466334896166987547257487047183881628199983668518000910197987",
+ "13842521112365108087725039904948872289730786568469683976372377853164252494752",
+ "3830559505943186272618534143266118508463381443414165428900505002474439179836",
+ "17704863473432653834041116667846189591617394753001613253930974854399793083900",
+ "875580502229441633079974792778818749112423694973231971690365132230865385439",
+ "1971134273535892826573832061354985059300866001765691176219451252512658771248",
+ "4865738840363990164915013008693722144676933915103280504727326977328013515878",
+ "1148603338028060679975883868174895825055359423662532941509525326937127571764",
+ "17506086433923270253695698017062834613463718526046463655503742220257039588796",
+ "21580033018107258179208198773211859664893072138803756118939260252922297665067",
+ "15411900706973212043830142913959920716501447427702082030760032355626616412240",
+ "12219699506725448409610279620972339448030565224304464695714944121760832152291",
+ "4525719544192047521328360848269156485222470829314314216955024799558286708479",
+ "19667371373588322336224317159113441765198420040800065314868656839300028747331",
+ "18916925604689704279265158984702141998345424765142129953154245912230835240445",
+ "12789343981741773931665143789673052782408749041041266509485929045869073416222",
+ "3094428508959717445577232225505810354980663487713729230015754183012845687401",
+ "18544590634480965569098056786078005630500574069468005220462377474861119476492",
+ "20990087440247450018723844204951613913840993427110495085701200965767234569705",
+ "17552251989761134508416634118845221324472178264364440017634233349418103869223",
+ "21000797802575507763447855752602183842956182733750968489641741136166640639409",
+ "19292751508591545849778577901067988044973302547209758604667395356943370737868",
+ "18314088316445539319869442180584299715533304874169767778761887632882728399870",
+ "15003745150856597539000559910957155642193629735521291045949652201905498569732",
+ "7839443900003691950104175747634267110464104444913379977500178134209666299140",
+ "13568305490393393394812598233983935295266242465548739772708079888867621061127",
+ "6453005227995051361096639028742707098785560656441339640433794156400437698140",
+ "1420171596348195609536167209221442141824294918625468780931400849866478645240",
+ "8347329128252205996443084339884155586061343024498283583400215109265013719709",
+ "7893774494551056447960817286805128884970061671041428326788899872964096959040",
+ "8970476243368194065341537088653900235777512204874037182428362347342487241690",
+ "239049405935404678508864874854718951364753739466303321590415544572014148257",
+ "15772878921699764223771017074289335629553777447709755479885293350677783703695",
+ "5416082112919155131434995906647355834510201879607888732259087164602171650389",
+ "4384524908062410354304345761652962203632712291085564157560146286207296352050",
+ "4210984612917608245844011498198864216639269565627982123611519493203177283139",
+ "18816442907032290878644773027005263628136050677095986565400687355912498966559",
+ "21443510232279945782338486087712914668515437675585863788610958361560172084515",
+ "3234314779308300525339049581669531363375743827111579883853941968586490182859",
+ "11029499234949696730080035941750777601416171837281021031653841244636590396063",
+ "11145210633226924132308292113124660576759662647204939721872338908644906571564",
+ "4583160563963432761409369246361117506465307518522062239686649163525543782173",
+ "9813992026757562966842771727657080117609486122615087352428596024939855084450",
+ "10084171857039480706430282187972782725948479260179367780776125786119489581409",
+ "3874212709197875589640151274548083098712939093643165182881681226579903752816",
+ "21595542491397091124739711708612983479307589335640792812157875295064235960610",
+ "2068530815441314105493629066002923150651375034543842424822712297257260726954",
+ "2673459852071215292298131389250564595426361004231758522146794940265552265806",
+ "8591046256746588406353455230465605224309754008961178558834659065898923355164",
+ "1020055192431352394776887540248098706183934464205704158014904833376067287118",
+ "11085709480582865378042656141271006552092494690130782253913953070642865919312",
+ "5673844083530503489429922596812992664928167369104420134641855283771127716005",
+ "10492199162275168254265892158402955076490959375050993042712629236807564461542",
+ "2280843393156259739329331366624245275580688891778782679394848304764573859886",
+ "6807797027131305026345508953353882265754363485246407959111359919046340709440",
+ "12692191384043938397944633973317584101723715998700063415107128429315536223446",
+ "19818676957110967644349139912613239435706480354664804036688552936554140369382",
+ "18055602608192644695569077694296748842203151828348990995792087204755925787339",
+ "20934555391215769430553078793246717148484784880715746179415906355043590089450",
+ "11420705181439111353998210442417752592951340005396931802449360401461783159557",
+ "19878854521263746227125001670931867821366047088989510542865511663910116386085",
+ "8568201846715449867087132677683368912214864824182424933182820310911278496552",
+ "19198701614488576617610339232794062430644024620523684127268879880793305460015",
+ "15262122764244854433806270478871594904740306012582364033343126589996733802868",
+ "6412758421155818207287638337822550233376667015263373809976157264137577776202",
+ "17371585001641430978766734501830788427263945848682170096055857509304472649262",
+ "20262970042379497707724791203314262108784948621691331141565359315001027736581",
+ "3859750447119748295302212198327542106766447958113540005985799287718502362717",
+ "1172269945800307665458943534144481495673510885455899148864236015097947176746",
+ "8164247467959680477306326470118519335673181279975551434197731340070491876250",
+ "4513977811114181395323888111232002391599397736872779927267726121435887238972",
+ "1075250595927474080680862736233039825365918646878264905022213616210377518447",
+ "18658420120424372681792175914064174056413842231969276203770574969914576681364",
+ "17769673440848360838244654765103041739044212539359630263894092078288342647801",
+ "4319086204044362848967484441065231939136453667264715596505827197873119273506",
+ "11221173270629292820060668122527062274557317856738971635698169204652845111606",
+ "8635411372759272135249379415383299350267629947167809163276219879514948820576",
+ "926977621651476360285369760355547766944001783780761167546467658394097283069",
+ "17702143780592866375901805387463459229828093905183622296234691441436877570082",
+ "629612289140842594504574984021125242351317893847688437087866691775821981724",
+ "19990548577495092294245865870717186004301934545721835081514347926537975465539",
+ "7124830628609719908679298707909792306162298058570958688501370177898647946696",
+ "14620227791860703231425817538142948793892390269806790476396226159679984968174",
+ "18495581997440241868332244230687799183899751339442721677540757155760745277888",
+ "16922065056093401385376103551657968760602009001905886435813054626317776258714",
+ "9969610601962874779035054685661667941954971427956866645694064022029705170229",
+ "15281641269114187762159685323068136816556739502211864119670902056596295644116",
+ "12114994625438879103001132949163961965524612903017200394727056658298824651596",
+ "4840986177718281128440833017205097196672382395936939379498412745183060615212",
+ "12847307562796769659308999092658905656250954898192781948610713494470441775991",
+ "20290096217351155282642224215178246911041509999959311313223857240001143893317",
+ "16151664509646153154405691138084115125600386733136285504828908979176781265710",
+ "13848845391482751436287906247470303487958950799995701248612703022979890932133",
+ "6335716166231441585596963683321661194889815181545222079376536449814718259931",
+ "1824302750039354704619545544386637317858342555634601563660279997221547953768",
+ "11327469654081586239268713126961534952233559223228327222485848924908493444712",
+ "10077703415170135154603829433031861799853903739210136452726077323833067256620",
+ "16368073884579385814331927334821006319227867093692644942500207970751483237405",
+ "10621580796499573269115131164341885791299038227955222944695715163010783205295",
+ "2099241376651019397894434242565225315652133572870234550073686122343103853816",
+ "17104632243449417396641550271977294699471083572885397875525767745512335891599",
+ "1935453754847256492223646005402770357836971113012418013930273797463411526183",
+ "7492761611332930896292052363224494314920390056637668407353957465667515477934",
+ "16836705924460095689555600825174696605443212968244843485187771119291716736958",
+ "16995495500678141665340056658079449793587669420913589967848082091551329904176",
+ "16097379973857697753436437302681608056543122759719328497348770844548177814262",
+ "17476569537128329379528694049566216604638194592812108658767104922628767500420",
+ "17997217989870184804787026924935938133194070033518938653831611194683423549591",
+ "17573343771046232580761295935281170028624495346579002725814597714902588657750",
+ "2450087639204541254902859018960918562514681200270997307467560465282168310665",
+ "17288084325555056222618040923753050382954155896826087372317882602328092535440",
+ "21837047676579063581498107773514419735425738753079336764356909012851439336687",
+ "370061273472837873736743292149368449614309676635341873070086681342317566380",
+ "420725183996224279379885018872359102189091670793820517618337092091910692771",
+ "4966571645678139143731798992823327185758562224229132271884647901363447388530",
+ "5039558223429273757296118284876763395391635773837549121798873235133698166026",
+ "14663152729953724779401067486012084029581847325524052152795817923033297673686",
+ "7201040456590575809960214033959496417566605177095808543357813677845263237276",
+ "16872945504528960415453618286121813996587432836152082188694652370255998768595",
+ "4914824783780909279212078186433590922437371437384817332713271291839616026466",
+ "17503018483514413315464207189113334433424965178631599286655188843769810245465",
+ "4087750571011463387872022799241315348852213278729592692674275176152296405923",
+ "4006961923780091252337105595934918049936238157468198971234322013673884171131",
+ "4481908842184366902145805444001507554481032302978790080019710161108326487967",
+ "13532316826436461968093937893872910736305115143550039673102602344678825540956",
+ "11602986656925867325907196773754426955346837006705269228226729102186031417465",
+ "15306992574062791537454541745213815567999895856471097922112648012979731636068",
+ "4497571735611504561173050536899411999551839050319538712220770383407135602945",
+ "2571242673174714867278075260451133687893879636121064640779554188161591611843",
+ "7070272070524747733177730083966686149849667613589868731851816020060781720851",
+ "1308310289745495626002351437755820460104812708071634598163946330870933261232",
+ "9483468192990391193401121929514821570714432121414330663623018046165053411090",
+ "7317568349845215930675847155716598288688799068821709820024570206796617676748",
+ "1918505733423704616434273602054555051755671749253598966287072464475922854850",
+ "15158168161084905689406532256983805923258003804476527617207287404280855731962",
+ "6855540174355511438343304861678411868002455139032857270673849263857877330771",
+ "5989863238360846166935911112885654223487221280254816980802479355446167746774",
+ "20283337058688740322296928691341300752003492063748410749625272920572074851396",
+ "18957132189629332408653055312790838576277703952267542471751593810468444454136",
+ "15764518568966520670995753676429154315765754748131847346608706222194564055358",
+ "7192524197002826721654253762628934164676539329903087107420445743247046038858",
+ "142950766663597487919643890566358241353679421113406309294925836697585309311",
+ "15012262168187689680572958978610204856600235635916074406168861726626292993057",
+ "20795666834671497603181209610179324236645779324677512349797033323222380300794",
+ "12650341271833683789775531792948185319868795529390391267833516836256688318306",
+ "5597700232877580665749288204589530549415282468176625525368428476461504532052",
+ "20949303924691159143653175365242293984396858344688574262804199947001630916385",
+ "10746523145835332938672833282581864816136388045771578294905302886974358762209",
+ "4998982766221590779170630035756820066555357949247521575936385387288356143784",
+ "6936999580131731861735955554005106460473097800566952971315565150681540640020",
+ "6670695360676548472482680016233507548657051302712214051977034166870814430578",
+ "12210816592786563975173850937247594401582085430897698766795696447223454826466",
+ "14933901149105284237676334791785996160108290333321693498322435129559137152007",
+ "3848529433916624869590379003597911090976938589461403388133685310398004369431",
+ "12778805225074604003024964969486878839359935515509480774809299341511161183802",
+ "3288267180428684202786697419666969564766921974531343432588030535602163038467",
+ "1272672432174256751826350693883913844502039730140570583479554071765667798207",
+ "21130828804874452930669244946376257892693846272313548250936991077452679117587",
+ "21254559353072473881932828401787134230282801383134765683324465204971002861493",
+ "4116075860631781527931204624078712926526805345818156200756399332393348685924",
+ "17435888597009729827411190999389277840088354756277916760187756022854497211746",
+ "15837398163415665169712832984380121382150588321621493928953938599666110830812",
+ "17988638446757562417082379159769772097890681265659458369075768452342579854303",
+ "8144561030363576879343874888624208577604401139613622673042754207987577727758",
+ "20020299925602421262203305284307419339160247406220693128040712457114283033661",
+ "2945951415037890626891130390523013930737768652394758977777336357159436605764",
+ "1505954324723537402640844232704189835623922400329086438898375859826553573763",
+ "11851584491756305117491374581845512067704002072833714119284164514457248861803",
+ "14471204965036278214508938537949717553799007630471016532866101610339050785912",
+ "7163557293233604902868673807221391042191134560333950452577270522828534690707",
+ "17291625782465108601367695465389799786592304061550212130987221355832952230827",
+ "10240907112109243116543462081552827576656826251172050843989873656917271396422",
+ "20702261919346727858635106264046787321170414155594199951578791234276181642650",
+ "16678253307828004252292273162411388452019952018258857370242272543091326285541",
+ "19810917631941180098047817620026253706643400683524412974923209268916769874447",
+ "3357220165225360610202375608872621445880880830154732998557832689480921421791",
+ "4392285438534542495332422274902727975330102148971785438164412161504066619105",
+ "14642025133729666610167675086855441462580619607677226879159952689184960379911",
+ "18142623439987890999821892559271093087005885278955082040377769578204898750505",
+ "11769399023330099592616157336702104329646487200891911089287290893650532639221",
+ "7261353756299584174448625214367175510387913706095214313669922259027644778060",
+ "10406994568199070863112470594593301582798997458844791396920771226539013327304",
+ "7475277967562870216712397220016587384793504784585573136176313471517144184018",
+ "9598064630327104406929367986473441777975480987434868213697837347643980267620",
+ "21137410002545951849752865514437404724653771608225272412595423069852350320648",
+ "12345612867231779996383303763804719815752861524077922121654106906093103051400",
+ "16461750199070055335468534730937701659470268635084522644824623393184528879703",
+ "7829250842543018165409887731515254191943527926556191989558018633300783421935",
+ "19801151644322693878208767560968285812646931156576102755771403150148125880648",
+ "808770634664491371274943928223981161442027957963181999892266696287962813461",
+ "2298122748772261447929855283951027113218922003687701626762072351622993276571",
+ "17407798064458858450209051887305178872029674498718760624162479511390762310526",
+ "18585562277464562541666582720366573863334618817908062612923861658144918595030",
+ "733976598693219656339731904831283238690050114241501938501377743874139460889",
+ "11316063986696838098122262534148335669847478050407756877728672233736962269417",
+ "17614529714381496379478130066245111825610297227468263851608027100133421612826",
+ "12110694197729365219340374599835523099651939156213930558791147158357810646901",
+ "4337343008663255658976574468931581484970687989356019720784093082313510905405",
+ "1379188959674402095268172673987199124815512095460112504778179157481327937561",
+ "3116148242507754420428768481157196067508084836097458698846114802493377512591",
+ "13306507137873332434793374848948087993544118494881134631519748904811343155566",
+ "18496878480807017010077624766326681523549495609998881196570603040242554712562",
+ "3940126764022508707486095199473913866137718790062498893812401335738707507732",
+ "10030078765792498033316282784150304209584388923549357286679864120250994473810",
+ "18519871685760382462428068450331593474924737719734568498029727699878543899254",
+ "12599428893576891013523136950822667754415283296587096197120138265392279834128",
+ "16038578953099895530943034305356008247313649524436132877362941968861459073483",
+ "14319233878082524834510736727226054073026413911339853399113450188859080424272",
+ "13710161613540579690732775978855380876556751245265568031703536595040993113748",
+ "14958726446649273856607176275240008023824615720456760403465034344703779274727",
+ "20935428111942360630758629263346308597806819928838924586682307174931367773605",
+ "5826394436548487315966647466017047216786257295199620110266250301500717796281",
+ "31401797997389676486806123612280306684597605608110075525648021056710776011",
+ "10784171495708237485952707518956314344821522727746927291389338644844400581452",
+ "11604345371765580191117799693565193618158448665352599382713281103552305960442",
+ "1378145039624937931836538950217364481423707761527018494355648047365613434790",
+ "10284294167221806561993937798090888689421933711157676807977401896199778472860",
+ "8233695574758520342808807499924062869636681352769371531557726871630696672029",
+ "6570581391072134029876349038190171593169496519436674767949949730275868319732",
+ "4026501263908027819614805027945064360196399012004574117767831931274788631138",
+ "21091098569404004244061462065218203986433580687172854429523306262593782053656",
+ "20711772916118045406356429185975897495222240215931761100801599257137350834799",
+ "3165519312799351250309462589160165591299333587158531489859211268084164422251",
+ "16470663723473939739601217501478624726068461799539012562455639586886033078064",
+ "15672299304945968727435591100602007503785845873606917887638890765525875123857",
+ "21393538327627889838198844493522533627143658125568123117776524944297103649079",
+ "7688819203734248199049004650451546300187194458173935784579101984183800649342",
+ "6609663518412297884695057080546416278366560290439222127471462938252865438638",
+ "3476303650597281786976907813110835564442121684386467570637538230409080744769",
+ "20633582549754495054832414039299188930065286005370053173386561254823483851717",
+ "18067076834611402459142612082327591538480657933568191619109271502102126814407",
+ "157209609820117793892254328219308970217366919934739036156851508233236414461",
+ "1848396116513925340973398423998379465460554039715233953825786874352442451413",
+ "188642786730195655565401615804782553245486295156304142809552609651873793325",
+ "540089254487190924787439362270708251103955915909358626209177199653451469720",
+ "12796274768956950589847157187031845061404119522843128177103898080653493269942",
+ "1785666356337148874573621868025910291826158842346617719666738769156993598966",
+ "20649919247042517528354490854561347316237285929352042389729444382153378749538",
+ "9568390566108569727471722677925269460696523515877621230569682954652430518787",
+ "8590683334740232786825518158771304803451657249486419816607179533515442407283",
+ "9321198393538172042803957409292145345834077448228642847843261373640165958582",
+ "3651905214805616378360839954289447530035139753215923648216350128870943481828",
+ "1324345422558073117779462079218851558068746895262914344818945294328678893083",
+ "6666363895154434021620869731925915051086919707989020578203743660669796175288",
+ "9850757893972463103359995012900314323213006625927501272997539940766979170137",
+ "10214293226445704940138790188111862069675188797488928722469679760666574484266",
+ "16862124085118494177559484642483513597285992646267864845521573612482278871023",
+ "9172340118369291059693735314505606817316211450324955429310200429408035954801",
+ "1968992755714619414656181112336357119271845800144345284299978250769356388249",
+ "17192498940296212027365280042755701662136570107224000496521552617655679821443",
+ "10063385968535643122430064779260670089120686456635080613693015398478175344193",
+ "20101961459945738562625328882763768836449780661345042148985756598106706734632",
+ "12704305975772252539534386080950631076046431529894091327218544197389260775334",
+ "3008242816727585639441748210631464697850194693570485141354082562181236010097",
+ "7797705698071555811456747812384107102104184812467361013142453143842134807658",
+ "19323240331433203844038522035479659453946066968727795017745942269828428751105",
+ "1698137797127320576751729191866734754105401103859852376273763815257758421427",
+ "17656850887825900397821271738817912328294075224643535784810269137125067875996",
+ "20755447986835730799031196367323817361150623932048563112034040627213597261325",
+ "6221130271964372280138992636208062417325313096379273438539556580491430711297",
+ "11042709376363248213366896208587241517252100440844476816212498352999929578287",
+ "987361321094619571176752720390429919723900732295551211263814448408232028205",
+ "15077982986114392945859048373768437818569856001604485167476360943078774679228",
+ "6278894644165961404521866714059972066255652200107181684047812674333675794053",
+ "2649747800006903047073625320829560088088800522557851927539477888486006072675",
+ "2636278052351769676017824297717609512488651850924228608531372135635042762078",
+ "816232991472315395984098922575496846552245086608787214581606973359616326446",
+ "14372687274434205592004117128588852491871014819273428668840779210928924573820",
+ "7351401720390274950322621121981079413650308506660552567079785209176949174210",
+ "10275293929161727274572318228903710245677747557851999483919909420098936352013",
+ "14869686444606195206734119702227763209172799407142930791211203702643805341518",
+ "937617196362766626935279232045712623531859540210120280128165029613358941709",
+ "21331527351771920568751070369057714014285398281585036009305608379072813379081",
+ "4305436470381074948146072259605215282335211631970525440530773004228212378618",
+ "5894273721571292784412707230481346442881109207745969297947253583203466014760",
+ "6512250441044591603946512492071171861967500633638753443182294740883123881284",
+ "20863871952569294813936866452848141274047362082838805921071316386912981651979",
+ "18788566662709810970880679984141390717017951403407913908833463086244783373013",
+ "7784927597396249543149135503684024377171301321636804832597181795981969626201",
+ "13818519831569592521516488188127966399245767953522268350556654747680372036664",
+ "10515208647860053151690062640705322684876580250632027862984821874343071549235",
+ "797604926079325807488629085866693514275115789253871397971708541758696512985",
+ "8741784289526985522570446847275649913333939699807282742190607491216732972386",
+ "20966712704043418981047968701828936463778140093909973286855779694780086635828",
+ "11359697297415630167449040380538108774924967116147664240213257348125754475868",
+ "8070907838094569287067982462230761680706116783989613960066342967469297961118",
+ "1868550288036217638713133945402464194193242298015503906068429633793800456561",
+ "198709459347510170000840600179608479136663571567208109852828485236018304733",
+ "1601154135701845545733926027872374554514541574822026314034696802419388627041",
+ "4363994778006302991481199477873248350039564117453810275561422974475581105893",
+ "773054378219982710451611471050404495804413666789496412742983455527754059148",
+ "5209426340109575519362014651321132459061755868557415513439993327176584352934",
+ "16124961412020675839394907565568143713078242978522632778625312854364651991011",
+ "20812496670075231301471694692369245988519082317145989298573032859079075730004",
+ "3312489967581906638742585802390894285073229440039144559060030129184388053832",
+ "2967475373447822846542676378804990140732835322255774209561143670843223463335",
+ "19744585401442299381952694102570931935735276268739851233412754166721728873141",
+ "20026293345566344685499234599699178313754630774489046573312844763673073616936",
+ "2611303659034102517884318354550433047021831422518437228002960700934925644951",
+ "6230291832603218406134986471162106408091661326026848531605999413028246206577",
+ "9126162046556730019959291776456914453189657463686708035601186672661595109020",
+ "18827736146609035067773173111376739253733288103277133456626928961785293662143",
+ "2328703958261360872869074208611873245571971231035163763965210852182760438390",
+ "13796410059666172174899788866809560044715551934510722965495280798363043241416",
+ "1593663256684781552813616365605526150610454082601584196604084376715746899324",
+ "1565874145189898288764434737762721576951043839540107044892767693968417810945",
+ "8709849304563896945461696717753976956465219721409993781555147204068634555572",
+ "2994256803561260177499267243802460581941891553208150783951937342406846377191",
+ "10452746656507347152042187616753027475507881362159944564077673851918869542550",
+ "20130580998875572619695450234900655050996104101008767761546912649074040426200",
+ "18926933358104691474037431437316089682088433006245222723356764715400831411716",
+ "3783551594057498940671877156409957274854990650480535806320220142873170375307",
+ "7919031943604095374667473717154511882451510130166237539514111182596247372692",
+ "14518552587329209714850286012780632801030157943402419401997576700600952906519",
+ "4770764028263701271241862755569969531641408032906982530346384375773459918490",
+ "10866502826034731763529371496585294375373238783964914673031891984092997621879",
+ "4234148117462322266937279401468367908013627589417699250592523530383852950379",
+ "10747942066055887965185603234524367638106812660210378090215017248140719240336",
+ "2587411532912868255102795810490361867789634574022411742057853375399270197531",
+ "17350061113113681344498080520518808976916692173267298878258722510332360424059",
+ "16490282364669098969805528215926442920328903121380947471680517193373377657129",
+ "9274691782659584680377375192682066090127280485689527337429804211265749864190",
+ "7630965482352419767782717986075793694403609453648729580916814032587325374653",
+ "9483872310024003776681196467845329825094379763716541754956796450187787638623",
+ "12182966986735661215639970080491757244218854808156498220088212871061979325833",
+ "1853790963611367149183440339188924598268644281518961106776656221408171642714",
+ "17425077915972423995335545370701802959607559878032910147159424242864219303096",
+ "14571075346526399549826264845894977639678567831720652860528738036970272895919",
+ "5627701855249158721927849603102149698163511782011562166637339712383551336091",
+ "3620805686755372260289125555061886982808014642356719556961142525373021656729",
+ "11556995641752009899073583627136467840237831247117281278719511600076965602980",
+ "18960242154096055221658318882298412299294886669455506299567210308762501113202"
+ ],
+ [
+ "9174141306060971809979631725764298697615039980311809306145004207410652431953",
+ "4847693924685156250211477469465516228032151306221739650606132660616428517315",
+ "19669833054057639609249840291533340493211768292967819468538893000195036768991",
+ "19800508893433268850924828171290876015556093796000695603651522426066333836892",
+ "8244699449852279148780456022144420353408196866113049322676048275081354214716",
+ "1563672068712965454176533719400672258364596155638916268717470967009721945171",
+ "12723223712027468580318230235559705540011996847167975439677647504573149248849",
+ "19944398841194165937952509356635863229327574447452745793253427406349161295763",
+ "21218058308392585368594275702746106483411305671883946244077923955757637296177",
+ "18442884961885927579732373746933397748806426938144021013884176466434407012116",
+ "11138408360119814115926439449668526422561003790198269766757675305576549475808",
+ "12724564576884231109847024566806896391934587839830522481308995309797961575379",
+ "4897733190252075532660075013731462724561461746919488679609618967302541674417",
+ "4797748331306263412471031924618974997396620231469532262170060449304337691527",
+ "8626839560132907403537141283531395025838110825355541158539075100658769738351",
+ "6096293906324574249636975851522292408228519044739444932687579741964974917617",
+ "2351617695830568421216396081605990689071283678701192113347036659596049514149",
+ "3045682390398203085155257535118136303069379656645406266260961816947178911890",
+ "6935829264874515341379952008241845470659188886156484974987865751370715745075",
+ "19847439266968955911971997829840067368072860877451092633069920565944933744280",
+ "12795097343831149148337906863235678514689648096503928066579129201713661539889",
+ "10424580232112390318877053133877999442988769389050776486274146627765228950235",
+ "11651452649618223740363812212607761589812354035139843126315028745587570714609",
+ "21307929358023177131550002602820591970791247513576735567457471459920519084552",
+ "2579908580162153663820021562014873149811195641589016321720930006635393981680",
+ "8198198178555784054784079137247244121807775986273563786249987394640289859893",
+ "17176088986876377315956611075288620878117708836881362200541916957398026761276",
+ "671389874397910339333118510595007038137908096657753354622355890021074216004",
+ "19161949137729278558310070194809106779119877882343914445178348849980058405327",
+ "10827554013954037091657804154642286174226562252063767377995268439458401752538",
+ "11693672899474469123468133710607776304784343543318650064064636202512816205843",
+ "7026547767612627656560992117440221331093280829523426249915938274837157551621",
+ "14422968137896343032446633683271253661000603582016449215470992885331170459671",
+ "7685352543184863430081115767111935982586458632527708735083385591291346555502",
+ "14089009391529192464370954954330128327830078875414722902347666490457756695535",
+ "8424161061743752192085022963953944100289245618074575727145394775891645849043",
+ "9809236779073852557054640507912802523501426410996355424610807253990040160483",
+ "14100245203768962710288059230665566265892855964739454261791429988929622355986",
+ "7775683622333704945225255741567928967674629526812606133980425422182282014012",
+ "8739247215686497264451630351996892836638898510934389758205488381695687859658",
+ "9431876969679115468275053745264413939426444105271849398322497961102606290132",
+ "257914055321743732506701382989022126153391940932933566664491918941925247878",
+ "21801414068435960590201256257290267142214176965736081788536576642934903066059",
+ "9465495933537134443327560834432669768951376466867005153580146079082722525723",
+ "7862366214258716333873810314803222267215825847232397599183717032713290878315",
+ "10701164906390193792620967030790214270231326273599373762943959252633779929633",
+ "11951628827727068395937910010248864431667047516686609553745879936868276916066",
+ "14268744039571470490378560085356767818183790841094115879980723591887874138419",
+ "14468215915818797151199796266933432577607248341385185700017147731054148927023",
+ "1523824033338639123415809477892820349580561577160869448927791050266158538520",
+ "13559991428776910947424645696251487328999214391124402586267086012691140984198",
+ "18151203063828433535061866995346135260543721730169485344610433976436663085882",
+ "13436242600153492361692256644258899977135098134175123174795293078081801647137",
+ "9384556671429507406657070680351030238568956203341356106463890924933167416522",
+ "20321079285577981781556986944841048777999006905303986053275199507771332527205",
+ "13510502130738135726695195328780836716597947131948116750163533622597187969844",
+ "20903049289119144354363108865308751668897757360882852151457514926552553533040",
+ "5611953645512225417723205546533389174830971368309601830751921473015551069534",
+ "8816886019615642422040038431962872654062471314244185285424018745071289038220",
+ "16751828354835345790163611999302863949792305206769993810746019449909446216365",
+ "10421654749141018171116296259626916395875529220250947127973888230084671091757",
+ "6065225315766552671037285757918350882361743810888619479819895087632281975681",
+ "5737755346739850738724717271213687543479332312420206954339242459110768587128",
+ "14770522272891919220644639305274656491731294860310497013287297810648680944682",
+ "2777394791070450473479179489594969793054480209411136328689318984981401732197",
+ "10039559932930709555975364107098145624058027439566384376771787183526929807647",
+ "20757756003754261934858081777796652436155530474748550156383127600004580439167",
+ "13253166894715452480712170898662712132411702335275401581167208877688374856806",
+ "2037004052447343668129085129987646907388123739343356363273464870501805506884",
+ "21829471491172175426560705585746893969222010633542962882847909490991398830669",
+ "5130395545419191392223692116621486075405299333195732914002649716762739787586",
+ "20333821730990393095934147177227294218344864602777744425090741435432040213391",
+ "13629653802252084129446975515814037702423511189484562534040643669977716900228",
+ "18489091892360842692678715136565494502607711254719045543684163289077857041829",
+ "21380328601365035012832876315565064374684993115210423862017233170195286906080",
+ "2280052193465635727584791148501382679094142036232980037838088033232747821762",
+ "21415541711468815972744677841317235994302058341802530962394281077076174148777",
+ "17146992672828650459975820445250769505470616910596779130798889014378635881076",
+ "21676475584514120109058208398560066698690773910598518925936412952356431597439",
+ "18337052978997482578725645166749278142628133291693686105612531426715865276143",
+ "14864089429815580405957698645045711801464462794754089671996837547347950054532",
+ "10834607317840698149140890207826430113987295440254355899459691878793978994131",
+ "1157143498448645320415276909137008396665083714591338741616893578930275511205",
+ "5027542104048754930085470328670427788489455916338375169351586496298129661248",
+ "1922685817237874482932428650501872692326329693528175054457715565489676406535",
+ "3071473720617798005831658342971536643616129392641449174655528578463370685788",
+ "21091078808046042460442535848913779439792606439995062001271357804782672390627",
+ "19773167374024045118471391738750949555178717045037157435777574972149053404157",
+ "6418695831178793575992210834992785624340084513619644969535805236049937971859",
+ "6317875495482489567338519005308431806047606843913867465201005132273298011425",
+ "18001249545956637376455848019549801116909661454019565655561439372098476761813",
+ "15530167556609139699164228289904946047951254183080358784988008899829027775935",
+ "8702757129830652230304011519426558036441096750485189115358314568895250616455",
+ "6369986882953061252605652398893489899416599935424066958291402945530517772170",
+ "6842894437627604179732847187262933342846269043996061072487488027804029200046",
+ "20951621154051947571647917571547811655800779287153833018533872651413529893817",
+ "1219277535080749134805291725937516331501172121638812333911793209536894469364",
+ "11704605822590166851511022757496386950530399074796545751042566537118336773236",
+ "5983427701962592508775640503988144495847156070437130549832329402380170245893",
+ "20169091361583397776908351163571343158517532527313940288212943504015977979442",
+ "3347733015762117176159731683196584632702931062411889821726902331981723958255",
+ "16217509027282489850987935065936382820558307489954122630844029918951230268972",
+ "10781269196927764524006466217779648732772805761839205677745819812868343369087",
+ "10568911823766972365218731330080733630028238366288098114239172953421915095075",
+ "5568774544682750792074131352530555554984876659733959079036284517928264996437",
+ "17854353469028651373397049175548228061144941710027186166132671198740388767529",
+ "6573034112757039329551886086829829282007989555105157401271097204633906940776",
+ "14069627287078359391137554212536883450595451640858724555679971658981340584258",
+ "21119713641590541511025673864154852875977162278614553796484277752677323191505",
+ "12802116677235410441672624559825044917295689876859311183079161588690810005363",
+ "16037054471696658545113065872215787085337497333273419984439267709950724531124",
+ "11698654309680908244303850432833183602706804558317993513795996394673734185716",
+ "15147889780127043019188099948246961619198549928908180192590946633702778981583",
+ "3657342516407201801006680507925024451922115018712017224805778401726428603983",
+ "19776786467141868744713630352693556348834540992018636838044610844396164981103",
+ "7980994848490005281733955776875257044050741738176865989521982608944874160873",
+ "12415191330803073018395217955802011585094769098717180100014182475381600382452",
+ "9300986814650530426668152137665814177758578011365736727321578452726378799933",
+ "4412208980274764197258090802604347599791567698589180187154608728755887977460",
+ "2582317668924231956058541757507620542434237159213236485179804217989764223164",
+ "19860814395849792324574773787600734118308975251437485131415273418632757301303",
+ "2765909129639570206766170018363951893338720647679193401532780051354569922989",
+ "5402210382809272147099442645489124829067576777592680891367494969197685281513",
+ "21011104174655621871977821285307554463403659856745964274018020456838460357574",
+ "7018364707286303918877589672878574811337524823085078243421192184715151775983",
+ "136380103284908296988715215087018020601815024625535396780012012453684253071",
+ "15953315437474610448052466140270091879233956524793052736202793153707558909889",
+ "5912305909658884889781037379491781973092020933879206417274479331390062715252",
+ "21575635295587180789566592951559325743281772394055590203112195979769645712827",
+ "1541325805478255472079288730846072146731241030100908414806224735345400173350",
+ "17207219201921814683730773200330679841907450967511507012179337438654141678023",
+ "18266907794578843029196926509122804272900478710738403531664855427655744759655",
+ "1204224895193276222782842236712348692319665277014183965830735736728887994581",
+ "4023246588034712778784328407820569751989619386134504404739514704773521558127",
+ "9064437981037864995763386367268294611921404895425171966596873454090899491243",
+ "18733802217274421976148972926716884457128521840010001893311936746027998476583",
+ "684088380644531080099595788833220377905013807951051638705160997709156627273",
+ "11994830816367980341637110785269531718699655485484715851375754143223090344544",
+ "1831724566362300629700078416489434571462666430381219293205871349415506993475",
+ "476710745682537342427691635955087951551678644045621275039835625280220347951",
+ "3586272766499559446129476613035465343616602918105042144185864609818186807939",
+ "21220348736799044560439132291243370111879983677197111626309132298278891334631",
+ "13683795063599185801186093771702503913590598475095473714851383723199050309401",
+ "16118007386401646906425171859166434660243697555307927508268622819509657450614",
+ "20930641024767526790605168032291665313905337763598128831404465184891980632233",
+ "8098646212401100552303711812039666794078834386731698810205195111722330322418",
+ "11585783577173465460243373201831086724911159484415020913089605532852648999143",
+ "6939053275662244505087635417541857793206828446247848992283188764105131966721",
+ "12798043540382494855660472922674138947867597503468216532170157050160462426199",
+ "20713389801600667412553956346192236970217099413304167366340548074880917096741",
+ "8708207547232102069057776099666995672015399188924281674772351753887161579745",
+ "16016293152251662056020528248861487281148011452459422778601663166015837379163",
+ "14324897997637439510797191208789711173129460994362368408063402682894248793270",
+ "5652996184880208428967511742390474289004021508049280419259474250332590598159",
+ "9877106633097964013050071703002221796318046172981334418310092241450453368579",
+ "5385816971548914185604875069230499528103133871233951354186676373318036241822",
+ "8683091293306949708478955451280670950858818602696102489349595054818146782362",
+ "16854975838650963077652189417311897888852709425835763860743171659164792100482",
+ "2485160816649177905834265823672532710299580013309324666453183278408904845122",
+ "13571692148185502188613896013359942531817915076247598483272449919094247957149",
+ "11899399615412173136098732970606292047945698835588882297719609812145308198009",
+ "16827672312681684936590464376780346837611857292837989006980972390576065571472",
+ "15588237822592586948064701827497915157359094833395277985658706133691498343174",
+ "18356642512438827417103800170157877145465512961188328254773957819312191285168",
+ "21642368145757804795143182901389223409544979732781450480847315495418822041608",
+ "13104082060493963869934085622104709047787444250961437496674916673804812287386",
+ "1561532086277971111804773016487251313460788916643968126116038406859074212104",
+ "2718320602791009266532615731130512762296058687816604986701989820504700684864",
+ "6182683520717583142027400659687593712743548729948584058329789905227082638908",
+ "5757242145794370726637363237313640925174531077560764545993554185332488520899",
+ "13688467192244237790806289073845563960119021610896694359815485764764608925981",
+ "12528461541936459922472167643986446262977222390263675720335825628163511159437",
+ "4897268894447399415795897967133432014527122426051771866816059363418177665482",
+ "764332419588242767884018802335623760055144509861323437945071732931233600264",
+ "11755468878196093893190753985692714003062307843033761257593209352165323938879",
+ "6006022813561851182403581780143813226749481175437001910923100661321563995672",
+ "13901542382190510449243772206670622017835690746895066410475076631498053123535",
+ "17648853891656481911225897080296737974064729032668806126284849597245044343224",
+ "15106333841965710929952896897521673254279668876709612770907537801609875568099",
+ "20899315415025260484895459315726322363345188136910564549344894025053466430346",
+ "1409310408943258102775009950750654615881913956151269414096059752250092035807",
+ "3899088673345731523976816322438172722785832982334214339521575164464706226294",
+ "21406686765584824639201351330529610299177537976609066339927938099572420696135",
+ "9121591670793901722224770893633585291275002987585289305307167711146944200595",
+ "10711764678410479049841945177317023555168593838022414378232020467195337241279",
+ "6599257303974597452501135281719536074294806740553273627128065549267140155175",
+ "2142616913275380526921597026822750992917222975992774063376747381991404337593",
+ "16361086527663411948363284957489078505159658832010445114438602510508720771278",
+ "17122647864721668762640781848678028227021534122268561738445496382823789619088",
+ "21708018685042482318786273055293241752114005312590172460099480713746031274624",
+ "8303630654111760473056607545365338851734309857718959193970615705292826806179",
+ "3658686547507488906491014260011151850549759409901579684176172268581462329020",
+ "7720024124908065424512743488999250878143598904717873371853608249805302871508",
+ "8805244918657836956533473437651380347005779399042661429698187314657501156241",
+ "6303681354794120075893215838935586592706844702088252970663343726024171795351",
+ "21512507181643408509426104627003618425209526633080701556628608990726677651135",
+ "11835373417333287523801757951049679177935522717858158305516568595764125190183",
+ "13059698839045014411602727811400239840163533672024084777768305507840091151855",
+ "17635240655824524168378284083397931667938326555447077097306236826752492079430",
+ "3374412791113107178205006579112630099131939030015047870738873452427211677886",
+ "649711083340882271985565833699379436167716866997851102439037906608755280128",
+ "20002805138014565226408902156524463368767807620908543995020210484077706418135",
+ "11071355197960433041624284534649121637702414580710232237233568479006159191217",
+ "1105441595020980635809093220782460032826849883993030969714432603468135735502",
+ "9652765957610682812348919340146799318537766051849796416434577860126024594091",
+ "19248299650856496267902926731608572596705132576830681367365128976226233392929",
+ "15285802367070100569572399512275861017714681455564415244982064571963339715277",
+ "19970416835730683993734843405673457882587154729456022607061085470691843864556",
+ "1017865638757684714433500504002748241987153668285974836527484933462490771227",
+ "17284848056169793253916338792235498052654877955690514601079806604278964099314",
+ "11718277105372928962350331838305733149270432706448484259807630484543527733952",
+ "6670793378364949883511003949124179112275066568088468958915163969545409700112",
+ "17088789393958965094855662340742013087397643056458490270185660553870734946796",
+ "1930788514812600942005320214284180860980345276633471423966020111188605196111",
+ "8844343159753729614645407314580317697758296041737296276765583948670245312842",
+ "16657939543606018325703787748629433167511611178952563626096990460124133990109",
+ "15333343644239485619497914931918504163396626751908652058758135581206765801100",
+ "16533875915742793452819179569144271760125646811168930162441077117553849625884",
+ "19679534317472082858641184998487299940737032844519038845860980362664393659234",
+ "16385719932525604857740698205965045007053424961009717093945644387917936681719",
+ "14490521084213123170781774542655088188106794646066074998587858678154251198444",
+ "6386781978322405984893078797365492485297499058328348606653460996474947075858",
+ "17508047533433736707046937662428611868296556965172642086594091783148965906980",
+ "14904597000414815084666285064575232635645852687797347860862157463159487771060",
+ "14979972442969995336727018758631782107138089738395941038626891064816880204567",
+ "5299243186271864957800928637599294208954109271450189950375274196644046222516",
+ "16189884555052883188473617525411302750109401983487269295700675997730645714379",
+ "1645560170870292006287241616671417605853047420339675073261660626733726665673",
+ "17866745974872498136933906591373095763114066893081150553715211393380040095383",
+ "5744849574386643500716045532645657520001448510343827372577217716983339773799",
+ "14021966200238971589811034967347517039341058556783068950884921208853167419283",
+ "1201178089866013320759085637098781870734315826415474628546655403142858044361",
+ "5875644793836087035760988842421852197052681650818034527831700615895391179258",
+ "10875065950479466897559006840696567433921014267247530366235539292597441428702",
+ "2221662399199449388725697795500999209427453463134383582414172135385907744785",
+ "9758513532658579204941116584445291102215928928145103503086996542188799521709",
+ "20879593323317766577775570558015407573466986714590017262168011643343469361329",
+ "17225846522404915080676699509636264825833159640824918876741681229188434930856",
+ "15189442986691997434021855855358620506645387296294217783597931695143376252483",
+ "15973617135551858849206811241799666696907820418171736027820254766840973764431",
+ "11888113439449420418408437784450952639345990804839507528208325036625374967083",
+ "12365920814385241227394825974928370916184942218042429533600397623369545597697",
+ "11966175169612449906889690852332416255478894176917636726028104087408060623141",
+ "11163554022908212145274813635928762748847331295589087669583554722521180712379",
+ "15273476004030808005186443499782264987539818978741159793745891769358221570633",
+ "2013969196885866182480519514425192091338553670034650196068995589691938248955",
+ "5008975446746271526106846692137145404766553748264648461545948417006052208130",
+ "3926749194225734582453671614337621250954608160208554883789519551411469033731",
+ "1635544156808471185144068767649088695307748439189898784051754434524720057896",
+ "17144944482517962143604430553750908864860079758005337246916094084534304051981",
+ "13823503533305241872793740090687668844401004819859520464168798913603662683770",
+ "16335911272023134851779534303717879370955813837529588982953758998930285394340",
+ "14467284210444150699969889681308566002886261365990840091849371665183151060295",
+ "10578205764525658336257882813734672799527733392763965031628376897794294290414",
+ "18771425328697137255453620743509164311086906349726510394566012237817674245865",
+ "21804626093983212038528370352039806004465345685985435415809095637323683466452",
+ "12056805308954301132385034564357716323176447186932453788072119595595483786736",
+ "14307195735327805282612857510308008767450554777122724855715789120735513378827",
+ "6848201070063637295416045855906784325422580350462489495889308309540335269587",
+ "631364713487758647973016689203003205602593076699875191323345338325349259049",
+ "16214655556434201961140525501007839859074077768660052713461045928979956365067",
+ "20940788212183642266181811368870506130164462254923655617893660245551698033523",
+ "8257440848494309435270838240795567828478627302119374684511017376568090372435",
+ "13701089242130867705897643891164147923878521147124165292045879194108024940909",
+ "6895272953337895406509859406973110417619874994579965619097329249292199573333",
+ "530437169778092455975584310016745919549274205817234464915791595041990209639",
+ "9008612822403008353420189298381046023002474279157557733428254452507266389025",
+ "14863423501786052071018008300345884780479084379412157784789951872243409629758",
+ "20091026239041315645045502002997446404106877721183777765607724358538559881231",
+ "11103877261161399045807234470901399725912406134008627937945079980590775715243",
+ "21529163495181909351665093277427712610965764606448489357319207727176092439794",
+ "19540446772694448035410067193880900774391072899517686330271100773183944540294",
+ "17549510450820803306426739851959754252204444648959723652883552677325100583689",
+ "12252518814610348662318155253547558779974557529822012236107550517806390105567",
+ "8058115132085119666951861652409945532276905989404523986413207631657437321956",
+ "15916100116790431839835734530362130437167135501074855072245598938219364570910",
+ "14256533476494466694764843270015662315303617568641801280831873052211753536970",
+ "17865471381417606502707639037418669122823481329049436020149405646709537112534",
+ "14015711483636570179335132940981982618090553643653746531174110949872682031017",
+ "6075776171664976866533080327142904134938121198707020111533599997509054627652",
+ "6357981809351565370498807027309828058036389418343890944791766504532174516243",
+ "15145296985037303761634018005118672316118004891352906450983918852209191841446",
+ "2473672396516437070485250176897956191104549656554290725379242542480862701754",
+ "11059085933391482002269653121188853142706883316754376424538662772943167665341",
+ "14804069155713123448375113552227724310276294677318593116834685772120057819258",
+ "10146378656966122923223443263705119557842694560695035707977826044606938090895",
+ "21828309590915152213768434346306434851424116996828875020020066586363340244814",
+ "15568879616082229996551157805731419126872501425454775741945679993142071548779",
+ "17504079509060638501918729619244098692140123800571022969294759717277257664716",
+ "2998311560047298465700351970612785742605093777116697796464434026101441410385",
+ "20229972737818088327107446854254558628041027965197447598027135778783710740259",
+ "14884874200763033520375899992902136897590350894844904733314191389520252900641",
+ "9619409751736964504139815024141276029474791187139050183491749032619248817404",
+ "11534029087676783672833531415041588991838838078174102967049055562568798961925",
+ "17106297093375816944137015955705541133308466659538554159312635106186252148471",
+ "21676736161168806529097919794022110433487869702564846859065695507460463414524",
+ "12596447704589377083704857810305080195761099125652005594925931498073219198049",
+ "310943124066162607352831846280730445558498286205117614171844835745706684432",
+ "16013029710570597613246104892930389004941711962070683476555063566372534206859",
+ "14282564976066063966062366540992448474634085812789771416509095817495183298269",
+ "20757241092771652500911491636894210910134068426068355089789205706892703219255",
+ "17084251309147907751212619949757520468224028014308500329099194408342072624132",
+ "14680350698112448759886861002622963534698534998651150537754386791270019720748",
+ "17739512731440543100681958009173086667000199263945053345384367808940651002571",
+ "8967486063900234709994801661246451094429250620940593387993430620369318619734",
+ "3906067814916986286272005884942051451306945488494283077675304366798199289520",
+ "2517004675157816404807349457307096161030587393097616279110332574293494030636",
+ "9995302877359286298434340810356550712107485295049220989690824504445305103587",
+ "12849909876017357260683411536833847986127911582040960825577300322066595609115",
+ "18074515800779889507358182860997188274134395074469953155084226981497567860114",
+ "6692811728183968363967959295970424292426462800383828091752006855360167264617",
+ "17859827663908740084792157440799065184931609649811664442236242315795442091367",
+ "12243409340804252499520308602187370739653046835019551522661290645230850934962",
+ "3009118420068966587115224335717185828292538080040896739662684632413054772046",
+ "15856202298588272962175258696610233941787471472716811521132004805327415486141",
+ "7549804594729480554341356998842376772514802673462970334329441043324983960866",
+ "6390806437030742378988258255983502109201709511321162596105974797942236431761",
+ "17370236522182003753669946647208335160124999930136364231371998757664000198520",
+ "2261672244214630177095236704932243497157963117166120717011661647779055001646",
+ "17325026196605130064689259977831126468940872193987407658419640959345091161632",
+ "3631641025220845885502691330008982895233731506600778684638817282531001457735",
+ "8656561399441987116927438675277763317789561532507396244334062468892541066084",
+ "4069166732330197412844703565599514109399373916243310212229125901351402003915",
+ "19808198732373520522982274785888742523226720967259539531129335924093928174880",
+ "8555796834031869022510134190573521699378201702450788201649007358450530423866",
+ "17759660636058865290579521740750449606781204755231964378855563896473545202303",
+ "1335826395218609619260020055566056869243760115287254209950063597653055872566",
+ "21596200365241795669701682696176077888309278223833581800772036945674858315765",
+ "12619752319673193899296833725747186284394167228468888029626464753793997178599",
+ "17420588547980145067421969830249755561311178399975476925894947008643385243007",
+ "10337481272389772505654575850886249605422739785111225132545740838911222864209",
+ "17928431631046752749930349099366498612885288622404560316665023363985966878427",
+ "3075798659324203306711977985120251896073145961913793478792728028765206521425",
+ "4639500613932181914847461422373341918892878975546430906324216810326467690534",
+ "15396322795715441250300995201889120935591602515487993982711884319616897970533",
+ "6391276937505284102735701938724106665734769352007891548547667448647832351929",
+ "6811373320779057384916660178551330838095673247430496448933336925226142036083",
+ "6590973140323934807800215988687710942074412987201753370126190631819398102173",
+ "19364648614154949386936259588484266535262135334799266379433252509193375956715",
+ "4702754284612371917466042550086249683933140314858807272591351280832918881874",
+ "1081036249074169248236179367049085684430282426446509768147097371368406374049",
+ "18548093223441988703029589168425055383154624592689171393242936199350770119589",
+ "11098999608073377668352846814752381891400020647878345005629685447730764310163",
+ "16001262992680194260590639872321865154716987495605624862471107193457192704714",
+ "21696229443869118415905915570780926763029898831113534481730746953640692230062",
+ "11716215712634983607563947056324900205144202447594949676250978337464771243867",
+ "1778908113733035314726603632369389424542091991692308812147944884836647395775",
+ "4019081204388123040098634987844274011285321286777408246805308194144238418480",
+ "3473266952388383063447927231564219811787341139731701190625605897592140631276",
+ "10457881304788072618845101933412333126160339089704353596608910674508961127232",
+ "14926101732700077295531234099443522459232814784151318061435025890154852791802",
+ "4036967072197259618286839959572768559469665646019907384624959071646231971399",
+ "12776716624632228928613396031717959431597335742467953143594165782617234803915",
+ "18894783424164609284436913400522166453255844750192864579927645453695213022195",
+ "6303809107919167113924303987533838414137996606980561570652539716097058487126",
+ "4729698693443803882717817492985796053343431875965792864932005291979914613160",
+ "1645790034267553926884568714540144778649055395816210525904813567839945991808",
+ "8138260225269705405100573121045873922755899939885385491610389913906979427176",
+ "680936760009829486282006800072001712155424246576949107399338687767760991887",
+ "17240357869291182045663678468827695873425113788704614245279840174870850373113",
+ "19100963939745621863641468371111320143895293700517367016077996431570157414340",
+ "16188989656090417148189510820963186890780289777598053654241741803194118100843",
+ "18027402882394597868782011288920739982398714370069420860949975937357531046151",
+ "17780529984916796963712255733293310230026423072958099290880849386941451922559",
+ "20004531511171838591303710792081846238092292916166965045929062171308088520097",
+ "13855731634251510230399834192704620793850325654395687428672253016405315169901",
+ "16872938837392115669581040432902657478544143723662502779821325505282093696739",
+ "2541555081244462826761076743762714962901590548271316707071685417008817634653",
+ "5136424039269088350807839181761422963254683236279333039713142751702136147963",
+ "19216238128964101420135465007632926445321991494181045543846024053552797518994",
+ "18868537488540023742258053821537824724371813776839672880900985865823137839953",
+ "18246710415801024039719497716350501105591286880983169809863166130543617917249",
+ "20608694004331631709610739723463009412162748201282986294016482926528443868949",
+ "11318113915971658853560322943565673154831611543653209084299774855226816037778",
+ "16240989418312335385576389959938922684406585560688799437547298624184839261343",
+ "16171299673760267132909753100946681733778389681324959987573199154235691694977",
+ "8036823955656422391918380552495301547890420665617977624790236120392727764522",
+ "20269862530534739231936251654244170650781428788816658397167110617927916774329",
+ "2368678892744667199202318323282128737449992006513656480477288092472671147090",
+ "4618078962163037429845764284139891171861860687111566735174912070413086829215",
+ "12695350627501306162901105159009497730633599768443844225981772758225613194238",
+ "16356283146491744069785034066388746989409816380917535719898337817088223419024",
+ "6407893217596287850421377738867081146106659458551198123106454022096864887316",
+ "18168868018352364136212098098453930600797374324006271488950341490483455519349",
+ "18352629174410142476418438008157117497168118524562206830585500251463010761689",
+ "4344169393287991961961456515301754172943022039566219343212376057129143739343",
+ "19424839806870716108478074501405697296961947409763509419111261767390677718987",
+ "5796037897847804302272999466834285170265203646465480652521088328457333766863",
+ "17402105801450379889120987010453669096275392789725153915905747267778100864362",
+ "15540989618743824352651126288511222263828123668208146479603617243655978402205",
+ "945810410725426921570254447269595873973858272778720657523509910503434094174",
+ "6962323734045776666289031609372270190654631739266635759799844631053633876675",
+ "11382945272742312954364642163371436855283161775445664525053938433459897196647",
+ "18940251871958826726849623572811640436342841713786099464305053400421580490631",
+ "13969540696178305383564753026163726563325318478290740131984853424331762285147",
+ "4841983966001277917879506889862519614692143906356361564304719688757862622407",
+ "8939049562492171082419559182596894186639203815268680721033389307282239000385",
+ "19265363396776097866041313346787101192508520582744521467413665478819721956884",
+ "337106861429123598189388456471513480497137213511877011021531147545809512194",
+ "251367482782327915297484770356856386307188967585026711663629212746150191478",
+ "19506616511267234489421548744907283107923549136620297132842391511025844759064",
+ "20633589633280372440758096707466273580151526293980868749421563697429194761212",
+ "18833062060138888612708634036427140134887774731041742144004707524569102994071",
+ "2927291160590267909596732410727396533948837350308818016906834558527125752899",
+ "7095572562193114209617459307511041110255341231707924363346373597653253806883",
+ "14274988113217913224290208839851596837329960221329537670822013510325939323091",
+ "9965830780560026128320556230399915681196410289456547935188741323403719404039",
+ "10333365845496980935202034863900757172839454015352626511769637076650624839070"
+ ],
+ [
+ "15193892625865514930501893609026366493846449603945567488151250645948827690215",
+ "8655680243784803430516500496316192098841666200175185895457692057709359214457",
+ "11710807066713707084726423334946631888369490193496350458331067367713412617049",
+ "15442364818086019103203999366702499670382575019009657513015496640703659810202",
+ "1358747428976145481402682338881091555771254635226375581638965497131373838774",
+ "15658002471767984962034589730824699545808755102240624650914676102923421241582",
+ "6420480504329990097173256112095253518339231893829818344055438052479612135029",
+ "15457172495394305353698644252424643614748461590123908880271021612601244389162",
+ "5745943350537490600340174787616110056830333091917248931684290284533019091654",
+ "3877253492903478989342845512796806320713689655633086736499730391667425329322",
+ "11257677301507982757739320943403112189613848490812422490591766717141506751601",
+ "16906586852467953445509312290627525856126394969718997799028223470195783329296",
+ "15263589725854108297280528692120758129000336125328939290924952731952242586386",
+ "21735940039489460025710098364749096267519151075908323637361429746399161905338",
+ "20023056608360522105358681147781839024069418874082333862551226466128829664291",
+ "5677500725280079960679484373333947430817198394184436922575072427342643665917",
+ "3080516739494460477657748111767941482024045797587058388950619118994388252853",
+ "21486496065617100719537932626843898998311175055335457507845650282870586541596",
+ "5371049178920102602305531530023787518286335086323221270202212974241707302466",
+ "3074817222296007572297581554183445947239252698770067839721345984255386069425",
+ "19180807038569629573914331337874446591506172622522351734982093457681161813141",
+ "16937785199372956273358037645552299688842385008757508130180245705952406225194",
+ "1688218397616770248184651775433764527272029131542529408516364801909017591719",
+ "16315958669815317541884966612581197291281164499674338063931623110684590850347",
+ "6218230753007070123505625054833158632732536069700963073464625252554943737669",
+ "17774528060285257656595928889288330429565059134928074258373583886985960212139",
+ "16197131592052727313460949906369199026477758140133103701908949020106767192893",
+ "13418604038232148873269488320329340508522225417123160144993642839875173062296",
+ "7265658443160253752317166706266927598319661172006072732797351716897681315157",
+ "17200150079219747370109251547638276280610591698078334228421747259741754887",
+ "8627121890622175767416692555014275717515106888840919734160364408960047296494",
+ "14546964505431549758350267964924534495477687922558528647552728692912697049247",
+ "17132720822762740343718421124251772119916072270451579802112353604446214831761",
+ "234333065870376500756753915306346778417056884715946003873280290982247600083",
+ "18375643491701271245209094287106352436174133929245169725584150600992143374298",
+ "5158448692161567615645197008737390561357077078129599243188536485308363800282",
+ "614161645152783610732075198073600394068518413590650990586931263981193439341",
+ "12661793104597977909223565537293318966803153852970198322604479648383643541371",
+ "13041905650419760925682179803296711066088286278603171065755078690359168540579",
+ "15006023590144168506070897325649191051975999212058008674224953860265667513015",
+ "4983349941266961584317889823965291023669365981564144622292227613558024302012",
+ "482274340065333833495445682213681402212945945150526736364263233985449810602",
+ "3966893131006556898236790392613869798057510088913626163333804949895810673044",
+ "20923301526284527685000591080290190641416245135554916208054502046381491809443",
+ "20838692384005825835959734210506718428443540957544929066941550833051093000166",
+ "8282357714606447781782716442854085217089572080066047419459610560432999443766",
+ "5410651444876169088887579490283094453001167796545260026969919887357676973543",
+ "15276966646285075387317940436655285872037988805762800567413073418506412856419",
+ "15066911464727337689573664613158712498015597773345106524271610486257089622849",
+ "14583790985054968382519116885383608902981814292128186470697458065499359610203",
+ "12059090796146479535492139954279038037217093044815277624197659219529427760034",
+ "7273811886044732271171500579064359282424476926867187108258957006777685922641",
+ "1463086899665237074608503061872751147444637332808872866814340325832200880984",
+ "4403177494620214359779479537027014449448686844655371530169401219256448130398",
+ "10860968418848589590932601250051274256181778387706764281989724391784015147562",
+ "5268786978207139542368199165627108325282167169564314266747401266496556301775",
+ "10683355823176907476704511935094343405052640940909677712096702771871787224727",
+ "12998090263935761477316698114799901126086030852595294916463464609721875730852",
+ "21401280461419124637791689956622923839426783908187419462727763377498739154778",
+ "9827224472048063173905906705579289843819400982583185823840008976971109664519",
+ "6215804144039763858354471461864183189301201862376216122255322421321775987311",
+ "15461308489200344015891625455653488930440613755785081602434124530381300882814",
+ "19336334695450889400681207491394600659946256404722006637851709906131899294790",
+ "1712331165786355540802697725399423752392267480553199895882357858951999960061",
+ "18153038525983970702748717571053178456148003321236490384959117581005013333018",
+ "1080183517033034908031748897211289245459330899463186432840251241943892326023",
+ "8948022108193679628295152361559653763100984324221629445749311939820327674857",
+ "9553342289560502306921915013446606435600388298465288181461633559299564421155",
+ "12714965617376828547637017050548818007690047452402682720666099310241001848988",
+ "10945704657865102635748104464461970844653553427083981539165832149959193156197",
+ "17511714411688352203059545713591160825310809755917403629838415797949261359373",
+ "9253691969419856285051096287845246422848295397226841130282244592511676512433",
+ "12218945350859454581754463621617733341764245716874083264842931063272433793037",
+ "15268139709971695434346690496076067658968455677120655340969837725391575270485",
+ "7948825129295102283421620705853168119104356217418364837218892682579042520651",
+ "6887299291348589691868712194070626390224806410428583073294593431810559288717",
+ "3610235157455454109573625364057240708256027358184031380521552355839155549623",
+ "16532488069063334064099666525339953823111673083177894678898823509406678724969",
+ "19317517725107761280217103201908049748015068578935276576200982249386084367574",
+ "14980901224290526859762385599553818204548992110637275324411078408232697158492",
+ "7741797285700915051013289492475875831764653137095445146268474269974647962596",
+ "11964233864746181868467810392101989052496076326472717372132104394243614334823",
+ "12746657111181947224582102380049766839578185276220682311596480990298620200286",
+ "6408726946032901840418309506578019708113712492100046332894630652186614300568",
+ "20959261828945984489015610988397031913577918654575078054490013338416801523934",
+ "3173674599420546165852740604987014294355430358334465189504551707066179193914",
+ "16110281513253204315524614633789708146700074483476149119440509845258215816735",
+ "17135377580103690088853370572199271964414896742342749305424508776150797285064",
+ "1405769920008485935711505753346340073052795087429311991287498566024570212365",
+ "19088073362945853867763169651582894739272002359692597239222895238839593467749",
+ "19897231284455588615416169252449008151349728648961637517447194842672488184146",
+ "20476415629812014715153863754869742189693986277342067785614833846523246536739",
+ "11074321446706734150375041020583051611133090415774365192315805856051215270782",
+ "15231367549323128694183572409135806408519505225209496441892541205465727777072",
+ "10515952069292929457050921929301902464262874744159361114100398880194109971971",
+ "3216370118771824418364829250073852356774095079734089790620447714552849459645",
+ "1940445924652458480775282556203659335417827058983719042726494187979000691704",
+ "7899310668555694144370607061960060230071621529123669746309839400642332452086",
+ "3125410912833939638823760577011271607678545358020637189655641109813198731542",
+ "2980079409624774815878860133121670095839651294537928173829312563570356348730",
+ "3766498515736372882285796238406751547889526137955288498682767455795237989580",
+ "21751217522789414135074956130080241003845828660310903627224390345319859795839",
+ "4947229586642010378772262640583556676497656670779800090478805824039760706318",
+ "2168676839236948809859825591626629233985269801981092020040909992251312517552",
+ "21172906642114648036685108008020762271569381607092920279879047961076646303327",
+ "882675742500939602754673078407141697482716600335919344527751158504426951699",
+ "20942968937722199705624825492102184647835614761458159157410261242387423597787",
+ "21880640497503102067412608072166388563991106464538369680846671301780353850077",
+ "17593472026567804917122179982860735087124786197105685847979050530954084564297",
+ "4492875530722152383516030266828166766820778742874238188105265500984280376666",
+ "6799763500412433367637987497601148507907071065930142757525839585946238894092",
+ "7812331664758167657763399273963290017340604299019483750344476103319142702775",
+ "2222332747647756867926707541092465789402467819000336747029352557749400316077",
+ "20438798382149666667185974604464532451975024544676922060351031604444896151494",
+ "16155157103796724378615022758633778903205872772589663310774455593497441785913",
+ "20281325298063880945091623185126257485818350714264176365501683813650871716911",
+ "4922178080989486450454493110764936742315495846015561426329316977670113220071",
+ "19579063976700768282784922967523980346960151903154507737857728349662090787824",
+ "2458828873355000645851832396764221987760639423132968569631493912353159373462",
+ "21166618206785010755521994106737991950548963896649678270059527421944129497211",
+ "9131643699583013708059191290958290089892787165715294157378879201986981390031",
+ "1820371114511473946932363841206094088983972935646887524223011276305844153307",
+ "7264184404232663540867032945940974372967974872966180860960243405462016972362",
+ "11228656105550475045610757902396386402555430893045183008968975441800824215261",
+ "7151503559113638565935009743218857812859208253653498318591469659718664783964",
+ "16876040581364499037941813142092448836399042253618385783944016186340703846779",
+ "10334125383426918152464737478646460879481305348617711177774418125714273980769",
+ "18900559046103390399749767994653107625464807708680067464279674225251110804100",
+ "18685667289312169245526749652972366835289568864080726348092618145885982989561",
+ "19970582871354083670567197978171723431124602481748785146813441774826500485907",
+ "15873472427137024971035326229485784626398898771525077832924901475242073457867",
+ "9090803292122260583635467396769157643561973206888822931647063181944243467413",
+ "10156295009710074552070572489422360071526675259143523597882131082376797944708",
+ "18600630374968456966046654667577076758720435487386724419578803020365834014000",
+ "21292291483064245088298314957584631356250347533568992016547598449487977536460",
+ "2784266893057214755054197979675795184619614089277590464548240934105557638370",
+ "21206743389683892419024645604723431382001453245850423743581664552645211926469",
+ "7915761821775326316473924816837591351530533394717381318596295803119061411675",
+ "21881095237485064870468603451853549262304643738646051878343976465227744077912",
+ "2011784725603622472271597952122938645154942022107573948889667939904597454410",
+ "21059869383015715705096974077910228193608826877524913363323189378554601804559",
+ "13660545486380051482020817701263881806531607595506890631732662177505270213284",
+ "10831091042775967380899180760062457635694790868286967266013231823406639854653",
+ "149288128407476550494800886735600251983375852319258454101603889073198917321",
+ "4032475033542195421623899365282946172767274020529645277615759958662043553317",
+ "17860535012887415629230166789742533149365132198763199254812432302158542514395",
+ "611194463774512114860065022851497908950074400927073001695280142990812150583",
+ "5518364261187313845085346561539515049557757056751872639492957432879259341390",
+ "783263978868449790737487156609432867806742277074765259237378374864740012575",
+ "19059339826992310300213673274315612374137067865428300882729551175173242291657",
+ "3179709304184015397125565132235783368222831063701934511986753856772139349894",
+ "10954198701843076039176000728742415722273043852061382139560487789741501275316",
+ "16411266672500930935370066093245284646483148609897099268661795671514664627451",
+ "14614816948231085620934132277599546641612327229810158468490195811014141518325",
+ "2458257206135880430320027516329707989817636936777744813891328347210486074414",
+ "13549483340434455515002570470395006683062583844603627042649952800864870013910",
+ "14465927800403373425828183741641078057513049263889255157342086762479739044711",
+ "4039391352709218793104596256671892882216573882631238721514928981154171136548",
+ "12750457082077152291009387792121930725761848879916565703854704756389714536037",
+ "20703941646953337308096638741387402857948436803334980867971163138332859477843",
+ "20148755487317949638981041809982361196106823990400472213765926589941031736503",
+ "19035096428824471222963574043396024781574056587456391309795571372815435282399",
+ "13597108420431213178364236660710194375344287228654817880431599113069659963625",
+ "16737817219786305757887002253067607822378794077688837656791543060369162185533",
+ "5164935079689729145670846016031605160169301936105766707946436049006171651941",
+ "21653381930704765824477248798502813954284378782353810890869232482999795586793",
+ "2062605478140760101860087118379474541965619844748678233207247884294051836812",
+ "6841505950265078437298089354417829781031272459823272323626556598403583002674",
+ "18723551101558427097952125661588457059960574026361073828482106612260297969553",
+ "7898804490983679270754258611113569895515918945891808074921872907759024464249",
+ "10882278698112390755842292529204069263813359338030917602809789513528936860051",
+ "19447560013395173052961224723195565400117958329259001072560983848146677205053",
+ "6251288025262210726686494480483550276704856797649458538460443509657307219922",
+ "13176666617050786358406074057104742181338809005466316548399895981897535342946",
+ "20703225796049910173111490454489910459787604528779911406172217267261190895618",
+ "20336720518722954780604743873837334696992422089627753769439653667292899832714",
+ "21420427865372074512365684526694872695798980614525900481233709853915806389425",
+ "2498895690812694987926199054702295457557454143930759961192198950277119149872",
+ "18753512301709603592612141197073246313430368834576850495154922324845448997662",
+ "13229612292359498096055458608547157785066962647476451239567069089111704445000",
+ "2690879919643532184588441383789963956137193400890598777054187145581183393168",
+ "14142396602342548413722428497204107502988046500369932366351553161157672540408",
+ "20448725195660080278132534867269279218381543910636641344871383714386318629041",
+ "2559459540570011016181396098001618067535109329950570139376049832813577592045",
+ "2209294835847631004298393339896770055851570184195462947318472391473531519454",
+ "14610669112573509857774678749257346364319969641690596877040685661582231189775",
+ "15281088465087253563674405311018738676067395725444151577815750152538449780965",
+ "8600553033773805414817363397077178137667131851961144771667772828459236208319",
+ "2748346039979601666392027583251905158817539034260921486084376270967628661657",
+ "6854960712378511006304629447898292218014632388505703802374806527561178043857",
+ "20207552563190343462280438839438087615024485494479390954719687107061991587248",
+ "10281541252271366635718295778088948309847900730867531177275273130071062184625",
+ "18855605847424121529776135453072696981767402526737712879984848146282568841809",
+ "4160214035780913418097601322951078913381556877408879904436917334405689553255",
+ "2122867135885631508183413043949777333811557914428796322029495785048111325437",
+ "18793959580906171893053069386015945646795465354959679615181136313144978078417",
+ "1043591673717355695648236328597936528752358227297053230241551190351813693314",
+ "15686469257015275311444450012704351019335987785561570672026138336552980987277",
+ "14048856209379833670666148034655599475317994357805584661156301746235313941815",
+ "1011563953969880478397969933799483261900428580241502003261587014788238280391",
+ "19240556623066672446907714818724971233422104071815927265423017590508305430997",
+ "2121904286573815063480388650799381683473766736407678915747169455786741101182",
+ "6724437969134367395210139771738563153857495313330774537559578422672993498270",
+ "20206855573383441961836932177838081339503382415601366823182724056749038447809",
+ "3659051978213562322887447057085386386485486575515693147713900345497451171308",
+ "21246119528547168535908718411570119652856799993958321864163737649108920924448",
+ "10446114322905404392321651684574668727564081327779662579984472408056125404335",
+ "10052242287865403393859620372179811039720807230902452334457123873762222543944",
+ "6373462744579965543231173757071025010089494620309953425653057223643612177083",
+ "11716070974813426833631730493593924834405915845847679294742728105127112594434",
+ "6451284530793440411577197006976867289209413848762574411101073727224316913966",
+ "20143217291446069633369261481904349401356557325260758866598205109039367201468",
+ "7741896897172494958877302103827661518814930985518070029789560123401964418102",
+ "7414486245715284930410091802521351113719159777210731898112598211035848096490",
+ "6480506916211642204624111742530825907262535747743645014149694168805302825019",
+ "18349725066341807634895742572304899830893334427067633858521634672944685466440",
+ "1838291082333887710851505844271184097051704051003105078056248035350245616867",
+ "19201915197596065583046168024521824662441686729039260890206806469763190071269",
+ "11253788423541320580105520117231178489492440242200599071301755928628199128159",
+ "6048832714406694444296771635481934823208451249770515560893368035838759154821",
+ "6398008918881249487422929614611145638894557821587972164243877575640548705346",
+ "7013037564266297435879776776659289982125632651326438965546874242685502904730",
+ "5942504790082366811245813670914617310604940200824079289270465669331434165301",
+ "14344789199380317440464969138686896230070901882253997360605407637865754361287",
+ "19920212380356573378521292048728904573841049083972983190424200459025557666792",
+ "8983390577894750782268266038315113359711163721228398686939390484499979421166",
+ "14953991148867572055684497824790735528852361750007063016470842397064705671772",
+ "5592033578501586280289038012647352732276003389059749788953239057845882297561",
+ "14076883072716069263619564306953450824526010844333044566762059693672378725675",
+ "11108270411921226463443318601950168860230077781212396032908932369105145901793",
+ "3681277588815101350213324449908372578846563884174807724121308021640034446476",
+ "7194753190480156904207319938161903897566477363779122267985209483435838216959",
+ "21241255448366937244332942306324590869759761073985963892514045368815880517382",
+ "6203071960722514588958553813186803009742459823360660333787981951206442471249",
+ "19041823565851118046937769551785013706136778514067168239416647071096062639366",
+ "4928136619692555022185087228378238193895894009623071873887735418398682287593",
+ "16266329364886004534411977872528706660422476743809029518681886596981922182359",
+ "8814684891729998059175829142248330760704444206534875755023421115211106199303",
+ "11072277000652722690981202459933101924925520292174200155471966778637063588914",
+ "15889576313969861857250394875354819627977602318110620311480656842740292435237",
+ "6934515229262494305594741689326968268143898236690173897991110238064230886755",
+ "16212991575388366798683594066983659236103186124339324856776288894513503543244",
+ "21100508914867482363389012032457112622475533432309937238082785660233880354422",
+ "10381104469089401657446748653199843213201270332853172509558263968565255702795",
+ "8849389605935865968361613766905708889092097013638425059146677490704442276611",
+ "4826404934194100291623537890117339503344940312401101713754206109744511979962",
+ "9981819567268652304810465083896863711149056310505889216307212434682251812603",
+ "16218484218588441290424553684558267080330286201433140852298971691458926313766",
+ "21317661296916247018967238829275056855142711494630067664736600708605437812892",
+ "19523923008662567951910986132173659591346561824926093935331274289896011695634",
+ "21439241836891927940168832009944210084078628922824257988298290967895179737163",
+ "3818036890597976956138669961319975835941979944306305168232209375279960168960",
+ "10212547715001519604442389033695156945619060410131175896383181616280631586732",
+ "956283172524544133830416114111944076629240232397666924807554743752464221045",
+ "8545109273807246425343308224167362024331960554428088718932211551700420545275",
+ "5647769597708100114837534314408246331518385631750569421373379085922684908872",
+ "21776221280695269311212391423788179027868152904973644113087833004348746215729",
+ "15989020831232836203074762591626149244364214836699154611339161287030952623233",
+ "9384665943619921791886218744024370375464874104981653298499433530463000935024",
+ "15469006121097295841026542766455781293432005131673839148320165243166330403027",
+ "16103671377537767724271717097892044266704736999841135349844319906338275108222",
+ "842367229428650719054831004741080336526228967970570607897528985803108607790",
+ "8752325400224955775788313769797750158375262384121380328719514077259567119347",
+ "4803861091350023344885030428100876947830986453029412601567992550504530969575",
+ "7917553047944370948250445233027936387189889293110390303835890604428798853681",
+ "16378323148632546424902611135263436821435778030958161546757828745002247975096",
+ "19873719885630097137106352132870659633926425645300622070145979694717581586592",
+ "20324790419158243246762098227260178678767896786893299456278167341205663612964",
+ "4358908354524026935988729716331497263147669784003421920394531784876541301801",
+ "14403952632095852077754539203207047943619815438482171213105824864831554185165",
+ "16410713482142323347391147127545553384558868490870150984280601225023662513809",
+ "7304216341846662695189617252648753140769311862815448449926830269690397729157",
+ "16792943782280077475956215580025612636120139194657275471595325031090407485768",
+ "18494329391227402645175320826355306995912366111176422593669423022411884295357",
+ "3277597348237827068690736756050060740435013727549848360800059544123155276133",
+ "9396765756719511114743964794180256605700037182617127755220919249774110852382",
+ "5637053961584389263881381098869862042993858662768294676971865632259649027245",
+ "1752142832257643043564515360000718468888861086573246457619082905919623770956",
+ "14504506574384680785750882507533398260948836347427103366421836731538357314790",
+ "18947994518078004413210940685748534988014581551965984303066903086446389273117",
+ "8931855168578615387850254663107425567403115805663142600825724478150698936342",
+ "10982092525200624040399870568387498905840578524691489797530932831401946309626",
+ "4738907023206802373255186532236849256768509848242049657234258536668430260775",
+ "10888145285628319545262252531874405309329869513560101920454793431198094714989",
+ "4767721624212785367044047554655794533816937807005608600525762243335180089923",
+ "4054394679973840378112083329204220302222586590732553688297938891619998137578",
+ "15390471663419625573793381445844013245022413344196724396864223784781333233143",
+ "690498740448849288977645176879593806019080276382495160049117613302192708860",
+ "3326968907274045758110436838010900592335267522219473049427145975873344598768",
+ "19461545874830130561487975864151403334363998126023624462211037468138940028328",
+ "2255249425919459031033123095731665691066980364231819200773725596456576056043",
+ "17139538647342063569964264947811360956712827863014723985947727876623459280539",
+ "262834317961189780923232082352297808796511874872711860311746704570027370416",
+ "17784213646586812350819691264737755884800773322574478474130308351003659945289",
+ "9206479615073686723914227166450906925650471865894639492301222855979337534393",
+ "5955379232184076713510750681781395826148323482009739159408415185190732125682",
+ "16345512244217240951729073298135981012471478596479891072149124888060645303490",
+ "20053701095030547796310908765544502773063879272854547881438596069907281565287",
+ "11519146559536679602608982593432194283609736022486509747046459824035493513614",
+ "10868663839942247532249591973192159672852196011910414460124452013501564199585",
+ "12668355291693420029179738224611760713369106517542315102687346083105601320689",
+ "4091011252347209563858280520339886760216002486858313383741839652119084430270",
+ "11416347683590132388448480763970462739172261435271326798646502987745949753371",
+ "4462763980178675172541782335457125059884067698347130082276003539434128058577",
+ "21728891122467658477520865529973242372850367356840114983386033432316519759391",
+ "9556106604731806817435679463077765288658189491612307664294729425381901530224",
+ "5086982973132652080709554654284904229374030594786774699435814748257879554118",
+ "2278505454992311041650060186856758463754878439802195559533882189615578260695",
+ "16123495070352975934848591912315341924608875638550779884194576881433498909405",
+ "13177225503435100563531015597038445430211235761527278782674200718068329833622",
+ "11626932451843299545922103072142674578946680165802341368625957942237790110177",
+ "8872973246419344365802198448930136062421718851114220299577394844231810068090",
+ "11920016786052130191738519934437207519332291620474831138559948859328822621221",
+ "2773753221970604083383541092979093729869734021029185810064937974430862835870",
+ "1194583082499114147792330367943150006952486615245506995832323057119894886077",
+ "15293312601348482070373672684782686300692505365845870624263228679370968807837",
+ "2292156760291800990693425534213440357167359161992251338587906324724034592198",
+ "20920049766730284147153707151387304988393631464951398563908410768221002588086",
+ "3587899345078220957148828249287269521408604837648269936718299413697642586126",
+ "5857527906708110948691023855516662527925762284342493618496858248142623857037",
+ "18312267494676788897591109008609888960798722042916784593521762607767538629817",
+ "18354455618287562133438807735729369657256664914390381320892039403006410339493",
+ "18594037435499535688023807489676900345345731643180370940972090155512943637000",
+ "6361231157299815359812386352981667048590510979947935475914610076041390336883",
+ "6503045850716008738909204934356093641022474278658078426701342798380459107813",
+ "15826908470360778431798326530563200301151807861414464213699967513881040969457",
+ "913167165738148713876672473302437265273760468892350716109373788573860454641",
+ "5163418960719047707254162004625467116036830361107107814320243058319914687515",
+ "1852750695670141634014249062360862036043602867770163972096325792863710036947",
+ "16164029969996795952250343426848596535809001568622155377829217918121790073916",
+ "42291476149937488089591434144089904529405222471677684973768504172369443350",
+ "1329340386229357940610579826659090359930768580941108555938139535621252899508",
+ "14087936453397725507000489457270864434699508074557952952329368237400407748133",
+ "11454917885298514922755456675259734718428103879515668717779418480236210705323",
+ "17749966508430836878443008025013283275306943216523661550528505419303121693213",
+ "16617298839486771009961431205770630163409905047728421465641369616889696635464",
+ "5622873871440608391107520706189063847917690892897751818294742462879871297589",
+ "13537715561706278379083684257583804567523085149672090320983273122424669242274",
+ "12609629910090871112615676094781247031353826207267723991911250780907380059468",
+ "11881347692420971451998583525696964339513193164613288356598017302547676912004",
+ "3620434358220496198439193226313617496907852030586214671337652678218740406153",
+ "16586456872124455799862826347901525401871594428044067424833235946565396779382",
+ "19602593015746956165116919928045364895525104709835703557292833702385934632182",
+ "2465427491077301663150648330772125184470808854603184374760649420983178107738",
+ "12521323976712195518272978277895155774288446093713549157148428964880747896725",
+ "361951232333654306694462853852464888974834703718677826403016226307188397185",
+ "20048343816024297162848487251896481827914904696805156112188099141327595641104",
+ "997638030405613623344188782838773314122493364653596616029491564227193697621",
+ "10932007654988104622042938184134556963651043067553327861790671211490960094259",
+ "47171599193060570819891696279547021610376047998583333086685382152080932821",
+ "14669115378939104862697280661831896914139331878760241858539421915983017116504",
+ "17868874372855679948405169936193924176514630305572838555185339642210810710203",
+ "10178296575837129106771098084407669500326673901243393867574658658064222502028",
+ "11497182727976130924559852428316615034304736115488257034951588831868596612725",
+ "18847036158089242140209840241495282890278502700082131513222116906134183113862",
+ "15514518995390761662346743876733004358408187550386554449789531199638765348953",
+ "11474102901522012346251529527050392650125347221410246734211005177721289856415",
+ "6612195415835443084676700243243174090072629504450965229103970796390091290688",
+ "11572474094368358234669561324969692616275099241307798860733942350364532366113",
+ "3855324911963410548772360326122995145790506408472649961229511965629894550308",
+ "8802640003128749594245736338745752744580147773009816234644244502373660889677",
+ "15676839305513015047736600040932186843826469281853634239081282896349443894145",
+ "11124722103091011602185413968164672678635980457394627450785290630813993266691",
+ "15087674670944618980358596427703842917302233637812357643695687556421910213028",
+ "457555060782651847600218200815104907046227486293278645126081160142069992497",
+ "5340353060455057701755599760342180989590806327490432497082435572367648024359",
+ "3289809733259936118731355294329652879189400852472418229718273887860572748363",
+ "1821386174933044868215348232606758690922944887434531299978498726875279584854",
+ "17399236630582894158137572250502674699298844870791766041927951699287421557453",
+ "16772722824042046255416248879357647708113647471330900665176012648038469814744",
+ "331374066696126093678097185404981758791664151917354547180452342655690460271",
+ "5482079579065945934120471179616600325379965440378196448353560421120276746028",
+ "11861638874356162254375133266687016527365630872709665703116365332534843803431",
+ "19751278476934230895840638614095718373810690662562196455711240141902305648888",
+ "21017623330912840225230534280017695045717261514215145256795880310933667407841",
+ "9692530233397639077769939390011937602190121885296235066426091743618448584134",
+ "7914031992737639503490179289412369887137436318696390718781298556229610513180",
+ "5046304088054212585035723354298412694927209198400753780585596829596665931980",
+ "12735457541003664856181534137486291132119134214862779086936585300598349629287",
+ "8144204472889944485922664106370529127382213990656088602566223875490414163362",
+ "5526161442679804982165840590640681348630369336752481706044759543203459722566",
+ "4665464612431440885211271075488840033628676516298384234452346107374012633528",
+ "8451965709652752887539585363308640999657377914501438391781526068371105983117",
+ "18990458193856163728406448194111866469438835810342179114684453609893347662421",
+ "14602960690767985987882800342208585041637986661619503513589079723840776294824",
+ "294650277854196485752526848096008214721988745350555311479128101695333774927",
+ "9930361494944692931597991649915857642608730961125454734483697613693272941776",
+ "17972565769620820679641368732920396905240248490243886868922250461473059009007",
+ "11842743032528966560856860268344505094861546674985872961254820091273444880060",
+ "2260251491209762630871337015316066081541066308706934094017641769176593121838",
+ "21336986809148977544823484666876006147697590184356254785752148187171367963063",
+ "15637234083283356311249527335446193685599985235080555266374006156231977517227",
+ "7637477891046186378249227336975234440873859617986704147458186423096226771577",
+ "10435340982947407847927678888878882924793449778165415690957335683641419176012",
+ "21071574044063633264442120715854514033847137356154103023224485568597330648075",
+ "20085745552872944745120547909310789275453780111307008151203836541147270866122",
+ "2369255222739182549768488367357061329939116877812397072967912842660453854658",
+ "3320710154094663715463854219978294133429318041799642537800174050047893035878",
+ "2437552820481788519744888712380245016748276158860265401041560980354471184914",
+ "6687580113987208531705167517979176727449238324356562435678492283111952291541",
+ "13835828959457330678345759960614663723017667326485961761361157914420441377430",
+ "1823843951353887792473925888956554516299304358703549730900495356152013614424",
+ "18229384804985230011714562427207966412342158903455811854157839446374012856695",
+ "4983049472282717134994110428470567601005310848076496400503178535459679438524",
+ "2047051967230753763135778305592853785901616983565528680886843131244871631064",
+ "17059505494771925862841990046823342770591010831955480339095397897088168520686",
+ "5845823714127413134610517798305104245114036685335948729450609519089263487144",
+ "19810252752845594230307894817800427820113926573704856490871938876757561680148",
+ "20741340243371419379519807725035036726040739024854919427690724405113594586449",
+ "17305746835229988220561638584011917989169628535378748397361130724475478785704",
+ "16273970657972145440112726408308019138099820274904080726219726815138597785735",
+ "4927605725478881247988642936459897069651251926499343645614635597380235002430",
+ "4076655226193629464789557616268492785057128805549395585385432329518368497686",
+ "18134767316186963456589895259454813585756254459227058992203617493951135964914",
+ "20798436806114056077588608064161229365173163847083955162560624566238528904361",
+ "8811900287453512972593412116532745098600991077158875340182906101108258578231",
+ "1611466530857794066271650650204918615746591649578992581483080164777650137733",
+ "19520757346022691586967284723955378385034675472244175822936613026597514818901",
+ "8258287931139503595713718829279050060190693609290797346704848518381891359704",
+ "13807143439443425137076128013998009581746894329904809421858222329599144124143",
+ "2034200548964915935625429760202284220693125881760822084201315022529206424506",
+ "20594375914400911567795140472107624446159181622166676420027082349633992663301",
+ "17773828019575037451999782968066986504577459910353828196403976545023426528432",
+ "10645884969014005687699860915213473815514464399964009808411811895545112650817",
+ "3135829883501342672772973577699379927756997243617424917654928164800203666496",
+ "21807676600134151299257078976418813484444183016737321278512745883771478511369",
+ "14168063038909284721702678019083222059818438340503980617872573468231611140141",
+ "19022539506931505257153342575586362988716958060936788031721967221986624233067",
+ "919797128086310623571009200546035983274688764270933413427846490906074137487",
+ "10651353481391913627770814216074873532920753703051075188645774021198634943682",
+ "21601553598752750925049978818528421110707879819831249175157596816870100048288",
+ "9544964974935674319204796617933096476421551193682156030394816088243121582636",
+ "17113833205578964054057051521784698139661258340576694677296240312431808476286",
+ "9889647672195559279745677506312894570402108521106900082889976819798270827735",
+ "16028191999932520938901585234936954312994452706490572504997534210876573833649",
+ "19224701772787524647172128751148104366752057774529591812815327738829591289117",
+ "8065294760892477625290114823800398061529770004833832691347498933238361039736",
+ "8385011404987806129246014860479833290406969218526611328586242951296814426438",
+ "17626526623257098006524211054563886193098683828265081734658432468695686509315",
+ "9760584950604786147191288118087660976225563461953070125437519145090832114537",
+ "3282956645059793949082172795607530130101621492305193365378997603911833418463",
+ "3788543541342252822847978185963388795825378340921321139695221828685330606335",
+ "5728277403393912877393143174229934529937061751983246730506397742038949251701",
+ "20532577038632159357383817240596922896191478140446876998140515404169184846609",
+ "6138500779693128517529525961343097735306947649093633133232282430353593175172",
+ "16387038830089541476468870208162294639575042754761542956218362331966004300870",
+ "10184264376398708852688445921404363179240954227345322711923845040842165453208",
+ "12576299651793170522912156101640799825541149618303513174146382191633847258859",
+ "1340015400080181141720946234858756484323564628916867888877667239334982793481",
+ "733959369856163480135680991009606990817015555938726628110611986599242143578",
+ "11467033813562140192244869512537566463715027496952375979909160849747976831918",
+ "4619667645046391146577435774790188488541561222783010406420406869960248783331",
+ "58552761198135931030902257754896948615688045302818928845814661296914920622",
+ "1199849881730507352706524556330002080538296688430736582840314007371442152147",
+ "7124502590511184113044595527748024819132713282667933641439666531514739645089",
+ "8623660134669459112474551498616256867375253975034970808437732784494772311361",
+ "12655669439191191182341423414424342421477486764113555800095493091893820045534",
+ "18432703875775002490514477493898870315422995231506677048275960580528644904682",
+ "15467220287938881354678249472400749704814316816035426814619089032223454845193",
+ "2851120240492392321044027263769720216640877441121430445737594074121655318176",
+ "20519914249934881206828098454303256358482675671718589102535780334267934987941",
+ "17275124961392392047135728713829752470490098022504524438869454049765356211723",
+ "3323710067527231515807603961736782048796606296990840839366613937968342331886",
+ "4468708240622802562056471128793253296493002925988003094771284205007772045098",
+ "9006494818135081033869830730030943407240565201693254355620348420258773924028",
+ "2624130417875598753127999576825019766166727976335690685433712946223008520912",
+ "164131399455376615654870570697119442360078693174350746600132391198500093412",
+ "14931668887432843139264972187415200544679230597820424081936926034478502874299",
+ "1638753880783574431267395352024193675000113296497173968722590753809640941864",
+ "15505380865926802396097545843811910443367233632805651511272732002583232431557",
+ "17973744614207669251901495093091561913998272050499760575282030108740677066624",
+ "6137688223696761009295745609563284204827706564566466060484103844265403078408",
+ "14774243062532823236792831566222119634320864630838624098798648826842418775856",
+ "15864970393171078370207775103899428499600152663946379517190945807315353544891",
+ "19010063123357565300336230971672519561204810737546730911549311353159512986740",
+ "12607162829921425080830052984475623157169603642577010527391007035133383807243",
+ "17803108634879437217723652777640120469990779759700458421844361066182881628345",
+ "10065874953507223318296028499872542865030107611981933577973812883589535269142",
+ "3276471432535144390388324850641020151392959100393035635141206272558418581928",
+ "7532054601401798035926415744768772852833516520318445183340725930886329458991",
+ "18893822928119227829016544343228228897166113682019317256005502643243867377334",
+ "15940597493253236451533839310728876441657428995464658827726295547815292644378",
+ "4268009387843764409267791203070919313017052533005657826253994943184768120896",
+ "21611251949238422413354051947529388972078300717392131751061464498329326474580",
+ "12516447001729804412674006874184731098280474050775388553768469608793631490618",
+ "49838549447142926741568525697026885045023997277705726329780325103507790978",
+ "19763902910323896567698991616245963026306943100978479625077573937114135803058",
+ "12029297973430627253212633299020402005457460023136429653800185001711727387314",
+ "17676997725594777991384952086633589048516371093397126876621255518370680168503",
+ "10567543371894667303450346380722020266352683222046730266924342174164712049360",
+ "14583364850544999818712646438016435003942847076919084667364987497592599663937",
+ "17348091487238815837308569582101875357715798351834275089190053280855958465528",
+ "8743083090296259283603789316855921930102444739264013461469099560398359267240",
+ "15114064505647935792598848256320570567717917317803629185764147361301698519005",
+ "18332675991829764561879941291908436508530604635608341316693114747813051532006",
+ "1757567731797951053080580099911774643896363235228742197150882457231133285549",
+ "6526388717947413328592956348507481629843816325885832861915399601868279124246"
+ ],
+ [
+ "8243355230504186170667337521705529968548180153769821936979698914169521362326",
+ "21549235422807751640146583237936799392598740234259041629069949854834009192195",
+ "15309683586299089746803554818142261058154570215179112411063662706557055610156",
+ "12007539402495575255755232938576927941514879725482443887151392201585760698040",
+ "18793669376013417649313139054009540629720623019893420956495818743913188610515",
+ "6637074549079529416739232814950531409613090469922787253991308038219905474403",
+ "3042007484821627445120830225760006405192082634864137749621636257026891883326",
+ "5337388510268581167254715112479133594089770138749507073603490761032513368106",
+ "12325446798142239188409242319577957593792614990556679862642230477712636037037",
+ "676789245562467194073706116744095779362669155912771165373940448756070927910",
+ "5854747984773506278911353281567883752585612596682487681686710970786834920041",
+ "11245406467967785626327694659468342056789182160059009120973665143197638081760",
+ "10395601815816075071544509552592627172226369015806880764151195346316980080894",
+ "6756096862783612163697577917108261850810460757753491809406999449771712474223",
+ "1708595072322964393019739105130946639405776432058599259998973103484499438306",
+ "2817817145890818701877539103826217929456570347854153048034669346981432211659",
+ "20337270972708498869284875601749656006552838338471813066271573323209168221011",
+ "19192338172842323468707146045612196807750411464817516820711948717057036544820",
+ "17223253657227310295312621282100531845543865578630870272599545474783775759681",
+ "15004735209586276209064505708625280228119288986650187909395010184201059452346",
+ "3875652974956649356154345677088455126258183810851242537013757276075769588050",
+ "10514447960615206081458524578173743817818597124482828867666984705327684376752",
+ "2087647010835075851760610474040959236825470174942075295716631067964093542910",
+ "5927163251920754154392384551305623830535034440727310604898855074616515892551",
+ "20585333621997037505291454298836355589763292536744926081563336065939121006537",
+ "19320876518201905459682928158170419256739531666800973485138890064423348282196",
+ "15942638804716709831210239594904570403189415026144938623559274984027906868220",
+ "11197022744936474661934096628367688581641778841814728682794507017845346201383",
+ "11034020922250561671038205476395109731446686553549026383358725302157324264144",
+ "7574933006942933995255906769787776608010920618615581322603847524789684181970",
+ "10061361506744906780155460423367413099657465765582917482575074226383566926764",
+ "18611343221859570540963418999548488653944851224739716224660835306206658947980",
+ "17094203924957299390365889251598099482992645049968199405515681968938743421467",
+ "9407145832890449495071969940777105644547801064593141904558463573167881762713",
+ "10921438560879150587765515492087524756046482460218342400194862909363870270743",
+ "15101279960899220452674629307354995123411280418550386595937683027146194547144",
+ "1872357133681596467751878560069114718371273548294363719900935160833598069645",
+ "15505500304018853111989216259257978796595506623204851206292254759641600763191",
+ "2079667978353221447444850850900204451820443725835104896018664141845782871343",
+ "2852655320672908960411014862634757863509253400797831983637863741066632490909",
+ "2702824031197306101989338159138451445088523866133498139857862801497066633794",
+ "14553308731276493692643101846551382187575566516925133957384350697980935154102",
+ "4314969815396483242407853639218064117498232660761075778657880116870422414637",
+ "20236724297078811959918602376319440958076910292454596856154100774072250182183",
+ "6360017115980704736383763605019264589498600998515606807745670287390050560160",
+ "20856970531105411628054833058646203890148287930330473527735908484791842390307",
+ "17691356258507144960616314395885779533907781694329041597441621553108536658757",
+ "4464167934150673174817562382299722091160711333547138388803048452674668158635",
+ "11538922347277268848344412167140306567742076984016453903533772667841006045703",
+ "15558861252260038101730449864896864763293561339637017072015859069059083288561",
+ "931980552683520059135814229579184511049009637966018180567726214946979768011",
+ "12746506550979326220422215987591117730943427023997792332255149062957909690818",
+ "16416138987000536018990311324687201169959549714116951891693452597169869821726",
+ "7473835750915837381583185047008243788613524206396316652305987269933344653773",
+ "21223994082372071324452834147900730753626104062167370333103771844983134656961",
+ "11102363694946721470818933128034696027504133564649607436252022322296041603786",
+ "2666835000155694643357391634256423691785613060199379949509682292216642706081",
+ "16883033667413528795407641102416904598130659502290474063092941543309042023190",
+ "13093053604456598783294628038129487761924241298889312497497820946915331319389",
+ "7426349812936697309541457521193139970366533826612714195359894150484429907425",
+ "5243217285990182677741567384304278362485372018078770234262925321063263504918",
+ "21185490040917275396474067542756068684704036418473170810170344320388557093876",
+ "16181135763579884029508432324330748636846464150219757303321560798898398598349",
+ "18088358880437096005757355821526785623101357556483672471222924931365890201571",
+ "20418860027198053484245336569800730261127301261293595190270103940460998981236",
+ "2058948081811170389115771489993053947061173620273801887242248130631460165879",
+ "6353796008567532863300373986154930294334380098977007704532496889557690195858",
+ "15854609649070278722833415779491666201355987522519101725393408435189057056690",
+ "1355942327518086746604287131396672941922424788908995789539897301592998007690",
+ "10194046920666955610804398522181498854525794643476895032285888778350918459761",
+ "18342608728256650520630397534564293474806178807929639999068140223470256007117",
+ "16101948218093381908101491223075947943147313203969904451859930796280152622017",
+ "9866645853452683082481412876547916795343134459981103407915522925093474319332",
+ "9309485422719740772955698359258466728180120624442685713365406080485336040166",
+ "5201701081505060757054562398073722930344229781365241858092054974705598137660",
+ "5279555243870694216927790669819597822350327573071817682265773244733785382064",
+ "10661662716572743893824841881707597899963881485303936548294117975770384660590",
+ "4306964326426793675768869124893413588264762573088622132302954501394542576141",
+ "19945975928045383298785833694292459276727208605892865429301546022994613804030",
+ "5037834331249812829239656466783521330249138768989720606017856991559732121456",
+ "20693877087308232030611148201802513236570270737947270986743265610517665094074",
+ "17748932969923719316564673051784340920943155490113289807023660243301385585070",
+ "16950307665556055391386715682532553772527550247031548278958142572490582126842",
+ "15034211391483347494286112687349366897258989065045859280146461213731663274520",
+ "3455096385235320554100221104677124747996171720170690637998043454239897385610",
+ "11220329458242704347549150795173830262585759464331372299692251819012138352257",
+ "8230076319752658879891285909687940775399748755759819661970430769188439691274",
+ "4178690445391578185009939705412120505162313641744671740163024993195883735198",
+ "18632680236376151061913536149173846032710756800956417249233907621575802688710",
+ "14168747730472612819827430620596085566004981811676505988180237018638188025380",
+ "16777617016129912124437138351698263064579177499617525409625791377061066895460",
+ "403267570119386144603206457308168792379980670187570608148634410971295877610",
+ "11045890302538505532103216886575539246473207034538532950483165910580782953337",
+ "2632893274667647784827087132221744991131294771819888858265016332574437797556",
+ "14022461303364013571172470728150898521630042996798160127819093871974124417229",
+ "18349129573612583311962846403448135938849737390546876598640066736462315682295",
+ "8009723611300112743690923532773238474616291315457276539919568488041436720507",
+ "3287586297388209299132232426281031982329712892122181769502106059441842217623",
+ "19893256464101780566218598404932657965361824655069879954668551189408491121155",
+ "21779954643920608321663779655887581582907923850271820082121309309571440586162",
+ "13938145028737822338330333388496944993576078307754676998341398757402576278690",
+ "17280605833933949866452995551396279974325968699794264573823990818913515933775",
+ "11562775307500290654949270847967546133812416593099094805234457839659652146289",
+ "21556021192476590536800970202944195471695121915357500612310904064652863447972",
+ "17407055226077297021071802288772735837293135175537846248261973015744713174949",
+ "21295838064085671525042198277220548723525913660103018392096215316189390548013",
+ "14589917958236435754986191512564058641868109230240077937707647376289105324812",
+ "4538073055458854134606640263494592220617270326115451287834630189270577020111",
+ "21247609438242282269742265796811514090579388884916478939008977411932487423659",
+ "19263560475610984724826226948356735903574936974192558145730920786586162783055",
+ "1898614508331499418660051276594019416852890004788354240344418815409520758722",
+ "13346547977920686435662774643991891597826323722140876186086635239306340843003",
+ "12144969177194297999321084025481801838621405926243412487948189180755523714531",
+ "11624156909934489978766768065107924627236090741698411458481638802308500352917",
+ "8674349037900011131899280296161700067911742760618648557038290076406601619864",
+ "18627233188669469962636721109716646416813512041955577645627776298400086440228",
+ "1153719160094308748956884656041023320488424966635003188538565876464091909764",
+ "8000003066081501211900754070779689975656073731442793160620896624291841806771",
+ "12069801117560082050163959286673266840809976769131514316118288648293224324822",
+ "11694828863372498882861202648883355759680038037706633938668096525787115759720",
+ "1181495201505177954430275085371953511604847831716865494220845031383860562941",
+ "18321980275956746302814628602546438645691886543647725888694024551609678639266",
+ "2785661975937033521551267460848061931764727388015171856456622007438303671899",
+ "15557886094116287182932984983441793820379366058597052543066101158081817575352",
+ "175179830261452669822497364983291141568331314582563701393865403724263011876",
+ "10455128373814266139918350629083299308526836847946708764631040462916637941146",
+ "12622681406523708498691044494295298210175441851465578469593208754136900020434",
+ "9624138424345877000077746656879336097173254842107184716328214933320809030543",
+ "11726383465426411877912203592949370178096897707629953853811352568008881233112",
+ "17566146584557385507728086844334319515338136183689530813551207417981719751958",
+ "18423839150858891406289385710861955437811779173242111498197433255650436048047",
+ "17408376662161624435555256564084894291578222902661202310977717110546842356960",
+ "20995943422377609225953642092578140203148330329113983394181012996247925741957",
+ "10409490873284794620245703460832015892256721643100501421596423100640512505920",
+ "15047062105747285153444463303020356100177963702386173227676803770571846532695",
+ "4535940688608096040988822900684697329863791065464226849059470519882399535780",
+ "18980357680792173392910397806033731294240363676914829395702138582894418363978",
+ "16468042735091009392571235146440392007609078458297170996132218787642722263238",
+ "1869769403621899262774247370472546961521039203681166934356431996537822108263",
+ "6151829532330885020831674048300360431343535966534922988242884341920915237665",
+ "14373964388615044752046531046884609884388869283450342961030080770253954449754",
+ "21429869771065858399481388829822721985084474326196139156050788103070270663923",
+ "11836916222341149344359827526882466618136359738495035945807998286429671739008",
+ "4542193081188277792793758113018430324598765345700596639963408884670534634317",
+ "17262340128494663310404052919129368521415818617921877469042393034218456907650",
+ "11614110585474201606235056157412783071151951301104822431509283035322273244217",
+ "17241248261774133453753660970137875514052923171943595080766050681996607133130",
+ "2990875140768570679733810173464987023133165559726680992079139149034178002777",
+ "10032389096385585741539206260012253444831624820404318451026478423856181568200",
+ "8391217416130739565515338215591963109158836617019021044489286448654465296819",
+ "8553700889274799411012667201578367398970695661169430162294018618925895640041",
+ "13529692770771168133213371031275281478756443444824139121847596546264553079152",
+ "14478949636372928879378459122088894160202116364833386541382488835123981766413",
+ "18528743543311452855194545818079449921167163839226390851954136986727320245809",
+ "11724222260540829258562889360923785293478512718704276634048783603461995522859",
+ "2652532822068043785753514309321715043229885635900630208154874285707479247265",
+ "16473666207635815797882774885364997250503755116232911726426811919269547851975",
+ "12436631741803099512327160776479880302093882812091908650798222524569929954222",
+ "13061081443094122428989571162147084312340276850316867585582410062467362267361",
+ "20909566607465067204267258789556187669343825005173558971220332255443231196363",
+ "14278016202378252898173761523743422243750790190417896338147106476354187349947",
+ "7703701752136585609667768350038563449121231460368808945757767724712186009894",
+ "1622258312841010773225479468430896972269503924285598181547410615000034107894",
+ "4706114868510775588142857635375822293570353199661120256611528287780303504954",
+ "12723022498690150801900112713057006417552064300221766812928489357200260312668",
+ "7736508633931646965699972944684083339925061856252811104228904321699984469949",
+ "195095354858363944780141950724441876473553677166595890451203685104276178612",
+ "18877614091447727762374351623731936445361116363480970639310200637662433378180",
+ "17239262588506530491210045452642505719938421789517734104955853192075731537629",
+ "3391556611912995522919492308422471958888145521362922265487749943660431330300",
+ "10164629656754294522862462407441648133619259920942013682702008716587122474446",
+ "11939828733425435518898229234599966533928666730047925120030711579782543312731",
+ "17335155958861138542643885799966192412363788951639890938680530110842555336617",
+ "21068414996957890621467676209673805582866493104159841584377567318112060433438",
+ "18041291613104743972430309067462668732698702146146761776321539150844598296986",
+ "6149130772490689572076747194977244577047643214871016443290724757756394340290",
+ "12105848363324940274456322072887282559016226587661485273111872063034847034485",
+ "5683957548001811989600472365740829603387405501208071642225953069881259762607",
+ "16529542077365261070047716411124689196456625611983373158922227651721798753876",
+ "11961524596519782767188645738887896272947446382672325012202336646508449392990",
+ "9785728068011868312995387469680578201705397880590293454099364001157116688561",
+ "18127416268588083447440821307938591826251677223119815897950307944959875167560",
+ "19296461637807972438220899702591874518336722552660488565818484435311224286288",
+ "6801016831512114134395242293457679538495311188529990156831889204433183626116",
+ "2964298470426582070507861407971247200639242211740381994158541687335361446525",
+ "13485975887078791259342768620261671076376983307468484850600890777864999230190",
+ "18842264035089067687391583729082424222425351385494040849910540441253540345719",
+ "14703642210510851071131854548671393020078600676544458548174965732036621712435",
+ "21220214849253889952179905879367949668848598115028365535238742829171770487419",
+ "11808561815315084933226034934054773302447242219261466208644893422841430468026",
+ "13540888692913543742580940929469376532537583430034252053023468103862294761259",
+ "7244161097354558003276348625436123965060461415149286453943040900234287411785",
+ "14838699086047571226987010390426316539929576717533827724866261274778253262656",
+ "14556703155521968503536618488028548581329555701042498979115582733446728182407",
+ "7681623302896593715513288894378158777679657507901023568046253058158573848701",
+ "1088441387469941348668229287331864702951247349577784177659963097331109780661",
+ "7314603916265509104428110912296267885635061026393352039011815022900719549691",
+ "3986211915826218802854255636104488183733664187834078111248006041750140814882",
+ "7773946401984571616670752866609685859292708427659817737120107917606152933392",
+ "2842014599902358831415178364343115068084073955515903534808862171830738904933",
+ "5310724334723991338015239276468023426385678184604207589409781216959654582406",
+ "5255222348968955358505450804240823699077014235887887249383824524518164498567",
+ "4683270496545943333741165516340250527555279356319043788098737100323469078711",
+ "1419863943011284607504318632953959861647793372073243840131919334395882404459",
+ "7983638904317557271319561780754076927110887040374328063199742162092282580125",
+ "5569432847705373609838086039153225563020182698189928344759413994203981320990",
+ "15459233133041758499623402905899885787129812358908703405750502906067055055230",
+ "13557004098047782158753673078158469379829777184696159361573537670440394932233",
+ "15455882302725774286899673141535924396516348007554186719344822187820635072053",
+ "3420919058826876625284567898132572990967515410265578892047210512917031439632",
+ "20100418454140979684745740106982178755085746706837715848777042819378494283102",
+ "2569258507332519764813672456351707773863376375715947817185409500202699032309",
+ "11051426796304102496144764766958179671506736496976882366028801902480842422589",
+ "12740229748287653735988491742372785228070141556372656548689214318469788908817",
+ "21628842595664718258888324339774974922449098458375293925060310284267692457557",
+ "16339231976272978519029290439531768093693541721039081313180796119705575069472",
+ "40124736742096746520902512885311967045111742860721554225254094895613700655",
+ "17732965892472841235257958105891466451086090480423956940377743815006013439",
+ "21822629194074446176794925064792912534191501981075390813302606875002422233533",
+ "9308214945046921143097017249780654286051601646816113552080893008307002107495",
+ "1407926751839535775233537792971129618756456590720440342541085713782189375466",
+ "5640645423977029900985251540406734874840031539109774937559862819450972865688",
+ "5033216407501194252797695593441325021622991729008118693554186469034086370061",
+ "8067057037475400447259522316648004416684453970851364075976857314405950145375",
+ "3763719773038467529952189678629891209905984306908045328296798459182240539135",
+ "16939797418368521863388331657892541744299855742774206972703171911218723184714",
+ "4830944198856568835319759101429165879092462296316662230100861015921313890231",
+ "12704214658232136513943612645116991664417275945120192627735782298715562058820",
+ "9273823420095008025667777982828688153052061387261780450903573585273931011552",
+ "11055274871946976331353174512200687536982312509623944578515862663278819898965",
+ "6608499500253253446996042326570359354182967780655057286059057541317584758989",
+ "20888058022129906086941050692798413401844596394165346138911969309287247738108",
+ "13297667979268130800823342819300433555314639138313483863899090834749801969571",
+ "18968104066692458124571065270953767119743779337036553042450471941512165236867",
+ "14932841303199490878640323744926137685749952622800747995690439854118498001885",
+ "6250599214474930878673138968631643032807502364864165001640712550360147900771",
+ "13872044280192246670253542029636668414586465840988190477111017540404431909403",
+ "81456119668307937036914780206985985650137679027930766352442712034886058018",
+ "8178364156193615628946078892680068624209694278864784660439209878556857933585",
+ "20847565685305938921688196081711559611104247746032524045765048360946563554616",
+ "14790603163347071870110696142274029411377352843070075577069234486581346354229",
+ "18977464663780407707262531952390299277523056655145169930121579582916387871374",
+ "16780630803676794749613238124686604459373604071531057035207376612438682381040",
+ "20186476042367781999034353334494913683828163385175556939730585228743410724033",
+ "6782638209588187356802454014110236225878206067794807253486060610876934918759",
+ "8993456778572039939715813797180666624819850516232234360679317411311388323391",
+ "19966302498904269727099815984264954717659138861990152509516897188319443441697",
+ "20169703794592063233917650314404110898564218327366603108408586484609331826027",
+ "5979829627203584558315118820578826847995466683728103070319484562170838879477",
+ "8237679343008214539352062545936737645555361114339038346011678993504862443129",
+ "12382432100828502258569798167004899872248210099869176340581848176730802349663",
+ "1568185664985590267262857882936657784210740515169196983171026814738347336756",
+ "21214766447038120613598232832812136678657988502205964335817205381807920739938",
+ "7692941991237742474520327457310452870153482370889548010226143053981890424652",
+ "13595129445265049664221406027681079958478209116108739005508499004805469917071",
+ "19188096071580221579092496028987371780642557049389322053081699235155567772173",
+ "17975673380464001374676034638564230054429981676012676440863525293845130019904",
+ "20841685157342026757711329464299804445471940020955209397956987009823404283299",
+ "7510778644672212989684926383821874729073504800968951172295535413714975603558",
+ "5412964648109092367425127656145675316528154462488440576988541278054587052058",
+ "6998001450950528857399821530729656471745472711969582871968416561472553420135",
+ "10017795190513370580285083759517584035694996563220913850722002288744022757377",
+ "12113185651597474067026664715619946415749981707739597619454641751791169267554",
+ "20451540737363571466111039734160615184627155382583098695879349204357410296631",
+ "729116950403569953818905038668361626861855541652418271170712441039707291924",
+ "6874571610670154627346562968411422088198077609945741147515101915358108207688",
+ "20307824547105117373454598908217917152093200208838326389260620574762152675045",
+ "8758875530447210792904496135011086289851932865540018278850670496425499052683",
+ "13224694410602002105805224454797207933944742532123981533211431845662395381395",
+ "6621493224766717216701548708726891168784911176896760330321592836065310482866",
+ "13937858022779991611039558948054774910543950212969141252259896915615778617893",
+ "4917806030251482092362529677296731621677399228082641707762616055246746126061",
+ "16304922224312728276104330461175394847795848175925462853738047204383447573035",
+ "16678452722472429203861326329044632626530032631343862086351886162579978046420",
+ "9974691111613144697061424119079539196535411918411684404824080439336446439564",
+ "12391128852318795781829794456501239823062804741032268163807689059014957151322",
+ "16376931186038869228971542812469753097050036606517944132293138523631153279825",
+ "3057841358487505418761470758562979965285993261118087156094367416201750095404",
+ "15045409518037090814105826994439679855639635253710791541219370329682069820225",
+ "13442376736433669968016223589180307683361433436806777011753497283272674012644",
+ "18917174176736242961299708438032963296686220808211170958894252981698475343631",
+ "11380920704380401611525239094209208940853859054744619020167150893676619275400",
+ "5399632748693319676480270098239871368958944610827825094400876104909425716392",
+ "3072779406768337118240884091792704214322792415195488652476136252175179362880",
+ "8351873470285292321562674159922105545256148886389216816367528787141186556758",
+ "19039526722628732399365091326361517675801947890934047817293511021151913744591",
+ "11316453563295765895775061205389385485172841919365628835333993250531664655988",
+ "7850755275953939062184858524678116551304016605992491147837939252676680785208",
+ "189663666172994057560830062107872734380479327839628938168402275701561917176",
+ "8944554955574110171273295960753608410178793391130829960067372967633462961614",
+ "7116498249918759493875054905542634690892118438594298685578805598675410965669",
+ "2535963611074434631003149876163530430931993688129878286594756194015465278460",
+ "18022460558081751594574692271414706303627866472796139479944146908393139741182",
+ "15341193598946540230880135952221211503846552166425406354080863978843527894671",
+ "2942431717153385426545606490874257811230086292797817271859433296359160259239",
+ "3009774438756820489964746831334449123894740822794580986556997529296717581423",
+ "9496138301121689616049759054935646143502980987880350156990306735995260671175",
+ "4076156724842725224174300000468119057699244699381290980710548119313376968129",
+ "20301500572584246879220468905731058339249778940966192891128325027181404226629",
+ "12240449395531309263037726882974869058539543342019721791945417590157321444565",
+ "2734576041547526732946886809654954568832411068107541730145912482251139322538",
+ "1913611111144137178181099357504813610426696502807761974432419767623037547574",
+ "8323981703091520786969788588517080546120036429535328021157459160571413370125",
+ "17608089795804665912003122420873117027406690592641558991713120617999818930151",
+ "17954961401611739290579723858653246962839079599354059880628870682426849304674",
+ "7693642591048722104105715300765742636898670019493041402551952316778508785882",
+ "10925165536949195683545612102300879902373347522535838874708839717193999335745",
+ "16740598974035404805544189925980303793846400946043080633235004418045311113846",
+ "3028458114292500648266975052798389647613432243149006395166123161184170940972",
+ "2817600861932061603203157785548222970685465773360278995551965365313604217882",
+ "2811366666795973435332404603090484498270752802044239619104866535127344245139",
+ "6901007103297959557257110184636027233977945890205420866896244199105220459744",
+ "6811040256124961160848956238308470640308462502755753004833080999365205628787",
+ "846642049586630199735666112786431409696508103735494916428842550432654381594",
+ "13061166881718302681365231291832588791959186056326831853549555763101859584396",
+ "1581547457654855644173875819143310956457964952802128135344084991507959176621",
+ "12591698412731075291488515328885878994038884715020576113812619060374399968487",
+ "7129047166046749599109058206849766841261983329246180789653876287940952140294",
+ "17780920041966559015242418384239510699940753783778307759603993814380170147815",
+ "11411967002648206460094819913767451172535988461576286592244752756526683869398",
+ "6535147980143805768211908880661065989475773196469834562468932004056012068981",
+ "12872366293792794368642323198969017581196463071340612957009439105182673573396",
+ "3845096876544992085668616039795853840768469571100517631039776002796484609549",
+ "20386025860348257305841141103130861239832870083066852913792413739711579490278",
+ "5663975388273723452136125938377376330824298621841190787892884430812699456136",
+ "20880523335705106555101009571713688438858731841737802690910851430800496104934",
+ "8664815262171336902475127109386834836220742848950659183106085559300961747316",
+ "15212672296023611959246835252860546019670000046804751249547303425954183847429",
+ "3786255974807528210793957400325837912933369979823637013145025357556219775102",
+ "19646410587152058982763388053845872310164493339475512721275474101828150077273",
+ "14407426259630290801648546162995549804322572985407158009259933675410180400077",
+ "1275955073103101917295562169849127375209112030395179332033340866715396722452",
+ "5487750760448101899937260261898752719887276580825994742322208269609306618405",
+ "12414079753210256499611439235670285717945909010061941159696368398137523291140",
+ "18058271753030912252347026705895506604519018890772902865355002646910918153759",
+ "13935235821735626611156505080089322797654275868806802361406549798199236177528",
+ "17110498079878546324718511787669387410942622969712445909354000807236690314957",
+ "10687508266469903792000405420136150569946636272800228999781195239976105560612",
+ "1277956894120355360649091990517188151791867400124079104247693321263057601099",
+ "929982009519538400155920125117423265869657236620766216139182914925009802954",
+ "16559970949358997473575123467518158994842000800881347427572300986319432656507",
+ "863852544580033885106607226598354103099120172650200980695458006092725115354",
+ "436810575313416269983882563851323926836428928449351162094565391723605483516",
+ "6334913013691170767138698286357556285297887475783792365865857018173994149486",
+ "17785859069146472999908840832788077051672090890508101583397157534162626183973",
+ "427206014337914391283601765560115825767253196347193816620589108299037926541",
+ "15115704735938262072587983952645382098893412471333885175144579020987265065203",
+ "12017969315449748476118643575203596675122272214009056004034938899095907760206",
+ "20642434407226804845623813766397536183962927868804716012482833199686414302852",
+ "18982318327848493301474677819747807686491978396022748137991684529478469330097",
+ "2306193794828709014215315860179466106408084703631347012188232489780230095671",
+ "7060813397820173935956757571314686808083877731722252822508055423697679476893",
+ "9925864312610988474999359617458205534034473691089101964213562993662824159034",
+ "14036238569106986370932971272638702550236692459418895654245682921654874601312",
+ "9509048813859143088347263336607686057099400727479311504780670742158653486206",
+ "6842166521132564137619008158396211111980991013087076743268157882198576269675",
+ "10217353423046013950417213172971567565900229914457220187215408404202554351836",
+ "18220384419265532097596052952017594673237799959023133602933674050572298730193",
+ "17866822945198657177461453619458294532377313634196332518543246556611008452933",
+ "17694368679979949511817467967015330546905282492241200905890171992458134240678",
+ "18971922685739566979638356009544944454629162680819328093994329160719843056737",
+ "18684937612086669383439812199377945074448160740155966772829350355651237261795",
+ "9235876281667970051504588287667786944160228843888838710239865727309603061015",
+ "6187574163551283282357553100017400574873868151705871779659681332774938473442",
+ "17196369096305464930639002419417036905613312721767481044644254878990952814786",
+ "18296927216321111202881056198300973553112302777685079899199090840516364581791",
+ "4983948188027170589078739023086929105628955321978589464920358286161528573448",
+ "2276814237931645487686771259585160667452008745791625290365802841496721618760",
+ "4138273157833414032755498052453436990872835066620446328921138739885868998379",
+ "5835580830979414828575054128735121537583042482361311845838347096674448689116",
+ "20992630219061340843601881100837482710979119542034786928296223633950908472388",
+ "1118381353525339785976839119511758587763620520383755136959051018516094253090",
+ "10337002023922138844951367775712178432524190386722995225923120494344904079950",
+ "9765947418137225404722546740514250763898752374389411503005283184253024586058",
+ "15411836962046751164622748177831913963909013265942110958658714173394711125370",
+ "20722527012138131360820192152290968950993396481440050289358737370268218859591",
+ "16585853587281811014582898583977502965045639444130273779047322749735299560207",
+ "21436098743421172924014781240823435281025352300035264733201366114473419058727",
+ "14178112462860881459540462916598447735177675761773338824394753907217898488960",
+ "2590560710846804342662010467713568407285290476715663333366063002353018991264",
+ "17949223181156469858379065899254284317305309247290121304422294912030586532673",
+ "6940063127036366626640075420306454154706369567406835284901717013872681276911",
+ "13212339415583029091219180722363760875223983190396769244985733901171214077679",
+ "11143838426689049623360248250302972103117784521940658207527698432687552942591",
+ "4994693363062895106345077091869420711664571716019971952890352464184561249569",
+ "7785839099197795033948112451740381108555553042322704038905686323540025631473",
+ "15291655295654923849266753004503491258117644584862711291502217292211074445996",
+ "18223946690101945712849081159295298164630378278313069852577349403051751559726",
+ "13247893325056509281811135293440873471348664328435966021736203439379360560346",
+ "1838627965154116499570588511051176331708387980121591719463695143475045130831",
+ "21746931323535899361372833028120884537569529325326959379977185108159655128847",
+ "1569229799996373000993208676467175871896208509249271061977636872731081653113",
+ "18668959729045139805375896352501526759923123936419773886979446262254907152787",
+ "12698285530824454564359053510831159718450594302921296519937334733529589738160",
+ "5743752602883180080321224936560739109224279187008023590149271256478879997507",
+ "17615461436426765950762679333452659818080751337498512367037395397687644820677",
+ "4379963027402443949761342437016192165148025657715626365315450970388283739261",
+ "12622442863880120105122485141053297017921305018805552070109568547893924027508",
+ "16493349884995741255319414030015325273883108492981717376626952633010860098410",
+ "11501183900713163689133184470477728399861217340901493951105967658399341986313",
+ "13184464903575565740074003127437693743650101614906307232173855163739473476900",
+ "19056993236227362680720448341933549082689888775458266843506880469982452347227",
+ "1180947252747369471066257076205537751320494098262241412291924855089764608729",
+ "16229532924404554580195616835338949126663348103713418556119694233568376894947",
+ "8604714607572995451336310555882946070542334844212691610961393592348706930493",
+ "8362594100280133221998296898045505539071433915735634439526614339277300552370",
+ "16399159148365956463951582514857891684943332179297226423628752792536028483990",
+ "20791958918883897879651946680726738927333774947616022833294686415482396438838",
+ "6976099533465307077876553477341301102578695004868981952387720840685240842560",
+ "17588607896443047770053818219711270035985826074286753981361920802895326076124",
+ "12865981806811655044812914486873432317316688987331760480657262748139002813688",
+ "19080259696546964979932036247707282742365340353585423017939782931928015046575",
+ "5475353703257038456872747308072401784844227202792527428899399083236860900298",
+ "699444932025038530835460727165156424336147795146205258896894678525124927461",
+ "15695622674480818777943366659102932349783785381339274197766151422625765388038",
+ "7644428489984569999599080644830401450294253782967784792584750934960812468382",
+ "2484044190398385977417569061356693291812041338880061938702052957819048506706",
+ "8456986467797277421685766156179980502998860530369856189405630837033584471075",
+ "5054041625001826317568038929780665383894838531896986763764007995985738029810",
+ "5197336058480822437408118036219119090707158130910220019747427914262297331861",
+ "8896147437242770809876821567936215621570430903276974181159659855796295866923",
+ "20755757167342693300106178757642141909843395817794855978028122598254488316281",
+ "12495257799325917448205113238508489684392516282807104246531380538192500498286",
+ "17639970982424592615983334078785592256655637539816187733799215839326807071148",
+ "8140016957188286078776165555436655378303814378750387793587919949009492167586",
+ "17209468066776420206923060639618147772644663380208004030591040036263548572020",
+ "2619409586309117922582791327977378099828554504012201484641253637770276078843",
+ "11172679254412598275301264634812740710430873755458899712228629497147611473029",
+ "16829502099778629987235691213955928527920624415791356237580609633148661633897",
+ "592799060717298365629187138482067858694007427100574367745567028165989185342",
+ "16864381084532235865281462338072964457337415344658720676113860956416999505572",
+ "1015589663070446561434523645329239389344944669662180065723984179503017360337",
+ "9982212112174542265411457778485410853904388759147308861218634697975431894510",
+ "5412525702631618381358272227447367851318305617863423359948039591381065713581",
+ "9852930575259000100332996271562617389630146990442517175422889296173516799181",
+ "6036993105785310658467845672504384047591296265363803946714632979523201713762",
+ "1821500632172143873156399122734194851200445368324858351038486833883177057468",
+ "21556520116213603298246786137688925835788594639953568860110645708136881336676",
+ "658318860971707056155247027603536846915894897192791739866840963356575472681",
+ "602842622617647573132938965729563329852165494525296971607175031334298950242",
+ "1151063223719891516862415316972915766442753873652837551132768558136109394634",
+ "20030054542089253165409106868864476953251573918915762537158006593968012247497",
+ "14455078111822464502989472874268580626098857184523941794725425258923962713053",
+ "1699191450188970110166570608380346465689006650580298122024202987580198200132",
+ "13971136504849280501801880342723497383580392506287195375689019810750613223527",
+ "11259011415071078991947983706483998982146186263873384729739331890304233635860",
+ "17741270384736018529047001790810396141344433078911295725171243367964019815741",
+ "3617456068852846022110280599700245470402025130645759911795429861830057016581",
+ "18773989857774369564707484486703863617112883499664601804221477949481034222590",
+ "391101570414854801618801587626783162239406618115954162053108159404294160435",
+ "3752824438659815340558915518196975380567589032517034180452547083690665271869",
+ "13652227089592801810376789544861979384538590096633526007583054323554301421745",
+ "5753030785259259818058977992956569985665739253964735992489420513570911607",
+ "12794765444364718066463627091127875266371595037234762762560519184694440318642",
+ "1844165267423966444579133456200541636533189889959706801468771335509321515822",
+ "799352162562582415493264759184613437140226428304061991778193411771388762097",
+ "15915114786946818157476898276501926276831197920612814619300062353559927906953",
+ "13041871949144831370743756131359537126101784549008553888408794912277392285626",
+ "1684702427149441531010110315726002248751792272226034774456204740385384491604",
+ "10195318610969070608511028432066597876456281143783329459466964443360549551082",
+ "13714193389971576085579160116206487363436474313560046541969781285568217247624",
+ "12202470771012770210445954644081270058473831351768121852596394422757629850892",
+ "7784616613742667796197638965440313242748565680231200921682296807888993222090",
+ "18581613859576442652033888735999982405110741068271804741467526764394720805037",
+ "14828223806255884089537896775456938290494683211666564494946175120085694803958",
+ "6191868112332934762674478056112840408041237177775248347690069948259811627101",
+ "6055199518589075551800066499277675747934144570099354689629636497613775458486",
+ "20043219892592698889412649805669712950039510114250762278667968995416842502234",
+ "10591576812697540586115991527347511638405122244793393962099090930538459086772",
+ "8146910292072979142616688207315340017602882692938548874592904341871514175303",
+ "15451576003386544225828312996072681331940167554848966592330715947662789205180",
+ "21156998090948310800651324456525534600543417534335507361948830316109451323115",
+ "21421497039083336739241851024868234958744697872115637345287618993148799764131",
+ "8835309990713613011240324096693076755485475658999871502819747407829989219746",
+ "13102158958973358955423565573049580406238531533936309830903999596178966162490",
+ "19927703189662863743499379923522860979653455328626544661291243971618992342837",
+ "18417771183154820005238210056528713167003520086953806649233005148247829186154",
+ "13242250186667974182640987653516460478853973058739850129463954545512907574522",
+ "10971901023853281329361069638276077765206234747340067637718378767976633645829",
+ "20436550472837870181409690438226695091760115955076127106091878852797639823191",
+ "683842651763399941903331243661454687566310039977770092715404267515366625429",
+ "3304534668380354910105587611199035768704466410761708200478786163367382500984",
+ "14327892159763789670354328059011011973128878640806462164819794130243254129821",
+ "13712101990593648405837473744314130986494510088132644940425089514662460031793",
+ "1270386163717136732049662990020454155453019401464056820650142849751291739739",
+ "4559668312052315567004252521434018809625818725552950834596073025095274632653",
+ "10289456013947128246221059115194021747046925564818529566042034047888244657473",
+ "6981981682422059144716871555026845840161063380660424650450978975416029699739",
+ "13275723002453843398308458799872954358948259042779675411059905047590837397361",
+ "18372074965684100000331046096891533070433189717560527825752357282553296305210",
+ "6007153627662867365254986874716350833679184737288669421698890656788831322929",
+ "11557682792813633323168221751485510314542594132819842305598531070629168100143",
+ "10536598621155464430657941977974614272794233321865085717974545329727298277125",
+ "20566123440884795144385782557360498238445700080133152934423121801124172346047",
+ "5484210585392274768700243869223282957415576141086566136019633416151230114084",
+ "4675266041161206862174450141632759296562489084453522360678052892725376421684",
+ "14506966485061491552710372008504993235111668026216492386033611735228479487468",
+ "3682565950309631924420685101131217452257499881999322497664342243267291843503",
+ "16753306733039910894513530708776251948831720207834805689601646616427039909037",
+ "11892397629144764406188085785897237236955294380381710017192179450763501663923",
+ "17027229171478232498721421673139332166581061755210509139252013418924500461243",
+ "3560458480908782960366816146149753544371185355186140843210760460011482921556",
+ "2523290942811919827064721825289040221770310594770466909167316010377190569820",
+ "17586848354290518015476851435178627882600199642491204839902589087637701736514",
+ "18771893348474501482962831973790983143756587183687952333177929270650139940171",
+ "6788202157749582404834375771398928959748074435244246320016871403739257327326",
+ "11025631863450004428764861086496374449453982180198151399523240056816657483248",
+ "3256907622263919521402687344729539839835290137654795380148237049547054026004",
+ "729757374802086603625382264910105909740146180896096383332210024077887641124",
+ "19863253866253150070643618896444516678169346690564661550005769233120838139485",
+ "12468569017378925985548033310919519222810416238732327538088208928920140959143",
+ "712344748962578398623451251358410865586764243720605242158768608887082462846",
+ "8546087066371010720013920767653366050032317738437010080974697619001241722483",
+ "17144825509786899110344839698077839239721239583625175190269757913667929043953",
+ "10651563297701188942358589203989937961905153035428112097802788565849122022100",
+ "19602341346389413323180922571631527509531683866957468565049297030414658843948",
+ "9238186664745057178430953403953596421917515090260446457039212350976296818523",
+ "263640414028390180122517954487976369901122460517389747631764885875587715955",
+ "2311641918305077640172935641310996393584851078677397516017312506521775283636",
+ "12911852110192471656473443086611566556755106535388637084532737811151296554463",
+ "10436700004928765835031725654432267178079115705246966695358470216435798181674",
+ "12755555289896266917759922247555708737024386059041699214870911784508162783525",
+ "17390583422165077903045260639521919716984664232208360646931078032292219709718",
+ "7412526952366864882775200227476857681850213243362827192310877977391550357930",
+ "5016060582872027330190350728607317487069057897723717249157495640519710863591",
+ "70447200134990075406173842139872041532268968648265338736409860251327029352",
+ "1545500244158153586647380894391367444874762740407966854865957002078767363820",
+ "2082567114283705201161441383508830647153064041365131752708347264051557391980",
+ "7773933577113494097575644205473257493685202208592412633139277067190461074505",
+ "15907352821797623044340355088248954282080052141018731890243639338361458586983",
+ "2453390435048874114321626738320866552399505338711520013030652128583351121221",
+ "9182038581165182763924458518550360578443802241218652973210280653624820005202",
+ "13176557622325900598244222336641110473108400343854387783748570353220729582767",
+ "10599983241136666078578113335543683963633036808782400964809769571709020578918",
+ "1430816790456574892099931300141571059151141389317227589818258647628212654923",
+ "7207251746626434553568433426934231676780727971853793874008147862305418016123",
+ "3847365229378532841231862621068765430417579646617713430532944299440264931969",
+ "922422158589085666348657924088867593873646110588554410818179794404300446471",
+ "4298485174770134050325487753075508760849575591910135387686931072102416450479",
+ "9475141350581193757416877790061277619494551108434152557051757495614692231364",
+ "7750163624390542388958191386016094472536166330496081849246099823270737686866",
+ "14363173695671306304956071467171940429435853698217676411185837490356013810171",
+ "3402134714494071567155197273072160417049647120230862441840621369782667867977",
+ "11378968132153772980874973211734670604659991740586197794619174704886870525408",
+ "2500862781199005154907185089778932765489906994365960644306361544820582839768",
+ "21880931942133046355810983155922578513531850539420426025723154879488808270315",
+ "17850206894189265929807971665186479441938275634968267590809377452033564010382",
+ "18427883853363251276513100116480886898434829323430684895879968439179171503760",
+ "18758795974827407022563870795763356401215175366078230621502388363785425038612",
+ "15672649260544536516531393740985073476934112035694203841471047634286525005174",
+ "14497479780124030172334631091033639981498927489925809517218125709975200816290",
+ "11190855071574099336548308963044121660452976926988171712775481672446931541539",
+ "8339442292395337481335048552147626044800877206694030770577319544121541364092",
+ "2461178629683239975488518502624530284391365519847067341739449204945212652770",
+ "3972313936510404965199308344697399140590038866586718833591813109326652018667",
+ "3224811019580618549699828950033477378112059204060062023677479068506440937528",
+ "18443657715765406615721041820828109800966587434816919981514222787674698772960",
+ "666201271764511484388505793135876064418452477237751508215203932379618265382",
+ "4434899717815685275523711262432486808621984251515429736982413712108987655422",
+ "14584918585762085382434085071460369807803840154636220934254933165793423091295",
+ "15646480282455307022430957975574008173154630787861430193406352480280577045711",
+ "402840791633175231660910669665966910050981784044822648466848382615330599909",
+ "15437492296189220094817534101128968523410729375545135146260659057729649968314",
+ "13987760171743052442513877961667805977500573882586118554487715622045738218279",
+ "12589095501858681021442730872878907609617459069328956803139727387371467358051",
+ "17551064250089164193025672794811675406761638177060737129533175904585851772273",
+ "13500706213131978087516005477128059726177752268287240395927379509000435850498",
+ "7331629294073516250840302816971095420668983701195024195892939287001016568514",
+ "12949377725980318589136021850295478499564248427839661600142796482665024587971",
+ "3988955063770305621858590171391799353484164878730082586815877210936858093890",
+ "20512156157023978986265779260320491356890557397261515752540394821171756173724",
+ "11624190532749034673782735319581023504009231230729490439584417709012081446066",
+ "12473562150323140802035699452896239306300376623759190078147999182702752528013",
+ "21504777935543484323252258287484534200045631968996932563017737909760083499017",
+ "16104745906544338230790783632377375683831341202924378150021598903321494336736",
+ "8312554144734150053969625169851557776466370096299754626528722906617398229171"
+ ],
+ [
+ "14715728137766105031387583973733149375806784983272780095398485311648630967927",
+ "12450793357728630597819493697261391961392738728208603858426218806728799382497",
+ "4427733724068610336929510244982091587998132283636864368924406075658439074153",
+ "17863554236640577761956319447874252524561947852685470820159498661269344021716",
+ "10723868775598272126873918500257797117892409794706524915527428530195343520361",
+ "8041366806917098496431513544630989490693774700064656765914266570204855843526",
+ "13046986480231887538692223126751085950758763070227069247275787663666591811005",
+ "20228999562936372999611354929112125019466353738760451044697249912024766542482",
+ "14238976012080913074226552202264063302466135977295108038770514743089287570221",
+ "19486717852389551661121716850619781027370627632295683938875312739716376501717",
+ "15733057748709959668511822511174594221965585899587926036013893958610587491491",
+ "12041333229715539748857491855115983195198694619439452683631630426350435252478",
+ "1829888811413627407640409778757789140470123549237476514374669162490680512211",
+ "10288898018349095056494632386514957183841700001184195479721999387950102580094",
+ "7360553146019695788111059047354435502690072975650576744373916804385350955674",
+ "17476063720528136669048514677420727796180556343667231122803521620226101935369",
+ "18384724266969916899691009636435516722111206340289089258767862754828208946542",
+ "11046121967047431151707881264774621308937270618998625466342467829704953599782",
+ "20018232138773775379089542131722766973741687507582662224374276186775807685863",
+ "7926534193496947015875888176706209291021745851605316909116853588598743879034",
+ "8826996877877607049084007876351017199517432230182001641783930871320527792100",
+ "11760708819943554023765145606995747732169597984739408998714117029765838566505",
+ "19598000655770319703844060561747179253151181702222064644764822676806532882514",
+ "15036675263180992517064890091049355832990063162957265821390555448206776251789",
+ "1053420874580688637503969479036991299021138740018858993455108201424412879748",
+ "3723543690610038931361367959096800720510056325209292666118208798533818425035",
+ "4599370243050726453512484851927735252841106375733105184316191846221056036380",
+ "18291400382386598447603657416871816375751118990979359745849342284893280004873",
+ "300341627009231088404894405580745838091318300821994947846008201887884150151",
+ "13332605655619720841053062902143052543375741442250678582318225211621890248982",
+ "13197729598850829723360679245789196039442968018972826673455394330035263151299",
+ "510788688496484172389408566109007465667555285205327059265048317979249570221",
+ "1685584118031999835794907889275254096486823415278284757369286336252006457602",
+ "15103945090904102223538479231258677032197950627619049222966748226967974852043",
+ "6653802896618953033344296077900828173967467309849915708475948018848254380036",
+ "9254803560511166426410537422101769642611302194250107918342410310963831784950",
+ "17006557344160230194691541621666219420787918477303225545533644141096551358258",
+ "773112329554511160545400721342977593377624843987783062638455005748446223137",
+ "6671483881284330250685026918783029584764740571210869197688044338476895092050",
+ "20812941492969561606721983530907505914064782270990490150214736286311482532652",
+ "1156984923268097592347582093730300227184163551449762803735684309575717323017",
+ "15303159756724065068145651405407765401796657934219121639364061501460295743948",
+ "18999785075801878445291021498876384414176522501978873700451842582224940767334",
+ "3782716983967799050957535371991538595453996691838733068933109780481907925378",
+ "810443910646366078824923626573819081371243815242873044781414798707744583851",
+ "3940687718063184864573934886068875138239553970085689518511531571139105765743",
+ "1222092197964451545227395363538155091563596468425395922702697716100572937718",
+ "11901775018663948557424314950737290815973735008800495766054692238446226616230",
+ "21839369981774608005059280910009281502958794510307248992429390932011110951241",
+ "819873152679629471918450179717035855395702808145570990556719950289951175212",
+ "2918016794043041559376798791171848118057043459636680115122516324180788251680",
+ "10788401265856066217998495397128704450484607734353922353470809976686155443188",
+ "13599498756047543641157208425687419183141596017402196474108059160235795892976",
+ "4993390793677030007023804867617329393931635615810976661139461248253851471412",
+ "973050533401342110180605419751137563184725082821038770229241448201970125921",
+ "14313276246574487682858906899808269544140218917497205965354285099641091349756",
+ "18746777136177241043722556179260854313319807637092383577312657349740719965076",
+ "14517023428366357570216698819722831600577825429761151189605029742824536459972",
+ "20223198094330596704408798588338060788093323967112845691364940702136543962642",
+ "2924401185705980722600796492514644487545258803954418619331883216838542308543",
+ "485440919681570468713530641755278841324413691217763990572458853294843435089",
+ "21560476826107225363638525612645382878298890750874072774141701406519608285783",
+ "7856508582404120415593106596945280577031904101959961641860467517902309769386",
+ "1505151890969527772884247006998953879441745452105187039442954300997320053301",
+ "18861812597641777105968621029392243993700881183944538936666186678355756609806",
+ "11964609307983840306843122014689504510236749206766494519381451521217569407396",
+ "17764783391855759749651949748230026302359698415337858912932633638930034077791",
+ "16562247632438820849068750036602367255890087581186727955070681252413797347277",
+ "3341595358840888933968836940161983842834749603437573997372892853189756769506",
+ "3198140245778498430686233550970322127895441994253754893043542706415030678798",
+ "9829840339700031668849847901844029075426216057792062644639239580989060312114",
+ "5999422607425238131817993672620301343082348300090537110946144186609066413585",
+ "19901271533560906428202710740924807375620638454776660078183104891177283526156",
+ "16697165654181109350158134734382046723004976300078845885330478879604895897280",
+ "19171906568090360833249366643372143476587242793789646446664643684138123124668",
+ "5557557332632668793539639636185643553639926364115539987556075445308999628265",
+ "4797522865199880517123583692586561796505378758857130153602827907909887751116",
+ "15409514194242892627651944305634286919424076146534027188938906487506413405089",
+ "10407013998132974348561594118793213466618426284969698091916131778477581263008",
+ "2534925381155806875978186916525958864791165037467997034976228683909613017312",
+ "16140842893634434452708565053572928560639256480905937421023970743339301598617",
+ "7517617592925372620130293329989654305076737363747701594349097857054039164182",
+ "17572708764253481596340159581412737527195601517063980704204677005617144607526",
+ "16697796470163537491131716229045730242536059781538196375577575057386248458494",
+ "38275164685285960308550480834951641755153240877853193094138358285155638204",
+ "19780228589871041196871406056718374983456578990309085234484187723923738516508",
+ "4573417308961077301452769955811063226515352449986725327722241421281202736681",
+ "4768055042642730073498433238804346134649067788593835428664493008393684000706",
+ "17566912618951175959416490797476610679702184562687840273697859062459883449046",
+ "11477598695424707935165112148975667441147635429812599883095916948275334113413",
+ "3408907078049921938725945268376819484694115736385272440041090673225197146180",
+ "2488590561390551829094067182419871806900177001183027832070626654223650976899",
+ "12116557895894464059885135778994901345424716569754903115015740397131803733982",
+ "15881232965640921626180413777392630630338847181632662075996983398726326426432",
+ "20914323757596181391651855665547258251038466184617935369425714249299063760685",
+ "4275923143992397246911855313401177253209967573031785993454148836244404305934",
+ "13098973753894185378061607442839048669135765294488505596582737281481575045554",
+ "7995472162206735324879506324600884378126850726543803581430135236761716527753",
+ "3690915804478314734124615543749602171459078573370790663994412906012450478823",
+ "1256453655839486811750227055618146120819862944082463957526146264573763714294",
+ "4406492967670422538631080907830590263463047897583684262207883537903678091970",
+ "13380843970691717863215678292643800288491103227905602355694129412234174194363",
+ "19680159398793220289979983679401118779763854719759576408245027038965290325739",
+ "8515713472495355510508289305321355004480161123461789103991491891201940557902",
+ "18392703846804297332972535728243845000077361414687818948278976164182674947067",
+ "19823604647876421559318429394175186838817554072847524297827763377975574273192",
+ "17719715026846703054856559310322577442906188886145763860157972477138788247667",
+ "8745282777320550983079435446349157218001552450433897097227622172209480270781",
+ "3259368608255603766247016957318442624095407655100612967940789373312058996520",
+ "3379679235619387594255002628664818227413294377266729211815713998759100259668",
+ "10282673789366804521601844018863748004632586596870138135887183100195194767004",
+ "8431227731426467642712572981755086675999345721043460063547234289139267810255",
+ "14117058124827023634266519281629142766485227596060997608233088670325722698559",
+ "17113232771025226173986361792697170950811880770802373827827162227101499645884",
+ "9906220434844104062978204733717072107397540599291396561476275675218575564970",
+ "711369587296778404961826907371863989722457674941832862265420496583620086218",
+ "10995654568685707735109869974152491589223292425449581061000447170660561828729",
+ "17197923097868441003908860864777521604587651639410061820516916970875615238246",
+ "3121715947184842829391029463556305441693293825061846129844634146823663627601",
+ "8817835750782344079827519863863370969960597321588294656839911940551490704717",
+ "21074199894730915603594812797833479514843396752652846676596119472522115586998",
+ "8903588044620722375103549330291845285230849782400990458525441823641905996819",
+ "7157451412319473873395155428325762769952294079544485671397508107346256362850",
+ "5366933733103001902997281886950280717532636892191522349820059149392915169558",
+ "3729196254269053915687004590799382892429870424157270200083981101426772909827",
+ "3918096703119862723362353838062260616080657756068272173354821697584630247209",
+ "11073027330528765229119199873305594827907404967404841004751556462671634016839",
+ "16424651511178205757967439516888026957937418127900739730326874335888617161971",
+ "17036562818332519536292487256920458988625450115083747105277938048739292827058",
+ "795554890382567685751618566957270321871701261784565632343709559354970377145",
+ "633072079840093073847779349151531317793918731920375040247534587265858418734",
+ "19421194221177975514787747427021411300539454454371387008642591623632727982196",
+ "9954719107136377193496025917640974425520732567100168938432529522254697824571",
+ "8674312532180246290069249621352567303340886011365637785384772665860996736758",
+ "14809129550856657213168714888239735820810817787153747648450536960647330811703",
+ "18479959092813678391370975524549834571584338614798320263799188362327888537937",
+ "11754080849414921164216607793483937490683185256818320971638570891360029327056",
+ "10287736699385961112844233987245832756528102056561178731804188514133469579013",
+ "14370616700332892416887680617217669883953806003377620695037833373409292189021",
+ "12131262377053219810698216976753909777223459611599034218924662817794274728701",
+ "15129974113281645648506209149692470898425572316691306513209191313993708898437",
+ "7871644959999350003348485402403894487663479920989578076708137744830000430296",
+ "1576915733292398470896862707357585951921545131195468346129170132189223165938",
+ "13316238922195025030929715018519212370128739646325014577776776032463179349855",
+ "15160020868051885495078648274966503057453505806774983308629511566464684311627",
+ "1692269682153339201433258246771340974628904846837119864247013056373782718416",
+ "19628837155426033423644376042848583705054394443378101622337255362403724735047",
+ "19222966046507618124793516210121558272031295169005274768240595331459420997142",
+ "12990748614547458190976906297393525840623470679364771518133250166378979874463",
+ "10124996030376091099517250678153357142212975502206884325977282211158514276950",
+ "17630673366223237394418802287655202715156124721482801416980858260564381593966",
+ "6743037447395702022066513290929048145404894812633440602191382691018136524423",
+ "3910195434942407507599129230554588207801501224467133349280934483448828467487",
+ "2025953242925331197360540874793022332074847486979998082380244277507702608951",
+ "17290925253475198968609624243667228472127383792887388480830073536530705682760",
+ "15557314422719360545874148111856256188428921052029295715627017447052250706766",
+ "19758557148246918190283097589287660972538989627091387035573386136809005998935",
+ "10859351185398338650386876904094285059182038967427299340069909694684844129362",
+ "3496018793417449121342556434800740598384008787187762642325224753304909741349",
+ "13695501250971489187692201493870442254612771332042272465953359508617675704938",
+ "13572242195808512474816152630443442412961099907068902213470234329372028271256",
+ "6257061132956659095252686302119011010885219692712894010340612889095488866530",
+ "4330599809632843338876238530496396340118064854909940219910748808728579051913",
+ "9157987606978264109338780586425009211347479724574125407732261019832259951031",
+ "2328698634372378957406958821467382289342903425118775270878244960387352862845",
+ "20636525922386221727012980541907198653039323429055563362662406273278160984146",
+ "15847894355448175995216566821171916679432807087340467956339517156584053817157",
+ "1942360378421747943668019094002571732886982847410366696537432314848905467679",
+ "9512432294361739988724195228775769058251373607278744642461344881575127503031",
+ "7373765909536890992660842391636719615263272667672747352621337161184389163446",
+ "16805165862480928364732162070809175154629112007405963636466097184868514458659",
+ "7667777941325858499291332847392489530780564386762784335358233711706517931292",
+ "6446208647487337326336908745536052288215677968074882840304817109073334759485",
+ "11285516171986135785540153632137541881991922296507010937224736080386568662797",
+ "10115214387228124714106659470937696440920497755599449040012569123044717722706",
+ "15485618097017003479590081826451772255273462073640651108645768569284210541135",
+ "14933383877101576453093795963534828854771957327481830015228527838452944594646",
+ "12699366929120600543724208703956381057734625711467645612998923493410472579972",
+ "12636366946456086231704939526732303791619337704833963854669708252203542584210",
+ "12149350767700952579168066320091211427411187251056390220529300991824437924228",
+ "7521252564104984899409328139379375498829232271563704354107116269254046402507",
+ "12033991121152464927378622393121300999333393690763174606686511857615848602007",
+ "17232776948709347607296344257668859070263618035653710252910881198999758003380",
+ "8692908682458431891302516268928916165669902656866484222966303081483718910104",
+ "1253076047322637463481069610081050841277544153675308425513468857300598987482",
+ "17753389824587331559955818909257943804816005297310986968447179587639048799696",
+ "5220269242560242526244582743085713945173060875457087963936380952653150665967",
+ "17126848126303954156127690428371193690154903947228604938919561454676410821149",
+ "16844245036721981603144243350071451732279678956963696493069130132912694448751",
+ "16797761350119564409426534689125994845767740388070744929816576998448097719798",
+ "19353620610135120026060560134469588460709151673182029068633909633596535108020",
+ "19135326024992044270104645311242450367403619348108625528873986701416220617679",
+ "17665816362466043406415418194780245586053150534372814020191541209753248047067",
+ "11399583108978058354832763133747562621839059603612742599115200702193127837394",
+ "10094334549114303273265943473013412623520307578724043117639269488721170750917",
+ "21601458494506173036246860827162868889968956934810679234022762622742359366252",
+ "6386580477827919478878489737663301647954047211008970416851133263802072756591",
+ "4792043837032853062947152822210390150724912812294333339974827814683543135564",
+ "20876886123310865680023706563792643033695666593071136348323857270657128199374",
+ "5931154799422838405687052216230902279350178420072288819326391251206607447359",
+ "5239679324690579237822809044372316561806419523557737441242604861240795339076",
+ "10385003741667422202343482240152986976068622687279646189490976516013598227432",
+ "8464156248644168452015929033942509092145250244998026718035923409819766539834",
+ "13177537753162628205208392995644675716264814191265988042404781479197639366733",
+ "5919477377826036950488668794024141041792143979412430063956231337921980979482",
+ "1351402666854456730370541080745509803482004768817122599092881844387000676155",
+ "6818673776641149273361875347660949176445649468306471072411086367313332518455",
+ "1366646945884507587781123424154966453464902291438811059924651777083838835678",
+ "16219293249111347900064666257423013936256436002819357345030961998874555359000",
+ "779230149490072246312543789505064727370429119089791148581854356816464370377",
+ "18480337167389263493513952937037301086055810692872257722500635290543939189393",
+ "1345414110418158215433956620396568245327910182467730711109133441878095212920",
+ "12518315654451653143886317929532883727219058399486775127781649065277400104111",
+ "19716171362713656659833259243590727588692449255201500490000859973307782246016",
+ "1865072487559894165339723956247507020827160163812334855490266264867949416605",
+ "8915174456326318257703177400411158958853446829269268103252573093652570933472",
+ "20191934956657253997484040571514242713447218897800997897558899754776252309230",
+ "3900170788760364547006546697350123842323924137566872497612605525517074710000",
+ "2242244954905694264442292936230335662862827521454977184433268725352453968501",
+ "17212753633823250440920113486091598217346743686574392123683302470302281044057",
+ "11939276774333100126191320505078174289237596631307779156488772314461752488631",
+ "361355126674011999247836373885105218009746852422112563922207274436194144681",
+ "3861054771271956681986534133247127581996350841974597302976225613765246291116",
+ "19968479093411941747037123171825881488638273087679549521610505739311299462846",
+ "8537196135596544183619390135426012949552627827993128615534814021127294540392",
+ "2438879838432432949185118142364194193697006515067980632650379470739663214843",
+ "10769366200854175394348657213265947929465261545591304593688343101111720627317",
+ "8455019976119342575889554308499186802278388693477937667704910645050957262689",
+ "20644389417984700539779514908032253651696357386572813102276555909201716748299",
+ "8820039786383750409041489202684137325382534899692778928304664068322226640076",
+ "8636461459675525672530300171201543901107046823820677414340465229975162161919",
+ "9061524648737340075438868917468774023866583922769991567001812766008277156749",
+ "7602969742956570438827438826124187210014769304752116695796494779120606534919",
+ "17880480383024583813657184645997268710007005482705400161841684734099773182094",
+ "12468433127385453618607022105559942067759302463679348320088817783890080634670",
+ "5227335513133160328788197758812517500875193491652227971114102085123079105787",
+ "6151293357148965084809035339276030775032864902311425722089088413878852880603",
+ "13699219811250783019541356007733829713463891996344484242492968708316395244276",
+ "20523944015644472920486129305620987253227711059638489683670518491277805771642",
+ "10421521516830672217871475174620176828341870738569247402138774913961149048583",
+ "15243709334491280025949017219424981672670169674700467979049999809115231651422",
+ "15516151337135073170256217447458198066207320794936363948307836943072374966170",
+ "17337341094266438501679457986886656365327787301649468585664115813920643670255",
+ "13262611487153423909813660830277859169133522588408913308784951544213550636850",
+ "18531665394082016871726276363920851282983017715104457591860421181826617619235",
+ "3700454591945927209171569025131477008196191968736477330379417168348613474972",
+ "3604972001659087732761769946443190920343158947813896848729866695375607825911",
+ "20952949990925307134028293094501736726689724950451065635729323134614933963162",
+ "9405357171465854081502883779215538022417071330241830295392540662303830897477",
+ "21638057691528924765719568024989208898293733581278465977164525893773900371884",
+ "1423261214711655336057796638966786076518765517452404205191550645234914655224",
+ "4051452662373209612509106830833400151748328181316060758960838588997502328136",
+ "18894191275634392250799133342573131067016712303481664374003128715704286175519",
+ "8319722910647187566775047002603641370685637216565762886509056643924765393708",
+ "18376807271218398458453428415456722166053637869198381036620575958015471551748",
+ "12035584964270041086110602893321059914382792217135345721427943800456312398294",
+ "12648928151571890511419082198798501903838843998709266232987169892491925610349",
+ "21412038262513052722667255278175073999553643537758589877888129674442282140610",
+ "7706735190856341161262212613554225730619876208755452623628315796884166016734",
+ "10999966015370832078836488333389544875338251739488999274500058322944383211399",
+ "4088296406085952300442596245852961024918851819760395990644634222875937267642",
+ "19399822412575078284884340953745677500886533272999950579143260384703504507006",
+ "3008499431966541245607724530938385192395211534821775780577277325698653345072",
+ "21447244586691806434401916456546893987941039399147865009673973728056412619884",
+ "893624395222035047010673050230651164575948871010677581303166873938544655581",
+ "21402344785412208717452894839332459679574051179708007417742748857146495441368",
+ "9392712010553327328684355664342647815409597079361837524976044019430681532876",
+ "11566000613582826375650817776243972243778859250974226949316472392849073658674",
+ "12900046757905605731200852057204734685283283637014313056501123642345467590346",
+ "2147232762440136333246788660102778148879449441151868600321283583777116020664",
+ "16301766972982581403924204059742972933467455194833897714073756335881543890771",
+ "9546560122931098895129690583175071306095759562194496054583390881525378967396",
+ "3814097068175987733354103462855355721851435755267819873064912557751073632829",
+ "10704509016547426355599213335456446765914211024738080860797634337598031536580",
+ "11921271012710313311785310319425095342886561942032945429395596578758895308264",
+ "21265249694322068914280109016742517903125526413969519857556032179013285196924",
+ "7207578215754030787157150149235357460121567678249968060366462431427104673093",
+ "20820013978092841458072065536574129286011620075823185493370309064760526240362",
+ "16441600678335369077753559950421185577542163640313037056248177018465084864223",
+ "297097313501884278852369638329400055327872945847645211148627847628970916078",
+ "18298084629287541333205519012404334789930413367615524379442280529941257264699",
+ "15206243674059814574375077493088319889784970587286591062649045683132661681752",
+ "18726053049188513051286348977772545167577661574609708038977390139794201099882",
+ "20262858185621074639529176348089123044694437795099449154711162805012934737131",
+ "2249345697973053772423677422936999849381692933292653912080014325442939977122",
+ "20814726663898441680439335735982981967722006066824203970896314191676769388296",
+ "3816485989624386223507317175678560807682224519267326958526058565555245734714",
+ "16741230612980371365533431648017361867585544111098407772560748428499802539906",
+ "2436865301432265520692873922135716828388518032014231744012990863912440945389",
+ "5265261577128499220460184630262997769060828863581478135168474766310582001180",
+ "20550548783058990082416235781987882123241946829605049684648813233836863290502",
+ "21523044301008793877416122201092687874337292497403523925455260117417170777735",
+ "9283421400783174646451499708802113832695004549893166692004850391713463380536",
+ "17813773547838391112844362681067751767404443478918792865885006908077545151618",
+ "16486730475669947890512191574075897324037778751496940417084163322433837359720",
+ "11367125189013824464048785896422572845103707778462525259651446893275289247873",
+ "4759445724467851058773503846834304672223785226936531021666916376323562671488",
+ "782273457631193956426744043048759353979593033245260492990657945904665284910",
+ "13487130697992008212099652811750242205045881544509489831523448570173633517977",
+ "15621563974535086891768796441515013364217522966350445838133979748032034816142",
+ "19364835034502915244801518193980688426244659266819997726035650961451415757173",
+ "21037385853462058267099182407141652124171361973889761119816789091401609511088",
+ "20434791917020905003166852059282129255412677606775079570484129378535005615291",
+ "4835039666519156760310260600042269943079463379265872618778854224413385690994",
+ "17796521681519947552208651467058827825861565135255248123077469895978163706264",
+ "2823350440792171019111081223801188552138104039380675927963458669980277420276",
+ "16030935304664378631941573945857397096373696981104104381156313618686049806120",
+ "17523561865544155408760007908067668065236326734119657233234283826019015377013",
+ "3861341406966982603014220134107636493882146780655211775629734223927755221098",
+ "1327887013530867777305056212037691710827939709365211251951525926327942169414",
+ "16874372098146373517691588057974501095408377103185981262983559391956463291137",
+ "1335930538845994150082853775454018356383085560294444442667355553131066129276",
+ "16846954448852864630121063053695845658867759327963014776419090787323732938912",
+ "1910615356880143423765930148112668984411979710628153215580997630269783916489",
+ "8793723522335768214688108364110927144836722932802666660252079036893034856492",
+ "3725321587522884864935206279104882080790553804758085564413847527197687551835",
+ "17549397166194503933313005107479073474671951786436058351827338574279485542057",
+ "6575272615526665941236934551769345604089554458721499014263130089965203838692",
+ "19479945993771870488240738504390121923410154808673876321101554256856036124677",
+ "15218540520084042504179141700157006972641510542203443030571191341196460163766",
+ "11605382280428426652337162672330854829498688801746852913129963366330544359414",
+ "19452583367341408020642116770501289011436457479987875413223766731278874726613",
+ "2498463382382553480222037299113185800507848748313035345734629490930688205092",
+ "1815123960727364421144419865126922339611466868807520419660969560789979822474",
+ "20531692711768862540943545541715345229360673134388506876856593310216372259130",
+ "21106443640856542784867046664180461359993554892163126756059125921876166419615",
+ "8538925154199646282458477113696635826112766123791239931164489946578874271866",
+ "6179996393486486548378164504724190431464526698002381214818146508779777698063",
+ "1334556948430115939422649531996020210538905726908545666936164977436729124944",
+ "14555087544451841622469763698691954343538388285983305607235034906273022598676",
+ "3263678860186354326206053303615515256258748076250020171477442794745232038780",
+ "1342606052959540554052550853649027290857482440100275878202185177537473434874",
+ "19067318604617984900108104413860593038444834168491290140413988853573796446193",
+ "11453576191720077983310542494091726783885546118293459348522522324645101050430",
+ "3772400828106882724656632136643514300687950364203707059277582466654856015909",
+ "19928616354232846804233301414766074864065580313304404532140360351457581578733",
+ "17669618023197654971616078177762451816976570462585423216749814198562722234016",
+ "20487504497482961764356160511764652912371612840137405927810776425577238052311",
+ "15959943319286858239034503624455112049217253792773599324329593237810330429519",
+ "18384331160163107383609864825156022277275076414745740108239579270660154123750",
+ "11807744905122445070761653068499781933485269571078706728521902995972849333739",
+ "21636069700028297640587439425598371999203459272489053044479958900301869951268",
+ "5974406255004817187688462241155741022204236935194897255519053490391727654963",
+ "18655439470676485950283686008645538637216956533059508817637925480405213882893",
+ "15164692255429309369428108531856612257028649418370969640920631880841690009016",
+ "12342219963417210875401056442100023070134657858086394031902694268469750570612",
+ "481209231155250366998260270814874408671884781003382050138985430923825730090",
+ "3242985953168013112117560001466320034030784952490866310190327264524235633420",
+ "13671160391160864796369771052335315926068131063004086507703804642392143876725",
+ "16716228406804746939632807079686149044089946710213611348848847599210659020138",
+ "9496049727665863372935045496498617414460003517119878231671018103126084599100",
+ "16483340875218689502751737973203780724082025375353804209734656041473116836207",
+ "2627597076078148403546873341483726933849452415436198036537442451261384383723",
+ "20527956374075302103516613197928664717455732919429461243667758971357150882342",
+ "11711450220231538029408058975978592998998598526983681112180323327131923215776",
+ "14877293714143600802178367397934915488570060506993092692625720179311507474506",
+ "17326201000468992158693082078045140389930457394232528033746431682308160431934",
+ "8241890704089720408679017565592201736334812957892898769189351788325500937732",
+ "6134985085876540657808139826388808003135254271482158519839818774839726308917",
+ "6944918715501093472287921248184355748547193680657762762284351108190443908482",
+ "20293371855859360749476040038457808453751087076170457949707661658124460443795",
+ "12686929429491234226470786986230897140429036877303905464553700071658994784104",
+ "17469937611674874489854850805106365496296990924579100118175990663783068480118",
+ "4389315288495042551686883151731749050970801790377604942482415778510472384968",
+ "11356013296312574683565144017425132580728729177241949155779586695189495537084",
+ "5103616537832821778796048073410908442363049367034544148603830689894368565040",
+ "17797731362169406634431131949969435652804582561417001546024888062211188454886",
+ "14413974530545126251158359344156378502844867672748912889426381728267720393327",
+ "18860675036245741580291857551498220749884348391920381715922087052471051304459",
+ "2078681010293955893545295223175290151677764183673754633340142745613957031877",
+ "11594462210573371469687203943585180057860108341927961420756260896877407822187",
+ "8232172476137304604696594035794651005660416081930158074561971898151387789159",
+ "16234745736110953717672420346414210260779855851076189537371942811750295876135",
+ "12403261277735118438898936378116787991453555210970659659639856670648844247938",
+ "10260185954137740247486488192570496092684935183379388125044125653647328054023",
+ "12655661577981598013787126068450556825218951206788052328715378240540030673155",
+ "18875782029492829253540920061867800401544385695523240332551730645990253683286",
+ "13000939909369679921538945109975441940863265779072482929455684540500587590629",
+ "239651505606383903278277662841450805219997298453219985892834268956273681444",
+ "14053674646208577108881262953518523519057705122297176784230960366018789686467",
+ "3606574524342197944154321263420984044427893927972300192386619594198948706444",
+ "4925738689374393290519002876270198297196104042467164940497567711764321354393",
+ "9820857610236925174040210045575219513594477725958302510866127781620764675531",
+ "8644935227560188528158307606853375529544842899940616765747319983176480635667",
+ "12589563927120228887319930197852404057542625019034806374830349240796880735981",
+ "13728987671030134173563628755348391107370774536000844606094840710456114349003",
+ "15280672692530045491619672502933299001869276703035606138561063102232345967821",
+ "21236672540209166733321925277807375026701626666734236841532747395149863205571",
+ "18193368154219306112046312834283644566129199372283662927472078427038205531636",
+ "17828956732555553542546753429670551891943977601119756829631880115504235233984",
+ "16641047964358580103472953437535358748387376425127849904658691126285684204504",
+ "7196281413799658043487145161620082973834461754768351228587249162400339111893",
+ "21279455923934963235610861427104388147894350922169838127737714784897083581830",
+ "10868227810739752166142906769497786680491652628709341836398414527811509748689",
+ "2545479497580424357309396388184225593698470568625667945691755386799845345027",
+ "18560104754451358950174079457178017278416450108044438296553162755384040068059",
+ "11209544817144484509471895492404241079181269159060632258040504564376475442191",
+ "14007605578670373547623429803718323316371456029307063658189484725071020560017",
+ "19316201371814679831554697580647476192318282119512681720915001227483533198021",
+ "16788142218280927569387096932066591137887806957079516944927766625343518189548",
+ "961359518362994763330685811948798278197676602059504713988410706948791494727",
+ "19776591693739287332042935252284088014720557305781829207369487992244783048185",
+ "9480779019638564372864984254416095889603560407402750333423136372713778963272",
+ "7812061847536565125280880398757948966749177710701972331770694629380983832516",
+ "14806224217889264732099766866344263686300132511433376375954468192761174167878",
+ "10982734897602724370866115596864634266746118759609469486863878972425453415519",
+ "9054801238670111257982773992849940941038784597792282084645523468554872244495",
+ "16788499373458165601983802204061832376825550128562541027433580619384299691535",
+ "4361212778425224413929793165968418385407821814716394404713983701050982051159",
+ "21198869506404830651226227162808186595284220877501140400488215541390720176503",
+ "7255012904510681544072472510832565052731304049336267892176928038570971034121",
+ "9737409770400739938717035426255379270654933363992002237053138761832402079248",
+ "14206577906412186888550704503752653056320975796075254442765439825369882967977",
+ "19036632138581200062386943078412086222459679497578993523004498970778925638274",
+ "2855178582526872375806959544405581665248537620420194093904041355969926293337",
+ "12896727255458884273207928529421874672712973447260798892551468479503233439215",
+ "20930350939164528694912500193219456539952966506926646436560438515643683077210",
+ "184093243282405111677536457857692693581379037444126410664343605529966199122",
+ "15658149328429348710722591333703516363901544310832580304722884306208924451465",
+ "17544235160628712643216064131303569753533519783718786133736357990785709619346",
+ "9378984995834426590515136439048146470293781405649183047514776402081048834772",
+ "15827462476470655610816981948418438654022314364182315935007413461648751735708",
+ "13474113844360907776462232979612140726930720201237003164521648175005015977732",
+ "1846676454601041085237775396212630553832771346942418764660365576890630152018",
+ "8958790186410745003596973786908460746144469347369569174866696175944574520886",
+ "16716100142556090678395507171596864615262575578180211444515549196841601774046",
+ "17584363243087108058467208592097637069605249776196694465943790236027601639916",
+ "15462568643993327150997687623907692370120490318886920754261967569094539968909",
+ "11670427917584674115542198398366950879185738970881616803513412243898491416455",
+ "5883010686944177614793479335292002976406988590121850032334552332298599405710",
+ "20848023045403944451304856285219275218146149181988087184275301094312642906291",
+ "20892609628755793476767683891284835591758207667306100001065280698890821585620",
+ "11041559416099382923560246079300939393371149141074957197352566129686429429340",
+ "17004024027027164912556351303862470964296900000646134239805113699616064012220",
+ "110742314120280698533248152539115345099402903868297760208823130532853128340",
+ "13611598917097489441998314826578736196564311189470688979687759717921520208428",
+ "20362978391139708024092837231934567580385484740720090300868417284017430844864",
+ "4130975720087443718484415210347908638971321493417335260526136858657572592254",
+ "15799784358302997284875412214187555553319485274948108081666806701893845835839",
+ "12410480753305882251320943831026503736012757975027018073585110506521877824193",
+ "11835843853657957571888855948788121206617247107501669280697395787347649231752",
+ "3326313455005237548503557557286834479752096887215379141590090769222516357133",
+ "3193633369267878319453517203588676707547172638050950764150162277144428673066",
+ "3543696055990388683071939150214505536733386566291338758519836333135488212473",
+ "453840133795717001022433249997110059635014609516452256954528366651276289770",
+ "10086004265216215714804100477403907145516617200748655771783383139854288214070",
+ "18938459257787140207383332020952460039308194017940327258304986766920440675756",
+ "18017538799787896442217663532610710859333377084532654794368604069493775630216",
+ "5517691591172342790575564654696650661133600869824307632295945043592492062300",
+ "5846204096126701465613249085053971321249645306247508562697696901334354225619",
+ "3177064511134248081568628736306700282095095665917536853000298191943047784014",
+ "7886005759395499452194553110700824805018792487440311729836576312028682853862",
+ "19249432464407391173245558257296856631584193393398113008165174416171947900609",
+ "16818455958785909569371690525990846776263170512884599090849081099178789681425",
+ "16250344336602567919050898941410625842485562539342327155695417850618940905704",
+ "6273998461375119044609362240019558608655450921258416376794979330773412610302",
+ "15933077340738498731035173703791932079747269039222967104684412531145625747085",
+ "17631878023023477567294765381542867314814954498487832435087010633074888584009",
+ "3387656327342575368928488173891176548794878068816523542226413637288662472792",
+ "15770343706243316227190526252701886989383556270818375222569120097305537622560",
+ "21025947829537149117391184273139276031347299127217645728072786010534368285621",
+ "11728430055160129100077268133090903533902452454196978455625432056779499908581",
+ "2184576630760971645143677026393147474439766939689140114811262608230414186937",
+ "20744811853491523948066896610767067484129121010717068573365370365324040781186",
+ "5378129452609441814399329369785055593231824205814541852039878139773312247469",
+ "18082900764136659604287793533371380099349929291808230688664846500365863263118",
+ "10463958995559323021196963984934883570109613942564610388110191948063546468897",
+ "244120224370345949702567256216804961153505781666838608095297311545160357032",
+ "17924705581798291273661662368787600134425123985006190354093511903371507000154",
+ "3107793385049037773698181795186417899797325916401357881664725445733609110598",
+ "5665818573123185227274537904890713907625420710982346291959547939830358917272",
+ "967322682615997637785254033877348832211978156650281338584051044602311410196",
+ "19419941178285529854771216440310658103611219351729270204884834098822007849679",
+ "6901963792883328370624032472781824547409040392368725235274158498520441238159",
+ "13721659825627300509722716825333808233371435398666022190921612703736274379535",
+ "2784281502858555298249063959836879135450746982163416748737579846439268828933",
+ "9904373282060708277943634486822397019446454722637742217276784802015824898651",
+ "5782567592658163731724098371574354386783075175203877502094122152538152467682",
+ "10854330629450460532485325799036675355255970975925867222693267730198057197195",
+ "7162558805520478103072398765799613453839879264508883857822705210986309908966",
+ "14561060495007338369036260685346480181377385446422680685283066135483167829865",
+ "11521954935420160563214644175207412771411940789064933791820101643809540481492",
+ "3893071612329582305940837979511590531534863287842007408024123330272447072664",
+ "19982770443796802008915975147614604175753586689418309845602797606117149147490",
+ "19714753609495058998670661272525609201695470529132258598980221623379639411831",
+ "10656632215192474178114431876399520721084839753473211054259843433641616176373",
+ "15519943627473966175746342389219894179761085602008029155282295063466585111230",
+ "429220418726674010600368106136723992478318707196454289985261340376476917460",
+ "16943119555428737036287647863079565463224985076466268175824843518378134856246",
+ "7079268853451648384434335899135383974808119657387366504271184409878695702895",
+ "5787261347913259367727842908192773692002199385877294080619854106978539332397",
+ "8254314874636465273639128395147895313719165057850599581478980264860146008069",
+ "15417738281457065064716789110361253613929614783743035738325702945037527193953",
+ "8995940809050737092434676062651493038351424361820394016896779859938155003450",
+ "8930952966754141446126393622188683431566029237395186071059700311531927009283",
+ "9012970415439810859538557593310902447051948348093454112737452817814629449500",
+ "21700461010267441715993595978543322483687194036588160210184366057201658507847",
+ "19191426116308521669196161733982754533604260068907220372422504926794231257150",
+ "18022413735343984488479130392027693687461867574196874267731354592562070094392",
+ "13853879871506882218224060020827336496729967255850404386800036291019021382781",
+ "13303720125164503437055631247918150173085142868095887759030649510172293881844",
+ "12463581809293287384469946044562671884924464520288697069370030386140109068261",
+ "20468619377263375923071378952981485015200979956112400596511865225946853604157",
+ "16682148710681177357125570715056314888342059670705617513402649433802720432267",
+ "16299073895000203963165709887505572454180623116454760411179563591228007694413",
+ "6439155427163506786329349605983728674821430800627321435200421453561910062302",
+ "16531483734580605436075637034861280240342858648848575098901014901746112480232",
+ "17413802217650584016261506268242623594956116228659732892682224912798301233645",
+ "19833018739354446018077109493089909435818386368530968355647208939546565982905",
+ "13005203599293796776324509750491064421128717423989464867065044987475986374420",
+ "15433711189444672576513248931602290892518442446252602686878477157678233603772",
+ "11272192842480959445178012145556234469776261923967845001064211055340129168135",
+ "21349777755000957327199310930646977290027138137542241555905014230683052104267",
+ "2414795183415356147955181901405712632718942970568205736628916600696077941534",
+ "13910388410253717440990758214044472114511432613509643223811561885135488623236",
+ "10073917454281511762447567386654530277776617831005093724557094001489771821135",
+ "15674657915196276639699997458656008228696751013801231738985398708672037426000",
+ "12030695425048598984176709301472822771003849589255577773183310838231109921591",
+ "6658172369461756755506276881582345916252610724131747740625283609123100367529",
+ "6460801016753822141904293563006139350014125998787400018150863192907944207957",
+ "10798491465896968361800574703868612181389697312199241920447162078078725409638",
+ "6331917501914253534943383807348566698937757752033630507696817298838693259937",
+ "21521172968280414216108032807577565012642487518706778276505136864150789112592",
+ "11443202152743097070847729825799673217706162711935940510632741405015900516668",
+ "10360970774813507384412119692215277392320350056791930702078433469299837875151",
+ "8111678922881662305935841208620197469657237670526301850210945861223648259810",
+ "3828566775247110089904016755996284741548002327940628727687176763639903716661",
+ "21019871488460899469684764817167629979753844957147537040703291790231271795829",
+ "11744049805554498869931942573519884330545637954557542018916739662277241821806",
+ "4521092770491436085084640166923844634777984445583984077999595768778116564222",
+ "2428018726292924561718904390333390438951211767580762396913313600061529081905",
+ "2672992591753804066533616673591169777906973091506536575810912266557203322920",
+ "5631180351966611479340932319081124575466459942666630580683510336616679680271",
+ "10149209329290376952496655294191511204529081153402908137750268385347783758010",
+ "18292794133971639465196495021864699906132845458944945214425906730119328661326",
+ "21442863185355178191454777233963814974940050392649316620141474331670970354424",
+ "3768420898310640667772098495371174917665155708578905018940113026409140957987",
+ "13677778555119984843885943251631654212176086447994430552012266440677394344669",
+ "13884681165958999171515885225547717032289759601884108191367706162606597842698",
+ "123196094575938824660055152882088188411485715788351262262924974166600702398",
+ "1121836698372380581784934880625694675020871234049336489788624481922395781738",
+ "20941331435492311592529607715649713508861806194386837398916323083940590908651",
+ "2470912827043971002614412337239267059969980871643559631900987795139200233821",
+ "10806505189594612637071931546921663393081238567888534876058498530874738324701",
+ "667951375802630033661777802749339877422061577764798227349674331630120025667",
+ "18416355600415187627018330134584431345513028652497077471935121971918269469363",
+ "14167152054564590179475064444026440101215733530475912312508414765738108715862",
+ "18633695428427030575173671831485026260967985663658201463236228419717189642766",
+ "152822669216765741203342297512101138657182497046533047369566701489981099230",
+ "13835701173750333056481994253160471551109858589047436642253159392878873667798",
+ "3993942321148722649703549241999711668949060533276325947207349685002693878681",
+ "15582244332423092177434976075689385819450099629893355758782548118218073388706",
+ "15110236879710270343688993144525012407319759236015974251051640787524859884359",
+ "5104405092803829419537383694663582438349376353030379488011426113631155364320",
+ "11034886586481561934231698674217393887518948538322130743646058638919797229737",
+ "21614370562083755709911993869347579638113152610927033622836963904672826178593",
+ "11909716327216431973191112809713028257963610176155315584304717743448686635887",
+ "9670047520194835060472941420215502268522351803257892125345072551055025494562",
+ "8752044341583145728028411582583224350471084864272507077624316823400738066962",
+ "20685513123216586620977713797881862528998788503897607377725195418550074311551",
+ "20219162196364967181713755472576994456615542213293827108438968625041058321145",
+ "18287830464300889532838439052863785386620820747210980263612361113628554829988",
+ "10146051396529576924597355409059465520468869175466632446875430377637660889879",
+ "13466459020798488583841582724067017412922317425102130151754649408559458307937",
+ "14062280191830459071860023268317938748180670907089383563443465249500572357980",
+ "18486553995294693573565546696966437493113894571993019524170031057367640632085",
+ "11156566424349445901806390826392443373766529722049710427351550423908421767094",
+ "209671637225069235519570008386635562520193585953162475265417907100134848923",
+ "17226989944018790920809176115775819865824823495740082575382169759054625372382",
+ "15644589951345053163188258692419292119540702867922222648564209455819510994564",
+ "3689635641036835670663293726548900381724135109917216986885298700630212836435",
+ "3367607896403464195671402279459329078003744183784952830994679539910724667259",
+ "6227320552634621985217890398406127207902736210419315868051857823685244516725",
+ "7357930890687295365886228617478473072206575811998185548162905341534675558305",
+ "9337019296542497689612612043175604595811913796434346282222317112981594913389",
+ "14658782859891978670907070276103444826326577838777644289370207112293812556778",
+ "1700861002075407761970169168361393086239805454951858464329713573177596208454",
+ "8422307882422345667268572118847227804767508317685246864132851358134342544918",
+ "3824678171886439611637777800578730196591582015637069631407414390326082519384",
+ "7520989644070067743500997565082513560943860081670904302057616063200273050286",
+ "5278276919931895959830110725703210158384647399821914390314400092195592076331",
+ "14590632939277529585876696200177152214896495867542780671631701634592299041714",
+ "14365499645924743985349770983085181263329435144891175678390938245209017764418",
+ "2519790270252875654107597063434691592006935573176284731324585122712988059511",
+ "17688843544040778657269233842324532395371012201506418912518394656290716826075",
+ "16584068781164994465207120381716024087231836173689783891650623302438290695506",
+ "12224860044594664185598615945328866758529752520066027818906177267571423023661",
+ "13664317767999211366109254182438581912610775541954425083255023643648887081779",
+ "19324196860555787958873349597666822462940695051471419602454830948112942481945",
+ "15338841226759355791277440652242849878000656382388414806186764010001628984934",
+ "11076363155150973228897602285090741665942726007445165132980573631249449594126",
+ "11228309866140794620879641097623963859536328868056691748463227126359575786386",
+ "4762608512226640372168720665137259637840828925512114281702049841301872652787",
+ "18282645934358125859102195916568492018711932725386725562892735740355836227532",
+ "12803228415054755333149187333584509982900042807310255834005394843350472605458",
+ "17675693156369747720817703064233611574822178844066411565804543111769294187197",
+ "9900029048144575309490519431063332695303076438539483419053219772370202428926",
+ "3684590949621971596368895784562632626464811455818343794800044114209066071601",
+ "5443335602638685057982926800093482287199751584817191972983546508574786160090",
+ "11352900694666160844325992247118358443639716695965864728670968730093466793722",
+ "9836739435541786452166525951732520477055729763398281521212184905286650567233",
+ "8222926590877635625730738050718327099397892409701316035188479123499338707893",
+ "8154558268770648194631329585722892880905143452138234292827603893129808716905",
+ "20661038342485310632612091028394348057035659683250957045340774030445861865592",
+ "9136910062528018177460276667688174167129493547069053533874280111057356360561",
+ "4362513385797089229061458501847196255783651860098500705320631416351847846956",
+ "2061137061600029258110405980965338431925491466724330216028866028449889153371",
+ "14607676885409772552908782897874144975643999944034675480739173900267789420534",
+ "215346512487318428553079809620502708407272005519315271404209452927497999118",
+ "18044026902282362371439577283764019415115969502361960218708274179281044595578",
+ "9652478245641134951513165220881528043195466248948069255527062590256621034842",
+ "20994154929281322813927859895894589885437941429166007529912073756113466975582",
+ "20752721666010515144550782025078875036488075535083563976118804420187462745253",
+ "20857028711523544595627940704882176284224509745902984714255291431664146535922",
+ "9631521770540523913735742126933921923952197512938165111866628665235591582568",
+ "18950423265182779471595998716023482060645307106263127634953888715515988505533",
+ "1436791836740130330138273456892846001841969807914099860317370076565131805680",
+ "18145299176463660895047063984288790313564980703886502044680749544519011424826",
+ "7008134596456692891696131297028980612714475387065733972352529833092170154127",
+ "18054087496593103261596842546955317831262607456582498514349407492750291465651",
+ "2460661191051979147731673103829326449069370361298340160666765010767300969003",
+ "1121019547339042268901204213478561141018690742635442229019134496736639790078",
+ "13486140142607002128358893931572108539446504181590991898872881746144618091798",
+ "14485083458755292442253176062192342099468601222388603924363708902524652589634",
+ "17684636079328478898730536417772675839399177918554869673260926729643471105206",
+ "12382939536995562937141167025903251534081453604974163882762565576243762872206",
+ "5191757256912351314880102858899907666377813090645991709894707944196053941770",
+ "18397247107649643640823283145149323187327745749077714626730537494597891967945",
+ "21508632378351416585385353654317189405917247727406155133342616741543833680788",
+ "19108354768686907995261340253443420621814860995097718380505789237761300853182",
+ "3649609518051015699386442513879956346519312025847003339036530556474594795760",
+ "11893851425092314587513815253407979901615516208632062595457152391110352908805",
+ "13296593391067251947204447959241604616835056311051696511507435925462940176830",
+ "18493557674615580922923001229788184231889430766683327472934879670006059540367",
+ "7669746659590113244880799806073731587177781693253502772068846650012974230120",
+ "19370654200032786851343971085637480775724705092664059950989935645178139099864",
+ "1331955346226787928500793024038189892044219824334532771311923855914410290305",
+ "14488880297827410405382492933041130286687512096290491259710680579157544248910",
+ "6760882547908259908954677726421351194118695606292587659467769365205068189814"
+ ]
+ ],
+ "M": [
+ [
+ [
+ "2910766817845651019878574839501801340070030115151021261302834310722729507541",
+ "19727366863391167538122140361473584127147630672623100827934084310230022599144"
+ ],
+ [
+ "5776684794125549462448597414050232243778680302179439492664047328281728356345",
+ "8348174920934122550483593999453880006756108121341067172388445916328941978568"
+ ]
+ ],
+ [
+ [
+ "7511745149465107256748700652201246547602992235352608707588321460060273774987",
+ "10370080108974718697676803824769673834027675643658433702224577712625900127200",
+ "19705173408229649878903981084052839426532978878058043055305024233888854471533"
+ ],
+ [
+ "18732019378264290557468133440468564866454307626475683536618613112504878618481",
+ "20870176810702568768751421378473869562658540583882454726129544628203806653987",
+ "7266061498423634438633389053804536045105766754026813321943009179476902321146"
+ ],
+ [
+ "9131299761947733513298312097611845208338517739621853568979632113419485819303",
+ "10595341252162738537912664445405114076324478519622938027420701542910180337937",
+ "11597556804922396090267472882856054602429588299176362916247939723151043581408"
+ ]
+ ],
+ [
+ [
+ "16023668707004248971294664614290028914393192768609916554276071736843535714477",
+ "17849615858846139011678879517964683507928512741474025695659909954675835121177",
+ "1013663139540921998616312712475594638459213772728467613870351821911056489570",
+ "13211800058103802189838759488224684841774731021206389709687693993627918500545"
+ ],
+ [
+ "19204974983793400699898444372535256207646557857575315905278218870961389967884",
+ "3722304780857845144568029505892077496425786544014166938942516810831732569870",
+ "11920634922168932145084219049241528148129057802067880076377897257847125830511",
+ "6085682566123812000257211683010755099394491689511511633947011263229442977967"
+ ],
+ [
+ "14672613178263529785795301930884172260797190868602674472542654261498546023746",
+ "20850178060552184587113773087797340350525370429749200838012809627359404457643",
+ "7082289538076771741936674361200789891432311337766695368327626572220036527624",
+ "1787876543469562003404632310460227730887431311758627706450615128255538398187"
+ ],
+ [
+ "21407770160218607278833379114951608489910182969042472165261557405353704846967",
+ "16058955581309173858487265533260133430557379878452348481750737813742488209262",
+ "593311177550138061601452020934455734040559402531605836278498327468203888086",
+ "341662423637860635938968460722645910313598807845686354625820505885069260074"
+ ]
+ ],
+ [
+ [
+ "16789463359527776692258765063233607350971630674230623383979223533600140787105",
+ "17179611066821656668705197789232102741366879862607190942874777813024566441829",
+ "18653277315487164762584377009009109585010878033606596417396490909822722930739",
+ "7373070639853668650581790286343199505413793790160702463077019294817051722180",
+ "4823864393442908763804841692709014014130031798360007432734996408628916373879"
+ ],
+ [
+ "19196309854577132760746782449135315310664418272926255500908899397538686486585",
+ "18123132816088485879885148351452823314623055244145916622592591084094232513914",
+ "18436594886553181913092702411547018228276047601279727265790147051821171174455",
+ "15167500404313194506503404655898040457721633218143681920692711693000769735187",
+ "9437986152015460505719924283993842205604222075968464846270136901243896809793"
+ ],
+ [
+ "21445376105821232747280055223032050399373725161014449207033808524504027971613",
+ "49684738714301073369749035791061182456037935161360748355432247732088942674",
+ "9826409059947591908303145327284336313371973037536805760095514429930589897515",
+ "8494798325496773219358794086647759478982958403252584257436898618394561204124",
+ "21251937175072447337747316555423152807036003235223125066270735279039060889959"
+ ],
+ [
+ "5539100337780919206842837176908516952801756637410959104376645017856664270896",
+ "6297628909516159190915174165284309160976659474973668336571577778869958189934",
+ "12792263637464508665199868777503118105486490400267592501708855807938962470650",
+ "17254685306085558791725544672172906900581495686070720065168939143671412445514",
+ "3590396502942934679818900672232030233017710909687947858184099000783280809247"
+ ],
+ [
+ "19055249881366445073616526879263250763682650596233071589085239500077496415637",
+ "7367697936402141224946246030743627391716576575953707640061577218995381577033",
+ "1322791522030759131093883057746095061798181102708855007233180025036972924046",
+ "20456741074925985565499300081580917471340328842103779922028754640077047587707",
+ "9059147312071680695674575245237100802111605600478121517359780850134328696420"
+ ]
+ ],
+ [
+ [
+ "8266021233794274332054729525918686051968756165685671155584565440479247355160",
+ "7947823415909040438587565055355894256799314737783432792935458921778371169026",
+ "16508811191852041977017821887204137955816331040385276110261643892701458724933",
+ "1804800467126006102677564831888710635194614232739335985819349312754063580223",
+ "11189892034806587650995829160516587240879881493093022855087765921356611070470",
+ "20567450145123179140729389574352706949280207113956641415022972885523439610844"
+ ],
+ [
+ "4666756311257455192796774305229624459258864488677689058174087310651786875914",
+ "11389253665835451896363091846189307652796786468610595637047377864063404843117",
+ "18793736599347263150867965517898541872137378991464725717839931503944801692688",
+ "4206344588923325482680116848820594823631536459347642329098796888497153867720",
+ "1739462481670645248707834504605096139894257554120906850613041004917967456145",
+ "18514227342636266640333254638454588508118462110178719555586534011641424431745"
+ ],
+ [
+ "17887039315911403193186866703775654467672391491657957999455462537283842145802",
+ "2824959020572825365047639014537190268717891749361604043531643698340708119767",
+ "12521547103713919592301476538318318223836047611311454785951907894055964264287",
+ "8658146183671258251984364885894342376430874614261222570603159082682815800788",
+ "154390145585284450772861151318029820117470958184878116158462181541183085587",
+ "7593705166056392393963956710828665339496927193740869686529339432486182720653"
+ ],
+ [
+ "5529559239163081088908568555890212324771345012509269613465629182165427812002",
+ "3729910453162885538930719732708124491456460687048972152311428493400220125686",
+ "11942815243552870715777415109008273807076911177089425348095503288499102855779",
+ "498938524453430895689241565973888863905147713935369405079343247530256066618",
+ "3976257517234324421403708035200810671331954932478384823208414346189926720724",
+ "723540703523219510043977323240437576248315561543814629392162302024056718473"
+ ],
+ [
+ "13306548824219676333032339487546407241767961556934015003605485324283250885682",
+ "7970147269291664639740298762956131361316495463191268382513594527221399186752",
+ "20633313939958767604804835838065337107615699351647541991788258289962727735454",
+ "17162090859520817529294904484646695645841022315617926715432606252643123848792",
+ "9181379842957190051440498041153333325098774266789773971685141362947015398641",
+ "7051606617662816798224904133351061549832959857069896192072217769241273559278"
+ ],
+ [
+ "16619522548478824222688310091434959542211899852679631815023615875678448806029",
+ "14965311177811968100298579672135357167599499478246106482433786066289128683961",
+ "9792733250919070275775594069208673385381167169182805600474820364274865306108",
+ "2069253833779081039049908513863485270550301879399727430830923273191877809560",
+ "15847298987712771667136245955631872888473964330474501593909263901393348546986",
+ "12244443532166430060291409356011430759892629145539185535677568234713942157668"
+ ]
+ ],
+ [
+ [
+ "19332164824128329382868318451458022991369413618825711961282217322674570624669",
+ "12346323761995603285640868741615937712088302657627126374070962894016296466118",
+ "3913895681115272361294397190916803190924061797587910478563401817340941991811",
+ "7048322889096718105055545382948709082135086733564574465991576956878202831861",
+ "10375086910057323893637057154182902576957472442368661576421122036461645295833",
+ "12765622911241487148932810040772504127756393086809438933166282251044289864727",
+ "266900212758702307861826326591090138389415348463003233900705815890364224151"
+ ],
+ [
+ "14435131616556129905356866638030823183270286404767286105643513738132789033353",
+ "5780976801287540146775934937953368730928109502001687434229528186520268917700",
+ "1618320442446662026869390273942730786145909339107736579759397243640902802126",
+ "3818399583522206096165108192531271582827953520684743806492664825009577810261",
+ "11764506724346386316602508039052965575734225646587104133777798242528580374987",
+ "2414215974836165993714858157462355581258152126063378817495129367240311967136",
+ "17609437036230923129211608175600293197801044251801590649435913902851695334081"
+ ],
+ [
+ "363438080029711424794236047863047716381155074181485245036621530063262917196",
+ "535766679023716739184211613469394818313893958493710642899297971974381051070",
+ "5305068908469731303772738758164870877638068032868328180355958394150421214337",
+ "10807632568240507366657354568432178961148417327580695024415275247652313539292",
+ "15964415873358391713354948903242729080763777490509563223190335273158191600135",
+ "20700362719972015883260687302741075186857660623182772413609788566925949033885",
+ "10135127975676256977820296631533839366076919827597067890970660746228807376456"
+ ],
+ [
+ "4251490167543116819728642817282216847143714366441358372252125244838181656331",
+ "7745587495915033527847242564710473705100826890903278244320948416581724663023",
+ "11741113129223221800185946819924457344647035336264986754437921049066977440806",
+ "11630296782890656599545188109639399768829653360050213193782325240600583381364",
+ "16861140446185941149398487176581839232380972247302922484807333229513905651035",
+ "365879246117123675211400356410703684399715291171114630107795112994207447819",
+ "21725607857580053522363567649763546934441685061337033780528788383243719579033"
+ ],
+ [
+ "9222866548596464928765000608129177609426964853736257576074550520759533736918",
+ "10261578281201197531384003420612639018011405529775212563256392340336951230146",
+ "15644037447921591571869862919382888810859308861783088910843592577202362807673",
+ "12752004188139535619565478547449108772137477456363099481095747591698702436636",
+ "4205805109630387448825516813913983509046636797101589615147198457314360427718",
+ "21047095155106717901091873146599497621258071512562421967648909471775919992713",
+ "15624165295872926124160584750951090817255240214488120310950503163805737026315"
+ ],
+ [
+ "15064589937731741958666763896598138037875460434244947486199623542160035749721",
+ "1801577872277160959016940766173040841160105238799805406938450020949902989173",
+ "2896766420608048344829901127120623317655260981420052771341833288256800199953",
+ "12828791469509204618898135640019714232831708508424682785876476343251730674999",
+ "21363471986981372923191391880511344708743312828234098289107697080824665183315",
+ "21372706354350795416381912271616633829725494570576895047490974943034914894898",
+ "16006531510217730955981102005088687858079561573088629102219485906666961331083"
+ ],
+ [
+ "2389357602244845938251345005183369360523566673990464798041306722747500447645",
+ "15275955107196234672088664710679934029171843237458844492987233368659104714648",
+ "8038797517535218686870517662905230585331773059774130312418943649247287196930",
+ "17923922393436914864421862212181654800719733137689602673604754147078808030201",
+ "12890519745320143484176500044628647247549456778462652469313611980363507314914",
+ "8058516556024397257577081553178859094042894928866720408652077334516681924252",
+ "768425396034382182896247252731538808045254601036758108993106260984310129743"
+ ]
+ ],
+ [
+ [
+ "12051363189633051999486642007657476767332174247874678146882148540363198906151",
+ "6387692555402871022209406699166470377527846400909826148301704257996818597444",
+ "5501161701967897191598344153113501150221327945211106479845703139297020305204",
+ "11704372055359680530622226011526065512090721245437046184430227296826364812961",
+ "1448611482943320179763394986273491989368427112997509352702795612841455555221",
+ "11429145481524962708631235759094055797723504985787912972575745356597208940857",
+ "18021858528471759023192195347788820214752298716891162685115069036283008604659",
+ "19817577944622399780828745167469547332167999743980557486183403063955748437619"
+ ],
+ [
+ "16868980302925985719076889965831700407328155411673408077166038059874616424216",
+ "14717432944340806781505761211058502775325970511884444497202848327581753493322",
+ "6273484270523289845253546319956998489830555038697388950038256377785540828355",
+ "7726043103954429233325852791166106732104332590864071922310309250010129731951",
+ "21052353119157611359715869265647287129868507410601603360127523286602350622783",
+ "14881796557136180514390287939887071460258251160875710427576954128871507002642",
+ "16341327439981153879863707938117355436152690262312411284193970279829974799334",
+ "10737675906107372302108775622264379258926415910493665638388971468924879578019"
+ ],
+ [
+ "17652699767629314433191915267767147860052614073432922215674211498672835339113",
+ "7457854400138129895665591719907473144796504905294990100367501377050420942800",
+ "2136850802972823585140870808569264373787409642804109426616292140046700710743",
+ "14029467347298896610468190615212519453678316548442709087191045978401072380889",
+ "17927699952921266007590534383984238136710494507499176330493504416180410161683",
+ "1404719213830610030709583332543456268094679432456284386108188509031502237811",
+ "15774757292079018355173698870903422490868220545526384876021336136892926326596",
+ "13992040374687149195439840459922227749294794072303579532004750946306028893274"
+ ],
+ [
+ "19895094843870397064274579657905921299619388074084417486420154568847155746891",
+ "943833985612967248618844364501030453998731991825395875139617731659343743483",
+ "18334641092245356682448009823797080853859186519922476229272838591594967878678",
+ "12440287044655505483131716236615633401781045711053210640202766768864619378050",
+ "19130942564098572936370308509908873069169152245172660555660369853346605570826",
+ "13687979327148217614616687417475244897906227789285703940171633508277844471062",
+ "16887921327479880141959363366262254722342925451159884082370074726344024008329",
+ "20378003125024698406589040864014894045124234695859352480989552885205935609512"
+ ],
+ [
+ "9961553412530901953022991497331082655746860319830309417179972582392489275965",
+ "17755268665220780466271147660314410613992814315871705414495724015443459797439",
+ "15394131279964876131165951719955566821453162041574233072088124095626652523043",
+ "12668230348320365182085867728169435383987570924921845106243310905832768752125",
+ "14046812111383844816383347755263287603387502282980410255379630204396960343368",
+ "11590093969266595252327261214735156204516524792938909229175092594303424141199",
+ "4623517074925959322927421514289132524032863498392441375476410779446526502799",
+ "11550389531965919926150256242174358326491059727918559332939872696684299343135"
+ ],
+ [
+ "408487396317981846281976563618407581852133413686169882346565860317912856432",
+ "10717757571561029382519744040791773994731123262749372629687813122941078154016",
+ "21323787615496251932181222397986048515693661833099659753170924658480548866921",
+ "20780799310067873093555276926357624414275975377319941015818682052081980020892",
+ "9948385944800296129032348634683354181546876394979291412116493575442898426065",
+ "4957033413111065858035065225611730571499258914257595411830870977545212164095",
+ "5227254936689728148737265263965107718869714128941995977191096572191110991079",
+ "3582814872786080867997255427740166393615552773099677831398251586195329933975"
+ ],
+ [
+ "2136737803483410555580163900871515004623198990079556379647848364282254542316",
+ "2965752098571712086281180512370022839542603960309127077035724860894697782076",
+ "1478525086510042909660572998242949118476342047444968703549274608283885678547",
+ "3563375996604290844805064443647611841824012587505923250907062088840679700555",
+ "15461452581843517997080348781604020486994675070532901120353124746087231692278",
+ "20472517020063295821544268171575414161230806406668271887185150097779785573889",
+ "21058001005918321995459971112208002381460494177332965873048074199074929946172",
+ "15805746645980285645504697043988763170971539673993759868487715403982423015009"
+ ],
+ [
+ "7141240965656437676130015766799708612940092856280620325870466265817008351948",
+ "21418010338098024788434337801477243267248314524079104488811186206038748626642",
+ "20272108634229595317682817969506273496034097230124371921628691470754475805838",
+ "16734095147399743907618148751687506877774623133599770145304816136018239803101",
+ "8439324632051181834455499457268557602816180314723268640869118054114888151316",
+ "4953900961796661020464968131122569974581908893169105485631905994366550928492",
+ "18071625983692455679240094911529791119099077429122520426399552756115503123111",
+ "19638917592063029281156873227053827678889868373299664608974791764751784473040"
+ ]
+ ],
+ [
+ [
+ "708458300293891745856425423607721463509413916954480913172999113933455141974",
+ "14271228280974236486906321420750465147409060481575418066139408902283524749997",
+ "15852878306984329426654933335929774834335684656381336212668681628835945610740",
+ "14650063533814858868677752931082459040894187001723054833238582599403791885108",
+ "5582010871038992135003913294240928881356211983701117708338786934614118892655",
+ "17817167707934144056061336113828482446323869140602919022203233163412357573520",
+ "16618894908063983272770489218670262360190849213687934219652137459014587794085",
+ "10883405878649359800090160909097238327402403049670067541357916315880123123342",
+ "7439184039942350631846254109167666628442833987137988596039526179738154790587"
+ ],
+ [
+ "2727663760525187222746025175304386977552466570311228286110141668880678011929",
+ "16992375884417886634716738306539629570444547136030480542879886913528563834233",
+ "4178586893949624406750122665277033849762243490544460031634329370298105635905",
+ "2517914797385699886738929430037355069462619900197972886482360691236776726214",
+ "20164173810534657634631187494276970100735049909727379228976555863615716408280",
+ "19970958827248077001061220127605534603528515080207197493660642269195127427214",
+ "15606275977308968307194602612931727810866183872589808138812916593200446820753",
+ "12261436001550634140750381230737452634746867040398895669545077774504957433511",
+ "10405309809257831434323731445544896504541938387524726028487604098725193737428"
+ ],
+ [
+ "13408856444092113657034337770571899796129642125690066226794939383190876435468",
+ "19768080898957882918527124226120459667739640387901357739011662191034806046251",
+ "16749889646056241484852997428132695501278739424507088920371060969471495213919",
+ "12331609790192161246735870679870317366088443875784324655482358218146673901073",
+ "15769331739277556832196167201116801527901089923090632364403958141614820528626",
+ "5227172275505968397128736045169568430462701766148126842874241545343535393924",
+ "919073378344729780131814412541912290691661039815032069498359347682919854836",
+ "17858725475505870077023114050620337312678855554361132257763133392017321111169",
+ "21805188450184460363143840112266872832328782034569970452376470141743078343745"
+ ],
+ [
+ "15808413311863154368918155104905222670782553225279887458053980771135357021692",
+ "12828907214414139667587331812274388831051429093098655261887619166452245292431",
+ "19323880880917307340820066456419195877039970908109908221992925424585030574269",
+ "17591732412986269470826282099678922890996647592922237928486497997144096433314",
+ "5282593184575641056912422403901924986019740793240905758215569065763629999318",
+ "16013130707598525718519250412251656096494468043256226360413191733653074896117",
+ "928381583587170989315021718439506896903185927814675820160976165627097308915",
+ "13354336789663524324458402003354905134416094005220899335023797754517805691310",
+ "8780135673134081873589118311874067764073719549433574820315100541871522642766"
+ ],
+ [
+ "3334957744389892864165113989538814646945861179021194859030934481494560681812",
+ "10553413566358881045095498839713459314577909144176577153981801574128014927353",
+ "18894321506279909207228932263261226433242541255661384643559047811974513999438",
+ "20211894014628303327332299342564779073614790317614402383971270594430055013904",
+ "16723480621932556506775906903415088312771104391224076734252099577243237899106",
+ "1131872547334579236404174618548801749854242069301712398106619948805304881636",
+ "17386814048141719093058723520379257085987299288710382497237609774141718421404",
+ "13729980537487612221640320393867198844745491357830417754869369043292518007370",
+ "15860780436383591737179656321807464721751913977397035980422407138400867838633"
+ ],
+ [
+ "14708550460111247278740231297332510059116901767161326454481923990389610737973",
+ "3132820559166321299152015048428879769905404947939291493327190426785911502819",
+ "8658132367999084824971296219169212568783540935524918908332001856872807119287",
+ "21064783047501777742084787259676320053480170916619513986794406566953069418035",
+ "20731000104011695148048713576219525164619502119638555785381543866326561323",
+ "17189725817866212967650950297463469529475851286172280116066228706121595462088",
+ "3310440878606659516028312898499559492876015493892608849966645073367377278233",
+ "18463918215326370595980949760897480127622730018343709491036454088497976892863",
+ "10894192430593140913557164014343360386192963621862346779515699758352916852228"
+ ],
+ [
+ "5060610877870389107953459328006060153180283860738879092399406248484265273634",
+ "9068988823145592214189961315730261367007076042069390630024839612151270430414",
+ "13160707893890865447331361630522644819624543031829773191665491273833460019183",
+ "13920568292534026180186486064598876780779571940988254327823480971820885713801",
+ "3894011501178134026216736522445829906312115650019712122802932677318433032635",
+ "17895318821130376385979570244603067634449453259842805202694945793852667231847",
+ "9777993060458301797155055013115849176281006051494461044565335406558308324220",
+ "16521293541516305251718414192107787058980727971856888501176820100904791554730",
+ "7744063601405355255689420547832904761861257642931934580021876189691881462544"
+ ],
+ [
+ "5444730929053688962452159157646022068806222098484627080046464163159451208522",
+ "1524118152994294864739915388438939180298324297960159419600850033701763764640",
+ "1334622237342346242862023763160346671504959163544406543315614662442562816653",
+ "16126317914306849967682996412350336172782726693375105190424151365140854833923",
+ "6345975085253358297751050638846919833013142450462810543971050115910612860460",
+ "2703875280053263252177031410407166981522153304496807669518295313468095058674",
+ "20550626512184448884716175825490086259235894802178999642552696391947509065676",
+ "15013718986700828670892638677446258841869291160144196138236407826511808592486",
+ "4682264015512203762723381542642871160915706748420642731100634327658667608042"
+ ],
+ [
+ "12834108073603507925748862283503586970613250684810871463629807392488566121352",
+ "8422606792378744850363509404165092879785007388646473871019846954536829739979",
+ "9339209090550177650528715604504958143078492516052997365409534971861874881780",
+ "9141831918422847136631159987994781722269889810731887947045878986971886716767",
+ "18329180549061748373684938917948729366786279119056979983310618862430068636631",
+ "2009551904565170718789964252583363785971078331314490170341991643087565227885",
+ "3859729780601667888281187160881197567257456581829833310753128034179061564519",
+ "8535335342372994336873304745903510543599314397287086554558824692658347277251",
+ "14148514289641991520153975838000398174635263164584825009402034843810351225518"
+ ]
+ ]
+ ]
+}
diff --git a/test/modules/src/poseidon_gencontract.js b/test/modules/src/poseidon_gencontract.js
new file mode 100644
index 0000000..1ca16a5
--- /dev/null
+++ b/test/modules/src/poseidon_gencontract.js
@@ -0,0 +1,208 @@
+// Copyright (c) 2018 Jordi Baylina
+// License: LGPL-3.0+
+//
+
+const Contract = require("./evmasm");
+const { unstringifyBigInts } = require("ffjavascript").utils;
+const Web3Utils = require("web3-utils");
+
+const { C:K, M } = unstringifyBigInts(require("./poseidon_constants.json"));
+
+const N_ROUNDS_F = 8;
+const N_ROUNDS_P = [56, 57, 56, 60, 60, 63, 64, 63];
+
+function toHex256(a) {
+ let S = a.toString(16);
+ while (S.length < 64) S="0"+S;
+ return "0x" + S;
+}
+
+function createCode(nInputs) {
+
+ if (( nInputs<1) || (nInputs>8)) throw new Error("Invalid number of inputs. Must be 1<=nInputs<=8");
+ const t = nInputs + 1;
+ const nRoundsF = N_ROUNDS_F;
+ const nRoundsP = N_ROUNDS_P[t - 2];
+
+ const C = new Contract();
+
+ function saveM() {
+ for (let i=0; i=nRoundsP+nRoundsF/2)) {
+ for (let j=0; j=0; level--) {
+ let oldNode, newNode;
+ const sibling = resFind.siblings[level];
+ if (keyBits[level]) {
+ oldNode = [sibling, rtOld];
+ newNode = [sibling, rtNew];
+ } else {
+ oldNode = [rtOld, sibling];
+ newNode = [rtNew, sibling];
+ }
+ rtOld = hash0(oldNode[0], oldNode[1]);
+ rtNew = hash0(newNode[0], newNode[1]);
+ dels.push(rtOld);
+ ins.push([rtNew, newNode]);
+ }
+
+ res.newRoot = rtNew;
+
+ await this.db.multiDel(dels);
+ await this.db.multiIns(ins);
+ await this.db.setRoot(rtNew);
+ this.root = rtNew;
+
+ return res;
+ }
+
+ async delete(_key) {
+ const key = Scalar.e(_key);
+
+ const resFind = await this.find(key);
+ if (!resFind.found) throw new Error("Key does not exists");
+
+ const res = {
+ siblings: [],
+ delKey: key,
+ delValue: resFind.foundValue
+ };
+
+ const dels = [];
+ const ins = [];
+ let rtOld = hash1(key, resFind.foundValue);
+ let rtNew;
+ dels.push(rtOld);
+
+ let mixed;
+ if (resFind.siblings.length > 0) {
+ const record = await this.db.get(resFind.siblings[resFind.siblings.length - 1]);
+ if ((record.length == 3)&&(F.eq(record[0], F.one))) {
+ mixed = false;
+ res.oldKey = record[1];
+ res.oldValue = record[2];
+ res.isOld0 = false;
+ rtNew = resFind.siblings[resFind.siblings.length - 1];
+ } else if (record.length == 2) {
+ mixed = true;
+ res.oldKey = key;
+ res.oldValue = F.zero;
+ res.isOld0 = true;
+ rtNew = F.zero;
+ } else {
+ throw new Error("Invalid node. Database corrupted");
+ }
+ } else {
+ rtNew = F.zero;
+ res.oldKey = key;
+ res.oldValue = F.zero;
+ res.isOld0 = true;
+ }
+
+ const keyBits = this._splitBits(key);
+
+ for (let level = resFind.siblings.length-1; level >=0; level--) {
+ let newSibling = resFind.siblings[level];
+ if ((level == resFind.siblings.length-1)&&(!res.isOld0)) {
+ newSibling = F.zero;
+ }
+ const oldSibling = resFind.siblings[level];
+ if (keyBits[level]) {
+ rtOld = hash0(oldSibling, rtOld);
+ } else {
+ rtOld = hash0(rtOld, oldSibling);
+ }
+ dels.push(rtOld);
+ if (!F.isZero(newSibling)) {
+ mixed = true;
+ }
+
+ if (mixed) {
+ res.siblings.unshift(resFind.siblings[level]);
+ let newNode;
+ if (keyBits[level]) {
+ newNode = [newSibling, rtNew];
+ } else {
+ newNode = [rtNew, newSibling];
+ }
+ rtNew = hash0(newNode[0], newNode[1]);
+ ins.push([rtNew, newNode]);
+ }
+ }
+
+ await this.db.multiIns(ins);
+ await this.db.setRoot(rtNew);
+ this.root = rtNew;
+ await this.db.multiDel(dels);
+
+ res.newRoot = rtNew;
+ res.oldRoot = rtOld;
+
+ return res;
+ }
+
+ async insert(_key, _value) {
+ const key = Scalar.e(_key);
+ const value = F.e(_value);
+ let addedOne = false;
+ const res = {};
+ res.oldRoot = this.root;
+ const newKeyBits = this._splitBits(key);
+
+ let rtOld;
+
+ const resFind = await this.find(key);
+
+ if (resFind.found) throw new Error("Key already exists");
+
+ res.siblings = resFind.siblings;
+ let mixed;
+
+ if (!resFind.isOld0) {
+ const oldKeyits = this._splitBits(resFind.notFoundKey);
+ for (let i= res.siblings.length; oldKeyits[i] == newKeyBits[i]; i++) {
+ res.siblings.push(F.zero);
+ }
+ rtOld = hash1(resFind.notFoundKey, resFind.notFoundValue);
+ res.siblings.push(rtOld);
+ addedOne = true;
+ mixed = false;
+ } else if (res.siblings.length >0) {
+ mixed = true;
+ rtOld = F.zero;
+ }
+
+ const inserts = [];
+ const dels = [];
+
+ let rt = hash1(key, value);
+ inserts.push([rt,[1, key, value]] );
+
+ for (let i=res.siblings.length-1; i>=0; i--) {
+ if ((i0) && (F.isZero(res.siblings[res.siblings.length-1]))) {
+ res.siblings.pop();
+ }
+ res.oldKey = resFind.notFoundKey;
+ res.oldValue = resFind.notFoundValue;
+ res.newRoot = rt;
+ res.isOld0 = resFind.isOld0;
+
+
+ await this.db.multiIns(inserts);
+ await this.db.setRoot(rt);
+ this.root = rt;
+ await this.db.multiDel(dels);
+
+ return res;
+ }
+
+ async find(key) {
+ const keyBits = this._splitBits(key);
+ return await this._find(key, keyBits, this.root, 0);
+ }
+
+ async _find(key, keyBits, root, level) {
+ if (typeof root === "undefined") root = this.root;
+
+ let res;
+ if (F.isZero(root)) {
+ res = {
+ found: false,
+ siblings: [],
+ notFoundKey: key,
+ notFoundValue: F.zero,
+ isOld0: true
+ };
+ return res;
+ }
+
+ const record = await this.db.get(root);
+
+ if ((record.length==3)&&(F.eq(record[0],F.one))) {
+ if (F.eq(record[1],key)) {
+ res = {
+ found: true,
+ siblings: [],
+ foundValue: record[2],
+ isOld0: false
+ };
+ } else {
+ res = {
+ found: false,
+ siblings: [],
+ notFoundKey: record[1],
+ notFoundValue: record[2],
+ isOld0: false
+ };
+ }
+ } else {
+ if (keyBits[level] == 0) {
+ res = await this._find(key, keyBits, record[0], level+1);
+ res.siblings.unshift(record[1]);
+ } else {
+ res = await this._find(key, keyBits, record[1], level+1);
+ res.siblings.unshift(record[0]);
+ }
+ }
+ return res;
+ }
+}
+
+async function loadFromFile(fileName) {
+
+}
+
+async function newMemEmptyTrie() {
+ const db = new SMTMemDB();
+ const rt = await db.getRoot();
+ const smt = new SMT(db, rt);
+ return smt;
+}
+
+module.exports.loadFromFile = loadFromFile;
+module.exports.newMemEmptyTrie = newMemEmptyTrie;
+module.exports.SMT = SMT;
+module.exports.SMTMemDB = SMTMemDB;
diff --git a/test/modules/src/smt_hashes_mimc.js b/test/modules/src/smt_hashes_mimc.js
new file mode 100644
index 0000000..1cc2921
--- /dev/null
+++ b/test/modules/src/smt_hashes_mimc.js
@@ -0,0 +1,12 @@
+const mimc7 = require("./mimc7");
+const bigInt = require("big-integer");
+
+exports.hash0 = function (left, right) {
+ return mimc7.multiHash(left, right);
+};
+
+exports.hash1 = function(key, value) {
+ return mimc7.multiHash([key, value], bigInt.one);
+};
+
+exports.F = mimc7.F;
diff --git a/test/modules/src/smt_hashes_poseidon.js b/test/modules/src/smt_hashes_poseidon.js
new file mode 100644
index 0000000..0077f27
--- /dev/null
+++ b/test/modules/src/smt_hashes_poseidon.js
@@ -0,0 +1,18 @@
+
+const ZqField = require("ffjavascript").ZqField;
+const Scalar = require("ffjavascript").Scalar;
+
+const poseidon = require("./poseidon");
+
+const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
+
+
+exports.hash0 = function (left, right) {
+ return poseidon([left, right]);
+};
+
+exports.hash1 = function(key, value) {
+ return poseidon([key, value, F.one]);
+};
+
+exports.F = F;
diff --git a/test/modules/src/smt_memdb.js b/test/modules/src/smt_memdb.js
new file mode 100644
index 0000000..fbd2068
--- /dev/null
+++ b/test/modules/src/smt_memdb.js
@@ -0,0 +1,63 @@
+
+const Scalar = require("ffjavascript").Scalar;
+const ZqField = require("ffjavascript").ZqField;
+
+// Prime 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
+const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
+
+class SMTMemDb {
+ constructor() {
+ this.nodes = {};
+ this.root = F.zero;
+ }
+
+ async getRoot() {
+ return this.root;
+ }
+
+ _key2str(k) {
+ // const keyS = bigInt(key).leInt2Buff(32).toString("hex");
+ const keyS = k.toString();
+ return keyS;
+ }
+
+ _normalize(n) {
+ for (let i=0; i