mirror of
https://github.com/zkemail/zk-email-verify.git
synced 2026-01-10 05:58:08 -05:00
129 lines
3.8 KiB
Plaintext
129 lines
3.8 KiB
Plaintext
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(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() {
|
|
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;
|
|
}
|