diff --git a/circuits/dkim_header_regex.circom b/circuits/dkim_header_regex.circom index 98c7045d3..ce9570276 100644 --- a/circuits/dkim_header_regex.circom +++ b/circuits/dkim_header_regex.circom @@ -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]); } } diff --git a/circuits/email.circom b/circuits/email.circom index f2319cf7d..e2486aa28 100644 --- a/circuits/email.circom +++ b/circuits/email.circom @@ -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); @@ -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.