Skip to content

Commit

Permalink
rewrote email.circom to use anonymous syntax instead, making it way s…
Browse files Browse the repository at this point in the history
…maller
  • Loading branch information
Divide-By-0 committed Mar 31, 2023
1 parent 0e00293 commit bd41e9d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 72 deletions.
6 changes: 3 additions & 3 deletions circuits/dkim_header_regex.circom
Original file line number Diff line number Diff line change
Expand Up @@ -709,8 +709,8 @@ template DKIMHeaderRegex (msg_bytes) {
}
out <== final_state_sum[num_bytes];

signal output reveal[num_bytes];
for (var i = 0; i < num_bytes; i++) {
reveal[i] <== in[i] * (states[i+1][18] + states[i+1][14]);
signal output reveal[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
reveal[i] <== in[i+1] * (states[i+2][18] + states[i+2][14]);
}
}
94 changes: 25 additions & 69 deletions circuits/email.circom
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,10 @@ template EmailVerify(max_header_bytes, max_body_bytes, n, k, pack_size) {
// section of the "DKIM-Signature:"" line, along with the body hash.
// Note that nothing above the "DKIM-Signature:" line is signed.
component sha = Sha256Bytes(max_header_bytes);
for (var i = 0; i < max_header_bytes; i++) {
sha.in_padded[i] <== in_padded[i];
}
sha.in_padded <== in_padded;
sha.in_len_padded_bytes <== in_len_padded_bytes;
var msg_len = (256+n)\n;

component base_msg[msg_len];
for (var i = 0; i < msg_len; i++) {
base_msg[i] = Bits2Num(n);
Expand All @@ -88,97 +87,54 @@ template EmailVerify(max_header_bytes, max_body_bytes, n, k, pack_size) {
for (var i = msg_len; i < k; i++) {
rsa.base_message[i] <== 0;
}
for (var i = 0; i < k; i++) {
rsa.modulus[i] <== modulus[i];
}
for (var i = 0; i < k; i++) {
rsa.signature[i] <== signature[i];
}
rsa.modulus <== modulus;
rsa.signature <== signature;

// DKIM HEADER REGEX: 736,553 constraints
// This extracts the from and the to emails, and the precise regex format can be viewed in the README
component dkim_header_regex = DKIMHeaderRegex(max_header_bytes);
for (var i = 0; i < max_header_bytes; i++) {
dkim_header_regex.msg[i] <== in_padded[i];
}
dkim_header_regex.out === 2;
component from_revealer = ShiftAndPack(max_header_bytes, max_email_from_len, pack_size);
for (var i = 0; i < max_header_bytes; i++) {
// TODO: WARNING!!!!!!! CHECK FOR OFF BY ONE ERROR
from_revealer.in[i] <== dkim_header_regex.reveal[i+1];
}
from_revealer.shift <== email_from_idx;
for (var i = 0; i < max_email_from_packed_bytes; i++) {
reveal_email_from_packed[i] <== from_revealer.out[i];
}
log(dkim_header_regex.reveal[0]);
log(dkim_header_regex.out);
signal dkim_header_regex_out, dkim_header_regex_reveal[max_header_bytes];
(dkim_header_regex_out, dkim_header_regex_reveal) <== DKIMHeaderRegex(max_header_bytes)(in_padded);
dkim_header_regex_out === 2;
reveal_email_from_packed <== ShiftAndPack(max_header_bytes, max_email_from_len, pack_size)(dkim_header_regex_reveal, email_from_idx);

// BODY HASH REGEX: 617,597 constraints
// This extracts the body hash from the header (i.e. the part after bh= within the DKIM-signature section)
// which is used to verify the body text matches this signed hash + the signature verifies this hash is legit
component body_hash_regex = BodyHashRegex(max_header_bytes);
for (var i = 0; i < max_header_bytes; i++) {
body_hash_regex.msg[i] <== in_padded[i];
}
body_hash_regex.out === 1;
component bh_packer = VarShiftLeft(max_header_bytes, LEN_SHA_B64);
for (var i = 0; i < max_header_bytes; i++) {
// TODO: Verify off by 1 error
bh_packer.in[i] <== body_hash_regex.reveal[i];
}
bh_packer.shift <== body_hash_idx;
log(body_hash_regex.out);
signal bh_regex_out, bh_reveal[max_header_bytes];
(bh_regex_out, bh_reveal) <== BodyHashRegex(max_header_bytes)(in_padded);
bh_regex_out === 1;
// TODO: Verify no off by 1 error
signal shifted_bh_out[LEN_SHA_B64] <== VarShiftLeft(max_header_bytes, LEN_SHA_B64)(bh_reveal, body_hash_idx);
// log(body_hash_regex.out);

// SHA BODY: 760,142 constraints
// This verifies that the hash of the body, when calculated from the precomputed part forwards,
// actually matches the hash in the header
component sha_body = Sha256BytesPartial(max_body_bytes);
for (var i = 0; i < max_body_bytes; i++) {
sha_body.in_padded[i] <== in_body_padded[i];
}
for (var i = 0; i < 32; i++) {
sha_body.pre_hash[i] <== precomputed_sha[i];
}
sha_body.in_len_padded_bytes <== in_body_len_padded_bytes;
component sha_b64 = Base64Decode(32);
for (var i = 0; i < LEN_SHA_B64; i++) {
sha_b64.in[i] <== bh_packer.out[i];
}
signal sha_body_out[256] <== Sha256BytesPartial(max_body_bytes)(in_body_padded, in_body_len_padded_bytes, precomputed_sha);
signal sha_b64_out[32] <== Base64Decode(32)(shifted_bh_out);

// When we convert the manually hashed email sha_body into bytes, it matches the
// base64 decoding of the final hash state that the signature signs (sha_b64)
component sha_body_bytes[32];
for (var i = 0; i < 32; i++) {
sha_body_bytes[i] = Bits2Num(8);
for (var j = 0; j < 8; j++) {
sha_body_bytes[i].in[7-j] <== sha_body.out[i*8+j];
sha_body_bytes[i].in[7-j] <== sha_body_out[i*8+j];
}
sha_body_bytes[i].out === sha_b64.out[i];
sha_body_bytes[i].out === sha_b64_out[i];
}

// TWITTER REGEX: 328,044 constraints
// This computes the regex states on each character in the email body. For new emails, this is the
// section that you want to swap out via using the zk-regex library.
component twitter_regex = TwitterResetRegex(max_body_bytes);
for (var i = 0; i < max_body_bytes; i++) {
twitter_regex.msg[i] <== in_body_padded[i];
}

// This ensures we found a match at least once
component found_twitter = IsZero();
found_twitter.in <== twitter_regex.out;
found_twitter.out === 0;
signal twitter_regex_out, twitter_regex_reveal[max_body_bytes];
(twitter_regex_out, twitter_regex_reveal) <== TwitterResetRegex(max_body_bytes)(in_body_padded);
// This ensures we found a match at least once (i.e. match count is not zero)
signal is_found_twitter <== IsZero()(twitter_regex_out);
is_found_twitter === 0;

// PACKING: 16,800 constraints (Total: 3,115,057)
component twitter_revealer = ShiftAndPack(max_body_bytes, max_twitter_len, pack_size);
for (var i = 0; i < max_body_bytes; i++) {
// TODO: WARNING!!!!!!! CHECK FOR OFF BY ONE ERROR
twitter_revealer.in[i] <== twitter_regex.reveal[i];
}
twitter_revealer.shift <== twitter_username_idx;
for (var i = 0; i < max_twitter_packed_bytes; i++) {
reveal_twitter_packed[i] <== twitter_revealer.out[i];
}
reveal_twitter_packed <== ShiftAndPack(max_body_bytes, max_twitter_len, pack_size)(twitter_regex_reveal, twitter_username_idx);
}

// In circom, all output signals of the main component are public (and cannot be made private), the input signals of the main component are private if not stated otherwise using the keyword public as above. The rest of signals are all private and cannot be made public.
Expand Down

0 comments on commit bd41e9d

Please sign in to comment.