Skip to content

Commit

Permalink
fix: upload noir
Browse files Browse the repository at this point in the history
olehmisar committed Oct 24, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent e6b3ff9 commit b69a866
Showing 5 changed files with 115 additions and 2 deletions.
2 changes: 0 additions & 2 deletions apps/zkemail/src/lib/noir.ts
Original file line number Diff line number Diff line change
@@ -112,7 +112,6 @@ export class ZkEmailCircuitService {
}

async verify(proof: EmailProof) {
// TODO(security): get headersReveals and bodyReveals from proof
await this.#assertRevealsAgainstPublicInputs(proof);

const { headersReveals, bodyReveals } = this.toHeadersAndBodyReveals({
@@ -253,7 +252,6 @@ export interface EmailProof {
// TODO: signature is not needed really. It's here because `get_limbs` cannot except only public key
signatureBase64: string;
};
// TODO(security): define headersReveal and bodyReveas from proof.publicInputs
headersReveals: RevealStringPartRequest[];
bodyReveals: RevealStringPartRequest[];
}
10 changes: 10 additions & 0 deletions packages/zkemail/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "zkemail"
type = "lib"
authors = ["Oleh Misarosh <[email protected]>"]
compiler_version = ">=0.33.0"

[dependencies]
noir_rsa = { tag = "v0.2", git = "https://github.com/noir-lang/noir_rsa" }
noir_base64 = { tag = "v0.2.0", git = "https://github.com/noir-lang/noir_base64" }
string_search = { tag = "v0.1", git = "https://github.com/noir-lang/noir_string_search" }
32 changes: 32 additions & 0 deletions packages/zkemail/src/body_hash.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
global BODY_HASH_PREFIX = "bh=".as_bytes();
global BODY_HASH_END_MARKER = ";".as_bytes()[0];
global BODY_HASH_BASE64_LEN = 44;

pub fn body_hash_from_header<let HeadersLen: u32>(headers: [u8; HeadersLen]) -> [u8; 32] {
let body_hash_position = locate_body_hash(headers);

// verify that it is the body hash parameter indeed
let body_hash_prefix_position = body_hash_position - BODY_HASH_PREFIX.len();
for i in 0..BODY_HASH_PREFIX.len() {
assert(headers[body_hash_prefix_position + i] == BODY_HASH_PREFIX[i], "body hash prefix mismatch");
}

assert(headers[body_hash_position + BODY_HASH_BASE64_LEN] == BODY_HASH_END_MARKER, "body hash end marker mismatch");

let mut body_hash_base64 = [0 as u8; BODY_HASH_BASE64_LEN];
for i in 0..BODY_HASH_BASE64_LEN {
body_hash_base64[i] = headers[body_hash_position + i];
}

// noir team switched it up. encode = decode
noir_base64::base64_encode(body_hash_base64)
}

unconstrained fn locate_body_hash<let N: u32>(headers: [u8; N]) -> u32 {
// we don't care about the sizes here because it's unconstrained
let needle: string_search::SubString32 = string_search::SubString::new(BODY_HASH_PREFIX, BODY_HASH_PREFIX.len());
let haystack: string_search::StringBody16384 = string_search::StringBody::new(headers, headers.len());
let (result, match_position) = haystack.substring_match(needle);
assert(result, "body hash not found");
match_position + BODY_HASH_PREFIX.len()
}
61 changes: 61 additions & 0 deletions packages/zkemail/src/lib.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
mod reveal_string;
use reveal_string::RevealStringPart;
mod body_hash;

use noir_rsa::bignum::BigNum;
use noir_rsa::bignum::runtime_bignum::BigNumInstance;
use noir_rsa::bignum::fields::Params2048;
use noir_rsa::RSA;

global PUBKEY_LIMBS_LEN: u32 = 18;
global SIGNATURE_LIMBS_LEN: u32 = 18;

type BN2048 = BigNum<18, Params2048>;
type RSA2048 = RSA<BN2048, BigNumInstance<18, Params2048>, 256>;

global rsa: RSA2048 = RSA {};

pub fn assert_verify_email_signature<let HeadersLen: u32, let BodyLen: u32>(
headers: [u8; HeadersLen],
body: [u8; BodyLen],
pubkey_limbs: [Field; PUBKEY_LIMBS_LEN],
pubkey_redc_limbs: [Field; PUBKEY_LIMBS_LEN],
signature_limbs: [Field; SIGNATURE_LIMBS_LEN]
) {
let signature: BN2048 = BigNum::from_array(signature_limbs);
let pubkey: BigNumInstance<18, Params2048> = BigNumInstance::new(pubkey_limbs, pubkey_redc_limbs);

{
// verify that body hash from header matches body
let body_hash = std::hash::sha256(body);
assert(body_hash == crate::body_hash::body_hash_from_header(headers), "body hash does not match");
}

{
// verify header signature
let headers_hash = std::hash::sha256(headers);
assert(rsa.verify_sha256_pkcs1v15(pubkey, headers_hash, signature), "invalid email signature");
}
}

#[test]
fn test_email() {
let pubkey_limbs = [
0xe5cf995b5ef59ce9943d1f4209b6ab, 0xe0caf03235e91a2db27e9ed214bcc6, 0xafe1309f87414bd36ed296dacfade2, 0xbeff3f19046a43adce46c932514988, 0x324041af8736e87de4358860fff057, 0xadcc6669dfa346f322717851a8c22a, 0x8b2a193089e6bf951c553b5a6f71aa, 0x0a570fe582918c4f731a0002068df2, 0x39419a433d6bfdd1978356cbca4b60, 0x550d695a514d38b45c862320a00ea5, 0x1c56ac1dfbf1beea31e8a613c2a51f, 0x6a30c9f22d2e5cb6934263d0838809, 0x0a281f268a44b21a4f77a91a52f960, 0x5134dc3966c8e91402669a47cc8597, 0x71590781df114ec072e641cdc5d224, 0xa1bc0f0937489c806c1944fd029dc9, 0x911f6e47f84db3b64c3648ebb5a127, 0xd5
];
let pubkey_redc_limbs = [
0xa48a824e4ebc7e0f1059f3ecfa57c4, 0x05c1db23f3c7d47ad7e7d7cfda5189, 0x79bb6bbbd8facf011f022fa9051aec, 0x24faa4cef474bed639362ea71f7a21, 0x1503aa50b77e24b030841a7d061581, 0x5bbf4e62805e1860a904c0f66a5fad, 0x5cbd24b72442d2ce647dd7d0a44368, 0x074a8839a4460c169dce7138efdaef, 0x0f06e09e3191b995b08e5b45182f65, 0x51fad4a89f8369fe10e5d4b6e149a1, 0xdc778b15982d11ebf7fe23b4e15f10, 0xa09ff3a4567077510c474e4ac0a21a, 0xb37e69e5dbb77167b73065e4c5ad6a, 0xecf4774e22e7fe3a38642186f7ae74, 0x16e72b5eb4c813a3b37998083aab81, 0xa48e7050aa8abedce5a45c16985376, 0xdd3285e53b322b221f7bcf4f8f8ad8, 0x0132
];
let signature_limbs = [
0x5779c85587e51cb8de5c29d7fdfeb0, 0xcd7ea8b6119f76f117ecb5042f8fc0, 0xeb7ac32b81d5a87bc2046fa0004e27, 0x62708c43b0c07a8fe8bdc97c479138, 0xc1e90d184f22a80be4a484a6ebd462, 0x39f3ff00e47728aaf74802d2d1d07b, 0x0f39de2cf99bf20dab7b8ae9240acd, 0xf4875cb76ce2538f255d70476136d6, 0xde151a5005ca614d6af7dd01e2a083, 0x6fe12b286f3195cae005fd7d2a1766, 0xd6e43a3060eccc555f2ee1e2929932, 0x0d5fa7cc79c794ae80310b491a1b40, 0x9cff415204cbc05c772ede05903440, 0xe7190ccff38575ae70dd055cd892d2, 0xf34bb777c0c842b0e88738eafdf634, 0x21040437e1e945a201ff58e542be68, 0x12f254fa4a0fb776ffe8759eb9eefa, 0x12
];
let headers = "from:[email protected]\r\ncontent-type:text/plain; charset=us-ascii\r\nmime-version:1.0 (Mac OS X Mail 16.0 \\(3731.500.231\\))\r\nsubject:Hello\r\nmessage-id:<[email protected]>\r\ndate:Sat, 26 Aug 2023 12:25:22 +0400\r\nto:[email protected]\r\ndkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=icloud.com; s=1a1hai; t=1693038337; bh=7xQMDuoVVU4m0W0WRVSrVXMeGSIASsnucK9dJsrc+vU=; h=from:Content-Type:Mime-Version:Subject:Message-Id:Date:to; b=".as_bytes();
let body = "Hello,\r\n\r\nHow are you?\r\n".as_bytes();
assert_verify_email_signature(
headers,
body,
pubkey_limbs,
pubkey_redc_limbs,
signature_limbs
)
}
12 changes: 12 additions & 0 deletions packages/zkemail/src/reveal_string.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
struct RevealStringPart<let N: u32> {
from_index: u32,
part: [u8; N],
}

impl<let N: u32> RevealStringPart<N> {
fn assert_matches<let H: u32>(self, haystack: [u8; H]) {
for i in 0..N {
assert(haystack[self.from_index + i] == self.part[i], "invalid string reveal");
}
}
}

0 comments on commit b69a866

Please sign in to comment.