diff --git a/Cargo.lock b/Cargo.lock index 350c638..47760db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,9 +660,9 @@ checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "constant_time_eq" @@ -784,9 +784,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -795,22 +795,21 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] @@ -1547,9 +1546,9 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" +checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" dependencies = [ "indenter", "once_cell", @@ -2140,6 +2139,7 @@ dependencies = [ "halo2-regex", "halo2-rsa", "hex", + "home", "itertools", "js-sys", "log", @@ -4465,18 +4465,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", @@ -4916,12 +4916,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-rayon" -version = "1.0.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df87c67450805c305d3ae44a3ac537b0253d029153c25afc3ecd2edc36ccafb1" +checksum = "f0a399126782d706247a5f8fb033c3976e9edd3164664d7c97162923435cc972" dependencies = [ "js-sys", - "rayon", + "rayon-core", "spmc", "wasm-bindgen", ] @@ -5280,18 +5280,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.30" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7" +checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.30" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" +checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 0f57ba1..ebda607 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,6 +74,7 @@ tokio = { version = "1.16", features = [ "rt-multi-thread", "macros", ] } +home = { version = "=0.5.5" } [target.'cfg(target_family = "wasm")'.dependencies] diff --git a/README.md b/README.md index be10d22..71fda30 100644 --- a/README.md +++ b/README.md @@ -34,18 +34,25 @@ You can open the API specification by executing `cargo doc --open`. ## Test You can run the tests by executing `cargo test --release`. -## Description +## CLI +You can install CLI `zkemail` to prove and verify emails as follows: +`cargo install --path .` + To generate a proof and verify it on EVM, do: ```bash cargo build --release -cargo run --release -- gen-params --k 18 -cargo run --release -- gen-keys -cargo run --release -- gen-evm-verifier -cargo run --release -- evm-prove -cargo run --release -- evm-verify +zkemail gen-params --k 18 +zkemail gen-keys +zkemail gen-evm-verifier +zkemail evm-prove +zkemail evm-verify ``` To generate regex files for a new decomposed regex definition. do: ```bash -cargo run --release -- gen-regex-files --decomposed-regex-config-path new_regex_file.json --regex-files-prefix new_regex -``` \ No newline at end of file +zkemail gen-regex-files --decomposed-regex-config-path new_regex_file.json --regex-files-prefix new_regex +``` + +## WASM prover on browser +You can generate a proof on browser with our wasm prover. +For more information, please see `examples/web-client/README.md`. \ No newline at end of file diff --git a/configs/default_app.config b/configs/default_app.config index f641142..63b9a2a 100644 --- a/configs/default_app.config +++ b/configs/default_app.config @@ -35,7 +35,9 @@ "max_variable_byte_size": 1024, "substr_regexes": [ [ - "(?<=from:).*@.*(?=\r)" + "(?<=from:).*@.*(?=\r)", + "?", + "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|\\.|-)+@(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|\\.|-)+" ], [ "(?<=to:).*@.*(?=\r)" diff --git a/configs/wasm_email_verify.config b/configs/wasm_email_verify.config index 89c2d75..fe4710d 100644 --- a/configs/wasm_email_verify.config +++ b/configs/wasm_email_verify.config @@ -1,12 +1,12 @@ { "degree": 13, - "num_flex_advice": 300, - "num_range_lookup_advice": 19, + "num_flex_advice": 375, + "num_range_lookup_advice": 27, "num_flex_fixed": 3, "range_lookup_bits": 12, "sha256_config": { "num_bits_lookup": 8, - "num_advice_columns": 9 + "num_advice_columns": 13 }, "sign_verify_config": { "public_key_bits": 2048 @@ -22,7 +22,7 @@ "./test_data/from_substr_0.txt" ] ], - "max_variable_byte_size": 512, + "max_variable_byte_size": 1024, "substr_regexes": [ [ "(?<=from:).*@.*(?=\r)", diff --git a/examples/web-client/README.md b/examples/web-client/README.md index 32eb1f6..70743db 100644 --- a/examples/web-client/README.md +++ b/examples/web-client/README.md @@ -1,7 +1,21 @@ # Web client +This is an example web client for tests and benchmarks of halo2_zk_email. -This is an example web client for halo2_zk_email for benchmarking purposes. +## Setup +1. Ensure that `zkemail` CLI is already installed. +2. Under the `web-client` directory, run `chmod +x setup.bash` and `./setup.bash` +3. Open http://localhost:3000 on Google Chrome browser. -## Credits +## Tests +Please set up the local web server as described above and go to http://localhost:3000 first. +To run a test of a valid case, press the "Run test" button after "Run test of valid case". +To run a test of an invalid case in which a public key is modified, press the "Run test" button after "Run test of invalid case (invalid public key)". +## Bench +Please set up the local web server as described above and go to http://localhost:3000 first. +To measure a benchmark, enter the number of bench times in the form immediately after the "Select an email file." button and press "Run bench" below it. +To use your email in the benchmark, upload it by pressing the "Select an email file." button. +Its email header must be less than 1024 bytes, and its email body must be less than 512 bytes and satisfy the regex of "Hello (a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)+!". + +## Acknowledgment The web client and rust wasm code refers to [halo2 wasm guide](https://zcash.github.io/halo2/user/wasm-port.html) and [this repository](https://github.com/nalinbhardwaj/zordle/tree/main/test-client). diff --git a/examples/web-client/public/demo_wasm.eml b/examples/web-client/public/demo_wasm.eml new file mode 100644 index 0000000..8603b81 --- /dev/null +++ b/examples/web-client/public/demo_wasm.eml @@ -0,0 +1,85 @@ +Delivered-To: emailwallet.relayer@gmail.com +Received: by 2002:a05:7108:8190:b0:35d:a7ed:3d3f with SMTP id c16csp3477575gdv; + Sun, 10 Dec 2023 07:58:41 -0800 (PST) +X-Received: by 2002:a0d:d884:0:b0:5d7:1941:a9b with SMTP id a126-20020a0dd884000000b005d719410a9bmr2252254ywe.54.1702223921597; + Sun, 10 Dec 2023 07:58:41 -0800 (PST) +ARC-Seal: i=1; a=rsa-sha256; t=1702223921; cv=none; + d=google.com; s=arc-20160816; + b=iFKf5X1Imw98UKB6r0/jT/w+8ZQUwtqYasY7oOktiIaxteVLoJ9Y+WKthOl5h8Zx/p + 9QMd78mXdus08G1Uy++d974ufbKAgMNAMqUbfN27C71YLm6/vr6j62hghWqqH/hCsuIp + 7NM71n9W9oqymV8VXqd33ljPOk3Q5sxJ/5qHaxKlmzpgD7cog9s+/rMkz/+GY8ADyONX + 5Bjl0JjAMZD3O1ZqfyL3ZRQI7KLgFmuwKBR2VTAgO55ODUeAGfQRdCcrFC7ds3rchzpo + F1dWsmJI0wFHhvta2ZMXkWO8VgQ9Wr6HaLKi0vm9En+b9QxiHbTGLLjc4l3fICi8YTYN + XlHg== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=to:subject:message-id:date:from:mime-version:dkim-signature; + bh=GUspwlIIG/sP841vGpwvy3MPgVazLJpd/ow/iYyjBbU=; + fh=AKWw92sdXoMEDdHXKLL06vnizTpObKPGCfYXnoQDKO8=; + b=OwZ/cor6fk/L07nb373YlTMzD+tgh+BbSm6BUz3iElswDuKJCwq/VuPsZlOmdnBwJj + /plClik0nIxkORCzGqqpNDziiI8/TWEXD0ktLgq8CbKx7hLF0BSKPVAWwahF1OLjalm8 + +owoh23vmRu0rQ/WDBbCow6gOmp6rt7XLNNJk/0kZdKwUDbIgU1+nxE+a/QV20wUb7gE + Zmco67MdshkQpMHJp7gVYUgiyWbt3BhjRAN9+pk2sf01ItR7aiqiC2ql31VBO5iPydG6 + T7W1TJNTPoI8XVkh8fELytg3nVpV8vIRaG+6z5BBaXpMegFX+iWehTRQUTOdDPXg4jFi + dA3g== +ARC-Authentication-Results: i=1; mx.google.com; + dkim=pass header.i=@gmail.com header.s=20230601 header.b=MREa0ELt; + spf=pass (google.com: domain of suegamisora@gmail.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=suegamisora@gmail.com; + dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com +Return-Path: +Received: from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41]) + by mx.google.com with SMTPS id g78-20020a0ddd51000000b005d3d815e4ccsor1991901ywe.16.2023.12.10.07.58.41 + for + (Google Transport Security); + Sun, 10 Dec 2023 07:58:41 -0800 (PST) +Received-SPF: pass (google.com: domain of suegamisora@gmail.com designates 209.85.220.41 as permitted sender) client-ip=209.85.220.41; +Authentication-Results: mx.google.com; + dkim=pass header.i=@gmail.com header.s=20230601 header.b=MREa0ELt; + spf=pass (google.com: domain of suegamisora@gmail.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=suegamisora@gmail.com; + dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20230601; t=1702223921; x=1702828721; dara=google.com; + h=to:subject:message-id:date:from:mime-version:from:to:cc:subject + :date:message-id:reply-to; + bh=GUspwlIIG/sP841vGpwvy3MPgVazLJpd/ow/iYyjBbU=; + b=MREa0ELt0knVg0s8F6a6rPZNxgJRe7C5fQjpHS+Jlf0l6kKrsHOkf9pPW1aVScf6wt + 8rCmaO7mazJF/8u2ObMrZ8v4kL0CmYGRy57/LNdzk7DMBZskajYSRX909sw2DK0w7Znv + BSexoZlIeRqHOsqXA5qJ02hRCi1REnzHOy1oNkBpKqb/iVjCM9GtfSfTDdK7psjBArru + l4wuf7DFxNMdqKgH6VacEnLUQYjHIoiGJKbK3BO/uT2d4eA8Z7flDpYWzak8gAx9lABv + mxKWxKgP6zo08RWoAEGF53WmW+6Ft/nseg1cgJy0U/Yw+KOUy5nsiJLctajuYdhWBhch + FMew== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20230601; t=1702223921; x=1702828721; + h=to:subject:message-id:date:from:mime-version:x-gm-message-state + :from:to:cc:subject:date:message-id:reply-to; + bh=GUspwlIIG/sP841vGpwvy3MPgVazLJpd/ow/iYyjBbU=; + b=VLNYRexFGqVaJHdiViwkzXfeFTu/dW8grgXMrqSzeH6vUW39HaOca1w0gm6euKKIQv + v/oSPdqGy+6nD0UrcNFn0Fcz0jTFa5yJ0feiuE6WCjikHOTvQsScLAKhbN97C2mOjjz9 + hepDkVxF9GHA2TUBFlAAkd2lSm3BEMrxFk5JCNUfmuQSFIKqT1u8z9ToZ56Vk4R6ODip + rZ737NwB7VGv5YckRXPJH00SfdiO5R8WR8k5uxziYw02oCQ+mk0j8+2hGcodWdR2/eBs + H34DmCJAMkfIo80lTX9QFhqec2lGfA6xGnEy1WLEkB3qEtZEjlr+M0Q57Af85U1h/DK0 + tH9A== +X-Gm-Message-State: AOJu0YxMAQGL7080EZPDyVk2AIVutc3APVhNDpnBr0vAgJsnGZY3ohqR + +sQorRUF1maMuWadqj9fHzjPpWqxVCS3QMAusn5OA+UgoX8= +X-Google-Smtp-Source: AGHT+IE9q/z1n4s5Z13NEuqmBcqki+H5Iev2UiPber/ECbJxVrbO6lRiSHBYTPJWdUIiGpq0SXX5L9MnF3zUv52Eylw= +X-Received: by 2002:a81:8406:0:b0:5d4:2ab1:9f0a with SMTP id + u6-20020a818406000000b005d42ab19f0amr2100524ywf.42.1702223920881; Sun, 10 Dec + 2023 07:58:40 -0800 (PST) +MIME-Version: 1.0 +From: Sora Suegami +Date: Mon, 11 Dec 2023 00:58:29 +0900 +Message-ID: +Subject: Demo Email +To: emailwallet.relayer@gmail.com +Content-Type: multipart/alternative; boundary="00000000000021e38e060c29e4a6" + +--00000000000021e38e060c29e4a6 +Content-Type: text/plain; charset="UTF-8" + +Hello zkemail! + +--00000000000021e38e060c29e4a6 +Content-Type: text/html; charset="UTF-8" + +
Hello zkemail!
+ +--00000000000021e38e060c29e4a6-- diff --git a/examples/web-client/public/wasm_email_verify.config b/examples/web-client/public/wasm_email_verify.config index fd762c7..6aef00e 100644 --- a/examples/web-client/public/wasm_email_verify.config +++ b/examples/web-client/public/wasm_email_verify.config @@ -1,28 +1,28 @@ { "degree": 13, - "num_flex_advice": 300, - "num_range_lookup_advice": 19, + "num_flex_advice": 375, + "num_range_lookup_advice": 27, "num_flex_fixed": 3, "range_lookup_bits": 12, "sha256_config": { "num_bits_lookup": 8, - "num_advice_columns": 9 + "num_advice_columns": 13 }, "sign_verify_config": { "public_key_bits": 2048 }, - "header_config": { - "bodyhash_allstr_filepath": "bodyhash_allstr.txt", - "bodyhash_substr_filepath": "bodyhash_substr_0.txt", + "header_config": { + "bodyhash_allstr_filepath": "./public/bodyhash_allstr.txt", + "bodyhash_substr_filepath": "./public/bodyhash_substr_0.txt", "allstr_filepathes": [ - "from_allstr.txt" + "./public/from_allstr.txt" ], "substr_filepathes": [ [ - "from_substr_0.txt" + "./public/from_substr_0.txt" ] ], - "max_variable_byte_size": 512, + "max_variable_byte_size": 1024, "substr_regexes": [ [ "(?<=from:).*@.*(?=\r)", @@ -34,11 +34,11 @@ }, "body_config": { "allstr_filepathes": [ - "hello_body_allstr.txt" + "./public/hello_body_allstr.txt" ], "substr_filepathes": [ [ - "hello_body_substr_0.txt" + "./public/hello_body_substr_0.txt" ] ], "max_variable_byte_size": 512, diff --git a/examples/web-client/setup.bash b/examples/web-client/setup.bash new file mode 100755 index 0000000..c8286fd --- /dev/null +++ b/examples/web-client/setup.bash @@ -0,0 +1,7 @@ +#!/bin/bash +cd `dirname $0` +zkemail gen-params --k 13 --params-path ./public/params.bin +zkemail gen-keys --params-path ./public/params.bin --circuit-config-path ./public/wasm_email_verify.config --email-path ./public/demo_wasm.eml --pk-path ./public/bench.pk --vk-path ./public/bench.vk +yarn build:wasm +yarn build +yarn start \ No newline at end of file diff --git a/examples/web-client/src/bench-worker.ts b/examples/web-client/src/bench-worker.ts index 743b1b7..b8cd28f 100644 --- a/examples/web-client/src/bench-worker.ts +++ b/examples/web-client/src/bench-worker.ts @@ -1,6 +1,10 @@ import { expose, proxy } from 'comlink'; type MultiThread = typeof import('halo2-zk-email'); + +/** + * The public input of the default email verification circuit. + */ interface DefaultEmailVerifyPublicInput { // A decimal string of a commitment of the signature defined as poseidon(rsaSign). sign_commit: string, @@ -16,6 +20,10 @@ interface DefaultEmailVerifyPublicInput { body_substrs: string[], } +/** + * Fetch the trusted setup parameters for k=13. + * @returns The trusted setup parameters. + */ export async function fetchParams() { const response = await fetch('http://localhost:3000/params.bin'); const bytes = await response.arrayBuffer(); @@ -23,6 +31,10 @@ export async function fetchParams() { return params; } +/** + * Fetch the verification key of the default email verification circuit. + * @returns The verification key. + */ export async function fetchVk() { const response = await fetch('http://localhost:3000/bench.vk'); const bytes = await response.arrayBuffer(); @@ -30,13 +42,17 @@ export async function fetchVk() { return vk; } +/** + * Run a valid test of the default email verification circuit. + * @param emailStr The email string to be verified. + * @returns The result of the verification. + */ export async function runValidTest(emailStr: string) { const multiThread = await initMultiThread(); await fetchSaveConfigs(multiThread); const params = await fetchParams(); console.log(params); const publicKey = await fetchPublicKey(multiThread, emailStr); - // await genProvingKey(multiThread, params, emailStr, publicKey) const pkChunks = await fetchPkChunks(); console.log(pkChunks); if (pkChunks == null) { @@ -51,15 +67,17 @@ export async function runValidTest(emailStr: string) { return isValid; } +/** + * Run an invalid test of the default email verification circuit. + * @param emailStr The email string to be verified. + * @returns The result of the verification. + */ export async function runInvalidTest(emailStr: string) { const multiThread = await initMultiThread(); await fetchSaveConfigs(multiThread); const params = await fetchParams(); console.log(params); let publicKey = await fetchPublicKey(multiThread, emailStr); - // for (const i = 0; i < 512; i++) { - // publicKey[i+2] = - // } publicKey = '0x' + 'f'.repeat(publicKey.length - 2); const pkChunks = await fetchPkChunks(); console.log(pkChunks); @@ -75,39 +93,29 @@ export async function runInvalidTest(emailStr: string) { return isValid; } +/** + * Run a benchmark of the default email verification circuit. + * @param emailStr The email string to be verified. + * @param times The number of times to run the benchmark. + * @returns The benchmark results as a proxy of comlink. + */ export async function runBench(emailStr: string, times: number) { - // const multiThread = await import( - // 'halo2-zk-email' - // ); - // console.log(multiThread); - // await multiThread.default(); - // console.log(`hardware: ${navigator.hardwareConcurrency}`); - // await multiThread.initThreadPool(4); const multiThread = await initMultiThread(); await fetchSaveConfigs(multiThread); const params = await fetchParams(); console.log(params); const publicKey = await fetchPublicKey(multiThread, emailStr); - // await genProvingKey(multiThread, params, emailStr, publicKey) const pkChunks = await fetchPkChunks(); console.log(pkChunks); if (pkChunks == null) { throw new Error("pkChunks is null"); } const vk = await fetchVk(); - // const vk = await fetchVk(); - // console.log(vk); - // await fetch_save_configs(); - // const privateKey = multiThread.sample_rsa_private_key(bits_len); - // const publicKey = multiThread.generate_rsa_public_key(privateKey); - // const signature = multiThread.sign(privateKey, msg); const indexes = []; const benches: number[] = []; - // // const results = multiThread.multi_bench_2048_1024_circuit(params, pk, vk, publicKey, msg, signature, times); console.log("init"); for (let i = 0; i < times; i++) { indexes.push(i); - // await multiThread.initThreadPool(4); const start = performance.now(); const [proof, publicInput] = proveEmail(multiThread, params, pkChunks, emailStr, publicKey); console.log(proof); @@ -120,7 +128,6 @@ export async function runBench(emailStr: string, times: number) { if (!isValid) { throw new Error("verify failed"); } - // initOutput.__wbg_wbg_rayon_poolbuilder_free(navigator.hardwareConcurrency); } return proxy({ indexes: indexes, @@ -128,30 +135,40 @@ export async function runBench(emailStr: string, times: number) { }) } - -// async function genProvingKey(multiThread: MultiThread, params: Uint8Array, emailStr: string, publicKey: string) { -// // const multiThread = await import( -// // 'halo2-zk-email' -// // ); -// // console.log(multiThread); -// // await multiThread.default(); -// // console.log(`hardware: ${navigator.hardwareConcurrency}`); -// // await multiThread.initThreadPool(4); -// // const multiThread = await fetchSaveConfigs(); -// console.log(publicKey); -// await multiThread.gen_proving_key(params, emailStr, publicKey); -// } - +/** + * Prove the email string. + * @param multiThread The multi-threaded WASM module. + * @param params The trusted setup parameters. + * @param pkChunks The chunks of the proving key. + * @param emailStr The email string to be verified. + * @param publicKey The RSA public key. + * @returns The hex string of the proof and the public input. +*/ export function proveEmail(multiThread: MultiThread, params: Uint8Array, pkChunks: Uint8Array[], emailStr: string, publicKey: string): [string, DefaultEmailVerifyPublicInput] { const proofOut = multiThread.prove_email(params, pkChunks, emailStr, publicKey); return [proofOut[0], proofOut[1]]; } +/** + * Verify the proof. + * @param multiThread The multi-threaded WASM module. + * @param params The trusted setup parameters. + * @param vk The verification key. + * @param proof The hex string of the proof. + * @param publicInput The public input. + * @returns The result of the verification. +*/ export function verifyEmailProof(multiThread: MultiThread, params: Uint8Array, vk: Uint8Array, proof: string, publicInput: DefaultEmailVerifyPublicInput): boolean { const isValid = multiThread.verify_email_proof(params, vk, proof, publicInput); return isValid; } +/** + * Fetch the RSA public key from the Google DNS server. + * @param multiThread The multi-threaded WASM module. + * @param emailStr The email string to be verified. + * @returns The RSA public key. +*/ export async function fetchPublicKey(multiThread: MultiThread, emailStr: string) { console.log(emailStr); const url = multiThread.google_dns_url_from_email(emailStr); @@ -164,15 +181,17 @@ export async function fetchPublicKey(multiThread: MultiThread, emailStr: string) } +/** + * Fetch the chunks of the proving key. + * @returns The chunks of the proving key. +*/ export async function fetchPkChunks() { const response = await fetch('http://localhost:3000/bench.pk'); - // console.log(await response.blob()); if (response.body == null) { return; } const chunks: Uint8Array[] = []; let maxSize = 0; - // let idx = 0; const reader = response.body.getReader(); while (true) { @@ -180,8 +199,6 @@ export async function fetchPkChunks() { if (done) { break; } - // console.log(value.toString()); - // localStorage.setItem(`pk_chunk_${idx}`, value.toString()); chunks.push(value); maxSize += value.byteLength; } @@ -190,13 +207,14 @@ export async function fetchPkChunks() { return chunks; } - - +/** + * Fetch and save the configurations for the default email verification circuit. + * You must call this function once for each `multiThread` before calling any other functions in this module. + * @param multiThread The multi-threaded WASM module. +*/ export async function fetchSaveConfigs(multiThread: MultiThread) { const configParams = await fetchConfigParams(); let configParamsJson = JSON.parse(configParams); - // localStorage.setItem(configParamsJson.header_config.bodyhash_allstr_filepath, await fetchRegexFile(configParamsJson.header_config.bodyhash_allstr_filepath)); - // localStorage.setItem(configParamsJson.header_config.bodyhash_substr_filepath, await fetchRegexFile(configParamsJson.header_config.bodyhash_substr_filepath)); const bodyHashAllstrDef = await fetchRegexFile(configParamsJson.header_config.bodyhash_allstr_filepath); const bodyHashSubstrDef = await fetchRegexFile(configParamsJson.header_config.bodyhash_substr_filepath); console.log(bodyHashAllstrDef); @@ -241,128 +259,20 @@ async function fetchConfigParams() { } async function fetchRegexFile(filePath: string) { - const response = await fetch(`http://localhost:3000/${filePath}`); + const response = await fetch(`http://localhost:3000/${getFilename(filePath)}`); const regexConfig = await response.text(); return regexConfig; } -// export async function fetchParams() { -// /* eslint-disable-next-line no-restricted-globals */ -// console.log(self); -// console.log(window); -// /* eslint-disable-next-line no-restricted-globals */ -// window = self; -// console.log(window); -// const multiThread = await import( -// 'halo2-zk-email' -// ); -// console.log(multiThread); -// await multiThread.default(); -// console.log(`hardware: ${navigator.hardwareConcurrency}`); -// await multiThread.initThreadPool(4); -// const params = await multiThread.fetch_proving_key("http://localhost:3000/params.bin"); -// console.log(params); -// return params; -// } - -// export async function fetchPk() { -// /* eslint-disable-next-line no-restricted-globals */ -// window = self; -// const multiThread = await import( -// 'halo2-zk-email' -// ); -// console.log(multiThread); -// await multiThread.default(); -// console.log(`hardware: ${navigator.hardwareConcurrency}`); -// await multiThread.initThreadPool(4); -// const pk = await multiThread.fetch_public_key("http://localhost:3000/bench.pk"); -// console.log(pk); -// return pk; -// } - -// async function bench(multiThread: typeof import("halo2-rsa"), bits_len: number, msg: Uint8Array, times: number) { -// const privateKey = multiThread.sample_rsa_private_key(bits_len); -// const publicKey = multiThread.generate_rsa_public_key(privateKey); -// const signature = multiThread.sign(privateKey, msg); -// const indexes = []; -// const benches: number[] = []; -// const params = await fetch_params(); -// const pk = await fetch_pk(); -// const vk = await fetch_vk(); -// console.log("init"); -// for (let i = 0; i < times; i++) { -// indexes.push(i); -// const multiThread = await import( -// 'halo2-rsa' -// ); -// const initOutput = await multiThread.default(); -// const builder = await multiThread.initThreadPool(navigator.hardwareConcurrency); -// console.log(builder); -// const start = performance.now(); -// const proof = multiThread.prove_pkcs1v15_2048_1024_circuit(params, pk, publicKey, msg, signature); -// const sub = performance.now() - start; -// console.log(`index: ${ i }, bench: ${ sub } ms`); -// benches.push(sub); -// const isValid = multiThread.verify_pkcs1v15_2048_1024_circuit(params, vk, proof); -// console.log(isValid); -// // initOutput.__wbg_wbg_rayon_poolbuilder_free(navigator.hardwareConcurrency); -// } -// return proxy({ -// indexes: indexes, -// benches: benches -// }) -// } - -// export async function initHandlers(emailStr: string, times: number) { -// // const multiThread = await import( -// // 'halo2-zk-email' -// // ); -// // console.log(multiThread); -// // await multiThread.default(); -// // console.log(`hardware: ${navigator.hardwareConcurrency}`); -// // await multiThread.initThreadPool(4); -// if (multiThread == null) { -// throw new Error("multiThread is null"); -// } -// const params = await fetchParams(); -// console.log(params); -// // const pkChunks = await fetchPk(); -// // console.log(pkChunks); -// // if (pkChunks == null) { -// // throw new Error("pkChunks is null"); -// // } -// // const vk = await fetchVk(); -// // console.log(vk); -// // await fetch_save_configs(); -// // const privateKey = multiThread.sample_rsa_private_key(bits_len); -// // const publicKey = multiThread.generate_rsa_public_key(privateKey); -// // const signature = multiThread.sign(privateKey, msg); -// const indexes = []; -// const benches: number[] = []; -// // // const results = multiThread.multi_bench_2048_1024_circuit(params, pk, vk, publicKey, msg, signature, times); -// console.log("init"); -// for (let i = 0; i < times; i++) { -// indexes.push(i); -// const multiThread = await import( -// 'halo2-zk-email' -// ); -// await multiThread.default(); -// // await multiThread.initThreadPool(4); -// // const start = performance.now(); -// // const proof = await multiThread.prove_email(params, [], emailStr); -// // const sub = performance.now() - start; -// // console.log(`index: ${i}, bench: ${sub} ms`); -// // benches.push(sub); -// // const isValid = multiThread.verify_pkcs1v15_2048_1024_circuit(params, vk, proof); -// // console.log(isValid); -// // initOutput.__wbg_wbg_rayon_poolbuilder_free(navigator.hardwareConcurrency); -// } -// return proxy({ -// indexes: indexes, -// benches: benches -// }) -// } +function getFilename(filePath: string) { + const parts = filePath.split('/'); + return parts.pop(); +} +/** + * Initialize the multi-threaded WASM module. + * @returns The multi-threaded WASM module. + */ export async function initMultiThread() { const multiThread = await import( 'halo2-zk-email' diff --git a/src/utils.rs b/src/utils.rs index 1db48a6..17d0fbd 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -67,7 +67,7 @@ pub fn get_substr(input_str: &str, regexes: &[String]) -> Option<(usize, String) let regexes = regexes.into_iter().map(|raw| Regex::new(&raw).unwrap()).collect_vec(); let mut start = 0; let mut substr = input_str; - println!("first regex {}", regexes[0]); + // println!("first regex {}", regexes[0]); for regex in regexes.into_iter() { // println!(r"regex {}", regex); match regex.find(substr).unwrap() { @@ -80,7 +80,7 @@ pub fn get_substr(input_str: &str, regexes: &[String]) -> Option<(usize, String) } }; } - println!("substr {}", substr); - println!("start {}", start); + // println!("substr {}", substr); + // println!("start {}", start); Some((start, substr.to_string())) } diff --git a/src/wasm.rs b/src/wasm.rs index 9d605a8..b6a17b7 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -59,6 +59,18 @@ pub fn init_panic_hook() { console_error_panic_hook::set_once(); } +/// Initialize the configurations for [`DefaultEmailVerifyCircuit`]. +/// You must call this function once before calling any other functions in this module. +/// # Arguments +/// * `config_params` - a json string of [`EmailVerifyConfigParams`]. +/// * `bodyhash_allstr_def` - a string of [`AllstrRegexDef`] for the bodyhash. +/// * `bodyhash_substr_def` - a string of [`SubstrRegexDef`] for the bodyhash. +/// * `header_allstr_defs` - a list of strings of [`AllstrRegexDef`] for the headers. +/// * `header_substr_defs` - a list of strings of [`SubstrRegexDef`] for the headers. +/// * `body_allstr_defs` - a list of strings of [`AllstrRegexDef`] for the body. +/// * `body_substr_defs` - a list of strings of [`SubstrRegexDef`] for the body. +/// # Return values +/// Return a promise of `null`. #[wasm_bindgen] pub fn init_configs( config_params: String, @@ -144,6 +156,11 @@ pub fn init_configs( Ok(JsValue::NULL) } +/// Extract a selector and a domain name from the given email string and generate an url to fetch the public key from the google dns. +/// # Arguments +/// * `email_str` - an email string. +/// # Return values +/// Return a promise of the url string. #[wasm_bindgen] pub fn google_dns_url_from_email(email_str: String) -> Result { console_error_panic_hook::set_once(); @@ -153,6 +170,11 @@ pub fn google_dns_url_from_email(email_str: String) -> Result { Ok(url) } +/// Fetch the public key from the response of the google dns. +/// # Arguments +/// * `response` - a response string from the google dns. +/// # Return values +/// Return a promise of the public key string. #[wasm_bindgen] pub fn fetch_rsa_public_key(response: String) -> Result { console_error_panic_hook::set_once(); @@ -185,6 +207,14 @@ pub fn fetch_rsa_public_key(response: String) -> Result { // Ok(JsValue::NULL) // } +/// Generate a proof for the given email string and public key. +/// # Arguments +/// * `params` - a trusted setup parameter bytes. +/// * `pk_chunks` - a list of chunks of the proving key. +/// * `email_str` - an email string. +/// * `public_key_n` - a public key string. +/// # Return values +/// Return a promise of a list of the hex string of the proof and the public input. #[wasm_bindgen] pub fn prove_email(params: JsValue, pk_chunks: JsArray, email_str: String, public_key_n: String) -> Result { console_error_panic_hook::set_once(); @@ -205,27 +235,8 @@ pub fn prove_email(params: JsValue, pk_chunks: JsArray, email_str: String, publi let public_input = circuit.gen_default_public_input(); let proof = gen_proof_shplonk(¶ms, &pk, circuit, instances.clone(), &mut OsRng, None); log_1(&JsValue::from_str("proof generated")); - // { - // // let instances = public_input.instances::(); - - // let mut transcript_read = PoseidonTranscript::::new(&proof); - // let result = VerificationStrategy::<_, VerifierSHPLONK>::finalize( - // verify_proof::<_, VerifierSHPLONK, _, _, _>( - // params.verifier_params(), - // &pk.get_vk(), - // AccumulatorStrategy::new(params.verifier_params()), - // &[&instances.iter().map(Vec::as_slice).collect_vec()], - // &mut transcript_read, - // ) - // .map_err(|err| JsValue::from_str(&format!("verification error: {}", err.to_string())))?, - // ); - // if !result { - // return Err(JsValue::from_str("verification failed in the proof generation")); - // } - // } let proof_hex = format!("0x{}", hex::encode(&proof)); - // serde_wasm_bindgen::to_value(&proof).map_err(|err| JsValue::from_str(&format!("fail to serialize proof. Error: {}", err.to_string())))?; let public_input = serde_wasm_bindgen::to_value(&public_input).map_err(|err| JsValue::from_str(&format!("fail to serialize public input. Error: {}", err.to_string())))?; let mut js_array = JsArray::new(); js_array.push(&JsValue::from_str(&proof_hex)); @@ -233,6 +244,14 @@ pub fn prove_email(params: JsValue, pk_chunks: JsArray, email_str: String, publi Ok(js_array) } +/// Verify the proof for the given email string and public key. +/// # Arguments +/// * `params` - a trusted setup parameter bytes. +/// * `vk` - a verification key bytes. +/// * `proof` - a hex string of the proof. +/// * `public_input` - a public input json string. +/// # Return values +/// Return a promise of a boolean value. #[wasm_bindgen] pub fn verify_email_proof(params: JsValue, vk: JsValue, proof: JsValue, public_input: JsValue) -> Result { console_error_panic_hook::set_once(); @@ -267,6 +286,11 @@ pub fn verify_email_proof(params: JsValue, vk: JsValue, proof: JsValue, public_i Ok(JsValue::from_bool(result)) } +/// Configure the constraints definitions for [`DefaultEmailVerifyCircuit`]. +/// # Arguments +/// * `meta` - a constraint system. +/// # Return values +/// Return a [`DefaultEmailVerifyConfig`]. pub(crate) fn configure_wasm(meta: &mut ConstraintSystem) -> DefaultEmailVerifyConfig { let params = default_config_params(); let range_config = RangeConfig::configure( @@ -327,7 +351,7 @@ pub(crate) fn configure_wasm(meta: &mut ConstraintSystem) -> D } } -pub(crate) fn build_circuit(email_str: &str, public_key_n: &str) -> DefaultEmailVerifyCircuit { +fn build_circuit(email_str: &str, public_key_n: &str) -> DefaultEmailVerifyCircuit { let email_bytes = email_str.as_bytes().to_vec(); let public_key_n = BigUint::from_bytes_le(&hex::decode(&public_key_n[2..]).unwrap()); DefaultEmailVerifyCircuit {