mirror of
https://github.com/zkemail/zk-email-verify.git
synced 2026-01-09 13:38:03 -05:00
Merge pull request #202 from zkemail/feat/remove-qp-enc
Feat: Circuit for Removing the Quoted Printable Encoding in Email Body
This commit is contained in:
@@ -9,6 +9,7 @@ include "./lib/sha.circom";
|
||||
include "./utils/array.circom";
|
||||
include "./utils/regex.circom";
|
||||
include "./utils/hash.circom";
|
||||
include "./helpers/remove-soft-line-breaks.circom";
|
||||
|
||||
|
||||
/// @title EmailVerifier
|
||||
@@ -20,6 +21,7 @@ include "./utils/hash.circom";
|
||||
/// @param n Number of bits per chunk the RSA key is split into. Recommended to be 121.
|
||||
/// @param k Number of chunks the RSA key is split into. Recommended to be 17.
|
||||
/// @param ignoreBodyHashCheck Set 1 to skip body hash check in case data to prove/extract is only in the headers.
|
||||
/// @param removeSoftLineBreaks Set 1 to remove soft line breaks from the email body.
|
||||
/// @input emailHeader[maxHeadersLength] Email headers that are signed (ones in `DKIM-Signature` header) as ASCII int[], padded as per SHA-256 block size.
|
||||
/// @input emailHeaderLength Length of the email header including the SHA-256 padding.
|
||||
/// @input pubkey[k] RSA public key split into k chunks of n bits each.
|
||||
@@ -28,8 +30,10 @@ include "./utils/hash.circom";
|
||||
/// @input emailBodyLength Length of the email body including the SHA-256 padding.
|
||||
/// @input bodyHashIndex Index of the body hash `bh` in the emailHeader.
|
||||
/// @input precomputedSHA[32] Precomputed SHA-256 hash of the email body till the bodyHashIndex.
|
||||
/// @input decodedEmailBodyIn[maxBodyLength] Decoded email body without soft line breaks.
|
||||
/// @output pubkeyHash Poseidon hash of the pubkey - Poseidon(n/2)(n/2 chunks of pubkey with k*2 bits per chunk).
|
||||
template EmailVerifier(maxHeadersLength, maxBodyLength, n, k, ignoreBodyHashCheck) {
|
||||
/// @output decodedEmailBodyOut[maxBodyLength] Decoded email body with soft line breaks removed.
|
||||
template EmailVerifier(maxHeadersLength, maxBodyLength, n, k, ignoreBodyHashCheck, removeSoftLineBreaks) {
|
||||
assert(maxHeadersLength % 64 == 0);
|
||||
assert(maxBodyLength % 64 == 0);
|
||||
assert(n * k > 2048); // to support 2048 bit RSA
|
||||
@@ -122,6 +126,19 @@ template EmailVerifier(maxHeadersLength, maxBodyLength, n, k, ignoreBodyHashChec
|
||||
}
|
||||
computedBodyHashInts[i].out === headerBodyHash[i];
|
||||
}
|
||||
|
||||
if (removeSoftLineBreaks == 1) {
|
||||
signal input decodedEmailBodyIn[maxBodyLength];
|
||||
signal output decodedEmailBodyOut[maxBodyLength];
|
||||
component qpEncodingChecker = RemoveSoftLineBreaks(maxBodyLength);
|
||||
|
||||
qpEncodingChecker.encoded <== emailBody;
|
||||
qpEncodingChecker.decoded <== decodedEmailBodyIn;
|
||||
|
||||
qpEncodingChecker.isValid === 1;
|
||||
|
||||
decodedEmailBodyOut <== qpEncodingChecker.decoded;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
121
packages/circuits/helpers/remove-soft-line-breaks.circom
Normal file
121
packages/circuits/helpers/remove-soft-line-breaks.circom
Normal file
@@ -0,0 +1,121 @@
|
||||
pragma circom 2.1.6;
|
||||
|
||||
include "circomlib/circuits/comparators.circom";
|
||||
include "circomlib/circuits/mux1.circom";
|
||||
include "../utils/hash.circom";
|
||||
|
||||
/// @title RemoveSoftLineBreaks
|
||||
/// @notice This template verifies the removal of soft line breaks from an encoded input string
|
||||
/// @dev Soft line breaks are defined as "=\r\n" sequences in the encoded input
|
||||
/// @param maxLength The maximum length of the input strings
|
||||
/// @input encoded An array of ASCII values representing the input string with potential soft line breaks
|
||||
/// @input decoded An array of ASCII values representing the expected output after removing soft line breaks
|
||||
/// @output isValid A signal that is 1 if the decoded input correctly represents the encoded input with soft line breaks removed, 0 otherwise
|
||||
template RemoveSoftLineBreaks(maxLength) {
|
||||
signal input encoded[maxLength];
|
||||
signal input decoded[maxLength];
|
||||
signal output isValid;
|
||||
|
||||
// Helper signals
|
||||
signal r;
|
||||
signal processed[maxLength];
|
||||
signal isEquals[maxLength];
|
||||
signal isCr[maxLength];
|
||||
signal isLf[maxLength];
|
||||
signal tempSoftBreak[maxLength - 2];
|
||||
signal isSoftBreak[maxLength];
|
||||
signal shouldZero[maxLength];
|
||||
signal rEnc[maxLength];
|
||||
signal sumEnc[maxLength];
|
||||
signal rDec[maxLength];
|
||||
signal sumDec[maxLength];
|
||||
|
||||
// Helper components
|
||||
component muxEnc[maxLength];
|
||||
|
||||
// Deriving r from Poseidon hash
|
||||
component rHasher = PoseidonModular(2 * maxLength);
|
||||
for (var i = 0; i < maxLength; i++) {
|
||||
rHasher.in[i] <== encoded[i];
|
||||
}
|
||||
for (var i = 0; i < maxLength; i++) {
|
||||
rHasher.in[maxLength + i] <== decoded[i];
|
||||
}
|
||||
r <== rHasher.out;
|
||||
|
||||
// Check for '=' (61 in ASCII)
|
||||
for (var i = 0; i < maxLength; i++) {
|
||||
isEquals[i] <== IsEqual()([encoded[i], 61]);
|
||||
}
|
||||
|
||||
// Check for '\r' (13 in ASCII)
|
||||
for (var i = 0; i < maxLength - 1; i++) {
|
||||
isCr[i] <== IsEqual()([encoded[i + 1], 13]);
|
||||
}
|
||||
isCr[maxLength - 1] <== 0;
|
||||
|
||||
// Check for '\n' (10 in ASCII)
|
||||
for (var i = 0; i < maxLength - 2; i++) {
|
||||
isLf[i] <== IsEqual()([encoded[i + 2], 10]);
|
||||
}
|
||||
isLf[maxLength - 2] <== 0;
|
||||
isLf[maxLength - 1] <== 0;
|
||||
|
||||
// Identify soft line breaks
|
||||
for (var i = 0; i < maxLength - 2; i++) {
|
||||
tempSoftBreak[i] <== isEquals[i] * isCr[i];
|
||||
isSoftBreak[i] <== tempSoftBreak[i] * isLf[i];
|
||||
}
|
||||
// Handle the last two characters
|
||||
isSoftBreak[maxLength - 2] <== 0;
|
||||
isSoftBreak[maxLength - 1] <== 0;
|
||||
|
||||
// Determine which characters should be zeroed
|
||||
for (var i = 0; i < maxLength; i++) {
|
||||
if (i == 0) {
|
||||
shouldZero[i] <== isSoftBreak[i];
|
||||
} else if (i == 1) {
|
||||
shouldZero[i] <== isSoftBreak[i] + isSoftBreak[i-1];
|
||||
} else if (i == maxLength - 1) {
|
||||
shouldZero[i] <== isSoftBreak[i-1] + isSoftBreak[i-2];
|
||||
} else {
|
||||
shouldZero[i] <== isSoftBreak[i] + isSoftBreak[i-1] + isSoftBreak[i-2];
|
||||
}
|
||||
}
|
||||
|
||||
// Process the encoded input
|
||||
for (var i = 0; i < maxLength; i++) {
|
||||
processed[i] <== (1 - shouldZero[i]) * encoded[i];
|
||||
}
|
||||
|
||||
// Calculate powers of r for encoded
|
||||
rEnc[0] <== 1;
|
||||
for (var i = 1; i < maxLength; i++) {
|
||||
muxEnc[i] = Mux1();
|
||||
muxEnc[i].c[0] <== rEnc[i - 1] * r;
|
||||
muxEnc[i].c[1] <== rEnc[i - 1];
|
||||
muxEnc[i].s <== shouldZero[i];
|
||||
rEnc[i] <== muxEnc[i].out;
|
||||
}
|
||||
|
||||
// Calculate powers of r for decoded
|
||||
rDec[0] <== 1;
|
||||
for (var i = 1; i < maxLength; i++) {
|
||||
rDec[i] <== rDec[i - 1] * r;
|
||||
}
|
||||
|
||||
// Calculate rlc for processed
|
||||
sumEnc[0] <== processed[0];
|
||||
for (var i = 1; i < maxLength; i++) {
|
||||
sumEnc[i] <== sumEnc[i - 1] + rEnc[i] * processed[i];
|
||||
}
|
||||
|
||||
// Calculate rlc for decoded
|
||||
sumDec[0] <== decoded[0];
|
||||
for (var i = 1; i < maxLength; i++) {
|
||||
sumDec[i] <== sumDec[i - 1] + rDec[i] * decoded[i];
|
||||
}
|
||||
|
||||
// Check if rlc for decoded is equal to rlc for encoded
|
||||
isValid <== IsEqual()([sumEnc[maxLength - 1], sumDec[maxLength - 1]]);
|
||||
}
|
||||
@@ -216,3 +216,45 @@ describe("EmailVerifier : Without body check", () => {
|
||||
await circuit.checkConstraints(witness);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EmailVerifier : With soft line breaks', () => {
|
||||
jest.setTimeout(10 * 60 * 1000); // 10 minutes
|
||||
|
||||
let dkimResult: DKIMVerificationResult;
|
||||
let circuit: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
const rawEmail = fs.readFileSync(
|
||||
path.join(__dirname, './test-emails/lorem_ipsum.eml'),
|
||||
'utf8'
|
||||
);
|
||||
dkimResult = await verifyDKIMSignature(rawEmail);
|
||||
|
||||
circuit = await wasm_tester(
|
||||
path.join(
|
||||
__dirname,
|
||||
'./test-circuits/email-verifier-with-soft-line-breaks-test.circom'
|
||||
),
|
||||
{
|
||||
recompile: true,
|
||||
include: path.join(__dirname, '../../../node_modules'),
|
||||
output: path.join(__dirname, "./compiled-test-circuits"),
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should verify email when removeSoftLineBreaks is true', async function () {
|
||||
const emailVerifierInputs = generateEmailVerifierInputsFromDKIMResult(
|
||||
dkimResult,
|
||||
{
|
||||
maxHeadersLength: 640,
|
||||
maxBodyLength: 1408,
|
||||
ignoreBodyHashCheck: false,
|
||||
removeSoftLineBreaks: true,
|
||||
}
|
||||
);
|
||||
|
||||
const witness = await circuit.calculateWitness(emailVerifierInputs);
|
||||
await circuit.checkConstraints(witness);
|
||||
});
|
||||
});
|
||||
|
||||
224
packages/circuits/tests/remove-soft-line-breaks.test.ts
Normal file
224
packages/circuits/tests/remove-soft-line-breaks.test.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import { wasm as wasm_tester } from 'circom_tester';
|
||||
import path from 'path';
|
||||
|
||||
describe('RemoveSoftLineBreaks', () => {
|
||||
let circuit: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
circuit = await wasm_tester(
|
||||
path.join(
|
||||
__dirname,
|
||||
'./test-circuits/remove-soft-line-breaks-test.circom'
|
||||
),
|
||||
{
|
||||
recompile: true,
|
||||
include: path.join(__dirname, '../../../node_modules'),
|
||||
output: path.join(__dirname, './compiled-test-circuits'),
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should correctly remove soft line breaks', async () => {
|
||||
const input = {
|
||||
encoded: [
|
||||
115,
|
||||
101,
|
||||
115,
|
||||
58,
|
||||
61,
|
||||
13,
|
||||
10,
|
||||
45,
|
||||
32,
|
||||
83,
|
||||
114,
|
||||
101,
|
||||
97,
|
||||
107,
|
||||
61,
|
||||
13,
|
||||
10,
|
||||
...Array(15).fill(0),
|
||||
],
|
||||
decoded: [
|
||||
115,
|
||||
101,
|
||||
115,
|
||||
58,
|
||||
45,
|
||||
32,
|
||||
83,
|
||||
114,
|
||||
101,
|
||||
97,
|
||||
107,
|
||||
...Array(21).fill(0),
|
||||
],
|
||||
};
|
||||
|
||||
const witness = await circuit.calculateWitness(input);
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
await circuit.assertOut(witness, {
|
||||
isValid: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail when decoded input is incorrect', async () => {
|
||||
const input = {
|
||||
encoded: [
|
||||
115,
|
||||
101,
|
||||
115,
|
||||
58,
|
||||
61,
|
||||
13,
|
||||
10,
|
||||
45,
|
||||
32,
|
||||
83,
|
||||
114,
|
||||
101,
|
||||
97,
|
||||
107,
|
||||
61,
|
||||
13,
|
||||
10,
|
||||
...Array(15).fill(0),
|
||||
],
|
||||
decoded: [
|
||||
115,
|
||||
101,
|
||||
115,
|
||||
58,
|
||||
45,
|
||||
32,
|
||||
83,
|
||||
114,
|
||||
101,
|
||||
97,
|
||||
108, // Changed last character
|
||||
...Array(21).fill(0),
|
||||
],
|
||||
};
|
||||
|
||||
const witness = await circuit.calculateWitness(input);
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
await circuit.assertOut(witness, {
|
||||
isValid: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle input with no soft line breaks', async () => {
|
||||
const input = {
|
||||
encoded: [104, 101, 108, 108, 111, ...Array(27).fill(0)],
|
||||
decoded: [104, 101, 108, 108, 111, ...Array(27).fill(0)],
|
||||
};
|
||||
|
||||
const witness = await circuit.calculateWitness(input);
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
await circuit.assertOut(witness, {
|
||||
isValid: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle input with multiple consecutive soft line breaks', async () => {
|
||||
const input = {
|
||||
encoded: [
|
||||
104,
|
||||
101,
|
||||
108,
|
||||
108,
|
||||
111,
|
||||
61,
|
||||
13,
|
||||
10,
|
||||
61,
|
||||
13,
|
||||
10,
|
||||
119,
|
||||
111,
|
||||
114,
|
||||
108,
|
||||
100,
|
||||
...Array(16).fill(0),
|
||||
],
|
||||
decoded: [
|
||||
104,
|
||||
101,
|
||||
108,
|
||||
108,
|
||||
111,
|
||||
119,
|
||||
111,
|
||||
114,
|
||||
108,
|
||||
100,
|
||||
...Array(22).fill(0),
|
||||
],
|
||||
};
|
||||
|
||||
const witness = await circuit.calculateWitness(input);
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
await circuit.assertOut(witness, {
|
||||
isValid: 1,
|
||||
});
|
||||
});
|
||||
|
||||
// Note: The circuit currently does not handle the case when the encoded input starts with a soft line break.
|
||||
// This test is included to document the expected behavior, but it will fail with the current implementation.
|
||||
xit('should handle input with soft line break at the beginning', async () => {
|
||||
const input = {
|
||||
encoded: [61, 13, 10, 104, 101, 108, 108, 111, ...Array(24).fill(0)],
|
||||
decoded: [104, 101, 108, 108, 111, ...Array(27).fill(0)],
|
||||
};
|
||||
|
||||
const witness = await circuit.calculateWitness(input);
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
await circuit.assertOut(witness, {
|
||||
isValid: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle input with soft line break at the end', async () => {
|
||||
const input = {
|
||||
encoded: [104, 101, 108, 108, 111, 61, 13, 10, ...Array(24).fill(0)],
|
||||
decoded: [104, 101, 108, 108, 111, ...Array(27).fill(0)],
|
||||
};
|
||||
|
||||
const witness = await circuit.calculateWitness(input);
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
await circuit.assertOut(witness, {
|
||||
isValid: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle input with incomplete soft line break sequence', async () => {
|
||||
const input = {
|
||||
encoded: [
|
||||
104,
|
||||
101,
|
||||
108,
|
||||
108,
|
||||
111,
|
||||
61,
|
||||
13,
|
||||
11, // Not a soft line break (LF should be 10)
|
||||
...Array(24).fill(0),
|
||||
],
|
||||
decoded: [104, 101, 108, 108, 111, 61, 13, 11, ...Array(24).fill(0)],
|
||||
};
|
||||
|
||||
const witness = await circuit.calculateWitness(input);
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
await circuit.assertOut(witness, {
|
||||
isValid: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.6;
|
||||
|
||||
include "../../email-verifier.circom";
|
||||
|
||||
component main { public [ pubkey ] } = EmailVerifier(640, 768, 121, 17, 1);
|
||||
component main { public [ pubkey ] } = EmailVerifier(640, 768, 121, 17, 1, 0);
|
||||
|
||||
@@ -2,4 +2,4 @@ pragma circom 2.1.6;
|
||||
|
||||
include "../../email-verifier.circom";
|
||||
|
||||
component main { public [ pubkey ] } = EmailVerifier(640, 768, 121, 17, 0);
|
||||
component main { public [ pubkey ] } = EmailVerifier(640, 768, 121, 17, 0, 0);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.6;
|
||||
|
||||
include "../../email-verifier.circom";
|
||||
|
||||
component main { public [ pubkey ] } = EmailVerifier(640, 1408, 121, 17, 0, 1);
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.6;
|
||||
|
||||
include "../../helpers/remove-soft-line-breaks.circom";
|
||||
|
||||
component main = RemoveSoftLineBreaks(32);
|
||||
160
packages/circuits/tests/test-emails/lorem_ipsum.eml
Normal file
160
packages/circuits/tests/test-emails/lorem_ipsum.eml
Normal file
@@ -0,0 +1,160 @@
|
||||
Delivered-To: shryas.londhe@gmail.com
|
||||
Received: by 2002:a05:6a20:3211:b0:1c3:edfb:6113 with SMTP id hl17csp180962pzc;
|
||||
Thu, 25 Jul 2024 22:18:47 -0700 (PDT)
|
||||
X-Google-Smtp-Source: AGHT+IEgtqWowrWYkB2rAc4WmSlRZfsHDbqLCUjqz3wqtdhYtUDW0pbUKqYB4mgcbyvY3kUnCqDw
|
||||
X-Received: by 2002:a05:6a20:8985:b0:1c2:8ece:97a6 with SMTP id adf61e73a8af0-1c47b2033b3mr3940252637.22.1721971127167;
|
||||
Thu, 25 Jul 2024 22:18:47 -0700 (PDT)
|
||||
ARC-Seal: i=2; a=rsa-sha256; t=1721971127; cv=pass;
|
||||
d=google.com; s=arc-20160816;
|
||||
b=0ubrCXDRIoRJJB6hiGIf3+srVHL9HhzHYLCroXhk1ylBgM6a0G/9D0iUFrZBQR86m0
|
||||
u9EOZPl6xnC9B2hZ2kSiX+RHGBA5L2kmLp3e+1p9bbUWUKht+7oktAHGf4GrLeQQtvvr
|
||||
EWKgfFXFX7h9um6cW1KXKjrFpjKiiRt+fLz+dTCjEbZKQFvZLq4wA+qfyCHSyWhl03Q9
|
||||
gxfjC15TaDTiRtXWx4oQnTK0bksZAxYgZxdMXf49FN6BDu1Kips5AFZ09J+md0OzLwDB
|
||||
BgISVJn8kKLBVtitGu8ZqNys878HOuWD8Ja6VYB0Y/JsRxsaN9NWbMj3cxQimpLxU6m2
|
||||
67pg==
|
||||
ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
|
||||
h=mime-version:msip_labels:content-language:accept-language
|
||||
:message-id:date:thread-index:thread-topic:subject:to:from
|
||||
:dkim-signature;
|
||||
bh=8d5kZ05ea5AARnUCNH/+/Q/4akky7qnD3rbHtzbKp4U=;
|
||||
fh=FfnB/GPJd1sNN0SCRER252+RYTKbHbUV3t5XeSm0vpo=;
|
||||
b=UcaOhF+x2CZr88L3TJ8FM7J3i7wPDDQCTgBSfq1zMu6kORk0ceeATcaUCZpEccvV8B
|
||||
/+KJVq7JUTkr3RNfkNxvQBbIgrR9oUztVz1QRx5a6IKLBteVQSUukQ+uEe6lwiBHKJeB
|
||||
g2CV9pxd4nmCrxyOv4LLDCWxVoZ0Odj0MSaUTJt8gpT7xh38gIpZ9gHwMHlVlgHllpf2
|
||||
8YuR/LaD9AlbhRpYuKKLbSPEAmDuoYSLBwRc9aD129FPQ41Ytr++Mx71WBUELmDMJtr3
|
||||
XUnyv8nXqwMAfRUFL/nl74AHaGHiHNre1gPEXYONp2e5qQ0MS0qItvp7y/3bL49HKe9U
|
||||
kSiA==;
|
||||
dara=google.com
|
||||
ARC-Authentication-Results: i=2; mx.google.com;
|
||||
dkim=pass header.i=@outlook.com header.s=selector1 header.b=AIJlaNkX;
|
||||
arc=pass (i=1);
|
||||
spf=pass (google.com: domain of shreyas_londhe@outlook.com designates 2a01:111:f400:feab::82b as permitted sender) smtp.mailfrom=shreyas_londhe@outlook.com;
|
||||
dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=outlook.com
|
||||
Return-Path: <shreyas_londhe@outlook.com>
|
||||
Received: from APC01-SG2-obe.outbound.protection.outlook.com (mail-sgaapc01olkn2082b.outbound.protection.outlook.com. [2a01:111:f400:feab::82b])
|
||||
by mx.google.com with ESMTPS id d9443c01a7336-1fed7fecf5esi29468855ad.553.2024.07.25.22.18.46
|
||||
for <shryas.londhe@gmail.com>
|
||||
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
|
||||
Thu, 25 Jul 2024 22:18:47 -0700 (PDT)
|
||||
Received-SPF: pass (google.com: domain of shreyas_londhe@outlook.com designates 2a01:111:f400:feab::82b as permitted sender) client-ip=2a01:111:f400:feab::82b;
|
||||
Authentication-Results: mx.google.com;
|
||||
dkim=pass header.i=@outlook.com header.s=selector1 header.b=AIJlaNkX;
|
||||
arc=pass (i=1);
|
||||
spf=pass (google.com: domain of shreyas_londhe@outlook.com designates 2a01:111:f400:feab::82b as permitted sender) smtp.mailfrom=shreyas_londhe@outlook.com;
|
||||
dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=outlook.com
|
||||
ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;
|
||||
b=nyKbl9yMhkDS24habjxvJFl277C5u2qcJmklpiaGgxguIaULGcnrZL5xr1wDMe7SR7CbiRFza+fPL7s6NFDiJ/vTNlx6h6FGwAk26Mcxqxe7PX+5ETVGIkGanygNNTr80bHZ+HCL5Az01AlE91/DAEAJpjMfIcC7JvqIQO9KEitlYP/hmGvfoLhTI60qOhccOTOTo+vuYzZB1qP3Ouyaa+dP1Xa7LutLmdryT8UwRmCFFqERt2DfuXgxSPdQ1CnP9a9v0fUf99D8JoThpEBFNeDSGe54EkvrkjDEqJ+O2jNlWk4Tsk4cIFCt1Q0LR3gEPY4+HT9PYrJRZh5TpVKRIg==
|
||||
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;
|
||||
s=arcselector10001;
|
||||
h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;
|
||||
bh=8d5kZ05ea5AARnUCNH/+/Q/4akky7qnD3rbHtzbKp4U=;
|
||||
b=DQCjmdkhlADgBgWO+SA6ywRWGcteea+UrjxMCxmt5LBv9sYTtt44DLMNOPc0y3XaqXkdOT/5iyq2V3yqG47M+HSX3AmLv9SdT+ZaLycq4nljH2YHofVl6tN+pPKYbm4Jofqf2yWVRocX3AWMKAECeo85p95A/laV88YCBeDIJ97AgMWL7u45EiAo/VpB9svNDtrPGbq3PDOaciU49fpvkP4prCm0mtMFDoaIDm4dt2M0Wmf2DI8eZfvcOTcB6rBN7WhY+b10LPUrLzLI/DSmumbFmA+KFJpuKqNXjwcRrlC5lZcY5ivZEaIgvS6rJ3atQ1aHvZhSUjj6Hp1abZr3Bw==
|
||||
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
|
||||
dkim=none; arc=none
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com;
|
||||
s=selector1;
|
||||
h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
|
||||
bh=8d5kZ05ea5AARnUCNH/+/Q/4akky7qnD3rbHtzbKp4U=;
|
||||
b=AIJlaNkX4MYKjjkCZrP3zoxXcfMOV284bM69uUPlY61XmrCjzDMPMFO1M+7pHEEhXIY21IfxuI+y1m1lSoupWmxLigM5LMeytWRbeaDujaRiYShF+RnZLS4QbrYjp9xKZ6S1cTERU5E/FtI0KC2wyWG7jZ+1uojKkAJLYlpVrZ0XgmMWJZEwMlNcMAVfdM7GQoAnTRUHCfafqg71MYywt+Hj7DYWKm6Ku5kJj3qnignrblodVz4giI5zZhLme/da9MOzDfBVm9RYVg/tkOmadw39tnCdMZj4W7LpseFuEUQd/tni05Tl6yW19/7DmgpZV9z7Mz45DTDdcBkvBeNJfw==
|
||||
Received: from PSAPR06MB3909.apcprd06.prod.outlook.com (2603:1096:301:2b::8)
|
||||
by KL1PR06MB7317.apcprd06.prod.outlook.com (2603:1096:820:145::8) with
|
||||
Microsoft SMTP Server (version=TLS1_2,
|
||||
cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7784.18; Fri, 26 Jul
|
||||
2024 05:18:38 +0000
|
||||
Received: from PSAPR06MB3909.apcprd06.prod.outlook.com
|
||||
([fe80::d51a:1004:15a4:b598]) by PSAPR06MB3909.apcprd06.prod.outlook.com
|
||||
([fe80::d51a:1004:15a4:b598%6]) with mapi id 15.20.7784.020; Fri, 26 Jul 2024
|
||||
05:18:38 +0000
|
||||
From: Shreyas Londhe <shreyas_londhe@outlook.com>
|
||||
To: "shryas.londhe@gmail.com" <shryas.londhe@gmail.com>
|
||||
Subject: Lorem Ipsum
|
||||
Thread-Topic: Lorem Ipsum
|
||||
Thread-Index: AQHa3xtFXs5xQ0/RFkWl0Dt9CzcMWQ==
|
||||
Date: Fri, 26 Jul 2024 05:18:38 +0000
|
||||
Message-ID:
|
||||
<PSAPR06MB390999BBE081241FE392E60FE0B42@PSAPR06MB3909.apcprd06.prod.outlook.com>
|
||||
Accept-Language: en-IN, en-GB, en-US
|
||||
Content-Language: en-IN
|
||||
X-MS-Has-Attach:
|
||||
X-MS-TNEF-Correlator:
|
||||
msip_labels:
|
||||
x-tmn: [UsH6vtCJGTK8st72lnJGj3GdF0i/joI6ObQGBQP9T231F9Fr3YYiDRzQKqDNM5MM]
|
||||
x-ms-publictraffictype: Email
|
||||
x-ms-traffictypediagnostic: PSAPR06MB3909:EE_|KL1PR06MB7317:EE_
|
||||
x-ms-office365-filtering-correlation-id: 27414cfe-d314-4004-98f0-08dcad3267c7
|
||||
x-microsoft-antispam:
|
||||
BCL:0;ARA:14566002|461199028|8060799006|19110799003|15030799003|440099028|3412199025|102099032;
|
||||
x-microsoft-antispam-message-info:
|
||||
/A4NNAr/tb/RjJPVpt0nRXjyji71Giyp3/HyJs5Pd8WiabReUcGu0jFcinzDfdW4kZohwyB58fPH319h8m5MJU4k7Ap07UAQK1Uayr1viLDGXC9BhM5o50nhAhv1JIAAx57QZWP8O7js3PEcHQInmJzpXBrYZ9T/yGGpIWZ/ptpINRFxrf/aZtndzbYXdhp4JdaRLUkB7cuEI+/Ydgfc0FRycr5R9FiYc/vRW+F5/bzTUZPGw5+wkE90SVnEx/BwIYycHG8LFp0sYej4m33YdbNQAuRGW+sO4FI+zi0Xm4sv5JPKehdov39F6awyCqj9xgvBa6mZ9On1qWbOkbdrPO1pUci+NpTc8cSl2uwhDxScm5GWvRqeRuzIOELQivuwPoqv+BeBGsRkb1i/wJDavOFD75A/ykJFhwtFFg2WMkL4QHBtuTRTOpRR3pv36D9mUMXZ6PUgPfFy3GKWfEBPGlN6jbew+w4NPz9PEDpg5K0gIGOxufPLhlxp/zrymFeh4S3EuPotgqUrfFi3wgCC3z8UWFfuezM/o2fNq+Bi9faCoxOUA3YqBbimzQo3UhORN/UPQN64ppm0Ldm/VWa2DTv9a3LJFEwRqocuIJGQREut5xwBOgHbeCEwhcETPQ+WeQGO+fX5JF3w+LPNNlYMc32Oyj6LobOTPzznNGeDl0g=
|
||||
x-ms-exchange-antispam-messagedata-chunkcount: 1
|
||||
x-ms-exchange-antispam-messagedata-0:
|
||||
=?iso-8859-1?Q?HgHDvlQs2qQmMbHkfiZrCnNmv8IdKRyFJdAPBTKt0kdy7rUTA7S6lw9g9P?=
|
||||
=?iso-8859-1?Q?dizQGj9w4uBEz95cGlJqcOaO/1lqq2lacdXQVk1W+xJTo4PJ83a1zypy1W?=
|
||||
=?iso-8859-1?Q?AuxnNdakaoh8ZwX9Y2WqOdeb+KyhFKP8SOZhmhE0yrOG/RShO218skO7wF?=
|
||||
=?iso-8859-1?Q?SSSXxk5dz/A94gBVv3H4bZD1dXKFbvEHQPRFMk1EG8dKONvFiCYXW9IISq?=
|
||||
=?iso-8859-1?Q?5sIwixUbJ7yCjC1dUl32m8efUvJ4EZ4NnuDyQUp3F62J/I+G+8QQPzmytY?=
|
||||
=?iso-8859-1?Q?+gQqdrzwi8uh2gqkX1aIZC1IZDymikQunPyzc5kjnJKAkpVhAfc7Lz3hwE?=
|
||||
=?iso-8859-1?Q?Pf0zl1xPkGQlqBY7Di2AdJii2hD+9BgdCpbfXaG5NYuMcHV1IquLXiUSYD?=
|
||||
=?iso-8859-1?Q?jiGvPxsZkhW6vYEB4UHa5257kzKWLXsYXGKibWTWiOIJ1LvJbhJqf8DZ2z?=
|
||||
=?iso-8859-1?Q?DbLHx2k415voT1LbSTnT6j8mn7O6oDjOP8LVzlzAlfWBxF1REkmusbc95t?=
|
||||
=?iso-8859-1?Q?W1buwpUqF+JqNHzdPTe11QwMq/KXExWau1vX7miDomysMRUo3QuiH8C1IX?=
|
||||
=?iso-8859-1?Q?YW2oDF+QYCEobP6W2iOCo7WqapQp8PDqwNbQLoS8fopf/jube6t9snIs7R?=
|
||||
=?iso-8859-1?Q?Ny8imXA1d9d41Xh8QxnIN70NIMbqKUMKKyDm6klMXTMjZnCQht+3eGqWUZ?=
|
||||
=?iso-8859-1?Q?DKYSS34Q4ifBEDEqOi5lhkg8HrcVcNotkKRMljZuCX1Clb+FZuRsahpXMJ?=
|
||||
=?iso-8859-1?Q?2FC6PeU0tXQBYWc2rD9vGCnT9+qrHG0cY5hs+LzbYfKw3Pq8+p/sSyAQSM?=
|
||||
=?iso-8859-1?Q?i5ch1oN6i4cCzOncZ8TN/GGZN004MBB+OHaNp071aRkqqLix0lhQLGP4hY?=
|
||||
=?iso-8859-1?Q?XHD0FS+t07mkW7pOnBYP89laxTDpuGw2ZKvGy6DUEYcSXS3nujeamXYraR?=
|
||||
=?iso-8859-1?Q?zUKQfu+0SUaGgoe3uIexst//uXTHpy8h4nm+bWNsU31C2EdGH/qgUdXe7T?=
|
||||
=?iso-8859-1?Q?mYZHL03uzOYBh81MYVE6GxDpWeGnFKpCw3aYnLH8MhmzeIP1wHsrkttJoh?=
|
||||
=?iso-8859-1?Q?uehR7s1hvxU7chWGY2dQb4FfJccls0PEKwOHk2BvqtBawe5/p5PD8M9eUJ?=
|
||||
=?iso-8859-1?Q?x+iMiptyavqxh82zEiuWkcIOcj1R2WPzI9cyxDUYCZ5CM56A5SKU+cKU+s?=
|
||||
=?iso-8859-1?Q?GfB8IMyemcjC3wAcE9hql5+1OCU4oKkSjZlzItDo5F9V9JmYLRMXSZUP3w?=
|
||||
=?iso-8859-1?Q?UbvTI7DVESPxDYnJUZMHp81jc9QRMaNabO3aI4RkYTzvG/JDFBF/p12Dag?=
|
||||
=?iso-8859-1?Q?BLdMdMHePvmjpiVNwfbrAjtRaQUYhUPmzZ2pwQueK4/1P5M=3D?=
|
||||
Content-Type: multipart/alternative;
|
||||
boundary="_000_PSAPR06MB390999BBE081241FE392E60FE0B42PSAPR06MB3909apcp_"
|
||||
MIME-Version: 1.0
|
||||
X-OriginatorOrg: outlook.com
|
||||
X-MS-Exchange-CrossTenant-AuthAs: Internal
|
||||
X-MS-Exchange-CrossTenant-AuthSource: PSAPR06MB3909.apcprd06.prod.outlook.com
|
||||
X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000
|
||||
X-MS-Exchange-CrossTenant-Network-Message-Id: 27414cfe-d314-4004-98f0-08dcad3267c7
|
||||
X-MS-Exchange-CrossTenant-originalarrivaltime: 26 Jul 2024 05:18:38.0606
|
||||
(UTC)
|
||||
X-MS-Exchange-CrossTenant-fromentityheader: Hosted
|
||||
X-MS-Exchange-CrossTenant-id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa
|
||||
X-MS-Exchange-CrossTenant-rms-persistedconsumerorg: 00000000-0000-0000-0000-000000000000
|
||||
X-MS-Exchange-Transport-CrossTenantHeadersStamped: KL1PR06MB7317
|
||||
|
||||
--_000_PSAPR06MB390999BBE081241FE392E60FE0B42PSAPR06MB3909apcp_
|
||||
Content-Type: text/plain; charset="iso-8859-1"
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus et imperdi=
|
||||
et neque. Cras mattis dolor eu ex pharetra blandit. Integer diam justo, int=
|
||||
erdum et erat at, elementum rhoncus neque. Sed dui enim, pretium non est eg=
|
||||
et, ornare eleifend ipsum.
|
||||
|
||||
--_000_PSAPR06MB390999BBE081241FE392E60FE0B42PSAPR06MB3909apcp_
|
||||
Content-Type: text/html; charset="iso-8859-1"
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Diso-8859-=
|
||||
1">
|
||||
<style type=3D"text/css" style=3D"display:none;"> P {margin-top:0;margin-bo=
|
||||
ttom:0;} </style>
|
||||
</head>
|
||||
<body dir=3D"ltr">
|
||||
<div class=3D"elementToProof" style=3D"font-family: Aptos, Aptos_EmbeddedFo=
|
||||
nt, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; c=
|
||||
olor: rgb(0, 0, 0);">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus et imperdi=
|
||||
et neque. Cras mattis dolor eu ex pharetra blandit. Integer diam justo, int=
|
||||
erdum et erat at, elementum rhoncus neque. Sed dui enim, pretium non est eg=
|
||||
et, ornare eleifend ipsum.</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
--_000_PSAPR06MB390999BBE081241FE392E60FE0B42PSAPR06MB3909apcp_--
|
||||
@@ -162,3 +162,25 @@ template AssertZeroPadding(maxArrayLen) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
pragma circom 2.1.6;
|
||||
|
||||
include "circomlib/circuits/poseidon.circom";
|
||||
include "./array.circom";
|
||||
|
||||
/// @title PoseidonLarge
|
||||
/// @notice Circuit to calculate Poseidon hash of inputs more than 16
|
||||
@@ -36,3 +38,46 @@ template PoseidonLarge(bitsPerChunk, chunkSize) {
|
||||
out <== Poseidon(halfChunkSize)(poseidonInput);
|
||||
}
|
||||
|
||||
/// @title PoseidonModular
|
||||
/// @notice Circuit to calculate Poseidon hash of an arbitrary number of inputs
|
||||
/// @notice Splits input into chunks of 16 elements (or less for the last chunk) and hashes them separately
|
||||
/// @notice Then combines the chunk hashes using a binary tree structure
|
||||
/// @notice This is a modified version from: https://github.com/burnt-labs/email-wallet/blob/b6601fed6fc1bf119739dce6a49e69d69144c5fa/circuits/utils/commit.circom#L24
|
||||
/// @param numElements Number of elements in the input array
|
||||
/// @input in: Array of numElements to be hashed
|
||||
/// @output out: Poseidon hash of the input array
|
||||
template PoseidonModular(numElements) {
|
||||
signal input in[numElements];
|
||||
signal output out;
|
||||
|
||||
var chunks = numElements \ 16;
|
||||
var last_chunk_size = numElements % 16;
|
||||
if (last_chunk_size != 0) {
|
||||
chunks += 1;
|
||||
}
|
||||
|
||||
var _out;
|
||||
|
||||
for (var i = 0; i < chunks; i++) {
|
||||
var start = i * 16;
|
||||
var end = start + 16;
|
||||
var chunk_hash;
|
||||
|
||||
if (end > numElements) { // last chunk
|
||||
end = numElements;
|
||||
var last_chunk[last_chunk_size] = Slice(numElements, start, end)(in);
|
||||
chunk_hash = Poseidon(last_chunk_size)(last_chunk);
|
||||
} else {
|
||||
var chunk[16] = Slice(numElements, start, end)(in);
|
||||
chunk_hash = Poseidon(16)(chunk);
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
_out = chunk_hash;
|
||||
} else {
|
||||
_out = Poseidon(2)([_out, chunk_hash]);
|
||||
}
|
||||
}
|
||||
|
||||
out <== _out;
|
||||
}
|
||||
@@ -12,6 +12,7 @@ type CircuitInput = {
|
||||
emailBodyLength?: string;
|
||||
precomputedSHA?: string[];
|
||||
bodyHashIndex?: string;
|
||||
decodedEmailBodyIn?: string[];
|
||||
};
|
||||
|
||||
type InputGenerationArgs = {
|
||||
@@ -19,8 +20,31 @@ type InputGenerationArgs = {
|
||||
shaPrecomputeSelector?: string;
|
||||
maxHeadersLength?: number; // Max length of the email header including padding
|
||||
maxBodyLength?: number; // Max length of the email body after shaPrecomputeSelector including padding
|
||||
removeSoftLineBreaks?: boolean;
|
||||
};
|
||||
|
||||
function removeSoftLineBreaks(body: string[]): string[] {
|
||||
const result = [];
|
||||
let i = 0;
|
||||
while (i < body.length) {
|
||||
if (i + 2 < body.length &&
|
||||
body[i] === '61' && // '=' character
|
||||
body[i + 1] === '13' && // '\r' character
|
||||
body[i + 2] === '10') { // '\n' character
|
||||
// Skip the soft line break sequence
|
||||
i += 3; // Move past the soft line break
|
||||
} else {
|
||||
result.push(body[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// Pad the result with zeros to make it the same length as the body
|
||||
while (result.length < body.length) {
|
||||
result.push('0');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Generate circuit inputs for the EmailVerifier circuit from raw email content
|
||||
@@ -97,6 +121,10 @@ export function generateEmailVerifierInputsFromDKIMResult(
|
||||
circuitInputs.precomputedSHA = Uint8ArrayToCharArray(precomputedSha);
|
||||
circuitInputs.bodyHashIndex = bodyHashIndex.toString();
|
||||
circuitInputs.emailBody = Uint8ArrayToCharArray(bodyRemaining);
|
||||
|
||||
if (params.removeSoftLineBreaks) {
|
||||
circuitInputs.decodedEmailBodyIn = removeSoftLineBreaks(circuitInputs.emailBody);
|
||||
}
|
||||
}
|
||||
|
||||
return circuitInputs;
|
||||
|
||||
Reference in New Issue
Block a user