-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from zkemail/chore/update-readme-0.3.2
Chore/update readme 0.3.2
- Loading branch information
Showing
9 changed files
with
695 additions
and
125 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,90 +5,119 @@ ZKEmail written in [NoirLang](https://noir-lang.org/) | |
|
||
In your Nargo.toml file, add the version of this library you would like to install under dependency: | ||
|
||
``` | ||
```toml | ||
[dependencies] | ||
zkemail = { tag = "v0.3.1", git = "https://github.com/zkemail/zkemail.nr", directory = "lib" } | ||
zkemail = { tag = "v0.3.2", git = "https://github.com/zkemail/zkemail.nr", directory = "lib" } | ||
``` | ||
|
||
The library exports the following functions: | ||
- `verify_dkim_1024` and `verify_dkim_2048` - for verifying DKIM signatures over an email header. This is needed for all email verifications. | ||
- `get_body_hash_by_index` - to get the body hash from the header. | ||
- `body_hash_base64_decode` - to decode the body hash from the header. | ||
- Above two methods are needed to verify the body hash of an email. This is only needed if you want to contrain something over the email body. | ||
- `dkim::RSAPubkey::verify_dkim_signature` - for verifying DKIM signatures over an email header. This is needed for all email verifications. | ||
- `headers::body_hash::get_body_hash` - constrained access and decoding of the body hash from the header | ||
- `headers::email_address::get_email_address` - constrained extraction of to or from email addresses | ||
- `headers::constrain_header_field` - constrain an index/ length in the header to be the correct name, full, and uninterrupted | ||
- `partial_hash::partial_sha256_var_end` - finish a precomputed sha256 hash over the body | ||
- `masking::mask_text` - apply a byte mask to the header or body to selectively reveal parts of the entire email | ||
- `standard_outputs` - returns the hash of the DKIM pubkey and a nullifier for the email (`hash(signature)`) | ||
|
||
Additionally, the `@zk-email/zkemail-nr` JS library exports an ergonomic API for easily deriving circuit inputs needed to utilize the Noir library. | ||
|
||
``` | ||
For demonstrations of all functionality, see the [examples](./examples). | ||
|
||
### Basic Email Verification | ||
A basic email verifier will often look like this: | ||
```rust | ||
use dep::zkemail::{ | ||
KEY_LIMBS_1024, dkim::verify_dkim_1024, get_body_hash_by_index, | ||
KEY_LIMBS_1024, dkim::RSAPubkey, get_body_hash_by_index, | ||
base64::body_hash_base64_decode, standard_outputs | ||
}; | ||
use dep::std::hash::sha256_var; | ||
|
||
// Somewhere in your function | ||
... | ||
verify_dkim_1024(header, header_length, pubkey, pubkey_redc, signature); | ||
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 computed_body_hash: [u8; 32] = sha256_var(body, body_length as u64); | ||
// verify the dkim signature over the asserted 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); | ||
// compute the sha256 hash of the asserted body | ||
let computed_body_hash: [u8; 32] = sha256_var(body.storage, body.len() as u64); | ||
// constain the computed body hash to match the one found in the header | ||
assert( | ||
signed_body_hash == computed_body_hash, "SHA256 hash computed over body does not match body hash found in DKIM-signed header" | ||
signed_body_hash == computed_body_hash, | ||
"SHA256 hash computed over body does not match body hash found in DKIM-signed header" | ||
); | ||
... | ||
``` | ||
From here, you can operate on the header or body with guarantees that the accessed text was signed by the DKIM key. | ||
|
||
You may also have an email where you need access to the header, but not the body. You can simply omit everything after `verify_dkim_signature` and proceed! | ||
|
||
### Usage with partial SHA | ||
|
||
You can use partial hashing technique for email with large body when the part you want to contrain in the body is towards the end. | ||
You can use partial hashing technique for email with large body when the part you want to constrain in the body is towards the end. | ||
|
||
Since SHA works in chunks of 64 bytes, we can hash the body up to the chunk from where we want to extract outside of the circuit and do the remaining hash in the circuit. This will save a lot of constraints as SHA is very expensive in circuit. | ||
Since SHA works in chunks of 64 bytes, we can hash the body up to the chunk from where we want to extract outside of the circuit and do the remaining hash in the circuit. This will save a lot of constraints as SHA is very expensive in circuit (~100 constraints/ byte). | ||
|
||
``` | ||
```rust | ||
use dep::zkemail::{ | ||
KEY_LIMBS_2048, dkim::verify_dkim_2048, get_body_hash_by_index, | ||
partial_hash::partial_sha256_var_end, base64::body_hash_base64_decode, | ||
KEY_LIMBS_2048, dkim::RSAPubkey, headers::body_hash::get_body_hash, | ||
partial_hash::partial_sha256_var_end | ||
}; | ||
|
||
... | ||
// verify the dkim signature over the header | ||
verify_dkim_2048(header, header_length, pubkey, pubkey_redc, 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); | ||
// verify the dkim signature over the asserted 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); | ||
// 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); | ||
// check the body hashes match | ||
let computed_body_hash = partial_sha256_var_end(partial_body_hash, body.storage(), body.len() as u64, partial_body_real_length); | ||
// constain the computed body hash to match the one found in the header | ||
assert( | ||
signed_body_hash == computed_body_hash, "Sha256 hash computed over body does not match DKIM-signed header" | ||
signed_body_hash == computed_body_hash, | ||
"SHA256 hash computed over body does not match body hash found in DKIM-signed header" | ||
); | ||
... | ||
``` | ||
|
||
Find more examples in the [examples](./examples) folder. | ||
### Extracting Email Addresses | ||
|
||
To and from email addresses can be extracted from the header with `get_email_address` | ||
```rust | ||
use dep::zkemail::get_email_address; | ||
... | ||
// define the header field to access (set "to" or "from") | ||
let to = comptime { "to".as_bytes() }; | ||
// constrained retrieval of the email header | ||
let to_address = get_email_address(header, to_header_sequence, to_address_sequence, to); | ||
... | ||
``` | ||
`to_address` is a "BoundedVec", meaning the output of a parsed email address "[email protected]" would export | ||
```json | ||
{ | ||
"storage": [122, 107, 101, 109, 97, 105, 108, 64, 112, 114, 111, 118, 101, 46, 101, 109, 97, 105, 108, 0, ..., 0], | ||
"len": 19 | ||
} | ||
``` | ||
which is easily interpreted with `Buffer.from(output.storage.slice(0, output.storage.len)).toString()`. You can additionally perform your own transformations or commitments in-circuit. | ||
|
||
|
||
## Using the Input Generation JS Library | ||
|
||
Install the library: | ||
``` | ||
yarn add @mach-34/zkemail-nr | ||
```console | ||
yarn add @zk-email/zkemail-nr | ||
``` | ||
|
||
### Usage | ||
See the [witness simulation](./js/tests/circuits.test.ts) and [proving](./js/tests/proving.test.ts) tests for an in-depth demonstration of each use case. | ||
|
||
``` | ||
import { generateEmailVerifierInputs } from "@mach-34/zkemail-nr"; | ||
```js | ||
// example of generating inputs for a partial hash | ||
import { generateEmailVerifierInputs } from "@zk-email/zkemail-nr"; | ||
|
||
const zkEmailInputs = await generateEmailVerifierInputs(emailContent, { | ||
maxBodyLength: 1280, // Same as MAX_PARTIAL_EMAIL_BODY_LENGTH in circuit | ||
maxHeadersLength: 1408, // Same as MAX_EMAIL_HEADER_LENGTH in circuit | ||
shaPrecomputeSelector: "some string in body up to which you want to hash outside circuit", // if you want to use partial hashing | ||
maxBodyLength: 1280, | ||
maxHeadersLength: 1408, | ||
shaPrecomputeSelector: "some string in body up to which you want to hash outside circuit", | ||
}); | ||
|
||
``` | ||
|
@@ -100,15 +129,13 @@ TODO | |
TODO | ||
|
||
## Todo | ||
- Negative Unit Testing | ||
- Expected InputGen testing | ||
- Robust from/ to string search implementation | ||
- Contract/ testing for UltraPlonk reintegrated | ||
- EVM Contract tests for email integration | ||
- Aztec Contract tests for email integration | ||
- 1024-bit key demo eml (current one is sensitive and cannot be provided in public repo) | ||
- DKIM Key pedersen hash function | ||
- Handle optional inputs (partial hashing, no body check, etc) gracefully again | ||
- Partial SHA256 hashing | ||
- Implementation with Regex | ||
- test does not exit on completion? | ||
- Implementation with Regex | ||
- Add constraint estimations and benchmarking | ||
- Add native proving scripts | ||
- Macro Impl | ||
|
||
By [Mach-34](https://mach34.space) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
DKIM-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=EhLyVPpKD7d2/+h1nrnu+iEEBDfh6UWiAf9Y5UK+aPNLt3fAyEKw6Ic46v32NOcZD | ||
M/zhXWucN0FXNiS0pz/QVIEy8Bcdy7eBZA0QA1fp8x5x5SugDELSRobQNbkOjBg7Mx | ||
VXy7h4pKZMm/hKyhvMZXK4AX9fSoXZt4VGlAFymFNavfdAeKgg/SHXLds4lOPJV1wR | ||
2E21g853iz5m/INq3uK6SQKzTnz/wDkdyiq90gC0tHQe8HpDRhPIqgL5KSEpuvUYmJ | ||
wjEOwwHqP6L3JfEeROOt6wyuB1ah7wgRvoABOJ81+qLYRn3bxF+y1BC+PwFd5yFWH5 | ||
Ry43lwp1/3+sA== | ||
from: [email protected] | ||
Content-Type: text/plain; charset=us-ascii | ||
Content-Transfer-Encoding: 7bit | ||
Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3731.500.231\)) | ||
Subject: Hello | ||
Message-Id: <[email protected]> | ||
Date: Sat, 26 Aug 2023 12:25:22 +0400 | ||
to: [email protected] | ||
|
||
Hello, | ||
|
||
How are you? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.