move imports to @zk-email and circomlib

This commit is contained in:
turnoffthiscomputer
2024-12-28 19:51:57 +01:00
parent 89b533d6a7
commit 0918928cf0
65 changed files with 81 additions and 3410 deletions

View File

@@ -1,14 +1,14 @@
pragma circom 2.1.9;
include "../utils/circomlib/bitify/bitify.circom";
include "circomlib/circuits/bitify.circom";
include "../utils/circomlib/hasher/shaBytes/shaBytesDynamic.circom";
include "../utils/circomlib/bitify/comparators.circom";
include "circomlib/circuits/comparators.circom";
include "../utils/circomlib/hasher/hash.circom";
include "../utils/circomlib/merkle-trees/binary-merkle-root.circom";
include "../utils/passport/customHashers.circom";
include "../utils/passport/signatureAlgorithm.circom";
include "../utils/passport/signatureVerifier.circom";
include "../utils/circomlib/utils/bytes.circom";
include "@zk-email/circuits/utils/bytes.circom";
template OPENPASSPORT_DSC(signatureAlgorithm, n_dsc, k_dsc, n_csca, k_csca, max_cert_bytes, dscPubkeyBytesLength, nLevels) {

View File

@@ -9,6 +9,7 @@ include "../utils/passport/passportVerifier.circom";
include "../utils/passport/disclose/disclose.circom";
include "../utils/passport/disclose/proveCountryIsNotInList.circom";
include "../utils/passport/ofac/ofac_name.circom";
//include "@zk-email/circuits/utils/bytes.circom";
template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN, FORBIDDEN_COUNTRIES_LIST_LENGTH) {
var kLengthFactor = getKLengthFactor(signatureAlgorithm);

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.6;
include "../bitify/comparators.circom";
include "../bitify/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "./bigIntFunc.circom";
include "./bigIntOverflow.circom";
include "../int/arithmetic.circom";

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.6;
include "../bitify/comparators.circom";
include "../bitify/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "./bigInt.circom";
include "./bigIntFunc.circom";
include "../int/arithmetic.circom";

View File

@@ -1,50 +0,0 @@
pragma circom 2.1.6;
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
template Num2Bits(n) {
signal input in;
signal output out[n];
var lc1=0;
var e2=1;
for (var i = 0; i<n; i++) {
out[i] <-- (in >> i) & 1;
out[i] * (out[i] -1 ) === 0;
lc1 += out[i] * e2;
e2 = e2+e2;
}
lc1 === in;
}
template Bits2Num(n) {
signal input in[n];
signal output out;
var lc1=0;
var e2 = 1;
for (var i = 0; i<n; i++) {
lc1 += in[i] * e2;
e2 = e2 + e2;
}
lc1 ==> out;
}

View File

@@ -1,142 +0,0 @@
pragma circom 2.1.6;
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
include "bitify.circom";
template IsZero() {
signal input in;
signal output out;
signal inv;
inv <-- in!=0 ? 1/in : 0;
out <== -in*inv +1;
in*out === 0;
}
template IsEqual() {
signal input in[2];
signal output out;
component isz = IsZero();
in[1] - in[0] ==> isz.in;
isz.out ==> out;
}
template ForceEqualIfEnabled() {
signal input enabled;
signal input in[2];
component isz = IsZero();
in[1] - in[0] ==> isz.in;
(1 - isz.out)*enabled === 0;
}
/*
// N is the number of bits the input have.
// The MSF is the sign bit.
template LessThan(n) {
signal input in[2];
signal output out;
component num2Bits0;
component num2Bits1;
component adder;
adder = BinSum(n, 2);
num2Bits0 = Num2Bits(n);
num2Bits1 = Num2BitsNeg(n);
in[0] ==> num2Bits0.in;
in[1] ==> num2Bits1.in;
var i;
for (i=0;i<n;i++) {
num2Bits0.out[i] ==> adder.in[0][i];
num2Bits1.out[i] ==> adder.in[1][i];
}
adder.out[n-1] ==> out;
}
*/
template LessThan(n) {
assert(n <= 252);
signal input in[2];
signal output out;
component n2b = Num2Bits(n+1);
n2b.in <== in[0]+ (1<<n) - in[1];
out <== 1-n2b.out[n];
}
// N is the number of bits the input have.
// The MSF is the sign bit.
template LessEqThan(n) {
signal input in[2];
signal output out;
component lt = LessThan(n);
lt.in[0] <== in[0];
lt.in[1] <== in[1]+1;
lt.out ==> out;
}
// N is the number of bits the input have.
// The MSF is the sign bit.
template GreaterThan(n) {
signal input in[2];
signal output out;
component lt = LessThan(n);
lt.in[0] <== in[1];
lt.in[1] <== in[0];
lt.out ==> out;
}
// N is the number of bits the input have.
// The MSF is the sign bit.
template GreaterEqThan(n) {
signal input in[2];
signal output out;
component lt = LessThan(n);
lt.in[0] <== in[1];
lt.in[1] <== in[0]+1;
lt.out ==> out;
}

View File

@@ -1,101 +1,6 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
template XOR() {
signal input a;
signal input b;
signal output out;
out <== a + b - 2*a*b;
}
template AND() {
signal input a;
signal input b;
signal output out;
out <== a*b;
}
template OR() {
signal input a;
signal input b;
signal output out;
out <== a + b - a*b;
}
template NOT() {
signal input in;
signal output out;
out <== 1 + in - 2*in;
}
template NAND() {
signal input a;
signal input b;
signal output out;
out <== 1 - a*b;
}
template NOR() {
signal input a;
signal input b;
signal output out;
out <== a*b + 1 - a - b;
}
template MultiAND(n) {
signal input in[n];
signal output out;
component and1;
component and2;
component ands[2];
if (n==1) {
out <== in[0];
} else if (n==2) {
and1 = AND();
and1.a <== in[0];
and1.b <== in[1];
out <== and1.out;
} else {
and2 = AND();
var n1 = n\2;
var n2 = n-n\2;
ands[0] = MultiAND(n1);
ands[1] = MultiAND(n2);
var i;
for (i=0; i<n1; i++) ands[0].in[i] <== in[i];
for (i=0; i<n2; i++) ands[1].in[i] <== in[n1+i];
and2.a <== ands[0].out;
and2.b <== ands[1].out;
out <== and2.out;
}
}
// * Beginning of the UNAUDITED section *
include "circomlib/circuits/gates.circom";
// Xor for n pairs
@@ -108,5 +13,3 @@ template Xor2(n) {
out[k] <== in1[k] + in2[k] - 2 * in1[k] * in2[k];
}
}
// * End of the UNAUDITED section *

View File

@@ -1,12 +1,12 @@
pragma circom 2.1.6;
include "./bitify.circom";
include "circomlib/circuits/bitify.circom";
//------------------------------------------------------------------------------
// calculate bin sum of NUM numbers each LEN BITS
// out is LEN + NUM - 1 LEN bit number
template BinSum(NUM, LEN){
template BinSum_sha1(NUM, LEN){
assert (LEN + NUM - 1 <= 253);
var OUT_LEN = LEN + NUM - 1;
signal input in[NUM][LEN];

View File

@@ -7,8 +7,8 @@ include "./powers/brainpoolP256r1pows.circom";
include "./powers/brainpoolP384r1pows.circom";
include "./powers/p256pows.circom";
include "./powers/p384pows.circom";
include "../bitify/bitify.circom";
include "../bitify/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "../int/arithmetic.circom";
include "./get.circom";

View File

@@ -1,8 +1,8 @@
pragma circom 2.1.6;
include "../../bitify/bitify.circom";
include "circomlib/circuits/bitify.circom";
template H(x) {
template H_sha1(x) {
signal output out[32];
var c[5] = [
0x67452301,
@@ -20,7 +20,7 @@ template H(x) {
}
}
template K(t) {
template K_sha1(t) {
signal output out[32];
var k[4] = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];

View File

@@ -11,11 +11,11 @@ template Sha1HashChunks(BLOCK_NUM) {
var i;
var k;
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component ha0 = H_sha1(0);
component hb0 = H_sha1(1);
component hc0 = H_sha1(2);
component hd0 = H_sha1(3);
component he0 = H_sha1(4);
component sha1Compression[BLOCK_NUM];
@@ -64,11 +64,11 @@ template Sha1HashBits(LEN) {
var i;
var k;
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component ha0 = H_sha1(0);
component hb0 = H_sha1(1);
component hc0 = H_sha1(2);
component hd0 = H_sha1(3);
component he0 = H_sha1(4);
component sha1Compression[BLOCK_NUM];

View File

@@ -37,7 +37,7 @@ template Sha1compression() {
component kT[80];
for (i = 0; i <= 79; i++){
kT[i] = K(i);
kT[i] = K_sha1(i);
}
component tTmp[80];
@@ -48,7 +48,7 @@ template Sha1compression() {
component fSum[5];
for (i = 0; i < 5; i++){
fSum[i] = BinSum(2, 32);
fSum[i] = BinSum_sha1(2, 32);
}
for (var t = 0; t <= 15; t++) {

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.6;
include "./rotate.circom";
include "../../bitify/comparators.circom";
include "circomlib/circuits/comparators.circom";
include "./f.circom";
include "./constants.circom";
include "../../int/arithmetic.circom";
@@ -29,7 +29,7 @@ template T(t) {
f.d[k] <== d[k];
}
component sumBinary = BinSum(5, 32);
component sumBinary = BinSum_sha1(5, 32);
var nout = 35;
for (k = 0; k < 32; k++) {

View File

@@ -1,101 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
/*
Binary Sum
==========
This component creates a binary sum componet of ops operands and n bits each operand.
e is Number of carries: Depends on the number of operands in the input.
Main Constraint:
in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1) +
+ in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1) +
+ ..
+ in[ops-1][0] * 2^0 + in[ops-1][1] * 2^1 + ..... + in[ops-1][n-1] * 2^(n-1) +
===
out[0] * 2^0 + out[1] * 2^1 + + out[n+e-1] *2(n+e-1)
To waranty binary outputs:
out[0] * (out[0] - 1) === 0
out[1] * (out[0] - 1) === 0
.
.
.
out[n+e-1] * (out[n+e-1] - 1) == 0
*/
/*
This function calculates the number of extra bits in the output to do the full sum.
*/
pragma circom 2.0.0;
function nbits(a) {
var n = 1;
var r = 0;
while (n-1<a) {
r++;
n *= 2;
}
return r;
}
template BinSum_circomlib(n, ops) {
var nout = nbits((2**n -1)*ops);
signal input in[ops][n];
signal output out[nout];
var lin = 0;
var lout = 0;
var k;
var j;
var e2;
e2 = 1;
for (k=0; k<n; k++) {
for (j=0; j<ops; j++) {
lin += in[j][k] * e2;
}
e2 = e2 + e2;
}
e2 = 1;
for (k=0; k<nout; k++) {
out[k] <-- (lin >> k) & 1;
// Ensure out is binary
out[k] * (out[k] - 1) === 0;
lout += out[k] * e2;
e2 = e2+e2;
}
// Ensure the sum;
lin === lout;
}

View File

@@ -1,47 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
/* Ch
000 0
001 1
010 0
011 1
100 0
101 0
110 1
111 1
out = a&b ^ (!a)&c =>
out = a*(b-c) + c
*/
pragma circom 2.0.0;
template Ch_t(n) {
signal input a[n];
signal input b[n];
signal input c[n];
signal output out[n];
for (var k=0; k<n; k++) {
out[k] <== a[k] * (b[k]-c[k]) + c[k];
}
}

View File

@@ -1,53 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
template H_sha256(x) {
signal output out[32];
var c[8] = [0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19];
for (var i=0; i<32; i++) {
out[i] <== (c[x] >> i) & 1;
}
}
template K_sha256(x) {
signal output out[32];
var c[64] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
for (var i=0; i<32; i++) {
out[i] <== (c[x] >> i) & 1;
}
}

View File

@@ -1,45 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
/* Maj function for sha256
out = a&b ^ a&c ^ b&c =>
out = a*b + a*c + b*c - 2*a*b*c =>
out = a*( b + c - 2*b*c ) + b*c =>
mid = b*c
out = a*( b + c - 2*mid ) + mid
*/
pragma circom 2.0.0;
template Maj_t(n) {
signal input a[n];
signal input b[n];
signal input c[n];
signal output out[n];
signal mid[n];
for (var k=0; k<n; k++) {
mid[k] <== b[k]*c[k];
out[k] <== a[k] * (b[k]+c[k]-2*mid[k]) + mid[k];
}
}

View File

@@ -1,28 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
template RotR(n, r) {
signal input in[n];
signal output out[n];
for (var i=0; i<n; i++) {
out[i] <== in[ (i+r)%n ];
}
}

View File

@@ -1,166 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
include "constants.circom";
include "t1.circom";
include "t2.circom";
include "./binsum.circom";
include "sigmaplus.circom";
include "sha256compression_function.circom";
template Sha256compression() {
signal input hin[256];
signal input inp[512];
signal output out[256];
signal a[65][32];
signal b[65][32];
signal c[65][32];
signal d[65][32];
signal e[65][32];
signal f[65][32];
signal g[65][32];
signal h[65][32];
signal w[64][32];
var outCalc[256] = sha256compression(hin, inp);
var i;
for (i=0; i<256; i++) out[i] <-- outCalc[i];
component sigmaPlus[48];
for (i=0; i<48; i++) sigmaPlus[i] = SigmaPlus();
component ct_k[64];
for (i=0; i<64; i++) ct_k[i] = K_sha256(i);
component t1[64];
for (i=0; i<64; i++) t1[i] = T1();
component t2[64];
for (i=0; i<64; i++) t2[i] = T2();
component suma[64];
for (i=0; i<64; i++) suma[i] = BinSum_circomlib(32, 2);
component sume[64];
for (i=0; i<64; i++) sume[i] = BinSum_circomlib(32, 2);
component fsum[8];
for (i=0; i<8; i++) fsum[i] = BinSum_circomlib(32, 2);
var k;
var t;
for (t=0; t<64; t++) {
if (t<16) {
for (k=0; k<32; k++) {
w[t][k] <== inp[t*32+31-k];
}
} else {
for (k=0; k<32; k++) {
sigmaPlus[t-16].in2[k] <== w[t-2][k];
sigmaPlus[t-16].in7[k] <== w[t-7][k];
sigmaPlus[t-16].in15[k] <== w[t-15][k];
sigmaPlus[t-16].in16[k] <== w[t-16][k];
}
for (k=0; k<32; k++) {
w[t][k] <== sigmaPlus[t-16].out[k];
}
}
}
for (k=0; k<32; k++ ) {
a[0][k] <== hin[k];
b[0][k] <== hin[32*1 + k];
c[0][k] <== hin[32*2 + k];
d[0][k] <== hin[32*3 + k];
e[0][k] <== hin[32*4 + k];
f[0][k] <== hin[32*5 + k];
g[0][k] <== hin[32*6 + k];
h[0][k] <== hin[32*7 + k];
}
for (t = 0; t<64; t++) {
for (k=0; k<32; k++) {
t1[t].h[k] <== h[t][k];
t1[t].e[k] <== e[t][k];
t1[t].f[k] <== f[t][k];
t1[t].g[k] <== g[t][k];
t1[t].k[k] <== ct_k[t].out[k];
t1[t].w[k] <== w[t][k];
t2[t].a[k] <== a[t][k];
t2[t].b[k] <== b[t][k];
t2[t].c[k] <== c[t][k];
}
for (k=0; k<32; k++) {
sume[t].in[0][k] <== d[t][k];
sume[t].in[1][k] <== t1[t].out[k];
suma[t].in[0][k] <== t1[t].out[k];
suma[t].in[1][k] <== t2[t].out[k];
}
for (k=0; k<32; k++) {
h[t+1][k] <== g[t][k];
g[t+1][k] <== f[t][k];
f[t+1][k] <== e[t][k];
e[t+1][k] <== sume[t].out[k];
d[t+1][k] <== c[t][k];
c[t+1][k] <== b[t][k];
b[t+1][k] <== a[t][k];
a[t+1][k] <== suma[t].out[k];
}
}
for (k=0; k<32; k++) {
fsum[0].in[0][k] <== hin[32*0+k];
fsum[0].in[1][k] <== a[64][k];
fsum[1].in[0][k] <== hin[32*1+k];
fsum[1].in[1][k] <== b[64][k];
fsum[2].in[0][k] <== hin[32*2+k];
fsum[2].in[1][k] <== c[64][k];
fsum[3].in[0][k] <== hin[32*3+k];
fsum[3].in[1][k] <== d[64][k];
fsum[4].in[0][k] <== hin[32*4+k];
fsum[4].in[1][k] <== e[64][k];
fsum[5].in[0][k] <== hin[32*5+k];
fsum[5].in[1][k] <== f[64][k];
fsum[6].in[0][k] <== hin[32*6+k];
fsum[6].in[1][k] <== g[64][k];
fsum[7].in[0][k] <== hin[32*7+k];
fsum[7].in[1][k] <== h[64][k];
}
for (k=0; k<32; k++) {
out[31-k] === fsum[0].out[k];
out[32+31-k] === fsum[1].out[k];
out[64+31-k] === fsum[2].out[k];
out[96+31-k] === fsum[3].out[k];
out[128+31-k] === fsum[4].out[k];
out[160+31-k] === fsum[5].out[k];
out[192+31-k] === fsum[6].out[k];
out[224+31-k] === fsum[7].out[k];
}
}

View File

@@ -1,112 +0,0 @@
// signal input hin[256];
// signal input inp[512];
// signal output out[256];
pragma circom 2.0.0;
function rrot(x, n) {
return ((x >> n) | (x << (32-n))) & 0xFFFFFFFF;
}
function bsigma0(x) {
return rrot(x,2) ^ rrot(x,13) ^ rrot(x,22);
}
function bsigma1(x) {
return rrot(x,6) ^ rrot(x,11) ^ rrot(x,25);
}
function ssigma0(x) {
return rrot(x,7) ^ rrot(x,18) ^ (x >> 3);
}
function ssigma1(x) {
return rrot(x,17) ^ rrot(x,19) ^ (x >> 10);
}
function Maj(x, y, z) {
return (x&y) ^ (x&z) ^ (y&z);
}
function Ch(x, y, z) {
return (x & y) ^ ((0xFFFFFFFF ^x) & z);
}
function sha256K(i) {
var k[64] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
return k[i];
}
function sha256compression(hin, inp) {
var H[8];
var a;
var b;
var c;
var d;
var e;
var f;
var g;
var h;
var out[256];
for (var i=0; i<8; i++) {
H[i] = 0;
for (var j=0; j<32; j++) {
H[i] += hin[i*32+j] << j;
}
}
a=H[0];
b=H[1];
c=H[2];
d=H[3];
e=H[4];
f=H[5];
g=H[6];
h=H[7];
var w[64];
var T1;
var T2;
for (var i=0; i<64; i++) {
if (i<16) {
w[i]=0;
for (var j=0; j<32; j++) {
w[i] += inp[i*32+31-j]<<j;
}
} else {
w[i] = (ssigma1(w[i-2]) + w[i-7] + ssigma0(w[i-15]) + w[i-16]) & 0xFFFFFFFF;
}
T1 = (h + bsigma1(e) + Ch(e,f,g) + sha256K(i) + w[i]) & 0xFFFFFFFF;
T2 = (bsigma0(a) + Maj(a,b,c)) & 0xFFFFFFFF;
h=g;
g=f;
f=e;
e=(d+T1) & 0xFFFFFFFF;
d=c;
c=b;
b=a;
a=(T1+T2) & 0xFFFFFFFF;
}
H[0] = H[0] + a;
H[1] = H[1] + b;
H[2] = H[2] + c;
H[3] = H[3] + d;
H[4] = H[4] + e;
H[5] = H[5] + f;
H[6] = H[6] + g;
H[7] = H[7] + h;
for (var i=0; i<8; i++) {
for (var j=0; j<32; j++) {
out[i*32+31-j] = (H[i] >> j) & 1;
}
}
return out;
}

View File

@@ -1,33 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
template ShR(n, r) {
signal input in[n];
signal output out[n];
for (var i=0; i<n; i++) {
if (i+r >= n) {
out[i] <== 0;
} else {
out[i] <== in[ i+r ];
}
}
}

View File

@@ -1,77 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
include "xor3.circom";
include "rotate.circom";
include "shift.circom";
template SmallSigma(ra, rb, rc) {
signal input in[32];
signal output out[32];
var k;
component rota = RotR(32, ra);
component rotb = RotR(32, rb);
component shrc = ShR(32, rc);
for (k=0; k<32; k++) {
rota.in[k] <== in[k];
rotb.in[k] <== in[k];
shrc.in[k] <== in[k];
}
component xor3 = Xor3(32);
for (k=0; k<32; k++) {
xor3.a[k] <== rota.out[k];
xor3.b[k] <== rotb.out[k];
xor3.c[k] <== shrc.out[k];
}
for (k=0; k<32; k++) {
out[k] <== xor3.out[k];
}
}
template BigSigma(ra, rb, rc) {
signal input in[32];
signal output out[32];
var k;
component rota = RotR(32, ra);
component rotb = RotR(32, rb);
component rotc = RotR(32, rc);
for (k=0; k<32; k++) {
rota.in[k] <== in[k];
rotb.in[k] <== in[k];
rotc.in[k] <== in[k];
}
component xor3 = Xor3(32);
for (k=0; k<32; k++) {
xor3.a[k] <== rota.out[k];
xor3.b[k] <== rotb.out[k];
xor3.c[k] <== rotc.out[k];
}
for (k=0; k<32; k++) {
out[k] <== xor3.out[k];
}
}

View File

@@ -1,50 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
include "./binsum.circom";
include "sigma.circom";
template SigmaPlus() {
signal input in2[32];
signal input in7[32];
signal input in15[32];
signal input in16[32];
signal output out[32];
var k;
component sigma1 = SmallSigma(17,19,10);
component sigma0 = SmallSigma(7, 18, 3);
for (k=0; k<32; k++) {
sigma1.in[k] <== in2[k];
sigma0.in[k] <== in15[k];
}
component sum = BinSum_circomlib(32, 4);
for (k=0; k<32; k++) {
sum.in[0][k] <== sigma1.out[k];
sum.in[1][k] <== in7[k];
sum.in[2][k] <== sigma0.out[k];
sum.in[3][k] <== in16[k];
}
for (k=0; k<32; k++) {
out[k] <== sum.out[k];
}
}

View File

@@ -1,58 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
include "./binsum.circom";
include "sigma.circom";
include "ch.circom";
template T1() {
signal input h[32];
signal input e[32];
signal input f[32];
signal input g[32];
signal input k[32];
signal input w[32];
signal output out[32];
var ki;
component ch = Ch_t(32);
component bigsigma1 = BigSigma(6, 11, 25);
for (ki=0; ki<32; ki++) {
bigsigma1.in[ki] <== e[ki];
ch.a[ki] <== e[ki];
ch.b[ki] <== f[ki];
ch.c[ki] <== g[ki];
}
component sum = BinSum_circomlib(32, 5);
for (ki=0; ki<32; ki++) {
sum.in[0][ki] <== h[ki];
sum.in[1][ki] <== bigsigma1.out[ki];
sum.in[2][ki] <== ch.out[ki];
sum.in[3][ki] <== k[ki];
sum.in[4][ki] <== w[ki];
}
for (ki=0; ki<32; ki++) {
out[ki] <== sum.out[ki];
}
}

View File

@@ -1,51 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
include "./binsum.circom";
include "sigma.circom";
include "maj.circom";
template T2() {
signal input a[32];
signal input b[32];
signal input c[32];
signal output out[32];
var k;
component bigsigma0 = BigSigma(2, 13, 22);
component maj = Maj_t(32);
for (k=0; k<32; k++) {
bigsigma0.in[k] <== a[k];
maj.a[k] <== a[k];
maj.b[k] <== b[k];
maj.c[k] <== c[k];
}
component sum = BinSum_circomlib(32, 2);
for (k=0; k<32; k++) {
sum.in[0][k] <== bigsigma0.out[k];
sum.in[1][k] <== maj.out[k];
}
for (k=0; k<32; k++) {
out[k] <== sum.out[k];
}
}

View File

@@ -1,45 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
/* Xor3 function for sha256
out = a ^ b ^ c =>
out = a+b+c - 2*a*b - 2*a*c - 2*b*c + 4*a*b*c =>
out = a*( 1 - 2*b - 2*c + 4*b*c ) + b + c - 2*b*c =>
mid = b*c
out = a*( 1 - 2*b -2*c + 4*mid ) + b + c - 2 * mid
*/
pragma circom 2.0.0;
template Xor3(n) {
signal input a[n];
signal input b[n];
signal input c[n];
signal output out[n];
signal mid[n];
for (var k=0; k<n; k++) {
mid[k] <== b[k]*c[k];
out[k] <== a[k] * (1 -2*b[k] -2*c[k] +4*mid[k]) + b[k] + c[k] -2*mid[k];
}
}

View File

@@ -2,8 +2,8 @@ pragma circom 2.1.5;
include "../../sha1/sha1compression.circom";
include "../../sha1/constants.circom";
include "../../../bitify/bitify.circom";
include "../../../utils/array.circom";
include "@zk-email/circuits/utils/array.circom";
include "circomlib/circuits/bitify.circom";
//Adapted from @zk-email/circuits/helpers/sha.circom
template Sha1Bytes(max_num_bytes) {
@@ -59,11 +59,11 @@ template Sha1General(maxBitsPadded) {
bitLengthVerifier.in[1] <== maxBitsPadded;
bitLengthVerifier.out === 1;
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component ha0 = H_sha1(0);
component hb0 = H_sha1(1);
component hc0 = H_sha1(2);
component hd0 = H_sha1(3);
component he0 = H_sha1(4);
component sha1compression[maxBlocks];

View File

@@ -1,159 +0,0 @@
pragma circom 2.1.9;
include "../../sha2/sha256_temp/constants.circom";
include "../../sha2/sha256_temp/sha256compression.circom";
include "../../../bitify/comparators.circom";
include "../../../bitify/bitify.circom";
include "../../../utils/array.circom";
/// @title Sha256Bytes
/// @notice Computes the SHA256 hash of input bytes
/// @input paddedIn Message to hash, padded as per the SHA256 specification; assumes to consist of bytes
/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(8 * maxByteLength))` bits
/// @output out The 256-bit hash of the input message
template Sha256Bytes(maxByteLength) {
signal input paddedIn[maxByteLength];
signal input paddedInLength;
signal output out[256];
var maxBits = maxByteLength * 8;
component sha = Sha256General(maxBits);
component bytes[maxByteLength];
for (var i = 0; i < maxByteLength; i++) {
bytes[i] = Num2Bits(8);
bytes[i].in <== paddedIn[i];
for (var j = 0; j < 8; j++) {
sha.paddedIn[i*8+j] <== bytes[i].out[7-j];
}
}
sha.paddedInLength <== paddedInLength * 8;
for (var i = 0; i < 256; i++) {
out[i] <== sha.out[i];
}
}
/// @title Sha256General
/// @notice A modified version of the SHA256 circuit that allows specified length messages up to a
/// max to all work via array indexing on the SHA256 compression circuit.
/// @input paddedIn Message to hash padded as per the SHA256 specification; assumes to consist of bits
/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(maxBitLength))` bits
/// @output out The 256-bit hash of the input message
template Sha256General(maxBitLength) {
// maxBitLength must be a multiple of 512
// the bit circuits in this file are limited to 15 so must be raised if the message is longer.
assert(maxBitLength % 512 == 0);
var maxBitsPaddedBits = log2Ceil(maxBitLength);
// Note that maxBitLength = maxBits + 64
signal input paddedIn[maxBitLength];
signal input paddedInLength;
signal output out[256];
signal inBlockIndex;
var i;
var k;
var j;
var maxBlocks;
var bitsLastBlock;
maxBlocks = (maxBitLength\512);
inBlockIndex <-- (paddedInLength >> 9);
paddedInLength === inBlockIndex * 512;
// These verify the unconstrained floor calculation is the uniquely correct integer that represents the floor
// component floorVerifierUnder = LessEqThan(maxBitsPaddedBits); // todo verify the length passed in is less than nbits. note that maxBitsPaddedBits can likely be lowered or made it a fn of maxbits
// floorVerifierUnder.in[0] <== (inBlockIndex)*512;
// floorVerifierUnder.in[1] <== paddedInLength;
// floorVerifierUnder.out === 1;
// component floorVerifierOver = GreaterThan(maxBitsPaddedBits);
// floorVerifierOver.in[0] <== (inBlockIndex+1)*512;
// floorVerifierOver.in[1] <== paddedInLength;
// floorVerifierOver.out === 1;
// These verify we pass in a valid number of bits to the SHA256 compression circuit.
component bitLengthVerifier = LessEqThan(maxBitsPaddedBits); // todo verify the length passed in is less than nbits. note that maxBitsPaddedBits can likely be lowered or made it a fn of maxbits
bitLengthVerifier.in[0] <== paddedInLength;
bitLengthVerifier.in[1] <== maxBitLength;
bitLengthVerifier.out === 1;
// Note that we can no longer do padded verification efficiently inside the SHA because it requires non deterministic array indexing.
// We can do it if we add a constraint, but since guessing a valid SHA2 preimage is hard anyways, we'll just do it outside the circuit.
// signal paddedIn[maxBlocks*512];
// for (k=0; k<maxBits; k++) {
// paddedIn[k] <== in[k];
// }
// paddedIn[maxBits] <== 1;
// for (k=maxBits+1; k<maxBlocks*512-64; k++) {
// paddedIn[k] <== 0;
// }
// for (k = 0; k< 64; k++) {
// paddedIn[maxBlocks*512 - k -1] <== (maxBits >> k)&1;
// }
component ha0 = H_sha256(0);
component hb0 = H_sha256(1);
component hc0 = H_sha256(2);
component hd0 = H_sha256(3);
component he0 = H_sha256(4);
component hf0 = H_sha256(5);
component hg0 = H_sha256(6);
component hh0 = H_sha256(7);
component sha256compression[maxBlocks];
for (i=0; i<maxBlocks; i++) {
sha256compression[i] = Sha256compression() ;
if (i==0) {
for (k=0; k<32; k++ ) {
sha256compression[i].hin[0*32+k] <== ha0.out[k];
sha256compression[i].hin[1*32+k] <== hb0.out[k];
sha256compression[i].hin[2*32+k] <== hc0.out[k];
sha256compression[i].hin[3*32+k] <== hd0.out[k];
sha256compression[i].hin[4*32+k] <== he0.out[k];
sha256compression[i].hin[5*32+k] <== hf0.out[k];
sha256compression[i].hin[6*32+k] <== hg0.out[k];
sha256compression[i].hin[7*32+k] <== hh0.out[k];
}
} else {
for (k=0; k<32; k++ ) {
sha256compression[i].hin[32*0+k] <== sha256compression[i-1].out[32*0+31-k];
sha256compression[i].hin[32*1+k] <== sha256compression[i-1].out[32*1+31-k];
sha256compression[i].hin[32*2+k] <== sha256compression[i-1].out[32*2+31-k];
sha256compression[i].hin[32*3+k] <== sha256compression[i-1].out[32*3+31-k];
sha256compression[i].hin[32*4+k] <== sha256compression[i-1].out[32*4+31-k];
sha256compression[i].hin[32*5+k] <== sha256compression[i-1].out[32*5+31-k];
sha256compression[i].hin[32*6+k] <== sha256compression[i-1].out[32*6+31-k];
sha256compression[i].hin[32*7+k] <== sha256compression[i-1].out[32*7+31-k];
}
}
for (k=0; k<512; k++) {
sha256compression[i].inp[k] <== paddedIn[i*512+k];
}
}
// Select the correct compression output for the given length, instead of just the last one.
component arraySelectors[256];
for (k=0; k<256; k++) {
arraySelectors[k] = ItemAtIndex(maxBlocks);
for (j=0; j<maxBlocks; j++) {
arraySelectors[k].in[j] <== sha256compression[j].out[k];
}
arraySelectors[k].index <== inBlockIndex - 1; // The index is 0 indexed and the block numbers are 1 indexed.
out[k] <== arraySelectors[k].out;
}
// for (k=0; k<256; k++) {
// out[k] <== sha256compression[maxBlocks-1].out[k];
// }
}

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.9;
include "../../../bitify/bitify.circom";
include "../../../bitify/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/bitify.circom";
include "../../other/fp.circom";
include "../../other/array.circom";
include "../../sha2/sha384/sha384_hash_bits.circom";

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.9;
include "../../../bitify/bitify.circom";
include "../../../bitify/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/bitify.circom";
include "../../other/fp.circom";
include "../../other/array.circom";
include "../../sha2/sha512/sha512_hash_bits.circom";

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.9;
include "./dynamic/sha1Bytes.circom";
include "./dynamic/sha256Bytes.circom";
include "@zk-email/circuits/lib/sha.circom";
// include "./dynamic/sha384Bytes.circom";
// include "./dynamic/sha512Bytes.circom";

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.6;
include "../bitify/comparators.circom";
include "../bitify/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
// Some templates for num operations

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.6;
include "../../circomlib/hasher/hash.circom";
include "../../circomlib/bitify/comparators.circom";
include "circomlib/circuits/comparators.circom";
include "../../circomlib/mux/mux1.circom";
// This circuit is designed to calculate the root of a binary Merkle

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.9;
include "../bitify/comparators.circom";
include "../bitify/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
// Computes the first n common bits of the hashes
template CommonBitsLengthFromEnd() {

View File

@@ -1,9 +1,9 @@
pragma circom 2.1.9;
include "../hasher/hash.circom";
include "../bitify/comparators.circom";
include "../bitify/bitify.circom";
include "../utils/array.circom";
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "@zk-email/circuits/utils/array.circom";
include "binary-merkle-root.circom";
include "getCommonLength.circom";

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../bitify/bitify.circom";
include "circomlib/circuits/bitify.circom";
// PKCS1v1.5 Padding Scheme
// 0x00 || 0x01 || PS || 0x00 || OID || Hash

View File

@@ -1,8 +1,8 @@
pragma circom 2.1.9;
include "../../../zkemail/lib/fp.circom";
include "@zk-email/circuits/lib/fp.circom";
include "./pkcs1v1_5Padding.circom";
include "../../bitify/bitify.circom";
include "circomlib/circuits/bitify.circom";
// For 2048bits RSA, CHUNK_SIZE = 64, CHUNK_NUMBER = 32
// For 3072bits RSA, CHUNK_SIZE = 64, CHUNK_NUMBER = 48

View File

@@ -1,8 +1,8 @@
pragma circom 2.1.9;
include "../../../zkemail/lib/fp.circom";
include "@zk-email/circuits/lib/fp.circom";
include "./pkcs1v1_5Padding.circom";
include "../../bitify/bitify.circom";
include "circomlib/circuits/bitify.circom";
// For 2048bits RSA, CHUNK_SIZE = 64, CHUNK_NUMBER = 32
// For 3072bits RSA, CHUNK_SIZE = 64, CHUNK_NUMBER = 48

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.6;
include "../../bitify/bitify.circom";
include "circomlib/circuits/bitify.circom";
template Mgf1Sha384(SEED_LEN, MASK_LEN) { //in bytes
var SEED_LEN_BITS = SEED_LEN * 8;

View File

@@ -1,254 +0,0 @@
pragma circom 2.1.6;
include "../bitify/bitify.circom";
include "../bitify/comparators.circom";
include "./functions.circom";
/// @title ItemAtIndex
/// @notice Select item at given index from the input array
/// @notice This template that the index is valid
/// @notice This is a modified version of QuinSelector from MACI https://github.com/privacy-scaling-explorations/maci/
/// @param maxArrayLen The number of elements in the array
/// @input in The input array
/// @input index The index of the element to select
/// @output out The selected element
template ItemAtIndex(maxArrayLen) {
signal input in[maxArrayLen];
signal input index;
signal output out;
component calcTotalValue = CalculateTotal(maxArrayLen);
component calcTotalIndex = CalculateTotal(maxArrayLen);
component eqs[maxArrayLen];
// For each item, check whether its index equals the input index.
for (var i = 0; i < maxArrayLen; i ++) {
eqs[i] = IsEqual();
eqs[i].in[0] <== i;
eqs[i].in[1] <== index;
// eqs[i].out is 1 if the index matches - so calcTotal is sum of 0s + 1 * valueAtIndex
calcTotalValue.nums[i] <== eqs[i].out * in[i];
// Take the sum of all eqs[i].out and assert that it is at most 1.
calcTotalIndex.nums[i] <== eqs[i].out;
}
// Assert that the sum of eqs[i].out is 1. This is to ensure the index passed is valid.
calcTotalIndex.sum === 1;
out <== calcTotalValue.sum;
}
/// @title CalculateTotal
/// @notice Calculate the sum of an array
/// @param n The number of elements in the array
/// @input nums The input array; assumes elements are small enough that their sum does not overflow the field
/// @output sum The sum of the input array
template CalculateTotal(n) {
signal input nums[n];
signal output sum;
signal sums[n];
sums[0] <== nums[0];
for (var i=1; i < n; i++) {
sums[i] <== sums[i - 1] + nums[i];
}
sum <== sums[n - 1];
}
/// @title SelectSubArray
/// @notice Select sub array from an array given a `startIndex` and `length`
/// @notice This is same as `VarShiftLeft` but with elements after `length` set to zero
/// @notice This is not used in core ZK-Email circuits at the moment
/// @param maxArrayLen: the maximum number of bytes in the input array
/// @param maxSubArrayLen: the maximum number of integers in the output array
/// @input in: the input array
/// @input startIndex: the start index of the sub array; assumes a valid index
/// @input length: the length of the sub array; assumes to fit in `ceil(log2(maxArrayLen))` bits
/// @output out: array of `maxSubArrayLen` size, items starting from `startIndex`, and items after `length` set to zero
template SelectSubArray(maxArrayLen, maxSubArrayLen) {
assert(maxSubArrayLen < maxArrayLen);
signal input in[maxArrayLen];
signal input startIndex;
signal input length;
signal output out[maxSubArrayLen];
component shifter = VarShiftLeft(maxArrayLen, maxSubArrayLen);
shifter.in <== in;
shifter.shift <== startIndex;
// Set value after length to zero
component gts[maxSubArrayLen];
for (var i = 0; i < maxSubArrayLen; i++) {
gts[i] = GreaterThan(log2Ceil(maxSubArrayLen));
gts[i].in[0] <== length;
gts[i].in[1] <== i;
out[i] <== gts[i].out * shifter.out[i];
}
}
/// @title VarShiftLeft
/// @notice Shift input array by `shift` indices to the left
/// @notice Output array length can be reduced by setting `maxOutArrayLen`
/// @notice Based on https://demo.hedgedoc.org/s/Le0R3xUhB
/// @param maxArrayLen The maximum length of the input array
/// @param maxOutArrayLen The maximum length of the output array
/// @input in The input array
/// @input shift The number of indices to shift the array to the left
/// @output out hifted subarray
template VarShiftLeft(maxArrayLen, maxOutArrayLen) {
assert(maxOutArrayLen <= maxArrayLen);
var bitLength = log2Ceil(maxArrayLen);
signal input in[maxArrayLen];
signal input shift;
signal output out[maxOutArrayLen];
component n2b = Num2Bits(bitLength);
n2b.in <== shift;
signal tmp[bitLength][maxArrayLen];
for (var j = 0; j < bitLength; j++) {
for (var i = 0; i < maxArrayLen; i++) {
var offset = (i + (1 << j)) % maxArrayLen;
// Shift left by 2^j indices if bit is 1
if (j == 0) {
tmp[j][i] <== n2b.out[j] * (in[offset] - in[i]) + in[i];
} else {
tmp[j][i] <== n2b.out[j] * (tmp[j-1][offset] - tmp[j-1][i]) + tmp[j-1][i];
}
}
}
// Return last row
for (var i = 0; i < maxOutArrayLen; i++) {
out[i] <== tmp[bitLength - 1][i];
}
}
/// @title AssertZeroPadding
/// @notice Assert that the input array is zero-padded from the given `startIndex`
/// @param maxArrayLen The maximum number of elements in the input array
/// @input in The input array;
/// @input startIndex The index from which the elements should be 0; assumes `startIndex - 1` to fit in `ceil(log2(maxArrayLen))` bits
template AssertZeroPadding(maxArrayLen) {
var bitLength = log2Ceil(maxArrayLen);
signal input in[maxArrayLen];
signal input startIndex;
component lessThans[maxArrayLen];
for (var i = 0; i < maxArrayLen; i++) {
lessThans[i] = LessThan(bitLength);
lessThans[i].in[0] <== startIndex - 1;
lessThans[i].in[1] <== i;
lessThans[i].out * in[i] === 0;
}
}
/// @title Slice
/// @notice Extract a fixed portion of an array
/// @dev Unlike SelectSubArray, Slice uses compile-time known indices and doesn't pad the output
/// @dev Slice is more efficient for fixed ranges, while SelectSubArray offers runtime flexibility
/// @param n The length of the input array
/// @param start The starting index of the slice (inclusive)
/// @param end The ending index of the slice (exclusive)
/// @input in The input array of length n
/// @output out The sliced array of length (end - start)
template Slice(n, start, end) {
assert(n >= end);
assert(start >= 0);
assert(end >= start);
signal input in[n];
signal output out[end - start];
for (var i = start; i < end; i++) {
out[i - start] <== in[i];
}
}
/// @title CheckSubstringMatch
/// @notice Check if a substring matches the input array
/// @param maxSubstringLen The maximum length of the substring
/// @input input The portion of the input array to check
/// @input substring The substring pattern to match
/// @output isMatch 1 if the substring matches, 0 otherwise
template CheckSubstringMatch(maxSubstringLen) {
signal input in[maxSubstringLen];
signal input substring[maxSubstringLen];
signal output isMatch;
// Ensure the first element of the pattern is non-zero
signal firstElementNonZero;
firstElementNonZero <== IsZero()(substring[0]);
firstElementNonZero === 0;
signal matchAccumulator[maxSubstringLen + 1];
signal difference[maxSubstringLen];
signal isZeroDifference[maxSubstringLen];
matchAccumulator[0] <== 1;
for (var i = 0; i < maxSubstringLen; i++) {
difference[i] <== (in[i] - substring[i]) * substring[i];
isZeroDifference[i] <== IsZero()(difference[i]);
matchAccumulator[i + 1] <== matchAccumulator[i] * isZeroDifference[i];
}
isMatch <== matchAccumulator[maxSubstringLen];
}
/// @title CountSubstringOccurrences
/// @notice Count the number of times a substring occurs in the input array
/// @param maxLen The maximum length of the input array
/// @param maxSubstringLen The maximum length of the substring
/// @input in The input array to search in
/// @input substring The substring to search for
/// @output count The number of occurrences of the substring in the input
template CountSubstringOccurrences(maxLen, maxSubstringLen) {
assert(maxLen >= maxSubstringLen);
signal input in[maxLen];
signal input substring[maxSubstringLen];
signal output count;
// Check for matches at each possible starting position
component matches[maxLen];
for (var i = 0; i < maxLen; i++) {
matches[i] = CheckSubstringMatch(maxSubstringLen);
for (var j = 0; j < maxSubstringLen; j++) {
if (i + j < maxLen) {
matches[i].in[j] <== in[i + j];
} else {
matches[i].in[j] <== 0;
}
}
matches[i].substring <== substring;
}
// Sum up all matches to get the total count
component summer = CalculateTotal(maxLen);
for (var i = 0; i < maxLen; i++) {
summer.nums[i] <== matches[i].isMatch;
}
count <== summer.sum;
}

View File

@@ -1,225 +0,0 @@
pragma circom 2.1.6;
include "../bitify/bitify.circom";
include "../bitify/comparators.circom";
include "./array.circom";
include "./constants.circom";
include "./functions.circom";
function computeIntChunkLength(byteLength) {
var packSize = MAX_BYTES_IN_FIELD();
var remain = byteLength % packSize;
var numChunks = (byteLength - remain) / packSize;
if (remain > 0) {
numChunks += 1;
}
return numChunks;
}
/// @title PackBytes
/// @notice Pack an array of bytes to numbers that fit in the field
/// @param maxBytes the maximum number of bytes in the input array
/// @input in the input byte array; assumes elements to be bytes
/// @output out the output integer array
template PackBytes(maxBytes) {
var packSize = MAX_BYTES_IN_FIELD();
var maxInts = computeIntChunkLength(maxBytes);
signal input in[maxBytes];
signal output out[maxInts];
signal intSums[maxInts][packSize];
for (var i = 0; i < maxInts; i++) {
for(var j=0; j < packSize; j++) {
var idx = packSize * i + j;
// Copy the previous value if we are out of bounds - we take last item as final result
if(idx >= maxBytes) {
intSums[i][j] <== intSums[i][j-1];
}
// First item of each chunk is the byte itself
else if (j == 0){
intSums[i][j] <== in[idx];
}
// Every other item is 256^j * byte
else {
intSums[i][j] <== intSums[i][j-1] + (1 << (8*j)) * in[idx];
}
}
}
// Last item of each chunk is the final sum
for (var i = 0; i < maxInts; i++) {
out[i] <== intSums[i][packSize-1];
}
}
/// @title PackByteSubArray
/// @notice Select sub array from the input array and pack it to numbers that fit in the field
/// @notice This is not used in ZK-Email circuits anywhere
/// @param maxArrayLen the maximum number of elements in the input array
/// @param maxSubArrayLen the maximum number of elements in the sub array
/// @input in the input byte array; assumes elements to be bytes
/// @input startIndex the start index of the sub array; assumes to be a valid index
/// @input length the length of the sub array; assumes to fit in `ceil(log2(maxSubArrayLen))` bits
/// @output out the output integer array
template PackByteSubArray(maxArrayLen, maxSubArrayLen) {
assert(maxSubArrayLen < maxArrayLen);
var chunkLength = computeIntChunkLength(maxSubArrayLen);
signal input in[maxArrayLen];
signal input startIndex;
signal input length;
signal output out[chunkLength];
component SelectSubArray = SelectSubArray(maxArrayLen, maxSubArrayLen);
SelectSubArray.in <== in;
SelectSubArray.startIndex <== startIndex;
SelectSubArray.length <== length;
component packer = PackBytes(maxSubArrayLen);
packer.in <== SelectSubArray.out;
out <== packer.out;
}
/// @title DigitBytesToInt
/// @notice Converts a byte array representing digits to an integer
/// @notice Assumes the output number fits in the field
/// @param n The number of bytes in the input array
/// @input in The input byte array; assumes elements are between 48 and 57 (ASCII numbers)
/// @output out The output integer; assumes to fit in the field
template DigitBytesToInt(n) {
signal input in[n];
signal output out;
signal sums[n+1];
sums[0] <== 0;
for(var i = 0; i < n; i++) {
sums[i + 1] <== 10 * sums[i] + (in[i] - 48);
}
out <== sums[n];
}
// NOTE: this circuit is unaudited and should not be used in production
/// @title SplitBytesToWords
/// @notice split an array of bytes into an array of words
/// @notice useful for casting a message or modulus before RSA verification
/// @param l: number of bytes in the input array
/// @param n: number of bits in a word
/// @param k: number of words
/// @input in: array of bytes
/// @output out: array of words
template SplitBytesToWords (l,n,k) {
signal input in[l];
signal output out[k];
component num2bits[l];
for (var i = 0 ; i < l ; i++){
num2bits[i] = Num2Bits(8);
num2bits[i].in <== in[i];
}
component bits2num[k];
for (var i = 0 ; i < k ; i++){
bits2num[i] = Bits2Num(n);
for(var j = 0 ; j < n ; j++){
if(i*n + j >= 8 * l){
bits2num[i].in[j] <== 0;
}
else{
bits2num[i].in[j] <== num2bits[l - (( i * n + j) \ 8) - 1].out[ ((i * n + j) % 8)];
}
}
}
for( var i = 0 ; i< k ; i++){
out[i] <== bits2num[i].out;
}
}
// Asserts that a given input is binary.
//
// Inputs:
// - in: an input signal, expected to be 0 or 1.
template AssertBit() {
signal input in;
in * (in - 1) === 0;
}
// The ByteMask template masks an input array using a binary mask array.
// Each element in the input array is multiplied by the corresponding element in the mask array.
// The mask array is validated to ensure all elements are binary (0 or 1).
//
// Parameters:
// - maxLength: The maximum length of the input and mask arrays.
//
// Inputs:
// - body: An array of signals representing the body to be masked.
// - mask: An array of signals representing the binary mask.
//
// Outputs:
// - out: An array of signals representing the masked input.
template ByteMask(maxLength) {
signal input in[maxLength];
signal input mask[maxLength];
signal output out[maxLength];
component bit_check[maxLength];
for (var i = 0; i < maxLength; i++) {
bit_check[i] = AssertBit();
bit_check[i].in <== mask[i];
out[i] <== in[i] * mask[i];
}
}
/// NOTE: this circuit is unaudited and should not be used in production
/// @title SplitBytesToWords
/// @notice split an array of bytes into an array of words
/// @notice useful for casting a message or modulus before RSA verification
/// @param l: number of bytes in the input array
/// @param n: number of bits in a word
/// @param k: number of words
/// @input in: array of bytes
/// @output out: array of words
template SplitSignalsToWords (t,l,n,k) {
assert(n*k >= t*l);
signal input in[l];
signal output out[k];
component num2bits[l];
for (var i = 0 ; i < l ; i++){
num2bits[i] = Num2Bits(t);
num2bits[i].in <== in[i];
}
for (var i = 0 ; i < t ; i ++){
}
component bits2num[k];
for (var i = 0 ; i < k ; i++){
bits2num[i] = Bits2Num(n);
for(var j = 0 ; j < n ; j++){
if(i*n + j >= l * t){
bits2num[i].in[j] <== 0;
}
else{
bits2num[i].in[j] <== num2bits[ (( i * n + j) \ t) ].out[ ((i * n + j) % t)];
}
}
}
for( var i = 0 ; i< k ; i++){
out[i] <== bits2num[i].out;
}
}

View File

@@ -18,7 +18,7 @@
*/
pragma circom 2.0.0;
include "../bitify/bitify.circom";
include "circomlib/circuits/bitify.circom";
// Returns 1 if in (in binary) > ct

View File

@@ -1,15 +0,0 @@
pragma circom 2.1.6;
function EMAIL_ADDR_MAX_BYTES() {
return 256;
}
function DOMAIN_MAX_BYTES() {
return 255;
}
// Field support maximum of ~253 bit
function MAX_BYTES_IN_FIELD() {
return 31;
}

View File

@@ -1,17 +0,0 @@
pragma circom 2.1.6;
/// @function log2Ceil
/// @notice Calculate log2 of a number and round it up
/// @param a The input value
/// @return The result of the log2Ceil
function log2Ceil(a) {
var n = a - 1;
var r = 0;
while (n > 0) {
r++;
n \= 2;
}
return r;
}

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.9;
include "../circomlib/hasher/hash.circom";
include "../circomlib/utils/bytes.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "./customHashers.circom";
template ComputeCommitment() {

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../circomlib/bitify/comparators.circom";
include "circomlib/circuits/comparators.circom";
template DateIsLess() {
signal input firstDay;

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.9;
include "../../circomlib/bitify/comparators.circom";
include "../../circomlib/bitify/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "./dateIsLess.circom";
template IsOlderThan() {

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.9;
include "../../circomlib/bitify/comparators.circom";
include "../../circomlib/bitify/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "./dateIsLess.circom";
template IsValid() {

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../circomlib/utils/bytes.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "../date/isOlderThan.circom";
template DISCLOSE() {

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.5;
include "../../circomlib/bitify/comparators.circom";
include "../../circomlib/utils/bytes.circom";
include "circomlib/circuits/comparators.circom";
include "@zk-email/circuits/utils/bytes.circom";
template ProveCountryIsNotInList(forbiddenCountriesListLength) {
signal input dg1[93];

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../circomlib/utils/bytes.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "../../circomlib/merkle-trees/binary-merkle-root.circom";
include "../computeCommitment.circom";

View File

@@ -1,7 +1,7 @@
pragma circom 2.1.9;
include "../circomlib/utils/array.circom";
include "../circomlib/utils/bytes.circom";
include "@zk-email/circuits/utils/array.circom";
include "@zk-email/circuits/utils/bytes.circom";
include "../circomlib/hasher/shaBytes/shaBytesDynamic.circom";
include "../circomlib/hasher/hash.circom";
include "./signatureAlgorithm.circom";

View File

@@ -9,7 +9,7 @@ include "secp256r1Verifier.circom";
// include "../circomlib/signature/rsa/verifyLargeRsaPkcs1v1_5.circom";
include "../circomlib/signature/rsa/verifyRsa3Pkcs1v1_5.circom";
include "../circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
include "../circomlib/utils/bytes.circom";
include "@zk-email/circuits/utils/bytes.circom";
template SignatureVerifier(signatureAlgorithm, n, k) {
var kLengthFactor = getKLengthFactor(signatureAlgorithm);

View File

@@ -1,128 +0,0 @@
pragma circom 2.1.6;
include "circomlib/circuits/comparators.circom";
/// @title Base64Decode
/// @notice Decodes a Base64 encoded string to array of bytes.
/// @notice Only support inputs with length = `byteLength` (no 0 padding).
/// @notice It is known that padding char '=' can be replaed with `A` to produce the same output
/// as Base64Lookup returns `0` for both, but a pracical attack from this is unlikely.
/// @param byteLength Byte length of the encoded value - length of the output array.
/// @input in Base64 encoded string; assumes elements to be valid Base64 characters.
/// @output out Decoded array of bytes.
template Base64Decode_ZK_EMAIL(byteLength) {
var charLength = 4 * ((byteLength + 2) \ 3); // 4 chars encode 3 bytes
signal input in[charLength];
signal output out[byteLength];
component bitsIn[charLength\4][4];
component bitsOut[charLength\4][3];
component translate[charLength\4][4];
var idx = 0;
for (var i = 0; i < charLength; i += 4) {
for (var j = 0; j < 3; j++) {
bitsOut[i\4][j] = Bits2Num(8);
}
for (var j = 0; j < 4; j++) {
bitsIn[i\4][j] = Num2Bits(6);
translate[i\4][j] = Base64Lookup();
translate[i\4][j].in <== in[i+j];
translate[i\4][j].out ==> bitsIn[i\4][j].in;
}
// Do the re-packing from four 6-bit words to three 8-bit words.
for (var j = 0; j < 6; j++) {
bitsOut[i\4][0].in[j+2] <== bitsIn[i\4][0].out[j];
}
bitsOut[i\4][0].in[0] <== bitsIn[i\4][1].out[4];
bitsOut[i\4][0].in[1] <== bitsIn[i\4][1].out[5];
for (var j = 0; j < 4; j++) {
bitsOut[i\4][1].in[j+4] <== bitsIn[i\4][1].out[j];
}
for (var j = 0; j < 4; j++) {
bitsOut[i\4][1].in[j] <== bitsIn[i\4][2].out[j+2];
}
bitsOut[i\4][2].in[6] <== bitsIn[i\4][2].out[0];
bitsOut[i\4][2].in[7] <== bitsIn[i\4][2].out[1];
for (var j = 0; j < 6; j++) {
bitsOut[i\4][2].in[j] <== bitsIn[i\4][3].out[j];
}
for (var j = 0; j < 3; j++) {
if (idx+j < byteLength) {
out[idx+j] <== bitsOut[i\4][j].out;
}
}
idx += 3;
}
}
/// @title Base64Lookup
/// @notice http://0x80.pl/notesen/2016-01-17-sse-base64-decoding.html#vector-lookup-base
/// @input in input character; assumes input to be valid Base64 character (though constrained implicitly).
/// @output out output bit value.
template Base64Lookup_ZK_EMAIL() {
signal input in;
signal output out;
// ['A', 'Z']
component le_Z = LessThan(8);
le_Z.in[0] <== in;
le_Z.in[1] <== 90+1;
component ge_A = GreaterThan(8);
ge_A.in[0] <== in;
ge_A.in[1] <== 65-1;
signal range_AZ <== ge_A.out * le_Z.out;
signal sum_AZ <== range_AZ * (in - 65);
// ['a', 'z']
component le_z = LessThan(8);
le_z.in[0] <== in;
le_z.in[1] <== 122+1;
component ge_a = GreaterThan(8);
ge_a.in[0] <== in;
ge_a.in[1] <== 97-1;
signal range_az <== ge_a.out * le_z.out;
signal sum_az <== sum_AZ + range_az * (in - 71);
// ['0', '9']
component le_9 = LessThan(8);
le_9.in[0] <== in;
le_9.in[1] <== 57+1;
component ge_0 = GreaterThan(8);
ge_0.in[0] <== in;
ge_0.in[1] <== 48-1;
signal range_09 <== ge_0.out * le_9.out;
signal sum_09 <== sum_az + range_09 * (in + 4);
// '+'
component equal_plus = IsZero();
equal_plus.in <== in - 43;
signal sum_plus <== sum_09 + equal_plus.out * (in + 19);
// '/'
component equal_slash = IsZero();
equal_slash.in <== in - 47;
signal sum_slash <== sum_plus + equal_slash.out * (in + 16);
out <== sum_slash;
// '='
component equal_eqsign = IsZero();
equal_eqsign.in <== in - 61;
1 === range_AZ + range_az + range_09 + equal_plus.out + equal_slash.out + equal_eqsign.out;
}

View File

@@ -1,264 +0,0 @@
pragma circom 2.1.6;
function div_ceil(m, n) {
var ret = 0;
if (m % n == 0) {
ret = m \ n;
} else {
ret = m \ n + 1;
}
return ret;
}
function log_ceil(n) {
var n_temp = n;
for (var i = 0; i < 254; i++) {
if (n_temp == 0) {
return i;
}
n_temp = n_temp \ 2;
}
return 254;
}
// m bits per overflowed register (values are potentially negative)
// n bits per properly-sized register
// in has k registers
// out has k + ceil(m/n) - 1 + 1 registers. highest-order potentially negative,
// all others are positive
// - 1 since the last register is included in the last ceil(m/n) array
// + 1 since the carries from previous registers could push you over
function getProperRepresentation(m, n, k, in) {
var ceilMN = div_ceil(m, n);
var out[100]; // should be out[k + ceilMN]
assert(k + ceilMN < 100);
for (var i = 0; i < k; i++) {
out[i] = in[i];
}
for (var i = k; i < 100; i++) {
out[i] = 0;
}
assert(n <= m);
for (var i = 0; i+1 < k + ceilMN; i++) {
assert((1 << m) >= out[i] && out[i] >= -(1 << m));
var shifted_val = out[i] + (1 << m);
assert(0 <= shifted_val && shifted_val <= (1 << (m+1)));
out[i] = shifted_val & ((1 << n) - 1);
out[i+1] += (shifted_val >> n) - (1 << (m - n));
}
return out;
}
// Evaluate polynomial a at point x
function poly_eval(len, a, x) {
var v = 0;
for (var i = 0; i < len; i++) {
v += a[i] * (x ** i);
}
return v;
}
// Interpolate a degree len-1 polynomial given its evaluations at 0..len-1
function poly_interp(len, v) {
assert(len <= 200);
var out[200];
for (var i = 0; i < len; i++) {
out[i] = 0;
}
// Product_{i=0..len-1} (x-i)
var full_poly[201];
full_poly[0] = 1;
for (var i = 0; i < len; i++) {
full_poly[i+1] = 0;
for (var j = i; j >= 0; j--) {
full_poly[j+1] += full_poly[j];
full_poly[j] *= -i;
}
}
for (var i = 0; i < len; i++) {
var cur_v = 1;
for (var j = 0; j < len; j++) {
if (i == j) {
// do nothing
} else {
cur_v *= i-j;
}
}
cur_v = v[i] / cur_v;
var cur_rem = full_poly[len];
for (var j = len-1; j >= 0; j--) {
out[j] += cur_v * cur_rem;
cur_rem = full_poly[j] + i * cur_rem;
}
assert(cur_rem == 0);
}
return out;
}
// 1 if true, 0 if false
function long_gt(n, k, a, b) {
for (var i = k - 1; i >= 0; i--) {
if (a[i] > b[i]) {
return 1;
}
if (a[i] < b[i]) {
return 0;
}
}
return 0;
}
// n bits per register
// a has k registers
// b has k registers
// a >= b
function long_sub(n, k, a, b) {
var diff[100];
var borrow[100];
for (var i = 0; i < k; i++) {
if (i == 0) {
if (a[i] >= b[i]) {
diff[i] = a[i] - b[i];
borrow[i] = 0;
} else {
diff[i] = a[i] - b[i] + (1 << n);
borrow[i] = 1;
}
} else {
if (a[i] >= b[i] + borrow[i - 1]) {
diff[i] = a[i] - b[i] - borrow[i - 1];
borrow[i] = 0;
} else {
diff[i] = (1 << n) + a[i] - b[i] - borrow[i - 1];
borrow[i] = 1;
}
}
}
return diff;
}
// a is a n-bit scalar
// b has k registers
function long_scalar_mult(n, k, a, b) {
var out[100];
for (var i = 0; i < 100; i++) {
out[i] = 0;
}
for (var i = 0; i < k; i++) {
var temp = out[i] + (a * b[i]);
out[i] = temp % (1 << n);
out[i + 1] = out[i + 1] + temp \ (1 << n);
}
return out;
}
// n bits per register
// a has k + m registers
// b has k registers
// out[0] has length m + 1 -- quotient
// out[1] has length k -- remainder
// implements algorithm of https://people.eecs.berkeley.edu/~fateman/282/F%20Wright%20notes/week4.pdf
function long_div(n, k, m, a, b){
var out[2][100];
m += k;
while (b[k-1] == 0) {
out[1][k] = 0;
k--;
assert(k > 0);
}
m -= k;
var remainder[100];
for (var i = 0; i < m + k; i++) {
remainder[i] = a[i];
}
var mult[200];
var dividend[200];
for (var i = m; i >= 0; i--) {
if (i == m) {
dividend[k] = 0;
for (var j = k - 1; j >= 0; j--) {
dividend[j] = remainder[j + m];
}
} else {
for (var j = k; j >= 0; j--) {
dividend[j] = remainder[j + i];
}
}
out[0][i] = short_div(n, k, dividend, b);
var mult_shift[100] = long_scalar_mult(n, k, out[0][i], b);
var subtrahend[200];
for (var j = 0; j < m + k; j++) {
subtrahend[j] = 0;
}
for (var j = 0; j <= k; j++) {
if (i + j < m + k) {
subtrahend[i + j] = mult_shift[j];
}
}
remainder = long_sub(n, m + k, remainder, subtrahend);
}
for (var i = 0; i < k; i++) {
out[1][i] = remainder[i];
}
out[1][k] = 0;
return out;
}
// n bits per register
// a has k + 1 registers
// b has k registers
// assumes leading digit of b is at least 2 ** (n - 1)
// 0 <= a < (2**n) * b
function short_div_norm(n, k, a, b) {
var qhat = (a[k] * (1 << n) + a[k - 1]) \ b[k - 1];
if (qhat > (1 << n) - 1) {
qhat = (1 << n) - 1;
}
var mult[100] = long_scalar_mult(n, k, qhat, b);
if (long_gt(n, k + 1, mult, a) == 1) {
mult = long_sub(n, k + 1, mult, b);
if (long_gt(n, k + 1, mult, a) == 1) {
return qhat - 2;
} else {
return qhat - 1;
}
} else {
return qhat;
}
}
// n bits per register
// a has k + 1 registers
// b has k registers
// assumes leading digit of b is non-zero
// 0 <= a < (2**n) * b
function short_div(n, k, a, b) {
var scale = (1 << n) \ (1 + b[k - 1]);
// k + 2 registers now
var norm_a[100] = long_scalar_mult(n, k + 1, scale, a);
// k + 1 registers now
var norm_b[100] = long_scalar_mult(n, k, scale, b);
var ret;
if (norm_b[k] != 0) {
ret = short_div_norm(n, k + 1, norm_a, norm_b);
} else {
ret = short_div_norm(n, k, norm_a, norm_b);
}
return ret;
}

View File

@@ -1,94 +0,0 @@
pragma circom 2.1.6;
include "../../circomlib/bitify/comparators.circom";
include "../../circomlib/bitify/bitify.circom";
include "../../circomlib/bitify/gates.circom";
include "./bigint-func.circom";
/// @template BigLessThan
/// @notice Less than comparison for big integers
/// @param n The number of bits in each chunk
/// @param k The number of chunks
/// @param a The first bigint; assumes to consist of `k` chunks, each of which must fit in `n` bits
/// @param b The second bigint; assumes to consist of `k` chunks, each of which must fit in `n` bits
/// @param out The output of the comparison
template BigLessThan(n, k){
signal input a[k];
signal input b[k];
signal output out;
component lt[k];
component eq[k];
for (var i = 0; i < k; i++) {
lt[i] = LessThan(n);
lt[i].in[0] <== a[i];
lt[i].in[1] <== b[i];
eq[i] = IsEqual();
eq[i].in[0] <== a[i];
eq[i].in[1] <== b[i];
}
// ors[i] holds (lt[k - 1] || (eq[k - 1] && lt[k - 2]) .. || (eq[k - 1] && .. && lt[i]))
// ands[i] holds (eq[k - 1] && .. && lt[i])
// eq_ands[i] holds (eq[k - 1] && .. && eq[i])
component ors[k - 1];
component ands[k - 1];
component eq_ands[k - 1];
for (var i = k - 2; i >= 0; i--) {
ands[i] = AND();
eq_ands[i] = AND();
ors[i] = OR();
if (i == k - 2) {
ands[i].a <== eq[k - 1].out;
ands[i].b <== lt[k - 2].out;
eq_ands[i].a <== eq[k - 1].out;
eq_ands[i].b <== eq[k - 2].out;
ors[i].a <== lt[k - 1].out;
ors[i].b <== ands[i].out;
} else {
ands[i].a <== eq_ands[i + 1].out;
ands[i].b <== lt[i].out;
eq_ands[i].a <== eq_ands[i + 1].out;
eq_ands[i].b <== eq[i].out;
ors[i].a <== ors[i + 1].out;
ors[i].b <== ands[i].out;
}
}
out <== ors[0].out;
}
/// @template CheckCarryToZero
/// @notice Check that in[] as a big integer is zero
/// @param n The number of bits in each chunk
/// @param m
/// @param k The number of chunks
/// @input in The input big integer; assumes elements to be in the range -2^(m-1) to 2^(m-1)
template CheckCarryToZero(n, m, k) {
assert(k >= 2);
var EPSILON = 3;
assert(m + EPSILON <= 253);
signal input in[k];
signal carry[k];
component carryRangeChecks[k];
for (var i = 0; i < k-1; i++){
carryRangeChecks[i] = Num2Bits(m + EPSILON - n);
if( i == 0 ){
carry[i] <-- in[i] / (1<<n);
in[i] === carry[i] * (1<<n);
}
else{
carry[i] <-- (in[i]+carry[i-1]) / (1<<n);
in[i] + carry[i-1] === carry[i] * (1<<n);
}
// checking carry is in the range of - 2^(m-n-1+eps), 2^(m+-n-1+eps)
carryRangeChecks[i].in <== carry[i] + ( 1<< (m + EPSILON - n - 1));
}
in[k-1] + carry[k-2] === 0;
}

View File

@@ -1,81 +0,0 @@
pragma circom 2.1.6;
include "../../circomlib/bitify/bitify.circom";
include "../../circomlib/bitify/comparators.circom";
include "../../circomlib/utils/sign.circom";
include "./bigint.circom";
include "./bigint-func.circom";
/// @title FpMul
/// @notice Multiple two numbers in Fp
/// @param a Input 1 to FpMul; assumes to consist of `k` chunks, each of which must fit in `n` bits
/// @param b Input 2 to FpMul; assumes to consist of `k` chunks, each of which must fit in `n` bits
/// @param p The modulus; assumes to consist of `k` chunks, each of which must fit in `n` bits
/// @output out The result of the FpMul; asserted to be less than `p`
template FpMul(n, k) {
assert(n + n + log_ceil(k) + 2 <= 252);
signal input a[k];
signal input b[k];
signal input p[k];
signal output out[k];
signal v_ab[2*k-1];
for (var x = 0; x < 2*k-1; x++) {
var v_a = poly_eval(k, a, x);
var v_b = poly_eval(k, b, x);
v_ab[x] <== v_a * v_b;
}
var ab[200] = poly_interp(2*k-1, v_ab);
// ab_proper has length 2*k
var ab_proper[100] = getProperRepresentation(n + n + log_ceil(k), n, 2*k-1, ab);
var long_div_out[2][100] = long_div(n, k, k, ab_proper, p);
// Since we're only computing a*b, we know that q < p will suffice, so we
// know it fits into k chunks and can do size n range checks.
signal q[k];
component q_range_check[k];
signal r[k];
component r_range_check[k];
component r_p_lt_check = BigLessThan(n,k);
for (var i = 0; i < k; i++) {
q[i] <-- long_div_out[0][i];
q_range_check[i] = Num2Bits(n);
q_range_check[i].in <== q[i];
r[i] <-- long_div_out[1][i];
r_range_check[i] = Num2Bits(n);
r_range_check[i].in <== r[i];
r_p_lt_check.a[i] <== r[i];
r_p_lt_check.b[i] <== p[i];
}
r_p_lt_check.out === 1;
signal v_pq_r[2*k-1];
for (var x = 0; x < 2*k-1; x++) {
var v_p = poly_eval(k, p, x);
var v_q = poly_eval(k, q, x);
var v_r = poly_eval(k, r, x);
v_pq_r[x] <== v_p * v_q + v_r;
}
signal v_t[2*k-1];
for (var x = 0; x < 2*k-1; x++) {
v_t[x] <== v_ab[x] - v_pq_r[x];
}
var t[200] = poly_interp(2*k-1, v_t);
component tCheck = CheckCarryToZero(n, n + n + log_ceil(k) + 2, 2*k-1);
for (var i = 0; i < 2*k-1; i++) {
tCheck.in[i] <== t[i];
}
for (var i = 0; i < k; i++) {
out[i] <== r[i];
}
}

View File

@@ -1,181 +0,0 @@
pragma circom 2.1.6;
include "./fp.circom";
/// @title RSAVerifier65537
/// @notice Verifies an RSA signature with exponent 65537.
/// @param n Number of bits per chunk the modulus is split into. Recommended to be 121.
/// @param k Number of chunks the modulus is split into. Recommended to be 17.
/// @input message[k] The message that was signed; assumes to consist of `k` chunks that fit in `n` bits (also constrained implicitly).
/// @input signature[k] The signature to verify; assumes to consist of `k` chunks that fit in `n` bits (also constrained implicitly).
/// @input modulus[k] The modulus of the RSA key (pubkey); assumes to consist of `k` chunks that fit in `n` bits (also constrained implicitly).
template RSAVerifier65537(n, k) {
signal input message[k];
signal input signature[k];
signal input modulus[k];
component padder = RSAPad(n, k);
for (var i = 0; i < k; i++) {
padder.modulus[i] <== modulus[i];
padder.message[i] <== message[i];
}
// Check that the signature is in proper form and reduced mod modulus.
component signatureRangeCheck[k];
component bigLessThan = BigLessThan(n, k);
for (var i = 0; i < k; i++) {
signatureRangeCheck[i] = Num2Bits(n);
signatureRangeCheck[i].in <== signature[i];
bigLessThan.a[i] <== signature[i];
bigLessThan.b[i] <== modulus[i];
}
bigLessThan.out === 1;
component bigPow = FpPow65537Mod(n, k);
for (var i = 0; i < k; i++) {
bigPow.base[i] <== signature[i];
bigPow.modulus[i] <== modulus[i];
}
// By construction of the padding, the padded message is necessarily
// smaller than the modulus. Thus, we don't have to check that bigPow is fully reduced.
for (var i = 0; i < k; i++) {
bigPow.out[i] === padder.out[i];
}
}
/// @title FpPow65537Mod
/// @notice Computes base^65537 mod modulus
/// @dev Does not necessarily reduce fully mod modulus (the answer could be too big by a multiple of modulus)
/// @param n Number of bits per chunk the modulus is split into.
/// @param k Number of chunks the modulus is split into.
/// @input base The base to exponentiate; assumes to consist of `k` chunks, each of which must fit in `n` bits
/// @input modulus The modulus; assumes to consist of `k` chunks, each of which must fit in `n` bits
/// @output out The result of the exponentiation.
template FpPow65537Mod(n, k) {
signal input base[k];
signal input modulus[k];
signal output out[k];
component doublers[16];
component adder = FpMul(n, k);
for (var i = 0; i < 16; i++) {
doublers[i] = FpMul(n, k);
}
for (var j = 0; j < k; j++) {
adder.p[j] <== modulus[j];
for (var i = 0; i < 16; i++) {
doublers[i].p[j] <== modulus[j];
}
}
for (var j = 0; j < k; j++) {
doublers[0].a[j] <== base[j];
doublers[0].b[j] <== base[j];
}
for (var i = 0; i + 1 < 16; i++) {
for (var j = 0; j < k; j++) {
doublers[i + 1].a[j] <== doublers[i].out[j];
doublers[i + 1].b[j] <== doublers[i].out[j];
}
}
for (var j = 0; j < k; j++) {
adder.a[j] <== base[j];
adder.b[j] <== doublers[15].out[j];
}
for (var j = 0; j < k; j++) {
out[j] <== adder.out[j];
}
}
/// @title RSAPad
/// @notice Pads a message for RSA signing.
/// @param n Number of bits per chunk the modulus is split into.
/// @param k Number of chunks the modulus is split into.
/// @input modulus The modulus of the RSA key (pubkey).
/// @input message The message to pad.
/// @output out The padded message.
template RSAPad(n, k) {
signal input modulus[k];
signal input message[k];
signal output out[k];
// The extra 152 bits comes from 0x3031300d060960864801650304020105000420
// This is due to padding from the RSASSA-PKCS1-v1_5 standard
var baseLen = 408;
var msgLen = 256;
signal paddedMessageBits[n*k];
component modulusN2B[k];
component messageN2B[k];
signal modulusBits[n*k];
signal messageBits[n*k];
for (var i = 0; i < k; i++) {
messageN2B[i] = Num2Bits(n);
messageN2B[i].in <== message[i];
for (var j = 0; j < n; j++) {
messageBits[i*n+j] <== messageN2B[i].out[j];
}
modulusN2B[i] = Num2Bits(n);
modulusN2B[i].in <== modulus[i];
for (var j = 0; j < n; j++) {
modulusBits[i*n+j] <== modulusN2B[i].out[j];
}
}
for (var i = msgLen; i < n*k; i++) {
messageBits[i] === 0;
}
for (var i = 0; i < msgLen; i++) {
paddedMessageBits[i] <== messageBits[i];
}
for (var i = baseLen; i < baseLen + 8; i++) {
paddedMessageBits[i] <== 0;
}
for (var i = msgLen; i < baseLen; i++) {
paddedMessageBits[i] <== (0x3031300d060960864801650304020105000420 >> (i - msgLen)) & 1;
}
component modulusZero[(n*k + 7 - (baseLen + 8))\8];
{
var modulusPrefix = 0;
for (var i = n*k - 1; i >= baseLen + 8; i--) {
if (i+8 < n*k) {
modulusPrefix += modulusBits[i+8];
if (i % 8 == 0) {
var idx = (i - (baseLen + 8)) \ 8;
modulusZero[idx] = IsZero();
modulusZero[idx].in <== modulusPrefix;
paddedMessageBits[i] <== 1-modulusZero[idx].out;
} else {
paddedMessageBits[i] <== paddedMessageBits[i+1];
}
} else {
paddedMessageBits[i] <== 0;
}
}
}
// The RFC guarantees at least 8 octets of 0xff padding.
assert(baseLen + 8 + 65 <= n * k);
for (var i = baseLen + 8; i < baseLen + 8 + 65; i++) {
paddedMessageBits[i] === 1;
}
component passedMessageB2N[k];
for (var i = 0; i < k; i++) {
passedMessageB2N[i] = Bits2Num(n);
for (var j = 0; j < n; j++) {
passedMessageB2N[i].in[j] <== paddedMessageBits[i*n+j];
}
out[i] <== passedMessageB2N[i].out;
}
}

View File

@@ -1,292 +0,0 @@
pragma circom 2.1.6;
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/sha256/constants.circom";
include "circomlib/circuits/sha256/sha256compression.circom";
include "circomlib/circuits/comparators.circom";
include "./fp.circom";
include "../utils/array.circom";
include "../utils/functions.circom";
/// @title Sha256Bytes
/// @notice Computes the SHA256 hash of input bytes
/// @input paddedIn Message to hash, padded as per the SHA256 specification; assumes to consist of bytes
/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(8 * maxByteLength))` bits
/// @output out The 256-bit hash of the input message
template Sha256Bytes(maxByteLength) {
signal input paddedIn[maxByteLength];
signal input paddedInLength;
signal output out[256];
var maxBits = maxByteLength * 8;
component sha = Sha256General(maxBits);
component bytes[maxByteLength];
for (var i = 0; i < maxByteLength; i++) {
bytes[i] = Num2Bits(8);
bytes[i].in <== paddedIn[i];
for (var j = 0; j < 8; j++) {
sha.paddedIn[i*8+j] <== bytes[i].out[7-j];
}
}
sha.paddedInLength <== paddedInLength * 8;
for (var i = 0; i < 256; i++) {
out[i] <== sha.out[i];
}
}
/// @title Sha256BytesPartial
/// @notice Computes the SHA256 hash of input bytes with a precomputed state
/// @input paddedIn Message to hash padded as per the SHA256 specification; assumes to consist of bytes
/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(8 * maxByteLength))` bits
/// @input preHash The precomputed state of the hash
/// @output out SHA hash the input message with the precomputed state
template Sha256BytesPartial(maxByteLength) {
assert(maxByteLength % 32 == 0);
signal input paddedIn[maxByteLength];
signal input paddedInLength;
signal input preHash[32];
signal output out[256];
var maxBits = maxByteLength * 8;
component sha = Sha256Partial(maxBits);
component bytes[maxByteLength];
for (var i = 0; i < maxByteLength; i++) {
bytes[i] = Num2Bits(8);
bytes[i].in <== paddedIn[i];
for (var j = 0; j < 8; j++) {
sha.paddedIn[i*8+j] <== bytes[i].out[7-j];
}
}
sha.paddedInLength <== paddedInLength * 8;
component states[32];
for (var i = 0; i < 32; i++) {
states[i] = Num2Bits(8);
states[i].in <== preHash[i];
for (var j = 0; j < 8; j++) {
sha.preHash[8*i+j] <== states[i].out[7-j];
}
}
for (var i = 0; i < 256; i++) {
out[i] <== sha.out[i];
}
}
/// @title Sha256General
/// @notice A modified version of the SHA256 circuit that allows specified length messages up to a
/// max to all work via array indexing on the SHA256 compression circuit.
/// @input paddedIn Message to hash padded as per the SHA256 specification; assumes to consist of bits
/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(maxBitLength))` bits
/// @output out The 256-bit hash of the input message
template Sha256General(maxBitLength) {
// maxBitLength must be a multiple of 512
// the bit circuits in this file are limited to 15 so must be raised if the message is longer.
assert(maxBitLength % 512 == 0);
var maxBitsPaddedBits = log2Ceil(maxBitLength);
// Note that maxBitLength = maxBits + 64
signal input paddedIn[maxBitLength];
signal input paddedInLength;
signal output out[256];
signal inBlockIndex;
var i;
var k;
var j;
var maxBlocks;
var bitsLastBlock;
maxBlocks = (maxBitLength\512);
inBlockIndex <-- (paddedInLength >> 9);
paddedInLength === inBlockIndex * 512;
// These verify the unconstrained floor calculation is the uniquely correct integer that represents the floor
// component floorVerifierUnder = LessEqThan(maxBitsPaddedBits); // todo verify the length passed in is less than nbits. note that maxBitsPaddedBits can likely be lowered or made it a fn of maxbits
// floorVerifierUnder.in[0] <== (inBlockIndex)*512;
// floorVerifierUnder.in[1] <== paddedInLength;
// floorVerifierUnder.out === 1;
// component floorVerifierOver = GreaterThan(maxBitsPaddedBits);
// floorVerifierOver.in[0] <== (inBlockIndex+1)*512;
// floorVerifierOver.in[1] <== paddedInLength;
// floorVerifierOver.out === 1;
// These verify we pass in a valid number of bits to the SHA256 compression circuit.
component bitLengthVerifier = LessEqThan(maxBitsPaddedBits); // todo verify the length passed in is less than nbits. note that maxBitsPaddedBits can likely be lowered or made it a fn of maxbits
bitLengthVerifier.in[0] <== paddedInLength;
bitLengthVerifier.in[1] <== maxBitLength;
bitLengthVerifier.out === 1;
// Note that we can no longer do padded verification efficiently inside the SHA because it requires non deterministic array indexing.
// We can do it if we add a constraint, but since guessing a valid SHA2 preimage is hard anyways, we'll just do it outside the circuit.
// signal paddedIn[maxBlocks*512];
// for (k=0; k<maxBits; k++) {
// paddedIn[k] <== in[k];
// }
// paddedIn[maxBits] <== 1;
// for (k=maxBits+1; k<maxBlocks*512-64; k++) {
// paddedIn[k] <== 0;
// }
// for (k = 0; k< 64; k++) {
// paddedIn[maxBlocks*512 - k -1] <== (maxBits >> k)&1;
// }
component ha0 = H(0);
component hb0 = H(1);
component hc0 = H(2);
component hd0 = H(3);
component he0 = H(4);
component hf0 = H(5);
component hg0 = H(6);
component hh0 = H(7);
component sha256compression[maxBlocks];
for (i=0; i<maxBlocks; i++) {
sha256compression[i] = Sha256compression() ;
if (i==0) {
for (k=0; k<32; k++ ) {
sha256compression[i].hin[0*32+k] <== ha0.out[k];
sha256compression[i].hin[1*32+k] <== hb0.out[k];
sha256compression[i].hin[2*32+k] <== hc0.out[k];
sha256compression[i].hin[3*32+k] <== hd0.out[k];
sha256compression[i].hin[4*32+k] <== he0.out[k];
sha256compression[i].hin[5*32+k] <== hf0.out[k];
sha256compression[i].hin[6*32+k] <== hg0.out[k];
sha256compression[i].hin[7*32+k] <== hh0.out[k];
}
} else {
for (k=0; k<32; k++ ) {
sha256compression[i].hin[32*0+k] <== sha256compression[i-1].out[32*0+31-k];
sha256compression[i].hin[32*1+k] <== sha256compression[i-1].out[32*1+31-k];
sha256compression[i].hin[32*2+k] <== sha256compression[i-1].out[32*2+31-k];
sha256compression[i].hin[32*3+k] <== sha256compression[i-1].out[32*3+31-k];
sha256compression[i].hin[32*4+k] <== sha256compression[i-1].out[32*4+31-k];
sha256compression[i].hin[32*5+k] <== sha256compression[i-1].out[32*5+31-k];
sha256compression[i].hin[32*6+k] <== sha256compression[i-1].out[32*6+31-k];
sha256compression[i].hin[32*7+k] <== sha256compression[i-1].out[32*7+31-k];
}
}
for (k=0; k<512; k++) {
sha256compression[i].inp[k] <== paddedIn[i*512+k];
}
}
// Select the correct compression output for the given length, instead of just the last one.
component arraySelectors[256];
for (k=0; k<256; k++) {
arraySelectors[k] = ItemAtIndex(maxBlocks);
for (j=0; j<maxBlocks; j++) {
arraySelectors[k].in[j] <== sha256compression[j].out[k];
}
arraySelectors[k].index <== inBlockIndex - 1; // The index is 0 indexed and the block numbers are 1 indexed.
out[k] <== arraySelectors[k].out;
}
// for (k=0; k<256; k++) {
// out[k] <== sha256compression[maxBlocks-1].out[k];
// }
}
/// @title Sha256Partial
/// @notice Calculates the SHA256 hash of a message with a precomputed state
/// @input paddedIn Message to hash padded as per the SHA256 specification; assumes to consist of bits
/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(maxBitLength))` bits
/// @input preHash The precomputed state of the hash; assumes to consist of bits
/// @output out The 256-bit hash of the input message
template Sha256Partial(maxBitLength) {
// maxBitLength must be a multiple of 512
// the bit circuits in this file are limited to 15 so must be raised if the message is longer.
assert(maxBitLength % 512 == 0);
var maxBitsPaddedBits = log2Ceil(maxBitLength);
// Note that maxBitLength = maxBits + 64
signal input paddedIn[maxBitLength];
signal input paddedInLength;
signal input preHash[256];
signal output out[256];
signal inBlockIndex;
var i;
var k;
var j;
var maxBlocks;
var bitsLastBlock;
maxBlocks = (maxBitLength\512);
inBlockIndex <-- (paddedInLength >> 9);
paddedInLength === inBlockIndex * 512;
// These verify we pass in a valid number of bits to the SHA256 compression circuit.
component bitLengthVerifier = LessEqThan(maxBitsPaddedBits); // todo verify the length passed in is less than nbits. note that maxBitsPaddedBits can likely be lowered or made it a fn of maxbits
bitLengthVerifier.in[0] <== paddedInLength;
bitLengthVerifier.in[1] <== maxBitLength;
bitLengthVerifier.out === 1;
component sha256compression[maxBlocks];
for (i=0; i<maxBlocks; i++) {
sha256compression[i] = Sha256compression() ;
if (i==0) {
for (k=0; k<32; k++ ) {
sha256compression[i].hin[32*0+k] <== preHash[32*0+31-k];
sha256compression[i].hin[32*1+k] <== preHash[32*1+31-k];
sha256compression[i].hin[32*2+k] <== preHash[32*2+31-k];
sha256compression[i].hin[32*3+k] <== preHash[32*3+31-k];
sha256compression[i].hin[32*4+k] <== preHash[32*4+31-k];
sha256compression[i].hin[32*5+k] <== preHash[32*5+31-k];
sha256compression[i].hin[32*6+k] <== preHash[32*6+31-k];
sha256compression[i].hin[32*7+k] <== preHash[32*7+31-k];
}
} else {
for (k=0; k<32; k++ ) {
sha256compression[i].hin[32*0+k] <== sha256compression[i-1].out[32*0+31-k];
sha256compression[i].hin[32*1+k] <== sha256compression[i-1].out[32*1+31-k];
sha256compression[i].hin[32*2+k] <== sha256compression[i-1].out[32*2+31-k];
sha256compression[i].hin[32*3+k] <== sha256compression[i-1].out[32*3+31-k];
sha256compression[i].hin[32*4+k] <== sha256compression[i-1].out[32*4+31-k];
sha256compression[i].hin[32*5+k] <== sha256compression[i-1].out[32*5+31-k];
sha256compression[i].hin[32*6+k] <== sha256compression[i-1].out[32*6+31-k];
sha256compression[i].hin[32*7+k] <== sha256compression[i-1].out[32*7+31-k];
}
}
for (k=0; k<512; k++) {
sha256compression[i].inp[k] <== paddedIn[i*512+k];
}
}
// Select the correct compression output for the given length, instead of just the last one.
component arraySelectors[256];
for (k=0; k<256; k++) {
arraySelectors[k] = ItemAtIndex(maxBlocks);
for (j=0; j<maxBlocks; j++) {
arraySelectors[k].in[j] <== sha256compression[j].out[k];
}
arraySelectors[k].index <== inBlockIndex - 1; // The index is 0 indexed and the block numbers are 1 indexed.
out[k] <== arraySelectors[k].out;
}
// for (k=0; k<256; k++) {
// out[k] <== sha256compression[maxBlocks-1].out[k];
// }
}

View File

@@ -1,254 +0,0 @@
pragma circom 2.1.6;
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "./functions.circom";
/// @title ItemAtIndex
/// @notice Select item at given index from the input array
/// @notice This template that the index is valid
/// @notice This is a modified version of QuinSelector from MACI https://github.com/privacy-scaling-explorations/maci/
/// @param maxArrayLen The number of elements in the array
/// @input in The input array
/// @input index The index of the element to select
/// @output out The selected element
template ItemAtIndex(maxArrayLen) {
signal input in[maxArrayLen];
signal input index;
signal output out;
component calcTotalValue = CalculateTotal(maxArrayLen);
component calcTotalIndex = CalculateTotal(maxArrayLen);
component eqs[maxArrayLen];
// For each item, check whether its index equals the input index.
for (var i = 0; i < maxArrayLen; i ++) {
eqs[i] = IsEqual();
eqs[i].in[0] <== i;
eqs[i].in[1] <== index;
// eqs[i].out is 1 if the index matches - so calcTotal is sum of 0s + 1 * valueAtIndex
calcTotalValue.nums[i] <== eqs[i].out * in[i];
// Take the sum of all eqs[i].out and assert that it is at most 1.
calcTotalIndex.nums[i] <== eqs[i].out;
}
// Assert that the sum of eqs[i].out is 1. This is to ensure the index passed is valid.
calcTotalIndex.sum === 1;
out <== calcTotalValue.sum;
}
/// @title CalculateTotal
/// @notice Calculate the sum of an array
/// @param n The number of elements in the array
/// @input nums The input array; assumes elements are small enough that their sum does not overflow the field
/// @output sum The sum of the input array
template CalculateTotal(n) {
signal input nums[n];
signal output sum;
signal sums[n];
sums[0] <== nums[0];
for (var i=1; i < n; i++) {
sums[i] <== sums[i - 1] + nums[i];
}
sum <== sums[n - 1];
}
/// @title SelectSubArray
/// @notice Select sub array from an array given a `startIndex` and `length`
/// @notice This is same as `VarShiftLeft` but with elements after `length` set to zero
/// @notice This is not used in core ZK-Email circuits at the moment
/// @param maxArrayLen: the maximum number of bytes in the input array
/// @param maxSubArrayLen: the maximum number of integers in the output array
/// @input in: the input array
/// @input startIndex: the start index of the sub array; assumes a valid index
/// @input length: the length of the sub array; assumes to fit in `ceil(log2(maxArrayLen))` bits
/// @output out: array of `maxSubArrayLen` size, items starting from `startIndex`, and items after `length` set to zero
template SelectSubArray(maxArrayLen, maxSubArrayLen) {
assert(maxSubArrayLen < maxArrayLen);
signal input in[maxArrayLen];
signal input startIndex;
signal input length;
signal output out[maxSubArrayLen];
component shifter = VarShiftLeft(maxArrayLen, maxSubArrayLen);
shifter.in <== in;
shifter.shift <== startIndex;
// Set value after length to zero
component gts[maxSubArrayLen];
for (var i = 0; i < maxSubArrayLen; i++) {
gts[i] = GreaterThan(log2Ceil(maxSubArrayLen));
gts[i].in[0] <== length;
gts[i].in[1] <== i;
out[i] <== gts[i].out * shifter.out[i];
}
}
/// @title VarShiftLeft
/// @notice Shift input array by `shift` indices to the left
/// @notice Output array length can be reduced by setting `maxOutArrayLen`
/// @notice Based on https://demo.hedgedoc.org/s/Le0R3xUhB
/// @param maxArrayLen The maximum length of the input array
/// @param maxOutArrayLen The maximum length of the output array
/// @input in The input array
/// @input shift The number of indices to shift the array to the left
/// @output out hifted subarray
template VarShiftLeft(maxArrayLen, maxOutArrayLen) {
assert(maxOutArrayLen <= maxArrayLen);
var bitLength = log2Ceil(maxArrayLen);
signal input in[maxArrayLen];
signal input shift;
signal output out[maxOutArrayLen];
component n2b = Num2Bits(bitLength);
n2b.in <== shift;
signal tmp[bitLength][maxArrayLen];
for (var j = 0; j < bitLength; j++) {
for (var i = 0; i < maxArrayLen; i++) {
var offset = (i + (1 << j)) % maxArrayLen;
// Shift left by 2^j indices if bit is 1
if (j == 0) {
tmp[j][i] <== n2b.out[j] * (in[offset] - in[i]) + in[i];
} else {
tmp[j][i] <== n2b.out[j] * (tmp[j-1][offset] - tmp[j-1][i]) + tmp[j-1][i];
}
}
}
// Return last row
for (var i = 0; i < maxOutArrayLen; i++) {
out[i] <== tmp[bitLength - 1][i];
}
}
/// @title AssertZeroPadding
/// @notice Assert that the input array is zero-padded from the given `startIndex`
/// @param maxArrayLen The maximum number of elements in the input array
/// @input in The input array;
/// @input startIndex The index from which the elements should be 0; assumes `startIndex - 1` to fit in `ceil(log2(maxArrayLen))` bits
template AssertZeroPadding(maxArrayLen) {
var bitLength = log2Ceil(maxArrayLen);
signal input in[maxArrayLen];
signal input startIndex;
component lessThans[maxArrayLen];
for (var i = 0; i < maxArrayLen; i++) {
lessThans[i] = LessThan(bitLength);
lessThans[i].in[0] <== startIndex - 1;
lessThans[i].in[1] <== i;
lessThans[i].out * in[i] === 0;
}
}
/// @title Slice
/// @notice Extract a fixed portion of an array
/// @dev Unlike SelectSubArray, Slice uses compile-time known indices and doesn't pad the output
/// @dev Slice is more efficient for fixed ranges, while SelectSubArray offers runtime flexibility
/// @param n The length of the input array
/// @param start The starting index of the slice (inclusive)
/// @param end The ending index of the slice (exclusive)
/// @input in The input array of length n
/// @output out The sliced array of length (end - start)
template Slice(n, start, end) {
assert(n >= end);
assert(start >= 0);
assert(end >= start);
signal input in[n];
signal output out[end - start];
for (var i = start; i < end; i++) {
out[i - start] <== in[i];
}
}
/// @title CheckSubstringMatch
/// @notice Check if a substring matches the input array
/// @param maxSubstringLen The maximum length of the substring
/// @input input The portion of the input array to check
/// @input substring The substring pattern to match
/// @output isMatch 1 if the substring matches, 0 otherwise
template CheckSubstringMatch(maxSubstringLen) {
signal input in[maxSubstringLen];
signal input substring[maxSubstringLen];
signal output isMatch;
// Ensure the first element of the pattern is non-zero
signal firstElementNonZero;
firstElementNonZero <== IsZero()(substring[0]);
firstElementNonZero === 0;
signal matchAccumulator[maxSubstringLen + 1];
signal difference[maxSubstringLen];
signal isZeroDifference[maxSubstringLen];
matchAccumulator[0] <== 1;
for (var i = 0; i < maxSubstringLen; i++) {
difference[i] <== (in[i] - substring[i]) * substring[i];
isZeroDifference[i] <== IsZero()(difference[i]);
matchAccumulator[i + 1] <== matchAccumulator[i] * isZeroDifference[i];
}
isMatch <== matchAccumulator[maxSubstringLen];
}
/// @title CountSubstringOccurrences
/// @notice Count the number of times a substring occurs in the input array
/// @param maxLen The maximum length of the input array
/// @param maxSubstringLen The maximum length of the substring
/// @input in The input array to search in
/// @input substring The substring to search for
/// @output count The number of occurrences of the substring in the input
template CountSubstringOccurrences(maxLen, maxSubstringLen) {
assert(maxLen >= maxSubstringLen);
signal input in[maxLen];
signal input substring[maxSubstringLen];
signal output count;
// Check for matches at each possible starting position
component matches[maxLen];
for (var i = 0; i < maxLen; i++) {
matches[i] = CheckSubstringMatch(maxSubstringLen);
for (var j = 0; j < maxSubstringLen; j++) {
if (i + j < maxLen) {
matches[i].in[j] <== in[i + j];
} else {
matches[i].in[j] <== 0;
}
}
matches[i].substring <== substring;
}
// Sum up all matches to get the total count
component summer = CalculateTotal(maxLen);
for (var i = 0; i < maxLen; i++) {
summer.nums[i] <== matches[i].isMatch;
}
count <== summer.sum;
}

View File

@@ -1,185 +0,0 @@
pragma circom 2.1.6;
include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "./array.circom";
include "./constants.circom";
include "./functions.circom";
function computeIntChunkLength(byteLength) {
var packSize = MAX_BYTES_IN_FIELD();
var remain = byteLength % packSize;
var numChunks = (byteLength - remain) / packSize;
if (remain > 0) {
numChunks += 1;
}
return numChunks;
}
/// @title PackBytes
/// @notice Pack an array of bytes to numbers that fit in the field
/// @param maxBytes the maximum number of bytes in the input array
/// @input in the input byte array; assumes elements to be bytes
/// @output out the output integer array
template PackBytes(maxBytes) {
var packSize = MAX_BYTES_IN_FIELD();
var maxInts = computeIntChunkLength(maxBytes);
signal input in[maxBytes];
signal output out[maxInts];
signal intSums[maxInts][packSize];
for (var i = 0; i < maxInts; i++) {
for(var j=0; j < packSize; j++) {
var idx = packSize * i + j;
// Copy the previous value if we are out of bounds - we take last item as final result
if(idx >= maxBytes) {
intSums[i][j] <== intSums[i][j-1];
}
// First item of each chunk is the byte itself
else if (j == 0){
intSums[i][j] <== in[idx];
}
// Every other item is 256^j * byte
else {
intSums[i][j] <== intSums[i][j-1] + (1 << (8*j)) * in[idx];
}
}
}
// Last item of each chunk is the final sum
for (var i = 0; i < maxInts; i++) {
out[i] <== intSums[i][packSize-1];
}
}
/// @title PackByteSubArray
/// @notice Select sub array from the input array and pack it to numbers that fit in the field
/// @notice This is not used in ZK-Email circuits anywhere
/// @param maxArrayLen the maximum number of elements in the input array
/// @param maxSubArrayLen the maximum number of elements in the sub array
/// @input in the input byte array; assumes elements to be bytes
/// @input startIndex the start index of the sub array; assumes to be a valid index
/// @input length the length of the sub array; assumes to fit in `ceil(log2(maxSubArrayLen))` bits
/// @output out the output integer array
template PackByteSubArray(maxArrayLen, maxSubArrayLen) {
assert(maxSubArrayLen < maxArrayLen);
var chunkLength = computeIntChunkLength(maxSubArrayLen);
signal input in[maxArrayLen];
signal input startIndex;
signal input length;
signal output out[chunkLength];
component SelectSubArray = SelectSubArray(maxArrayLen, maxSubArrayLen);
SelectSubArray.in <== in;
SelectSubArray.startIndex <== startIndex;
SelectSubArray.length <== length;
component packer = PackBytes(maxSubArrayLen);
packer.in <== SelectSubArray.out;
out <== packer.out;
}
/// @title DigitBytesToInt
/// @notice Converts a byte array representing digits to an integer
/// @notice Assumes the output number fits in the field
/// @param n The number of bytes in the input array
/// @input in The input byte array; assumes elements are between 48 and 57 (ASCII numbers)
/// @output out The output integer; assumes to fit in the field
template DigitBytesToInt(n) {
signal input in[n];
signal output out;
signal sums[n+1];
sums[0] <== 0;
for(var i = 0; i < n; i++) {
sums[i + 1] <== 10 * sums[i] + (in[i] - 48);
}
out <== sums[n];
}
// NOTE: this circuit is unaudited and should not be used in production
/// @title SplitBytesToWords
/// @notice split an array of bytes into an array of words
/// @notice useful for casting a message or modulus before RSA verification
/// @param l: number of bytes in the input array
/// @param n: number of bits in a word
/// @param k: number of words
/// @input in: array of bytes
/// @output out: array of words
template SplitBytesToWords (l,n,k) {
signal input in[l];
signal output out[k];
component num2bits[l];
for (var i = 0 ; i < l ; i++){
num2bits[i] = Num2Bits(8);
num2bits[i].in <== in[i];
}
component bits2num[k];
for (var i = 0 ; i < k ; i++){
bits2num[i] = Bits2Num(n);
for(var j = 0 ; j < n ; j++){
if(i*n + j >= 8 * l){
bits2num[i].in[j] <== 0;
}
else{
bits2num[i].in[j] <== num2bits[l - (( i * n + j) \ 8) - 1].out[ ((i * n + j) % 8)];
}
}
}
for( var i = 0 ; i< k ; i++){
out[i] <== bits2num[i].out;
}
}
// Asserts that a given input is binary.
//
// Inputs:
// - in: an input signal, expected to be 0 or 1.
template AssertBit() {
signal input in;
in * (in - 1) === 0;
}
// The ByteMask template masks an input array using a binary mask array.
// Each element in the input array is multiplied by the corresponding element in the mask array.
// The mask array is validated to ensure all elements are binary (0 or 1).
//
// Parameters:
// - maxLength: The maximum length of the input and mask arrays.
//
// Inputs:
// - body: An array of signals representing the body to be masked.
// - mask: An array of signals representing the binary mask.
//
// Outputs:
// - out: An array of signals representing the masked input.
template ByteMask(maxLength) {
signal input in[maxLength];
signal input mask[maxLength];
signal output out[maxLength];
component bit_check[maxLength];
for (var i = 0; i < maxLength; i++) {
bit_check[i] = AssertBit();
bit_check[i].in <== mask[i];
out[i] <== in[i] * mask[i];
}
}

View File

@@ -1,15 +0,0 @@
pragma circom 2.1.6;
function EMAIL_ADDR_MAX_BYTES() {
return 256;
}
function DOMAIN_MAX_BYTES() {
return 255;
}
// Field support maximum of ~253 bit
function MAX_BYTES_IN_FIELD() {
return 31;
}

View File

@@ -1,17 +0,0 @@
pragma circom 2.1.6;
/// @function log2Ceil
/// @notice Calculate log2 of a number and round it up
/// @param a The input value
/// @return The result of the log2Ceil
function log2Ceil(a) {
var n = a - 1;
var r = 0;
while (n > 0) {
r++;
n \= 2;
}
return r;
}

View File

@@ -68,9 +68,9 @@ testSuite.forEach(({ sigAlg, hashFunction, domainParameter, keyLength }) => {
),
{
include: [
// 'node_modules',
// './node_modules/@zk-kit/binary-merkle-root.circom/src',
// './node_modules/circomlib/circuits',
'node_modules',
'./node_modules/@zk-kit/binary-merkle-root.circom/src',
'./node_modules/circomlib/circuits',
],
}
);

View File

@@ -79,7 +79,13 @@ testSuite.forEach(({ sigAlg, hashFunction, domainParameter, keyLength }) => {
path.join(
__dirname,
`../circuits/prove/instances/${getCircuitName('prove', sigAlg, hashFunction, domainParameter, keyLength)}.circom`
)
), {
include: [
'node_modules',
'./node_modules/@zk-kit/binary-merkle-root.circom/src',
'./node_modules/circomlib/circuits',
],
}
);
});
@@ -91,7 +97,7 @@ testSuite.forEach(({ sigAlg, hashFunction, domainParameter, keyLength }) => {
const w = await circuit.calculateWitness(inputs);
await circuit.checkConstraints(w);
// circuits.getOutput takes way too long for ecdsa
if (sigAlg === 'ecdsa') {
if (true) {
console.log('skipping printing outputs to console for ecdsa');
return;
}