Skip to content

Commit

Permalink
Merge pull request #13 from zkemail/feat/feature-parity
Browse files Browse the repository at this point in the history
Feat/feature parity
  • Loading branch information
jp4g authored Oct 18, 2024
2 parents 9a75bad + ec2ae14 commit e375593
Show file tree
Hide file tree
Showing 27 changed files with 1,306 additions and 368 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
node_modules
target
dist
.tsbuildinfo
.tsbuildinfo
zk-email-verify
!*/email-*.eml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "recipient_search"
name = "email_mask"
type = "bin"
authors = ["Mach 34"]
compiler_version = ">=0.34.0"
compiler_version = ">=0.35.0"

[dependencies]
zkemail = { path = "../../lib"}
60 changes: 60 additions & 0 deletions examples/email_mask/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use dep::zkemail::{
KEY_LIMBS_2048, dkim::RSAPubkey, headers::body_hash::get_body_hash,
standard_outputs, Sequence, masking::mask_text
};
use dep::std::{collections::bounded_vec::BoundedVec, hash::sha256_var};

global MAX_EMAIL_HEADER_LENGTH: u32 = 512;
global MAX_EMAIL_BODY_LENGTH: u32 = 1024;

/**
* Verify an arbitrary email signed by a 2048-bit RSA DKIM signature and mask outputs
*
* @param header - The email header, 0-padded at end to the MAX_EMAIL_HEADER_LENGTH
* @param body - The email body, 0-padded at end to the MAX_EMAIL_BODY_LENGTH
* @param pubkey - The DKIM RSA Public Key modulus and reduction parameter
* @param signature - The DKIM RSA Signature
* @param body_hash_index - The index of the body hash in the partial hash array
* @param dkim_header_sequence - The index and length of the DKIM header field
* @param header_mask - The mask for the header
* @param body_mask - The mask for the body
* @return -
* 0: Pedersen hash of DKIM public key (root of trust)
* 1: Pedersen hash of DKIM signature (email nullifier)
*/
fn main(
header: BoundedVec<u8, MAX_EMAIL_HEADER_LENGTH>,
body: BoundedVec<u8, MAX_EMAIL_BODY_LENGTH>,
pubkey: RSAPubkey<KEY_LIMBS_2048>,
signature: [Field; KEY_LIMBS_2048],
body_hash_index: u32,
dkim_header_sequence: Sequence,
header_mask: [bool; MAX_EMAIL_HEADER_LENGTH],
body_mask: [bool; MAX_EMAIL_BODY_LENGTH]
) -> pub ([Field; 2], [u8; MAX_EMAIL_HEADER_LENGTH], [u8; MAX_EMAIL_BODY_LENGTH]) {
// check the body and header lengths are within bounds
assert(header.len() <= MAX_EMAIL_HEADER_LENGTH);
assert(body.len() <= MAX_EMAIL_BODY_LENGTH);

// verify the dkim signature over the header
pubkey.verify_dkim_signature(header, signature);

// extract the body hash from the header
let signed_body_hash = get_body_hash(header, dkim_header_sequence, body_hash_index);

// hash the asserted body
let computed_body_hash: [u8; 32] = sha256_var(body.storage, body.len() as u64);

// compare the body hashes
assert(
signed_body_hash == computed_body_hash, "SHA256 hash computed over body does not match body hash found in DKIM-signed header"
);

// mask the header and body
let masked_header = mask_text(header, header_mask);
let masked_body = mask_text(body, body_mask);

// hash the pubkey and signature for the standard outputs
let standard_out = standard_outputs(pubkey.modulus, signature);
(standard_out, masked_header, masked_body)
}
8 changes: 8 additions & 0 deletions examples/extract_addresses/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "extract_addresses"
type = "bin"
authors = ["Mach 34"]
compiler_version = ">=0.35.0"

[dependencies]
zkemail = { path = "../../lib"}
55 changes: 55 additions & 0 deletions examples/extract_addresses/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use dep::zkemail::{
KEY_LIMBS_2048, dkim::RSAPubkey,
headers::{body_hash::get_body_hash, email_address::get_email_address}, standard_outputs, Sequence,
MAX_EMAIL_ADDRESS_LENGTH
};
use dep::std::{collections::bounded_vec::BoundedVec, hash::sha256_var};

global MAX_EMAIL_HEADER_LENGTH: u32 = 512;
global MAX_EMAIL_BODY_LENGTH: u32 = 1024;

/**
* Verify an arbitrary email signed by a 2048-bit RSA DKIM signature and extract sender and recipient addresses
* @dev example of only constraining access to the header too
*
* @param header - The email header, 0-padded at end to the MAX_EMAIL_HEADER_LENGTH
* @param pubkey - The DKIM RSA Public Key modulus and reduction parameter
* @param signature - The DKIM RSA Signature
* @param from_header_sequence - The index and length of the "From" header field
* @param from_address_sequence - The index and length of the "From" email address
* @param to_header_sequence - The index and length of the "To" header field
* @param to_address_sequence - The index and length of the "To" email address
* @return -
* 0: Pedersen hash of DKIM public key (root of trust)
* 1: Pedersen hash of DKIM signature (email nullifier)
*/
fn main(
header: BoundedVec<u8, MAX_EMAIL_HEADER_LENGTH>,
pubkey: RSAPubkey<KEY_LIMBS_2048>,
signature: [Field; KEY_LIMBS_2048],
from_header_sequence: Sequence,
from_address_sequence: Sequence,
to_header_sequence: Sequence,
to_address_sequence: Sequence
) -> pub ([Field; 2], BoundedVec<u8, MAX_EMAIL_ADDRESS_LENGTH>, BoundedVec<u8, MAX_EMAIL_ADDRESS_LENGTH>) {
// check the body and header lengths are within bounds
assert(header.len() <= MAX_EMAIL_HEADER_LENGTH);

// verify the dkim signature over the header
pubkey.verify_dkim_signature(header, signature);

// extract to and from email addresses
let from = comptime {
"from".as_bytes()
};
let to = comptime {
"to".as_bytes()
};
// 16k gate cost? has to be able to be brought down
let from_address = get_email_address(header, from_header_sequence, from_address_sequence, from);
let to_address = get_email_address(header, to_header_sequence, to_address_sequence, to);

// hash the pubkey and signature for the standard outputs
let standard_out = standard_outputs(pubkey.modulus, signature);
(standard_out, from_address, to_address)
}
2 changes: 1 addition & 1 deletion examples/partial_hash/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "partial_hash"
type = "bin"
authors = ["Mach 34"]
compiler_version = ">=0.34.0"
compiler_version = ">=0.35.0"

[dependencies]
zkemail = { path = "../../lib"}
31 changes: 14 additions & 17 deletions examples/partial_hash/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use dep::zkemail::{
KEY_LIMBS_2048, dkim::verify_dkim_2048, get_body_hash_by_index, base64::body_hash_base64_decode,
partial_hash::partial_sha256_var_end, standard_outputs
KEY_LIMBS_2048, dkim::RSAPubkey, headers::body_hash::get_body_hash,
partial_hash::partial_sha256_var_end, standard_outputs, Sequence
};

global MAX_EMAIL_HEADER_LENGTH: u32 = 512;
Expand All @@ -24,36 +24,33 @@ global MAX_PARTIAL_EMAIL_BODY_LENGTH: u32 = 192;
* 1: Pedersen hash of DKIM signature (email nullifier)
*/
fn main(
header: BoundedVec<u8, MAX_EMAIL_HEADER_LENGTH>,
body: BoundedVec<u8, MAX_PARTIAL_EMAIL_BODY_LENGTH>,
pubkey: RSAPubkey<KEY_LIMBS_2048>,
signature: [Field; KEY_LIMBS_2048],
body_hash_index: u32,
header: [u8; MAX_EMAIL_HEADER_LENGTH],
header_length: u32,
body: [u8; MAX_PARTIAL_EMAIL_BODY_LENGTH], // use partial body length instead of full body length
body_length: u32,
dkim_header_sequence: Sequence,
partial_body_hash: [u32; 8],
partial_body_length: u32,
pubkey: [Field; KEY_LIMBS_2048],
pubkey_redc: [Field; KEY_LIMBS_2048],
signature: [Field; KEY_LIMBS_2048]
partial_body_real_length: u64
) -> pub [Field; 2] {
// check the body and header lengths are within bounds
assert(header_length <= MAX_EMAIL_HEADER_LENGTH, "Email header length exceeds maximum length");
assert(partial_body_length <= MAX_PARTIAL_EMAIL_BODY_LENGTH, "Partial email body length exceeds maximum length");
assert(header.len() <= MAX_EMAIL_HEADER_LENGTH, "Email header length exceeds maximum length");
assert(body.len() <= MAX_PARTIAL_EMAIL_BODY_LENGTH, "Partial email body length exceeds maximum length");

// verify the dkim signature over the header
verify_dkim_2048(header, header_length, pubkey, pubkey_redc, signature);
pubkey.verify_dkim_signature(header, signature);

// manually extract the body hash from the header
let body_hash_encoded = get_body_hash_by_index(header, body_hash_index);
let signed_body_hash: [u8; 32] = body_hash_base64_decode(body_hash_encoded);
let signed_body_hash = get_body_hash(header, dkim_header_sequence, body_hash_index);

// finish the partial hash
let computed_body_hash = partial_sha256_var_end(partial_body_hash, body, partial_body_length as u64, body_length as u64);
let computed_body_hash = partial_sha256_var_end(partial_body_hash, body.storage(), body.len() as u64, partial_body_real_length);

// check the body hashes match
assert(
signed_body_hash == computed_body_hash, "Sha256 hash computed over body does not match DKIM-signed header"
);

// hash the pubkey and signature for the standard outputs
standard_outputs(pubkey, signature)
standard_outputs(pubkey.modulus, signature)
}
42 changes: 0 additions & 42 deletions examples/recipient_search/src/main.nr

This file was deleted.

2 changes: 1 addition & 1 deletion examples/verify_email_1024_bit_dkim/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "verify_email_1024_bit_dkim"
type = "bin"
authors = ["Mach 34"]
compiler_version = ">=0.34.0"
compiler_version = ">=0.35.0"

[dependencies]
zkemail = { path = "../../lib"}
42 changes: 18 additions & 24 deletions examples/verify_email_1024_bit_dkim/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,58 +1,52 @@
use dep::zkemail::{
KEY_LIMBS_1024, dkim::verify_dkim_1024, get_body_hash_by_index, base64::body_hash_base64_decode,
standard_outputs
KEY_LIMBS_1024, dkim::RSAPubkey, headers::body_hash::get_body_hash,
standard_outputs, Sequence
};
use dep::std::hash::sha256_var;
use dep::std::{collections::bounded_vec::BoundedVec, hash::sha256_var};

global MAX_EMAIL_HEADER_LENGTH: u32 = 512;
global MAX_EMAIL_BODY_LENGTH: u32 = 1024;

/**
* Verify an arbitrary email signed by a 1024-bit RSA DKIM signature
* @dev TOTAL CONSTRAINTS: ~222,783
*
* @param body_hash_index - The index of the body hash in the partial hash array
* @param header - The email header, 0-padded at end to the MAX_EMAIL_HEADER_LENGTH
* @param header_length - The actual length of the email header
* @param body - The email body, 0-padded at end to the MAX_EMAIL_BODY_LENGTH
* @param body_length - The actual length of the email body
* @param pubkey_modulus_limbs - The DKIM RSA Pubkey
* @param redc_params_limbs - Barrett Reduction Parameter for Pubkey for efficient signature verification
* @param pubkey - The DKIM RSA Public Key modulus and reduction parameter
* @param signature - The DKIM RSA Signature
* @param body_hash_index - The index of the body hash in the partial hash array
* @param dkim_header_sequence - The index and length of the DKIM header field
* @return -
* 0: Pedersen hash of DKIM public key (root of trust)
* 1: Pedersen hash of DKIM signature (email nullifier)
*/
fn main(
header: BoundedVec<u8, MAX_EMAIL_HEADER_LENGTH>,
body: BoundedVec<u8, MAX_EMAIL_BODY_LENGTH>,
pubkey: RSAPubkey<KEY_LIMBS_1024>,
signature: [Field; KEY_LIMBS_1024],
body_hash_index: u32,
header: [u8; MAX_EMAIL_HEADER_LENGTH],
header_length: u32,
body: [u8; MAX_EMAIL_BODY_LENGTH],
body_length: u32,
pubkey: [Field; KEY_LIMBS_1024],
pubkey_redc: [Field; KEY_LIMBS_1024],
signature: [Field; KEY_LIMBS_1024]
dkim_header_sequence: Sequence
) -> pub [Field; 2] {
// check the body and header lengths are within bounds
assert(header_length <= MAX_EMAIL_HEADER_LENGTH);
assert(body_length <= MAX_EMAIL_BODY_LENGTH);
assert(header.len() <= MAX_EMAIL_HEADER_LENGTH);
assert(body.len() <= MAX_EMAIL_BODY_LENGTH);

// verify the dkim signature over the header
verify_dkim_1024(header, header_length, pubkey, pubkey_redc, signature);
pubkey.verify_dkim_signature(header, signature);

// extract the body hash from the header
let body_hash_encoded = get_body_hash_by_index(header, body_hash_index);

// base64 decode the body hash
let signed_body_hash: [u8; 32] = body_hash_base64_decode(body_hash_encoded);
let signed_body_hash = get_body_hash(header, dkim_header_sequence,body_hash_index);

// hash the asserted body
let computed_body_hash: [u8; 32] = sha256_var(body, body_length as u64);
let computed_body_hash: [u8; 32] = sha256_var(body.storage(), body.len() as u64);

// compare the body hashes
assert(
signed_body_hash == computed_body_hash, "SHA256 hash computed over body does not match body hash found in DKIM-signed header"
);

// hash the pubkey and signature for the standard outputs
standard_outputs(pubkey, signature)
standard_outputs(pubkey.modulus, signature)
}
2 changes: 1 addition & 1 deletion examples/verify_email_2048_bit_dkim/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "verify_email_2048_bit_dkim"
type = "bin"
authors = ["Mach 34"]
compiler_version = ">=0.34.0"
compiler_version = ">=0.35.0"

[dependencies]
zkemail = { path = "../../lib"}
Loading

0 comments on commit e375593

Please sign in to comment.