From d1ef521bb1ec11d5ef0622d2d82c61e00710751e Mon Sep 17 00:00:00 2001 From: Aditya Bisht <44467788+Bisht13@users.noreply.github.com> Date: Sat, 23 Mar 2024 04:17:00 +0530 Subject: [PATCH] feat: Add Wasm Bindings (#62) * update 2 files, create 6 files and delete 1 file * update 1 file and create 1 file * node.rs * wasm * update circom.rs and lib.rs * wasm_bindgen gen_from_raw_memory * reverse_string * call gen_from_raw_memory from js * disable neon for wasm * chore: delete .yarnrc * toolchain, docs * remove pkg dir * Revert "update 1 file and create 1 file" This reverts commit ae5b918e50b3d550bafebd37c0aad8ec4993c773. * cleanup * target_family wasm * remove neon from compiler * test stub * README * update package.json, wasm.test.js and packages/compiler/README.md * wasm-pack web README * tests * change from unwrap to expect in gen_from_raw_memory, formatting * gen_from_decomposed_memory * test: update email_addr.test.js * update tests * test: update simple_regex.test.js * chore: delete wasm.test.js * update circom.rs and lib.rs * add wasm-bindgen to api * feat: add wasm * chore: update version --------- Co-authored-by: Olof Andersson --- .github/workflows/test.yaml | 2 + .gitignore | 1 - package.json | 7 +- packages/apis/.gitignore | 1 - packages/apis/Cargo.toml | 18 +- packages/apis/README.md | 56 +-- packages/apis/package.json | 33 +- packages/apis/src/extract_substrs.rs | 460 +++++------------- packages/apis/src/lib.rs | 25 - packages/apis/src/padding.rs | 22 +- packages/circom/package.json | 7 +- packages/circom/tests/body_hash_regex.test.js | 38 +- packages/circom/tests/email_addr.test.js | 36 +- packages/circom/tests/email_domain.test.js | 32 +- packages/circom/tests/from_addr.test.js | 113 +++-- .../circom/tests/international_chars.test.js | 30 +- .../circom/tests/message_id_regex.test.js | 36 +- packages/circom/tests/negate_regex.test.js | 33 +- packages/circom/tests/simple_regex.test.js | 37 +- .../tests/simple_regex_decomposed.test.js | 30 +- packages/circom/tests/subject_all.test.js | 40 +- packages/circom/tests/timestamp.test.js | 36 +- packages/circom/tests/to_addr.test.js | 113 +++-- packages/compiler/Cargo.toml | 16 +- packages/compiler/README.md | 60 ++- packages/compiler/package.json | 33 +- packages/compiler/src/circom.rs | 30 +- packages/compiler/src/lib.rs | 68 ++- packages/compiler/src/node.rs | 102 ---- 29 files changed, 605 insertions(+), 910 deletions(-) delete mode 100644 packages/compiler/src/node.rs diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4fe726e..c184338 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -18,6 +18,8 @@ jobs: toolchain: stable override: true components: rustfmt, clippy + - name: Install wasm-pack + run: cargo install wasm-pack - name: Download circom (Linux) run: wget https://github.com/iden3/circom/releases/latest/download/circom-linux-amd64 -O /usr/local/bin/circom && chmod +x /usr/local/bin/circom - name: Install yarn diff --git a/.gitignore b/.gitignore index ee605be..caaf8d2 100644 --- a/.gitignore +++ b/.gitignore @@ -103,7 +103,6 @@ build/* target -index.node Cargo.lock .DS_Store diff --git a/package.json b/package.json index b5fb03a..09809b8 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "@zk-email/zk-regex", - "version": "1.0.0", + "version": "2.0.0", "private": true, "description": "zk regex circuit for content attestation", - "main": "node-apis/index.node", + "main": "pkg/zk_regex_compiler_bg.wasm", "workspaces": [ "packages/*" ], @@ -11,7 +11,8 @@ "Sora Suegami ", "Yush G ", "Javier Su ", - "Kata Choi " + "Kata Choi ", + "Aditya Bisht " ], "scripts": { "install": "yarn workspaces -pt run install", diff --git a/packages/apis/.gitignore b/packages/apis/.gitignore index 6ca71fb..6d41026 100644 --- a/packages/apis/.gitignore +++ b/packages/apis/.gitignore @@ -1,5 +1,4 @@ target -index.node **/node_modules **/.DS_Store npm-debug.log* diff --git a/packages/apis/Cargo.toml b/packages/apis/Cargo.toml index 8415595..21d65e4 100644 --- a/packages/apis/Cargo.toml +++ b/packages/apis/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "zk-regex-apis" -version = "1.2.0" +version = "2.0.0" license = "MIT" edition = "2018" -exclude = ["index.node"] authors = [ "Javier Su ", "Kata Choi ", "Sora Suegami ", "Yush G ", + "Aditya Bisht ", ] [lib] @@ -23,13 +23,7 @@ fancy-regex = "0.11.0" itertools = "0.10.3" thiserror = "1.0.40" serde_json = "1.0.95" - - -[dependencies.neon] -version = "0.10" -default-features = false -features = ["napi-6"] - -[features] -default = ["export_neon_main"] -export_neon_main = [] +wasm-bindgen = "0.2" +serde-wasm-bindgen = "0.6.5" +js-sys = "0.3.69" +wasm-bindgen-test = "0.3.42" diff --git a/packages/apis/README.md b/packages/apis/README.md index 4846300..57a0bc0 100644 --- a/packages/apis/README.md +++ b/packages/apis/README.md @@ -2,8 +2,6 @@ Helpful nodejs/Rust APIs in [zk-regex](https://github.com/zkemail/zk-regex/tree/main). -This project was bootstrapped by [create-neon](https://www.npmjs.com/package/create-neon). - ## Installing zk-regex-apis Installing zk-regex-apis requires a [supported version of Node and Rust](https://github.com/neon-bindings/neon#platform-support). @@ -24,17 +22,36 @@ If you have already installed the project and only want to run the build, run: $ npm run build ``` -This command uses the [cargo-cp-artifact](https://github.com/neon-bindings/cargo-cp-artifact) utility to run the Rust build and copy the built library into `./index.node`. +## Compiling zk-regex-apis to wasm + +### For web usage +Install `wasm-pack` if not already installed -## Exploring zk-regex-apis +```sh +cargo install wasm-pack +``` -After building zk-regex-apis, you can explore its exports at the Node REPL: +Compile the web package ```sh -$ npm install -$ node -> require('.').hello() -"hello node" +wasm-pack build --target nodejs +``` + +Pack the package (optional) + +```sh +wasm-pack build --target nodejs +cd pkg +npm pkg set type='module' +wasm-pack pack +``` + +The output package file will be `packages/compiler/pkg/zk-regex-apis-1.1.1.tgz` + +### For tests + +```sh +wasm-pack test --node ``` ## Available Scripts @@ -47,8 +64,6 @@ Installs the project, including running `npm run build`. ### `npm build` -Builds the Node addon (`index.node`) from source. - Additional [`cargo build`](https://doc.rust-lang.org/cargo/commands/cargo-build.html) arguments may be passed to `npm build` and `npm build-*` commands. For example, to enable a [cargo feature](https://doc.rust-lang.org/cargo/reference/features.html): ``` @@ -65,17 +80,16 @@ Same as [`npm build`](#npm-build) but, builds the module with the [`release`](ht ### `npm test` -Runs the unit tests by calling `cargo test`. You can learn more about [adding tests to your Rust code](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) from the [Rust book](https://doc.rust-lang.org/book/). +Runs the unit tests by calling `wasm-pack test --node`. ## Project Layout The directory structure of this project is: ``` -zk-regex-apis/ +zk-regex-compiler/ ├── Cargo.toml ├── README.md -├── index.node ├── package.json ├── src/ | └── lib.rs @@ -90,12 +104,6 @@ The Cargo [manifest file](https://doc.rust-lang.org/cargo/reference/manifest.htm This file. -### index.node - -The Node addon—i.e., a binary Node module—generated by building the project. This is the main module for this package, as dictated by the `"main"` key in `package.json`. - -Under the hood, a [Node addon](https://nodejs.org/api/addons.html) is a [dynamically-linked shared object](https://en.wikipedia.org/wiki/Library_(computing)#Shared_libraries). The `"build"` script produces this file by copying it from within the `target/` directory, which is where the Rust build produces the shared object. - ### package.json The npm [manifest file](https://docs.npmjs.com/cli/v7/configuring-npm/package-json), which informs the `npm` command. @@ -111,11 +119,3 @@ The Rust library's main module. ### target/ Binary artifacts generated by the Rust build. - -## Learn More - -To learn more about Neon, see the [Neon documentation](https://neon-bindings.com). - -To learn more about Rust, see the [Rust documentation](https://www.rust-lang.org). - -To learn more about Node, see the [Node documentation](https://nodejs.org). diff --git a/packages/apis/package.json b/packages/apis/package.json index 2bd5ed9..3a3ef49 100644 --- a/packages/apis/package.json +++ b/packages/apis/package.json @@ -1,39 +1,26 @@ { "name": "@zk-email/zk-regex-apis", - "version": "1.2.0", + "version": "2.0.0", "description": "apis compatible with [zk-regex](https://github.com/zkemail/zk-regex/tree/main).", "contributors": [ "Javier Su ", "Kata Choi ", "Sora Suegami ", - "Yush G " + "Yush G ", + "Aditya Bisht " ], - "main": "index.node", "repository": { "type": "git", "url": "git+https://github.com/zkemail/zk-regex.git" }, "scripts": { - "build": "cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics", + "build": "wasm-pack build --target nodejs --out-dir ./pkg/", "build-debug": "npm run build --", - "build-release": "npm run build -- --release", + "build-release": "npm run build --", "install": "npm run build-debug", - "install-release": "node-pre-gyp install --update-binary --fallback-to-build=false || npm run build-release", - "test": "cargo test", - "package": "node-pre-gyp package", - "upload-binary": "npm run package && node-pre-gyp-github publish" + "install-release": "npm run build-release", + "test": "wasm-pack test --node", + "upload-binary": "wasm-pack publish -t nodejs" }, - "license": "MIT", - "dependencies": { - "cargo-cp-artifact": "^0.1", - "@mapbox/node-pre-gyp": "^1.0", - "node-pre-gyp-github": "https://github.com/ultamatt/node-pre-gyp-github.git" - }, - "binary": { - "module_name": "index", - "host": "https://github.com/zkemail/zk-regex/releases/download/", - "remote_path": "{version}", - "package_name": "apis-{node_abi}-{platform}-{arch}.tar.gz", - "module_path": "./" - } -} \ No newline at end of file + "license": "MIT" +} diff --git a/packages/apis/src/extract_substrs.rs b/packages/apis/src/extract_substrs.rs index b73d655..67a3565 100644 --- a/packages/apis/src/extract_substrs.rs +++ b/packages/apis/src/extract_substrs.rs @@ -1,9 +1,11 @@ use fancy_regex::Regex; -use neon::prelude::*; +use js_sys::Array; use serde::{Deserialize, Serialize}; -use serde_json; + +use serde_wasm_bindgen::from_value; use thiserror::Error; -// use zk_regex_compiler::DecomposedRegexConfig; +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::*; /// A configuration of decomposed regexes. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -37,409 +39,174 @@ pub enum ExtractSubstrssError { RegexError(#[from] fancy_regex::Error), } -pub fn extract_substr_idxes( - input_str: &str, - regex_config: &DecomposedRegexConfig, -) -> Result, ExtractSubstrssError> { - // if input_str.len() > regex_config.max_byte_size { - // return Err(ExtractSubstrssError::InvalidInputLen(regex_config.max_byte_size,input_str.len())); - // } +#[wasm_bindgen] +pub fn extract_substr_idxes(input_str: &str, regex_config: JsValue) -> Array { + let regex_config_str = regex_config.as_string().unwrap(); + let regex_config: DecomposedRegexConfig = serde_json::from_str(®ex_config_str).unwrap(); let mut entire_regex_str = String::new(); for part in regex_config.parts.iter() { entire_regex_str += part.regex_def.as_str(); } - // entire_regex_str = format_regex_printable(&entire_regex_str)?; - let entire_regex = Regex::new(&entire_regex_str)?; - let entire_found = entire_regex.find(input_str)?.ok_or_else(|| { - ExtractSubstrssError::SubstringOfEntireNotFound(entire_regex, input_str.to_string()) - })?; + + let entire_regex = Regex::new(&entire_regex_str).unwrap(); + let entire_found = entire_regex + .find(input_str) + .unwrap() + .ok_or_else(|| { + ExtractSubstrssError::SubstringOfEntireNotFound(entire_regex, input_str.to_string()) + }) + .unwrap(); let mut start = entire_found.start(); let entire_end = entire_found.end(); let mut public_idxes = vec![]; - // let mut last_regex_str = String::new(); - // let part_regex_defs = regex_config.parts.iter().map(|part| part.regex_def.as_str()).collect_vec(); + for part_idx in 0..regex_config.parts.len() { // last_regex_str = last_regex_str + regex_config.parts[part_idx].regex_def.as_str(); - let regex = Regex::new(®ex_config.parts[part_idx].regex_def.as_str())?; - let found = regex.find_from_pos(&input_str, start)?.ok_or_else(|| { - ExtractSubstrssError::SubstringNotFound( - regex.clone(), - input_str[start..entire_end].to_string(), - ) - })?; + let regex = Regex::new(®ex_config.parts[part_idx].regex_def.as_str()).unwrap(); + let found = regex + .find_from_pos(&input_str, start) + .unwrap() + .ok_or_else(|| { + ExtractSubstrssError::SubstringNotFound( + regex.clone(), + input_str[start..entire_end].to_string(), + ) + }) + .unwrap(); let end = found.end(); - // if found.start() >= end { - // return Err(ExtractSubstrssError::EmptySubstring(regex, input_str[start..entire_end].to_string())); - // } + if regex_config.parts[part_idx].is_public { public_idxes.push((start, end)); } start = end; } - Ok(public_idxes) -} - -pub fn extract_email_addr_idxes( - input_str: &str, -) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/email_addr.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_email_domain_idxes( - input_str: &str, -) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/email_domain.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_email_addr_with_name_idxes( - input_str: &str, -) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/email_addr_with_name.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_from_all_idxes( - input_str: &str, -) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/from_all.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_from_addr_idxes( - input_str: &str, -) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/from_addr.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_to_all_idxes(input_str: &str) -> Result, ExtractSubstrssError> { - let regex_config = serde_json::from_str(include_str!("./decomposed_defs/to_all.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_to_addr_idxes(input_str: &str) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/to_addr.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_subject_all_idxes( - input_str: &str, -) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/subject_all.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_body_hash_idxes( - input_str: &str, -) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/body_hash.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_timestamp_idxes( - input_str: &str, -) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/timestamp.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_message_id_idxes( - input_str: &str, -) -> Result, ExtractSubstrssError> { - let regex_config = - serde_json::from_str(include_str!("./decomposed_defs/message_id.json")).unwrap(); - extract_substr_idxes(input_str, ®ex_config) -} - -pub fn extract_substr_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let regex_config_str = cx.argument::(1)?.value(&mut cx); - let regex_config = match serde_json::from_str::(®ex_config_str) { - Ok(regex_config) => regex_config, - Err(e) => return cx.throw_error(e.to_string()), - }; - let substr_idxes = match extract_substr_idxes(&input_str, ®ex_config) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; + let arr = Array::new_with_length(public_idxes.len() as u32); + for (i, idx) in public_idxes.iter().enumerate() { + let js_arr = Array::new_with_length(2); + js_arr.set(0, JsValue::from(idx.0 as u32)); + js_arr.set(1, JsValue::from(idx.1 as u32)); + arr.set(i as u32, JsValue::from(js_arr)); } - Ok(js_array) -} -pub fn extract_email_addr_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_email_addr_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) + arr } -pub fn extract_email_domain_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_email_domain_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) +#[wasm_bindgen] +pub fn extract_email_addr_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/email_addr.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } -pub fn extract_email_addr_with_name_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_email_addr_with_name_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) +#[wasm_bindgen] +pub fn extract_email_domain_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/email_domain.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } -pub fn extract_from_all_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_from_all_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) +#[wasm_bindgen] +pub fn extract_email_addr_with_name_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/email_addr_with_name.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } -pub fn extract_from_addr_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_from_addr_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) +#[wasm_bindgen] +pub fn extract_from_all_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/from_all.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } -pub fn extract_to_all_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - - let substr_idxes = match extract_to_all_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - - js_array.set(&mut cx, i as u32, start_end_array)?; - } +#[wasm_bindgen] +pub fn extract_from_addr_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/from_addr.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) +} - Ok(js_array) +#[wasm_bindgen] +pub fn extract_to_all_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/to_all.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } -pub fn extract_to_addr_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_to_addr_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) +#[wasm_bindgen] +pub fn extract_to_addr_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/to_addr.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } -pub fn extract_subject_all_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_subject_all_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) +#[wasm_bindgen] +pub fn extract_subject_all_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/subject_all.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } -pub fn extract_body_hash_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_body_hash_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) +#[wasm_bindgen] +pub fn extract_body_hash_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/body_hash.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } -pub fn extract_timestamp_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_timestamp_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) +#[wasm_bindgen] +pub fn extract_timestamp_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/timestamp.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } -pub fn extract_message_id_idxes_node(mut cx: FunctionContext) -> JsResult { - let input_str = cx.argument::(0)?.value(&mut cx); - let substr_idxes = match extract_message_id_idxes(&input_str) { - Ok(substr_idxes) => substr_idxes, - Err(e) => return cx.throw_error(e.to_string()), - }; - let js_array = JsArray::new(&mut cx, substr_idxes.len() as u32); - for (i, (start_idx, end_idx)) in substr_idxes.iter().enumerate() { - let start_end_array = JsArray::new(&mut cx, 2u32); - let start_idx = cx.number(*start_idx as f64); - start_end_array.set(&mut cx, 0, start_idx)?; - let end_idx = cx.number(*end_idx as f64); - start_end_array.set(&mut cx, 1, end_idx)?; - js_array.set(&mut cx, i as u32, start_end_array)?; - } - Ok(js_array) +#[wasm_bindgen] +pub fn extract_message_id_idxes(input_str: &str) -> Array { + let regex_config = include_str!("./decomposed_defs/message_id.json"); + extract_substr_idxes(input_str, JsValue::from_str(regex_config)) } #[cfg(test)] mod test { use super::*; - #[test] + #[wasm_bindgen_test] fn test_email_domain_valid() { let input_str = "suegamisora@gmail.com"; - let idxes = extract_email_domain_idxes(input_str).unwrap(); - assert_eq!(idxes, vec![(12, 21)]); + let idxes = extract_email_domain_idxes(input_str); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![12, 21]); } - #[test] + #[wasm_bindgen_test] fn test_email_addr_in_subject_valid() { let input_str = "This is sent for suegamisora@gmail.com"; - let idxes = extract_email_addr_idxes(input_str).unwrap(); - assert_eq!(idxes, vec![(17, 38)]); + let idxes = extract_email_addr_idxes(input_str); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![17, 38]); } - #[test] + #[wasm_bindgen_test] fn test_email_addr_with_name_valid1() { let input_str = "from:dummy@a.com "; - let idxes = extract_email_addr_with_name_idxes(input_str).unwrap(); - assert_eq!(idxes, vec![(18, 39)]); + let idxes = extract_email_addr_with_name_idxes(input_str); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![18, 39]); } - #[test] + #[wasm_bindgen_test] fn test_email_addr_with_name_valid2() { // "末神 奏宙" has 13 bytes. let input_str = "from:\"末神 奏宙\" "; - let idxes = extract_email_addr_with_name_idxes(input_str).unwrap(); - assert_eq!(idxes, vec![(22, 43)]); + let idxes = extract_email_addr_with_name_idxes(input_str); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![22, 43]); } - #[test] + #[wasm_bindgen_test] fn test_email_from_all_valid() { let input_str = "from:dummy@a.com \r\n"; - let idxes = extract_from_all_idxes(input_str).unwrap(); - assert_eq!(idxes, vec![(5, 40)]); + let idxes = extract_from_all_idxes(input_str); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![5, 40]); } - #[test] + #[wasm_bindgen_test] fn test_email_from_addr_valid() { let input_str = "from:dummy@a.com \r\n"; - let idxes = extract_from_addr_idxes(input_str).unwrap(); - assert_eq!(idxes, vec![(18, 39)]); + let idxes = extract_from_addr_idxes(input_str); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![18, 39]); } - #[test] + #[wasm_bindgen_test] fn test_code_in_email_address_valid() { let code_regex = DecomposedRegexConfig { // max_byte_size: 1024, @@ -459,29 +226,30 @@ mod test { ], }; let input_str = "sepolia+ACCOUNTKEY.0xabc123@sendeth.org"; - let idxes = extract_substr_idxes(input_str, &code_regex).unwrap(); - assert_eq!(idxes, vec![(21, 27)]); + let code_regex = JsValue::from_str(&serde_json::to_string(&code_regex).unwrap()); + let idxes = extract_substr_idxes(input_str, code_regex); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![21, 27]); } - #[test] + #[wasm_bindgen_test] fn test_body_hash_valid() { let input_str = "dkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1694989812; x=1695594612; dara=google.com; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=BWETwQ9JDReS4GyR2v2TTR8Bpzj9ayumsWQJ3q7vehs=; b="; - let idxes = extract_body_hash_idxes(input_str).unwrap(); - assert_eq!(idxes, vec![(219, 263)]); + let idxes = extract_body_hash_idxes(input_str); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![219, 263]); } - #[test] + #[wasm_bindgen_test] fn test_timestamp_valid() { let input_str = "dkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1694989812; x=1695594612; dara=google.com; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=BWETwQ9JDReS4GyR2v2TTR8Bpzj9ayumsWQJ3q7vehs=; b="; - let idxes = extract_timestamp_idxes(input_str).unwrap(); - assert_eq!(idxes, vec![(80, 90)]); + let idxes = extract_timestamp_idxes(input_str); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![80, 90]); } - #[test] + #[wasm_bindgen_test] fn test_message_id_valid() { let input_str = "message-id:\r\n"; - let idxes = extract_message_id_idxes(input_str).unwrap(); - assert_eq!(idxes, vec![(11, 79)]); + let idxes = extract_message_id_idxes(input_str); + assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![11, 79]); } } diff --git a/packages/apis/src/lib.rs b/packages/apis/src/lib.rs index 3836ac3..be43042 100644 --- a/packages/apis/src/lib.rs +++ b/packages/apis/src/lib.rs @@ -1,27 +1,2 @@ -use neon::prelude::*; pub mod extract_substrs; pub mod padding; -use extract_substrs::*; -use padding::pad_string_node; - -#[cfg(feature = "export_neon_main")] -#[neon::main] -fn main(mut cx: ModuleContext) -> NeonResult<()> { - cx.export_function("extractSubstrIdxes", extract_substr_idxes_node)?; - cx.export_function("padString", pad_string_node)?; - cx.export_function("extractEmailAddrIdxes", extract_email_addr_idxes_node)?; - cx.export_function("extractEmailDomainIdxes", extract_email_domain_idxes_node)?; - cx.export_function( - "extractEmailAddrWithNameIdxes", - extract_email_addr_with_name_idxes_node, - )?; - cx.export_function("extractFromAllIdxes", extract_from_all_idxes_node)?; - cx.export_function("extractFromAddrIdxes", extract_from_addr_idxes_node)?; - cx.export_function("extractToAllIdxes", extract_to_all_idxes_node)?; - cx.export_function("extractToAddrIdxes", extract_to_addr_idxes_node)?; - cx.export_function("extractSubjectAllIdxes", extract_subject_all_idxes_node)?; - cx.export_function("extractBodyHashIdxes", extract_body_hash_idxes_node)?; - cx.export_function("extractTimestampIdxes", extract_timestamp_idxes_node)?; - cx.export_function("extractMessageIdIdxes", extract_message_id_idxes_node)?; - Ok(()) -} diff --git a/packages/apis/src/padding.rs b/packages/apis/src/padding.rs index dd31b6c..d1eac4c 100644 --- a/packages/apis/src/padding.rs +++ b/packages/apis/src/padding.rs @@ -1,19 +1,15 @@ -use neon::prelude::*; +use js_sys::Array; +use wasm_bindgen::prelude::*; -pub fn pad_string(str: &str, padded_bytes_size: usize) -> Vec { +#[wasm_bindgen] +pub fn pad_string(str: &str, padded_bytes_size: usize) -> Array { let mut padded_bytes = str.as_bytes().to_vec(); padded_bytes.append(&mut vec![0; padded_bytes_size - padded_bytes.len()]); - padded_bytes -} -pub fn pad_string_node(mut cx: FunctionContext) -> JsResult { - let string = cx.argument::(0)?.value(&mut cx); - let padded_bytes_size = cx.argument::(1)?.value(&mut cx) as usize; - let padded_bytes = pad_string(&string, padded_bytes_size); - let padded_array = JsArray::new(&mut cx, padded_bytes_size as u32); - for (idx, byte) in padded_bytes.into_iter().enumerate() { - let js_byte = cx.number(byte); - padded_array.set(&mut cx, idx as u32, js_byte)?; + let arr = Array::new_with_length(padded_bytes.len() as u32); + for (i, byte) in padded_bytes.iter().enumerate() { + arr.set(i as u32, JsValue::from(*byte)); } - Ok(padded_array) + + arr } diff --git a/packages/circom/package.json b/packages/circom/package.json index ade754c..b404dac 100644 --- a/packages/circom/package.json +++ b/packages/circom/package.json @@ -1,13 +1,14 @@ { "name": "@zk-email/zk-regex-circom", - "version": "1.3.0", + "version": "2.0.0", "license": "MIT", "description": "regex verification circuits in circom for common regexes, generated with the compiler in [zk-regex](https://github.com/zkemail/zk-regex/tree/main).", "contributors": [ "Javier Su ", "Kata Choi ", "Sora Suegami ", - "Yush G " + "Yush G ", + "Aditya Bisht " ], "scripts": { "test": "jest", @@ -36,4 +37,4 @@ ] ] } -} \ No newline at end of file +} diff --git a/packages/circom/tests/body_hash_regex.test.js b/packages/circom/tests/body_hash_regex.test.js index 81e3991..df7dfd8 100644 --- a/packages/circom/tests/body_hash_regex.test.js +++ b/packages/circom/tests/body_hash_regex.test.js @@ -1,28 +1,30 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -import { readFileSync } from "fs"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(600000); describe("Bodyhash Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( + const email_addr_json = readFileSync( path.join(__dirname, "../circuits/common/body_hash.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/body_hash_regex.circom" - ), - templateName: "BodyHashRegex", - genSubstrs: true, - } + "utf8" ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "BodyHashRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/body_hash_regex.circom"), + circom + ); + circuit = await wasm_tester( path.join(__dirname, "./circuits/test_body_hash_regex.circom"), option @@ -31,14 +33,14 @@ describe("Bodyhash Regex", () => { it("bodyhash in the header", async () => { const signatureField = `dkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1694989812; x=1695594612; dara=google.com; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=BWETwQ9JDReS4GyR2v2TTR8Bpzj9ayumsWQJ3q7vehs=; b=`; - const paddedStr = apis.padString(signatureField, 1024); + const paddedStr = apis.pad_string(signatureField, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractSubstrIdxes( + const prefixIdxes = apis.extract_substr_idxes( signatureField, readFileSync( path.join(__dirname, "../circuits/common/body_hash.json"), @@ -56,14 +58,14 @@ describe("Bodyhash Regex", () => { it("timestamp after new line", async () => { const signatureField = `\r\ndkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1694989812; x=1695594612; dara=google.com; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=BWETwQ9JDReS4GyR2v2TTR8Bpzj9ayumsWQJ3q7vehs=; b=`; - const paddedStr = apis.padString(signatureField, 1024); + const paddedStr = apis.pad_string(signatureField, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractSubstrIdxes( + const prefixIdxes = apis.extract_substr_idxes( signatureField, readFileSync( path.join(__dirname, "../circuits/common/body_hash.json"), diff --git a/packages/circom/tests/email_addr.test.js b/packages/circom/tests/email_addr.test.js index fcffe84..012aa19 100644 --- a/packages/circom/tests/email_addr.test.js +++ b/packages/circom/tests/email_addr.test.js @@ -1,26 +1,28 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(120000); describe("Email Address Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( + const email_addr_json = readFileSync( path.join(__dirname, "../circuits/common/email_addr.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/email_addr_regex.circom" - ), - templateName: "EmailAddrRegex", - genSubstrs: true, - } + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "EmailAddrRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/email_addr_regex.circom"), + circom ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_email_addr_regex.circom"), @@ -30,14 +32,14 @@ describe("Email Address Regex", () => { it("only an email address", async () => { const emailAddr = "suegamisora@gmail.com"; - const paddedStr = apis.padString(emailAddr, 256); + const paddedStr = apis.pad_string(emailAddr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractEmailAddrIdxes(emailAddr)[0]; + const prefixIdxes = apis.extract_email_addr_idxes(emailAddr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -51,14 +53,14 @@ describe("Email Address Regex", () => { const prefix = "subject:"; const emailAddr = "suegamisora@gmail.com"; const string = prefix + emailAddr; - const paddedStr = apis.padString(string, 256); + const paddedStr = apis.pad_string(string, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractEmailAddrIdxes(string)[0]; + const prefixIdxes = apis.extract_email_addr_idxes(string)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); diff --git a/packages/circom/tests/email_domain.test.js b/packages/circom/tests/email_domain.test.js index 812a0c3..d546377 100644 --- a/packages/circom/tests/email_domain.test.js +++ b/packages/circom/tests/email_domain.test.js @@ -1,26 +1,28 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(120000); describe("Email Domain Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( + const email_addr_json = readFileSync( path.join(__dirname, "../circuits/common/email_domain.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/email_domain_regex.circom" - ), - templateName: "EmailDomainRegex", - genSubstrs: true, - } + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "EmailDomainRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/email_domain_regex.circom"), + circom ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_email_domain_regex.circom"), @@ -30,7 +32,7 @@ describe("Email Domain Regex", () => { it("test a regex of an email domain", async () => { const emailAddr = "suegamisora@gmail.com"; - const paddedStr = apis.padString(emailAddr, 256); + const paddedStr = apis.pad_string(emailAddr, 256); const circuitInputs = { msg: paddedStr, }; @@ -40,7 +42,7 @@ describe("Email Domain Regex", () => { for (let idx = 0; idx < 12; ++idx) { expect(0n).toEqual(witness[2 + idx]); } - const prefixIdxes = apis.extractEmailDomainIdxes(emailAddr)[0]; + const prefixIdxes = apis.extract_email_domain_idxes(emailAddr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); diff --git a/packages/circom/tests/from_addr.test.js b/packages/circom/tests/from_addr.test.js index f4f240f..9f62a86 100644 --- a/packages/circom/tests/from_addr.test.js +++ b/packages/circom/tests/from_addr.test.js @@ -1,49 +1,62 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(600000); describe("From Addr Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( - path.join(__dirname, "../circuits/common/from_all.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/from_all_regex.circom" - ), - templateName: "FromAllRegex", - genSubstrs: true, - } - ); - compiler.genFromDecomposed( - path.join(__dirname, "../circuits/common/email_addr_with_name.json"), - { - circomFilePath: path.join( + { + const email_addr_json = readFileSync( + path.join(__dirname, "../circuits/common/from_all.json"), + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "FromAllRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/from_all_regex.circom"), + circom + ); + } + { + const email_addr_json = readFileSync( + path.join(__dirname, "../circuits/common/email_addr_with_name.json"), + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "EmailAddrWithNameRegex" + ); + writeFileSync( + path.join( __dirname, "../circuits/common/email_addr_with_name_regex.circom" ), - templateName: "EmailAddrWithNameRegex", - genSubstrs: true, - } - ); - compiler.genFromDecomposed( - path.join(__dirname, "../circuits/common/email_addr.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/email_addr_regex.circom" - ), - templateName: "EmailAddrRegex", - genSubstrs: true, - } - ); + circom + ); + } + { + const email_addr_json = readFileSync( + path.join(__dirname, "../circuits/common/email_addr.json"), + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "EmailAddrRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/email_addr_regex.circom"), + circom + ); + } circuit = await wasm_tester( path.join(__dirname, "./circuits/test_from_addr_regex.circom"), option @@ -52,14 +65,14 @@ describe("From Addr Regex", () => { it("from field from beginning case 1", async () => { const fromStr = "from:suegamisora@gmail.com\r\n"; - const paddedStr = apis.padString(fromStr, 1024); + const paddedStr = apis.pad_string(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; + const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -71,14 +84,14 @@ describe("From Addr Regex", () => { it("from field from beginning case 2", async () => { const fromStr = "from:Sora Suegami \r\n"; - const paddedStr = apis.padString(fromStr, 1024); + const paddedStr = apis.pad_string(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; + const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -90,14 +103,14 @@ describe("From Addr Regex", () => { it("from field from beginning case 3 (email address as a name)", async () => { const fromStr = "from:dummy@example.com\r\n"; - const paddedStr = apis.padString(fromStr, 1024); + const paddedStr = apis.pad_string(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; + const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -109,14 +122,14 @@ describe("From Addr Regex", () => { it("from field from beginning case 4 (non-English string is used as a name)", async () => { const fromStr = 'from: "末神奏宙" \r\n'; - const paddedStr = apis.padString(fromStr, 1024); + const paddedStr = apis.pad_string(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; + const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -128,14 +141,14 @@ describe("From Addr Regex", () => { it("from field after new line case 1", async () => { const fromStr = "dummy\r\nfrom:suegamisora@gmail.com\r\n"; - const paddedStr = apis.padString(fromStr, 1024); + const paddedStr = apis.pad_string(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; + const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -147,14 +160,14 @@ describe("From Addr Regex", () => { it("from field after new line case 2", async () => { const fromStr = "dummy\r\nfrom:Sora Suegami \r\n"; - const paddedStr = apis.padString(fromStr, 1024); + const paddedStr = apis.pad_string(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; + const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -167,14 +180,14 @@ describe("From Addr Regex", () => { it("from field after new line case 3 (email address as a name)", async () => { const fromStr = "dummy\r\nfrom:dummy@example.com\r\n"; - const paddedStr = apis.padString(fromStr, 1024); + const paddedStr = apis.pad_string(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; + const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -186,14 +199,14 @@ describe("From Addr Regex", () => { it("from field after new line case 4 (non-English string is used as a name)", async () => { const fromStr = 'dummy\r\nfrom: "末神奏宙" \r\n'; - const paddedStr = apis.padString(fromStr, 1024); + const paddedStr = apis.pad_string(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; + const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); diff --git a/packages/circom/tests/international_chars.test.js b/packages/circom/tests/international_chars.test.js index f0bb5ba..3e1e46f 100644 --- a/packages/circom/tests/international_chars.test.js +++ b/packages/circom/tests/international_chars.test.js @@ -1,26 +1,28 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(300000); describe("Simple Regex Decomposed", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( + const email_addr_json = readFileSync( path.join(__dirname, "./circuits/international_chars_decomposed.json"), - { - circomFilePath: path.join( - __dirname, - "./circuits/international_chars_decomposed.circom" - ), - templateName: "InternationalCharsDecomposed", - genSubstrs: true, - } + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "InternationalCharsDecomposed" + ); + writeFileSync( + path.join(__dirname, "./circuits/international_chars_decomposed.circom"), + circom ); circuit = await wasm_tester( path.join( @@ -34,7 +36,7 @@ describe("Simple Regex Decomposed", () => { it("case 1", async () => { const input = "Latin-Extension=Ʃƣƙ Greek=ϕω Cyrillic=иЩ Arabic=أبت Devanagari=आदित्य Hiragana&Katakana=なツ"; - const paddedStr = apis.padString(input, 128); + const paddedStr = apis.pad_string(input, 128); const circuitInputs = { msg: paddedStr, }; diff --git a/packages/circom/tests/message_id_regex.test.js b/packages/circom/tests/message_id_regex.test.js index 57bbff4..2646544 100644 --- a/packages/circom/tests/message_id_regex.test.js +++ b/packages/circom/tests/message_id_regex.test.js @@ -1,26 +1,28 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(120000); describe("Message Id Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( + const email_addr_json = readFileSync( path.join(__dirname, "../circuits/common/message_id.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/message_id_regex.circom" - ), - templateName: "MessageIdRegex", - genSubstrs: true, - } + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "MessageIdRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/message_id_regex.circom"), + circom ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_message_id_regex.circom"), @@ -30,14 +32,14 @@ describe("Message Id Regex", () => { it("message id from beginning", async () => { const messageIdStr = `message-id:\r\n`; - const paddedStr = apis.padString(messageIdStr, 256); + const paddedStr = apis.pad_string(messageIdStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractMessageIdIdxes(messageIdStr)[0]; + const prefixIdxes = apis.extract_message_id_idxes(messageIdStr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -50,14 +52,14 @@ describe("Message Id Regex", () => { it("subject after new line", async () => { const messageIdStr = "dummy\r\nmessage-id:\r\n"; - const paddedStr = apis.padString(messageIdStr, 256); + const paddedStr = apis.pad_string(messageIdStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractMessageIdIdxes(messageIdStr)[0]; + const prefixIdxes = apis.extract_message_id_idxes(messageIdStr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); diff --git a/packages/circom/tests/negate_regex.test.js b/packages/circom/tests/negate_regex.test.js index b88789f..e2404af 100644 --- a/packages/circom/tests/negate_regex.test.js +++ b/packages/circom/tests/negate_regex.test.js @@ -1,23 +1,28 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(120000); describe("Negate Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( + const email_addr_json = readFileSync( path.join(__dirname, "./circuits/negate1.json"), - { - circomFilePath: path.join(__dirname, "./circuits/negate1_regex.circom"), - templateName: "Negate1Regex", - genSubstrs: true, - } + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "Negate1Regex" + ); + writeFileSync( + path.join(__dirname, "./circuits/negate1_regex.circom"), + circom ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_negate1_regex.circom"), @@ -27,7 +32,7 @@ describe("Negate Regex", () => { it("case 1 with regex 1", async () => { const input = "a: ABCDEFG XYZ."; - const paddedStr = apis.padString(input, 64); + const paddedStr = apis.pad_string(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -50,7 +55,7 @@ describe("Negate Regex", () => { it("case 2 with regex 1", async () => { const input = "a: CRIPTOGRAFíA."; - const paddedStr = apis.padString(input, 64); + const paddedStr = apis.pad_string(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -73,7 +78,7 @@ describe("Negate Regex", () => { it("case 3 with regex 1", async () => { const input = "a: あいう."; - const paddedStr = apis.padString(input, 64); + const paddedStr = apis.pad_string(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -96,7 +101,7 @@ describe("Negate Regex", () => { it("case 4 with regex 1", async () => { const input = "a: التشفير."; - const paddedStr = apis.padString(input, 64); + const paddedStr = apis.pad_string(input, 64); const circuitInputs = { msg: paddedStr, }; diff --git a/packages/circom/tests/simple_regex.test.js b/packages/circom/tests/simple_regex.test.js index 924096f..a13562b 100644 --- a/packages/circom/tests/simple_regex.test.js +++ b/packages/circom/tests/simple_regex.test.js @@ -1,25 +1,30 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(120000); describe("Simple Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromRaw("1=(a|b) (2=(b|c)+ )+d", { - substrsJsonPath: path.join( - __dirname, - "./circuits/simple_regex_substrs.json" - ), - circomFilePath: path.join(__dirname, "./circuits/simple_regex.circom"), - templateName: "SimpleRegex", - genSubstrs: true, - }); + const substrs_json = readFileSync( + path.join(__dirname, "./circuits/simple_regex_substrs.json"), + "utf8" + ); + const circom = compiler.gen_from_raw_memory( + "1=(a|b) (2=(b|c)+ )+d", + substrs_json, + "SimpleRegex" + ); + writeFileSync( + path.join(__dirname, "./circuits/simple_regex.circom"), + circom + ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_simple_regex.circom"), option @@ -28,7 +33,7 @@ describe("Simple Regex", () => { it("case 1", async () => { const input = "1=a 2=b d"; - const paddedStr = apis.padString(input, 64); + const paddedStr = apis.pad_string(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -51,7 +56,7 @@ describe("Simple Regex", () => { it("case 2", async () => { const input = "1=a 2=b 2=bc 2=c d"; - const paddedStr = apis.padString(input, 64); + const paddedStr = apis.pad_string(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -74,7 +79,7 @@ describe("Simple Regex", () => { it("case 3", async () => { const input = "1=a 2=b 2=bc 2=c da 1=a 2=cb 2=c 2=b dd"; - const paddedStr = apis.padString(input, 64); + const paddedStr = apis.pad_string(input, 64); const circuitInputs = { msg: paddedStr, }; diff --git a/packages/circom/tests/simple_regex_decomposed.test.js b/packages/circom/tests/simple_regex_decomposed.test.js index 39c2171..80e2c3d 100644 --- a/packages/circom/tests/simple_regex_decomposed.test.js +++ b/packages/circom/tests/simple_regex_decomposed.test.js @@ -1,26 +1,28 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(120000); describe("Simple Regex Decomposed", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( + const email_addr_json = readFileSync( path.join(__dirname, "./circuits/simple_regex_decomposed.json"), - { - circomFilePath: path.join( - __dirname, - "./circuits/simple_regex_decomposed.circom" - ), - templateName: "SimpleRegexDecomposed", - genSubstrs: true, - } + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "SimpleRegexDecomposed" + ); + writeFileSync( + path.join(__dirname, "./circuits/simple_regex_decomposed.circom"), + circom ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_simple_regex_decomposed.circom"), @@ -30,7 +32,7 @@ describe("Simple Regex Decomposed", () => { it("case 1", async () => { const input = "email was meant for @zkRegex."; - const paddedStr = apis.padString(input, 64); + const paddedStr = apis.pad_string(input, 64); const circuitInputs = { msg: paddedStr, }; diff --git a/packages/circom/tests/subject_all.test.js b/packages/circom/tests/subject_all.test.js index 55dae0d..ee27371 100644 --- a/packages/circom/tests/subject_all.test.js +++ b/packages/circom/tests/subject_all.test.js @@ -1,26 +1,28 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(120000); describe("Subject All Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( + const email_addr_json = readFileSync( path.join(__dirname, "../circuits/common/subject_all.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/subject_all_regex.circom" - ), - templateName: "SubjectAllRegex", - genSubstrs: true, - } + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "SubjectAllRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/subject_all_regex.circom"), + circom ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_subject_all_regex.circom"), @@ -30,14 +32,14 @@ describe("Subject All Regex", () => { it("subject from beginning", async () => { const subjectStr = "subject:This is a test.\r\n"; - const paddedStr = apis.padString(subjectStr, 256); + const paddedStr = apis.pad_string(subjectStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractSubjectAllIdxes(subjectStr)[0]; + const prefixIdxes = apis.extract_subject_all_idxes(subjectStr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -49,14 +51,14 @@ describe("Subject All Regex", () => { it("subject after new line", async () => { const subjectStr = "dummy\r\nsubject:This is a test.\r\n"; - const paddedStr = apis.padString(subjectStr, 256); + const paddedStr = apis.pad_string(subjectStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractSubjectAllIdxes(subjectStr)[0]; + const prefixIdxes = apis.extract_subject_all_idxes(subjectStr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -68,14 +70,14 @@ describe("Subject All Regex", () => { it("subject from beginning and non-English case", async () => { const subjectStr = "subject:これはテストです。\r\n"; - const paddedStr = apis.padString(subjectStr, 256); + const paddedStr = apis.pad_string(subjectStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractSubjectAllIdxes(subjectStr)[0]; + const prefixIdxes = apis.extract_subject_all_idxes(subjectStr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); diff --git a/packages/circom/tests/timestamp.test.js b/packages/circom/tests/timestamp.test.js index 59c0e96..195e838 100644 --- a/packages/circom/tests/timestamp.test.js +++ b/packages/circom/tests/timestamp.test.js @@ -1,26 +1,28 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(600000); describe("Timestamp Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( + const email_addr_json = readFileSync( path.join(__dirname, "../circuits/common/timestamp.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/timestamp_regex.circom" - ), - templateName: "TimestampRegex", - genSubstrs: true, - } + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "TimestampRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/timestamp_regex.circom"), + circom ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_timestamp_regex.circom"), @@ -30,14 +32,14 @@ describe("Timestamp Regex", () => { it("timestamp in the header", async () => { const signatureField = `dkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1694989812; x=1695594612; dara=google.com; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=BWETwQ9JDReS4GyR2v2TTR8Bpzj9ayumsWQJ3q7vehs=; b=`; - const paddedStr = apis.padString(signatureField, 1024); + const paddedStr = apis.pad_string(signatureField, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractTimestampIdxes(signatureField)[0]; + const prefixIdxes = apis.extract_timestamp_idxes(signatureField)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -49,14 +51,14 @@ describe("Timestamp Regex", () => { it("timestamp after new line", async () => { const signatureField = `\r\ndkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1694989812; x=1695594612; dara=google.com; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=BWETwQ9JDReS4GyR2v2TTR8Bpzj9ayumsWQJ3q7vehs=; b=`; - const paddedStr = apis.padString(signatureField, 1024); + const paddedStr = apis.pad_string(signatureField, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractTimestampIdxes(signatureField)[0]; + const prefixIdxes = apis.extract_timestamp_idxes(signatureField)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); diff --git a/packages/circom/tests/to_addr.test.js b/packages/circom/tests/to_addr.test.js index 79c01f9..f0d513e 100644 --- a/packages/circom/tests/to_addr.test.js +++ b/packages/circom/tests/to_addr.test.js @@ -1,49 +1,62 @@ -const circom_tester = require("circom_tester"); -const wasm_tester = circom_tester.wasm; +import circom_tester from "circom_tester"; import * as path from "path"; -const apis = require("../../apis"); +import { readFileSync, writeFileSync } from "fs"; +import apis from "../../apis/pkg"; +import compiler from "../../compiler/pkg"; const option = { include: path.join(__dirname, "../../../node_modules"), }; -const compiler = require("../../compiler"); +const wasm_tester = circom_tester.wasm; jest.setTimeout(600000); describe("To Addr Regex", () => { let circuit; beforeAll(async () => { - compiler.genFromDecomposed( - path.join(__dirname, "../circuits/common/to_all.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/to_all_regex.circom" - ), - templateName: "ToAllRegex", - genSubstrs: true, - } - ); - compiler.genFromDecomposed( - path.join(__dirname, "../circuits/common/email_addr_with_name.json"), - { - circomFilePath: path.join( + { + const email_addr_json = readFileSync( + path.join(__dirname, "../circuits/common/to_all.json"), + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "ToAllRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/to_all_regex.circom"), + circom + ); + } + { + const email_addr_json = readFileSync( + path.join(__dirname, "../circuits/common/email_addr_with_name.json"), + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "EmailAddrWithNameRegex" + ); + writeFileSync( + path.join( __dirname, "../circuits/common/email_addr_with_name_regex.circom" ), - templateName: "EmailAddrWithNameRegex", - genSubstrs: true, - } - ); - compiler.genFromDecomposed( - path.join(__dirname, "../circuits/common/email_addr.json"), - { - circomFilePath: path.join( - __dirname, - "../circuits/common/email_addr_regex.circom" - ), - templateName: "EmailAddrRegex", - genSubstrs: true, - } - ); + circom + ); + } + { + const email_addr_json = readFileSync( + path.join(__dirname, "../circuits/common/email_addr.json"), + "utf8" + ); + const circom = compiler.gen_from_decomposed_memory( + email_addr_json, + "EmailAddrRegex" + ); + writeFileSync( + path.join(__dirname, "../circuits/common/email_addr_regex.circom"), + circom + ); + } circuit = await wasm_tester( path.join(__dirname, "./circuits/test_to_addr_regex.circom"), option @@ -52,14 +65,14 @@ describe("To Addr Regex", () => { it("to field from beginning case 1", async () => { const toStr = "to:adityabisht@gmail.com\r\n"; - const paddedStr = apis.padString(toStr, 1024); + const paddedStr = apis.pad_string(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; + const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -71,14 +84,14 @@ describe("To Addr Regex", () => { it("to field from beginning case 2", async () => { const toStr = "to:Aditya Bisht \r\n"; - const paddedStr = apis.padString(toStr, 1024); + const paddedStr = apis.pad_string(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; + const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -90,14 +103,14 @@ describe("To Addr Regex", () => { it("to field from beginning case 3 (email address as a name)", async () => { const toStr = "to:dummy@example.com\r\n"; - const paddedStr = apis.padString(toStr, 1024); + const paddedStr = apis.pad_string(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; + const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -109,14 +122,14 @@ describe("To Addr Regex", () => { it("to field from beginning case 4 (non-English string is used as a name)", async () => { const toStr = 'to: "末神奏宙" \r\n'; - const paddedStr = apis.padString(toStr, 1024); + const paddedStr = apis.pad_string(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; + const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -128,14 +141,14 @@ describe("To Addr Regex", () => { it("to field after new line case 1", async () => { const toStr = "dummy\r\nto:adityabisht@gmail.com\r\n"; - const paddedStr = apis.padString(toStr, 1024); + const paddedStr = apis.pad_string(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; + const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -147,14 +160,14 @@ describe("To Addr Regex", () => { it("to field after new line case 2", async () => { const toStr = "dummy\r\nto:Sora Suegami \r\n"; - const paddedStr = apis.padString(toStr, 1024); + const paddedStr = apis.pad_string(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; + const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -166,14 +179,14 @@ describe("To Addr Regex", () => { it("to field after new line case 3 (email address as a name)", async () => { const toStr = "dummy\r\nto:dummy@example.com\r\n"; - const paddedStr = apis.padString(toStr, 1024); + const paddedStr = apis.pad_string(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; + const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -185,14 +198,14 @@ describe("To Addr Regex", () => { it("to field after new line case 4 (non-English string is used as a name)", async () => { const toStr = 'dummy\r\nto: "末神奏宙" \r\n'; - const paddedStr = apis.padString(toStr, 1024); + const paddedStr = apis.pad_string(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; + const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); diff --git a/packages/compiler/Cargo.toml b/packages/compiler/Cargo.toml index ed0bc8b..e1a7182 100644 --- a/packages/compiler/Cargo.toml +++ b/packages/compiler/Cargo.toml @@ -1,15 +1,15 @@ [package] name = "zk-regex-compiler" -version = "1.1.0" +version = "2.0.0" authors = [ "Javier Su ", "Kata Choi ", "Sora Suegami ", "Yush G ", + "Aditya Bisht ", ] license = "MIT" edition = "2018" -# exclude = ["index.node"] [[bin]] name = "zk-regex" @@ -33,12 +33,6 @@ clap = { version = "=4.2.1", features = ["derive"] } ahash = "=0.8.7" regex-automata = "0.4.5" regex = "1.10.3" - -[dependencies.neon] -version = "0.10" -default-features = false -features = ["napi-6"] - -[features] -default = ["export_neon_main"] -export_neon_main = [] +getrandom = { version = "0.2", features = ["js"] } +wasm-bindgen = "0.2" +serde-wasm-bindgen = "0.6.5" diff --git a/packages/compiler/README.md b/packages/compiler/README.md index 6c8b132..8759458 100644 --- a/packages/compiler/README.md +++ b/packages/compiler/README.md @@ -2,12 +2,8 @@ A compiler CLI in [zk-regex](https://github.com/zkemail/zk-regex/tree/main). -This project was bootstrapped by [create-neon](https://www.npmjs.com/package/create-neon). - ## Installing zk-regex-compiler -Installing zk-regex-compiler requires a [supported version of Node and Rust](https://github.com/neon-bindings/neon#platform-support). - You can install the project with npm. In the project directory, run: ```sh @@ -24,22 +20,41 @@ If you have already installed the project and only want to run the build, run: $ npm run build ``` -This command uses the [cargo-cp-artifact](https://github.com/neon-bindings/cargo-cp-artifact) utility to run the Rust build and copy the built library into `./index.node`. +## Compiling zk-regex-compiler to wasm -## CLI Usage -Please see "Compiler CLI" section in [zk-regex](https://github.com/zkemail/zk-regex/tree/main). +### For web usage +Install `wasm-pack` if not already installed -## Exploring zk-regex-compiler +```sh +cargo install wasm-pack +``` -After building zk-regex-compiler, you can explore its exports at the Node REPL: +Compile the web package ```sh -$ npm install -$ node -> require('.').hello() -"hello node" +wasm-pack build --target nodejs ``` +Pack the package (optional) + +```sh +wasm-pack build --target nodejs +cd pkg +npm pkg set type='module' +wasm-pack pack +``` + +The output package file will be `packages/compiler/pkg/zk-regex-compiler-1.1.1.tgz` + +### For tests + +```sh +wasm-pack test --node +``` + +## CLI Usage +Please see "Compiler CLI" section in [zk-regex](https://github.com/zkemail/zk-regex/tree/main). + ## Available Scripts In the project directory, you can run: @@ -50,8 +65,6 @@ Installs the project, including running `npm run build`. ### `npm build` -Builds the Node addon (`index.node`) from source. - Additional [`cargo build`](https://doc.rust-lang.org/cargo/commands/cargo-build.html) arguments may be passed to `npm build` and `npm build-*` commands. For example, to enable a [cargo feature](https://doc.rust-lang.org/cargo/reference/features.html): ``` @@ -68,7 +81,7 @@ Same as [`npm build`](#npm-build) but, builds the module with the [`release`](ht ### `npm test` -Runs the unit tests by calling `cargo test`. You can learn more about [adding tests to your Rust code](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) from the [Rust book](https://doc.rust-lang.org/book/). +Runs the unit tests by calling `wasm-pack test --node`. ## Project Layout @@ -78,7 +91,6 @@ The directory structure of this project is: zk-regex-compiler/ ├── Cargo.toml ├── README.md -├── index.node ├── package.json ├── src/ | └── lib.rs @@ -93,12 +105,6 @@ The Cargo [manifest file](https://doc.rust-lang.org/cargo/reference/manifest.htm This file. -### index.node - -The Node addon—i.e., a binary Node module—generated by building the project. This is the main module for this package, as dictated by the `"main"` key in `package.json`. - -Under the hood, a [Node addon](https://nodejs.org/api/addons.html) is a [dynamically-linked shared object](https://en.wikipedia.org/wiki/Library_(computing)#Shared_libraries). The `"build"` script produces this file by copying it from within the `target/` directory, which is where the Rust build produces the shared object. - ### package.json The npm [manifest file](https://docs.npmjs.com/cli/v7/configuring-npm/package-json), which informs the `npm` command. @@ -114,11 +120,3 @@ The Rust library's main module. ### target/ Binary artifacts generated by the Rust build. - -## Learn More - -To learn more about Neon, see the [Neon documentation](https://neon-bindings.com). - -To learn more about Rust, see the [Rust documentation](https://www.rust-lang.org). - -To learn more about Node, see the [Node documentation](https://nodejs.org). diff --git a/packages/compiler/package.json b/packages/compiler/package.json index 64e4360..9fa5670 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,39 +1,26 @@ { "name": "@zk-email/zk-regex-compiler", - "version": "1.1.0", - "description": "a compiler to generate a regex verification circuit in circom from a user-defined regex. Please check [zk-regex](https://github.com/zkemail/zk-regex/tree/main) for the detail.", - "main": "index.node", + "version": "2.0.0", + "description": "A compiler to generate a regex verification circuit in circom from a user-defined regex. Please check [zk-regex](https://github.com/zkemail/zk-regex/tree/main) for the detail.", "contributors": [ "Javier Su ", "Kata Choi ", "Sora Suegami ", - "Yush G " + "Yush G ", + "Aditya Bisht " ], "repository": { "type": "git", "url": "git+https://github.com/zkemail/zk-regex.git" }, "scripts": { - "build": "cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics", + "build": "cargo build && wasm-pack build --target nodejs --out-dir ./pkg/", "build-debug": "npm run build --", "build-release": "npm run build -- --release", "install": "npm run build-debug", - "install-release": "node-pre-gyp install --update-binary --fallback-to-build=false || npm run build-release", - "test": "cargo test", - "package": "node-pre-gyp package", - "upload-binary": "npm run package && node-pre-gyp-github publish" + "install-release": "npm run build-release", + "test": "wasm-pack test --node", + "upload-binary": "wasm-pack publish -t nodejs" }, - "license": "MIT", - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0", - "cargo-cp-artifact": "^0.1", - "node-pre-gyp-github": "https://github.com/ultamatt/node-pre-gyp-github.git" - }, - "binary": { - "module_name": "index", - "host": "https://github.com/zkemail/zk-regex/releases/download/", - "remote_path": "{version}", - "package_name": "compiler-{node_abi}-{platform}-{arch}.tar.gz", - "module_path": "./" - } -} \ No newline at end of file + "license": "MIT" +} diff --git a/packages/compiler/src/circom.rs b/packages/compiler/src/circom.rs index dfb9ac6..448c10a 100644 --- a/packages/compiler/src/circom.rs +++ b/packages/compiler/src/circom.rs @@ -357,22 +357,31 @@ impl RegexAndDFA { gen_substrs: bool, ) -> Result<(), CompilerError> { let circom = gen_circom_allstr(&self.dfa_val, template_name, &self.regex_str); + let mut circom_file = File::create(circom_path)?; + write!(circom_file, "{}", circom)?; if gen_substrs { - self.add_substrs_constraints(circom_path, circom)?; - } else { - let mut circom_file = File::create(circom_path)?; - write!(circom_file, "{}", circom)?; - circom_file.flush()?; + let substrs = self.add_substrs_constraints()?; + write!(circom_file, "{}", substrs)?; } + circom_file.flush()?; Ok(()) } + pub fn gen_circom_str( + &self, + template_name: &str, + ) -> Result { + let circom = gen_circom_allstr(&self.dfa_val, template_name, &self.regex_str); + let substrs = self.add_substrs_constraints()?; + let result = circom + &substrs; + Ok(result) + } + pub fn add_substrs_constraints( &self, - circom_path: &PathBuf, - mut circom: String, - ) -> Result<(), CompilerError> { + ) -> Result { let accepted_state = get_accepted_state(&self.dfa_val).unwrap(); + let mut circom: String = "".to_string(); circom += "\n"; circom += "\tsignal is_consecutive[msg_bytes+1][2];\n"; circom += "\tis_consecutive[msg_bytes][1] <== 1;\n"; @@ -427,9 +436,6 @@ impl RegexAndDFA { circom += "\t}\n"; } circom += "}"; - let mut circom_file = File::create(circom_path)?; - write!(circom_file, "{}", circom)?; - circom_file.flush()?; - Ok(()) + Ok(circom) } } diff --git a/packages/compiler/src/lib.rs b/packages/compiler/src/lib.rs index 14f6f33..cddab5f 100644 --- a/packages/compiler/src/lib.rs +++ b/packages/compiler/src/lib.rs @@ -2,22 +2,21 @@ use std::fs::File; use std::iter::FromIterator; pub mod circom; pub mod halo2; -pub mod node; pub mod regex; // #[cfg(test)] // mod tests; -use crate::node::*; use crate::regex::*; -use neon; use itertools::Itertools; use petgraph::prelude::*; use serde::{Deserialize, Serialize}; +use serde_wasm_bindgen::from_value; use std::collections::{BTreeMap, BTreeSet}; use std::path::PathBuf; use thiserror::Error; +use wasm_bindgen::prelude::*; /// Error definitions of the compiler. #[derive(Error, Debug)] @@ -57,19 +56,19 @@ pub enum SoldityType { Decimal, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct DFAState { r#type: String, state: usize, edges: BTreeMap>, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct DFAGraph { states: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct RegexAndDFA { // pub max_byte_size: usize, // Original regex string, only here to be printed in generated file to make it more reproducible @@ -78,7 +77,7 @@ pub struct RegexAndDFA { pub substrs_defs: SubstrsDefs, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct SubstrsDefs { pub substr_defs_array: Vec>, pub substr_endpoints_array: Option, BTreeSet)>>, @@ -162,6 +161,21 @@ pub fn gen_from_decomposed( } } +#[wasm_bindgen] +pub fn gen_from_decomposed_memory( + decomposed_regex_json: &str, + circom_template_name: &str, +) -> String { + let decomposed_regex_config: DecomposedRegexConfig = + serde_json::from_str(decomposed_regex_json).expect("failed to parse decomposed_regex json"); + let regex_and_dfa = decomposed_regex_config + .to_regex_and_dfa() + .expect("failed to convert the decomposed regex to dfa"); + regex_and_dfa + .gen_circom_str(&circom_template_name) + .expect("failed to generate circom") +} + pub fn gen_from_raw( raw_regex: &str, // max_bytes: usize, @@ -205,6 +219,38 @@ pub fn gen_from_raw( } } +#[wasm_bindgen] +pub fn gen_from_raw_memory( + raw_regex: &str, + substrs_json: &str, + circom_template_name: &str, +) -> String { + let substrs_defs_json: SubstrsDefsJson = + serde_json::from_str(substrs_json).expect("failed to parse substrs json"); + let regex_and_dfa = RegexAndDFA::from_regex_str_and_substr_defs(raw_regex, substrs_defs_json) + .expect("failed to convert the raw regex and state transitions to dfa"); + regex_and_dfa + .gen_circom_str(&circom_template_name) + .expect("failed to generate circom") +} + +#[wasm_bindgen] +pub fn gen_regex_and_dfa(decomposed_regex: JsValue) -> JsValue { + let decomposed_regex_config: DecomposedRegexConfig = from_value(decomposed_regex).unwrap(); + let regex_and_dfa = regex_and_dfa(&decomposed_regex_config); + let dfa_val_str = serde_json::to_string(®ex_and_dfa).unwrap(); + JsValue::from_str(&dfa_val_str) +} + +#[wasm_bindgen] +pub fn gen_circom(decomposed_regex: JsValue, circom_template_name: &str) -> String { + let decomposed_regex_config: DecomposedRegexConfig = from_value(decomposed_regex).unwrap(); + let regex_and_dfa = regex_and_dfa(&decomposed_regex_config); + regex_and_dfa + .gen_circom_str(&circom_template_name) + .expect("failed to generate circom") +} + pub(crate) fn get_accepted_state(dfa_val: &DFAGraph) -> Option { for i in 0..dfa_val.states.len() { if dfa_val.states[i].r#type == "accept" { @@ -224,14 +270,6 @@ pub(crate) fn get_accepted_state(dfa_val: &DFAGraph) -> Option { // max_state // } -#[cfg(feature = "export_neon_main")] -#[neon::main] -fn main(mut cx: neon::prelude::ModuleContext) -> neon::prelude::NeonResult<()> { - cx.export_function("genFromDecomposed", gen_from_decomposed_node)?; - cx.export_function("genFromRaw", gen_from_raw_node)?; - Ok(()) -} - #[cfg(test)] mod tests { use super::*; diff --git a/packages/compiler/src/node.rs b/packages/compiler/src/node.rs deleted file mode 100644 index eefc713..0000000 --- a/packages/compiler/src/node.rs +++ /dev/null @@ -1,102 +0,0 @@ -use crate::{gen_from_decomposed, gen_from_raw}; -use neon::context::Context; -use neon::prelude::*; - -pub(crate) fn gen_from_decomposed_node(mut cx: FunctionContext) -> JsResult { - println!("Starting gen_from_decomposed_node function"); - let decomposed_regex_path = cx.argument::(0)?.value(&mut cx); - println!("Decomposed regex path: {}", decomposed_regex_path); - let obj = cx.argument::(1)?; - - let circom_file_path = obj - .get_opt::(&mut cx, "circomFilePath")? - .map(|v| { - let path = v - .to_string(&mut cx) - .expect("circomFilePath must be null or string") - .value(&mut cx); - println!("Circom file path: {}", path); - path - }); - let circom_template_name = obj - .get_opt::(&mut cx, "templateName")? - .map(|v| { - let name = v - .to_string(&mut cx) - .expect("templateName must be null or string") - .value(&mut cx); - println!("Circom template name: {}", name); - name - }); - let gen_substrs = obj - .get_opt::(&mut cx, "genSubstrs")? - .map(|v| { - let gen = v - .as_value(&mut cx) - .downcast::(&mut cx) - .expect("genSubstrs must be null or boolean") - .value(&mut cx); - println!("Gen substrs: {}", gen); - gen - }); - println!("Calling gen_from_decomposed function"); - gen_from_decomposed( - &decomposed_regex_path, - circom_file_path.as_ref().map(|s| s.as_str()), - circom_template_name.as_ref().map(|s| s.as_str()), - gen_substrs, - ); - println!("Finished gen_from_decomposed_node function"); - Ok(cx.null()) -} - -pub(crate) fn gen_from_raw_node(mut cx: FunctionContext) -> JsResult { - let raw_regex = cx.argument::(0)?.value(&mut cx); - let obj = cx.argument::(1)?; - - // let halo2_dir_path = obj - // .get_opt::(&mut cx, "halo2DirPath")? - // .map(|v| { - // v.to_string(&mut cx) - // .expect("halo2DirPath must be null or string") - // .value(&mut cx) - // }); - let substrs_json_path = obj - .get_opt::(&mut cx, "substrsJsonPath")? - .map(|v| { - v.to_string(&mut cx) - .expect("circomFilePath must be null or string") - .value(&mut cx) - }); - let circom_file_path = obj - .get_opt::(&mut cx, "circomFilePath")? - .map(|v| { - v.to_string(&mut cx) - .expect("circomFilePath must be null or string") - .value(&mut cx) - }); - let template_name = obj - .get_opt::(&mut cx, "templateName")? - .map(|v| { - v.to_string(&mut cx) - .expect("templateName must be null or string") - .value(&mut cx) - }); - let gen_substrs = obj - .get_opt::(&mut cx, "genSubstrs")? - .map(|v| { - v.as_value(&mut cx) - .downcast::(&mut cx) - .expect("genSubstrs must be null or boolean") - .value(&mut cx) - }); - gen_from_raw( - &raw_regex, - substrs_json_path.as_ref().map(|s| s.as_str()), - // halo2_dir_path.as_ref().map(|s| s.as_str()), - circom_file_path.as_ref().map(|s| s.as_str()), - template_name.as_ref().map(|s| s.as_str()), - gen_substrs, - ); - Ok(cx.null()) -}