From 613711a336240b10be8dffb9935c00b3ad21fdbb Mon Sep 17 00:00:00 2001 From: SoraSuegami Date: Sun, 24 Mar 2024 00:54:45 +0900 Subject: [PATCH] Revert "feat: Add Wasm Bindings (#62)" This reverts commit d1ef521bb1ec11d5ef0622d2d82c61e00710751e. --- .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, 910 insertions(+), 605 deletions(-) create mode 100644 packages/compiler/src/node.rs diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c184338..4fe726e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -18,8 +18,6 @@ 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 caaf8d2..ee605be 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,7 @@ build/* target +index.node Cargo.lock .DS_Store diff --git a/package.json b/package.json index 09809b8..b5fb03a 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "@zk-email/zk-regex", - "version": "2.0.0", + "version": "1.0.0", "private": true, "description": "zk regex circuit for content attestation", - "main": "pkg/zk_regex_compiler_bg.wasm", + "main": "node-apis/index.node", "workspaces": [ "packages/*" ], @@ -11,8 +11,7 @@ "Sora Suegami ", "Yush G ", "Javier Su ", - "Kata Choi ", - "Aditya Bisht " + "Kata Choi " ], "scripts": { "install": "yarn workspaces -pt run install", diff --git a/packages/apis/.gitignore b/packages/apis/.gitignore index 6d41026..6ca71fb 100644 --- a/packages/apis/.gitignore +++ b/packages/apis/.gitignore @@ -1,4 +1,5 @@ target +index.node **/node_modules **/.DS_Store npm-debug.log* diff --git a/packages/apis/Cargo.toml b/packages/apis/Cargo.toml index 21d65e4..8415595 100644 --- a/packages/apis/Cargo.toml +++ b/packages/apis/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "zk-regex-apis" -version = "2.0.0" +version = "1.2.0" license = "MIT" edition = "2018" +exclude = ["index.node"] authors = [ "Javier Su ", "Kata Choi ", "Sora Suegami ", "Yush G ", - "Aditya Bisht ", ] [lib] @@ -23,7 +23,13 @@ fancy-regex = "0.11.0" itertools = "0.10.3" thiserror = "1.0.40" serde_json = "1.0.95" -wasm-bindgen = "0.2" -serde-wasm-bindgen = "0.6.5" -js-sys = "0.3.69" -wasm-bindgen-test = "0.3.42" + + +[dependencies.neon] +version = "0.10" +default-features = false +features = ["napi-6"] + +[features] +default = ["export_neon_main"] +export_neon_main = [] diff --git a/packages/apis/README.md b/packages/apis/README.md index 57a0bc0..4846300 100644 --- a/packages/apis/README.md +++ b/packages/apis/README.md @@ -2,6 +2,8 @@ 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). @@ -22,36 +24,17 @@ If you have already installed the project and only want to run the build, run: $ npm run build ``` -## Compiling zk-regex-apis to wasm - -### For web usage -Install `wasm-pack` if not already installed - -```sh -cargo install wasm-pack -``` - -Compile the web package - -```sh -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 -``` +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`. -The output package file will be `packages/compiler/pkg/zk-regex-apis-1.1.1.tgz` +## Exploring zk-regex-apis -### For tests +After building zk-regex-apis, you can explore its exports at the Node REPL: ```sh -wasm-pack test --node +$ npm install +$ node +> require('.').hello() +"hello node" ``` ## Available Scripts @@ -64,6 +47,8 @@ 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): ``` @@ -80,16 +65,17 @@ Same as [`npm build`](#npm-build) but, builds the module with the [`release`](ht ### `npm test` -Runs the unit tests by calling `wasm-pack test --node`. +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/). ## Project Layout The directory structure of this project is: ``` -zk-regex-compiler/ +zk-regex-apis/ ├── Cargo.toml ├── README.md +├── index.node ├── package.json ├── src/ | └── lib.rs @@ -104,6 +90,12 @@ 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. @@ -119,3 +111,11 @@ 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 3a3ef49..2bd5ed9 100644 --- a/packages/apis/package.json +++ b/packages/apis/package.json @@ -1,26 +1,39 @@ { "name": "@zk-email/zk-regex-apis", - "version": "2.0.0", + "version": "1.2.0", "description": "apis compatible with [zk-regex](https://github.com/zkemail/zk-regex/tree/main).", "contributors": [ "Javier Su ", "Kata Choi ", "Sora Suegami ", - "Yush G ", - "Aditya Bisht " + "Yush G " ], + "main": "index.node", "repository": { "type": "git", "url": "git+https://github.com/zkemail/zk-regex.git" }, "scripts": { - "build": "wasm-pack build --target nodejs --out-dir ./pkg/", + "build": "cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics", "build-debug": "npm run build --", - "build-release": "npm run build --", + "build-release": "npm run build -- --release", "install": "npm run build-debug", - "install-release": "npm run build-release", - "test": "wasm-pack test --node", - "upload-binary": "wasm-pack publish -t nodejs" + "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" }, - "license": "MIT" -} + "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 diff --git a/packages/apis/src/extract_substrs.rs b/packages/apis/src/extract_substrs.rs index 67a3565..b73d655 100644 --- a/packages/apis/src/extract_substrs.rs +++ b/packages/apis/src/extract_substrs.rs @@ -1,11 +1,9 @@ use fancy_regex::Regex; -use js_sys::Array; +use neon::prelude::*; use serde::{Deserialize, Serialize}; - -use serde_wasm_bindgen::from_value; +use serde_json; use thiserror::Error; -use wasm_bindgen::prelude::*; -use wasm_bindgen_test::*; +// use zk_regex_compiler::DecomposedRegexConfig; /// A configuration of decomposed regexes. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -39,174 +37,409 @@ pub enum ExtractSubstrssError { RegexError(#[from] fancy_regex::Error), } -#[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(); +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())); + // } let mut entire_regex_str = String::new(); for part in regex_config.parts.iter() { entire_regex_str += part.regex_def.as_str(); } - - 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(); + // 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 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()).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 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 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; } - 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(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) +} - arr +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) } -#[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_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) } -#[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_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) } -#[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_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) } -#[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_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) } -#[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)) +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) } -#[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_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) } -#[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_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) } -#[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_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)?; + } + 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) +} + +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) +} + +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_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_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_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_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_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)) +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)?; + } + + Ok(js_array) +} + +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) +} + +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) +} + +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) +} + +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) +} + +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) } #[cfg(test)] mod test { use super::*; - #[wasm_bindgen_test] + #[test] fn test_email_domain_valid() { let input_str = "suegamisora@gmail.com"; - let idxes = extract_email_domain_idxes(input_str); - assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![12, 21]); + let idxes = extract_email_domain_idxes(input_str).unwrap(); + assert_eq!(idxes, vec![(12, 21)]); } - #[wasm_bindgen_test] + #[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); - assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![17, 38]); + let idxes = extract_email_addr_idxes(input_str).unwrap(); + assert_eq!(idxes, vec![(17, 38)]); } - #[wasm_bindgen_test] + #[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); - assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![18, 39]); + let idxes = extract_email_addr_with_name_idxes(input_str).unwrap(); + assert_eq!(idxes, vec![(18, 39)]); } - #[wasm_bindgen_test] + #[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); - assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![22, 43]); + let idxes = extract_email_addr_with_name_idxes(input_str).unwrap(); + assert_eq!(idxes, vec![(22, 43)]); } - #[wasm_bindgen_test] + #[test] fn test_email_from_all_valid() { let input_str = "from:dummy@a.com \r\n"; - let idxes = extract_from_all_idxes(input_str); - assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![5, 40]); + let idxes = extract_from_all_idxes(input_str).unwrap(); + assert_eq!(idxes, vec![(5, 40)]); } - #[wasm_bindgen_test] + #[test] fn test_email_from_addr_valid() { let input_str = "from:dummy@a.com \r\n"; - let idxes = extract_from_addr_idxes(input_str); - assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![18, 39]); + let idxes = extract_from_addr_idxes(input_str).unwrap(); + assert_eq!(idxes, vec![(18, 39)]); } - #[wasm_bindgen_test] + #[test] fn test_code_in_email_address_valid() { let code_regex = DecomposedRegexConfig { // max_byte_size: 1024, @@ -226,30 +459,29 @@ mod test { ], }; let input_str = "sepolia+ACCOUNTKEY.0xabc123@sendeth.org"; - 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]); + let idxes = extract_substr_idxes(input_str, &code_regex).unwrap(); + assert_eq!(idxes, vec![(21, 27)]); } - #[wasm_bindgen_test] + #[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); - assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![219, 263]); + let idxes = extract_body_hash_idxes(input_str).unwrap(); + assert_eq!(idxes, vec![(219, 263)]); } - #[wasm_bindgen_test] + #[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); - assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![80, 90]); + let idxes = extract_timestamp_idxes(input_str).unwrap(); + assert_eq!(idxes, vec![(80, 90)]); } - #[wasm_bindgen_test] + #[test] fn test_message_id_valid() { let input_str = "message-id:\r\n"; - let idxes = extract_message_id_idxes(input_str); - assert_eq!(from_value::>(idxes.at(0)).unwrap(), vec![11, 79]); + let idxes = extract_message_id_idxes(input_str).unwrap(); + assert_eq!(idxes, vec![(11, 79)]); } } diff --git a/packages/apis/src/lib.rs b/packages/apis/src/lib.rs index be43042..3836ac3 100644 --- a/packages/apis/src/lib.rs +++ b/packages/apis/src/lib.rs @@ -1,2 +1,27 @@ +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 d1eac4c..dd31b6c 100644 --- a/packages/apis/src/padding.rs +++ b/packages/apis/src/padding.rs @@ -1,15 +1,19 @@ -use js_sys::Array; -use wasm_bindgen::prelude::*; +use neon::prelude::*; -#[wasm_bindgen] -pub fn pad_string(str: &str, padded_bytes_size: usize) -> Array { +pub fn pad_string(str: &str, padded_bytes_size: usize) -> Vec { let mut padded_bytes = str.as_bytes().to_vec(); padded_bytes.append(&mut vec![0; padded_bytes_size - padded_bytes.len()]); + padded_bytes +} - 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)); +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)?; } - - arr + Ok(padded_array) } diff --git a/packages/circom/package.json b/packages/circom/package.json index b404dac..ade754c 100644 --- a/packages/circom/package.json +++ b/packages/circom/package.json @@ -1,14 +1,13 @@ { "name": "@zk-email/zk-regex-circom", - "version": "2.0.0", + "version": "1.3.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 ", - "Aditya Bisht " + "Yush G " ], "scripts": { "test": "jest", @@ -37,4 +36,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 df7dfd8..81e3991 100644 --- a/packages/circom/tests/body_hash_regex.test.js +++ b/packages/circom/tests/body_hash_regex.test.js @@ -1,30 +1,28 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +import { readFileSync } from "fs"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(600000); describe("Bodyhash Regex", () => { let circuit; beforeAll(async () => { - const email_addr_json = readFileSync( + compiler.genFromDecomposed( path.join(__dirname, "../circuits/common/body_hash.json"), - "utf8" - ); - const circom = compiler.gen_from_decomposed_memory( - email_addr_json, - "BodyHashRegex" - ); - writeFileSync( - path.join(__dirname, "../circuits/common/body_hash_regex.circom"), - circom + { + circomFilePath: path.join( + __dirname, + "../circuits/common/body_hash_regex.circom" + ), + templateName: "BodyHashRegex", + genSubstrs: true, + } ); - circuit = await wasm_tester( path.join(__dirname, "./circuits/test_body_hash_regex.circom"), option @@ -33,14 +31,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.pad_string(signatureField, 1024); + const paddedStr = apis.padString(signatureField, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_substr_idxes( + const prefixIdxes = apis.extractSubstrIdxes( signatureField, readFileSync( path.join(__dirname, "../circuits/common/body_hash.json"), @@ -58,14 +56,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.pad_string(signatureField, 1024); + const paddedStr = apis.padString(signatureField, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_substr_idxes( + const prefixIdxes = apis.extractSubstrIdxes( 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 012aa19..fcffe84 100644 --- a/packages/circom/tests/email_addr.test.js +++ b/packages/circom/tests/email_addr.test.js @@ -1,28 +1,26 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(120000); describe("Email Address Regex", () => { let circuit; beforeAll(async () => { - const email_addr_json = readFileSync( + compiler.genFromDecomposed( 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 + { + circomFilePath: path.join( + __dirname, + "../circuits/common/email_addr_regex.circom" + ), + templateName: "EmailAddrRegex", + genSubstrs: true, + } ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_email_addr_regex.circom"), @@ -32,14 +30,14 @@ describe("Email Address Regex", () => { it("only an email address", async () => { const emailAddr = "suegamisora@gmail.com"; - const paddedStr = apis.pad_string(emailAddr, 256); + const paddedStr = apis.padString(emailAddr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_email_addr_idxes(emailAddr)[0]; + const prefixIdxes = apis.extractEmailAddrIdxes(emailAddr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -53,14 +51,14 @@ describe("Email Address Regex", () => { const prefix = "subject:"; const emailAddr = "suegamisora@gmail.com"; const string = prefix + emailAddr; - const paddedStr = apis.pad_string(string, 256); + const paddedStr = apis.padString(string, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_email_addr_idxes(string)[0]; + const prefixIdxes = apis.extractEmailAddrIdxes(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 d546377..812a0c3 100644 --- a/packages/circom/tests/email_domain.test.js +++ b/packages/circom/tests/email_domain.test.js @@ -1,28 +1,26 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(120000); describe("Email Domain Regex", () => { let circuit; beforeAll(async () => { - const email_addr_json = readFileSync( + compiler.genFromDecomposed( path.join(__dirname, "../circuits/common/email_domain.json"), - "utf8" - ); - const circom = compiler.gen_from_decomposed_memory( - email_addr_json, - "EmailDomainRegex" - ); - writeFileSync( - path.join(__dirname, "../circuits/common/email_domain_regex.circom"), - circom + { + circomFilePath: path.join( + __dirname, + "../circuits/common/email_domain_regex.circom" + ), + templateName: "EmailDomainRegex", + genSubstrs: true, + } ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_email_domain_regex.circom"), @@ -32,7 +30,7 @@ describe("Email Domain Regex", () => { it("test a regex of an email domain", async () => { const emailAddr = "suegamisora@gmail.com"; - const paddedStr = apis.pad_string(emailAddr, 256); + const paddedStr = apis.padString(emailAddr, 256); const circuitInputs = { msg: paddedStr, }; @@ -42,7 +40,7 @@ describe("Email Domain Regex", () => { for (let idx = 0; idx < 12; ++idx) { expect(0n).toEqual(witness[2 + idx]); } - const prefixIdxes = apis.extract_email_domain_idxes(emailAddr)[0]; + const prefixIdxes = apis.extractEmailDomainIdxes(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 9f62a86..f4f240f 100644 --- a/packages/circom/tests/from_addr.test.js +++ b/packages/circom/tests/from_addr.test.js @@ -1,62 +1,49 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(600000); describe("From Addr Regex", () => { let circuit; beforeAll(async () => { - { - 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( + 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( __dirname, "../circuits/common/email_addr_with_name_regex.circom" ), - 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 - ); - } + 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, + } + ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_from_addr_regex.circom"), option @@ -65,14 +52,14 @@ describe("From Addr Regex", () => { it("from field from beginning case 1", async () => { const fromStr = "from:suegamisora@gmail.com\r\n"; - const paddedStr = apis.pad_string(fromStr, 1024); + const paddedStr = apis.padString(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; + const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -84,14 +71,14 @@ describe("From Addr Regex", () => { it("from field from beginning case 2", async () => { const fromStr = "from:Sora Suegami \r\n"; - const paddedStr = apis.pad_string(fromStr, 1024); + const paddedStr = apis.padString(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; + const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -103,14 +90,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.pad_string(fromStr, 1024); + const paddedStr = apis.padString(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; + const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -122,14 +109,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.pad_string(fromStr, 1024); + const paddedStr = apis.padString(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; + const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -141,14 +128,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.pad_string(fromStr, 1024); + const paddedStr = apis.padString(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; + const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -160,14 +147,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.pad_string(fromStr, 1024); + const paddedStr = apis.padString(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; + const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -180,14 +167,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.pad_string(fromStr, 1024); + const paddedStr = apis.padString(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; + const prefixIdxes = apis.extractFromAddrIdxes(fromStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -199,14 +186,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.pad_string(fromStr, 1024); + const paddedStr = apis.padString(fromStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_from_addr_idxes(fromStr)[0]; + const prefixIdxes = apis.extractFromAddrIdxes(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 3e1e46f..f0bb5ba 100644 --- a/packages/circom/tests/international_chars.test.js +++ b/packages/circom/tests/international_chars.test.js @@ -1,28 +1,26 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(300000); describe("Simple Regex Decomposed", () => { let circuit; beforeAll(async () => { - const email_addr_json = readFileSync( + compiler.genFromDecomposed( path.join(__dirname, "./circuits/international_chars_decomposed.json"), - "utf8" - ); - const circom = compiler.gen_from_decomposed_memory( - email_addr_json, - "InternationalCharsDecomposed" - ); - writeFileSync( - path.join(__dirname, "./circuits/international_chars_decomposed.circom"), - circom + { + circomFilePath: path.join( + __dirname, + "./circuits/international_chars_decomposed.circom" + ), + templateName: "InternationalCharsDecomposed", + genSubstrs: true, + } ); circuit = await wasm_tester( path.join( @@ -36,7 +34,7 @@ describe("Simple Regex Decomposed", () => { it("case 1", async () => { const input = "Latin-Extension=Ʃƣƙ Greek=ϕω Cyrillic=иЩ Arabic=أبت Devanagari=आदित्य Hiragana&Katakana=なツ"; - const paddedStr = apis.pad_string(input, 128); + const paddedStr = apis.padString(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 2646544..57bbff4 100644 --- a/packages/circom/tests/message_id_regex.test.js +++ b/packages/circom/tests/message_id_regex.test.js @@ -1,28 +1,26 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(120000); describe("Message Id Regex", () => { let circuit; beforeAll(async () => { - const email_addr_json = readFileSync( + compiler.genFromDecomposed( path.join(__dirname, "../circuits/common/message_id.json"), - "utf8" - ); - const circom = compiler.gen_from_decomposed_memory( - email_addr_json, - "MessageIdRegex" - ); - writeFileSync( - path.join(__dirname, "../circuits/common/message_id_regex.circom"), - circom + { + circomFilePath: path.join( + __dirname, + "../circuits/common/message_id_regex.circom" + ), + templateName: "MessageIdRegex", + genSubstrs: true, + } ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_message_id_regex.circom"), @@ -32,14 +30,14 @@ describe("Message Id Regex", () => { it("message id from beginning", async () => { const messageIdStr = `message-id:\r\n`; - const paddedStr = apis.pad_string(messageIdStr, 256); + const paddedStr = apis.padString(messageIdStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_message_id_idxes(messageIdStr)[0]; + const prefixIdxes = apis.extractMessageIdIdxes(messageIdStr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -52,14 +50,14 @@ describe("Message Id Regex", () => { it("subject after new line", async () => { const messageIdStr = "dummy\r\nmessage-id:\r\n"; - const paddedStr = apis.pad_string(messageIdStr, 256); + const paddedStr = apis.padString(messageIdStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_message_id_idxes(messageIdStr)[0]; + const prefixIdxes = apis.extractMessageIdIdxes(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 e2404af..b88789f 100644 --- a/packages/circom/tests/negate_regex.test.js +++ b/packages/circom/tests/negate_regex.test.js @@ -1,28 +1,23 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(120000); describe("Negate Regex", () => { let circuit; beforeAll(async () => { - const email_addr_json = readFileSync( + compiler.genFromDecomposed( path.join(__dirname, "./circuits/negate1.json"), - "utf8" - ); - const circom = compiler.gen_from_decomposed_memory( - email_addr_json, - "Negate1Regex" - ); - writeFileSync( - path.join(__dirname, "./circuits/negate1_regex.circom"), - circom + { + circomFilePath: path.join(__dirname, "./circuits/negate1_regex.circom"), + templateName: "Negate1Regex", + genSubstrs: true, + } ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_negate1_regex.circom"), @@ -32,7 +27,7 @@ describe("Negate Regex", () => { it("case 1 with regex 1", async () => { const input = "a: ABCDEFG XYZ."; - const paddedStr = apis.pad_string(input, 64); + const paddedStr = apis.padString(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -55,7 +50,7 @@ describe("Negate Regex", () => { it("case 2 with regex 1", async () => { const input = "a: CRIPTOGRAFíA."; - const paddedStr = apis.pad_string(input, 64); + const paddedStr = apis.padString(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -78,7 +73,7 @@ describe("Negate Regex", () => { it("case 3 with regex 1", async () => { const input = "a: あいう."; - const paddedStr = apis.pad_string(input, 64); + const paddedStr = apis.padString(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -101,7 +96,7 @@ describe("Negate Regex", () => { it("case 4 with regex 1", async () => { const input = "a: التشفير."; - const paddedStr = apis.pad_string(input, 64); + const paddedStr = apis.padString(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 a13562b..924096f 100644 --- a/packages/circom/tests/simple_regex.test.js +++ b/packages/circom/tests/simple_regex.test.js @@ -1,30 +1,25 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(120000); describe("Simple Regex", () => { let circuit; beforeAll(async () => { - 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 - ); + 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, + }); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_simple_regex.circom"), option @@ -33,7 +28,7 @@ describe("Simple Regex", () => { it("case 1", async () => { const input = "1=a 2=b d"; - const paddedStr = apis.pad_string(input, 64); + const paddedStr = apis.padString(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -56,7 +51,7 @@ describe("Simple Regex", () => { it("case 2", async () => { const input = "1=a 2=b 2=bc 2=c d"; - const paddedStr = apis.pad_string(input, 64); + const paddedStr = apis.padString(input, 64); const circuitInputs = { msg: paddedStr, }; @@ -79,7 +74,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.pad_string(input, 64); + const paddedStr = apis.padString(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 80e2c3d..39c2171 100644 --- a/packages/circom/tests/simple_regex_decomposed.test.js +++ b/packages/circom/tests/simple_regex_decomposed.test.js @@ -1,28 +1,26 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(120000); describe("Simple Regex Decomposed", () => { let circuit; beforeAll(async () => { - const email_addr_json = readFileSync( + compiler.genFromDecomposed( path.join(__dirname, "./circuits/simple_regex_decomposed.json"), - "utf8" - ); - const circom = compiler.gen_from_decomposed_memory( - email_addr_json, - "SimpleRegexDecomposed" - ); - writeFileSync( - path.join(__dirname, "./circuits/simple_regex_decomposed.circom"), - circom + { + circomFilePath: path.join( + __dirname, + "./circuits/simple_regex_decomposed.circom" + ), + templateName: "SimpleRegexDecomposed", + genSubstrs: true, + } ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_simple_regex_decomposed.circom"), @@ -32,7 +30,7 @@ describe("Simple Regex Decomposed", () => { it("case 1", async () => { const input = "email was meant for @zkRegex."; - const paddedStr = apis.pad_string(input, 64); + const paddedStr = apis.padString(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 ee27371..55dae0d 100644 --- a/packages/circom/tests/subject_all.test.js +++ b/packages/circom/tests/subject_all.test.js @@ -1,28 +1,26 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(120000); describe("Subject All Regex", () => { let circuit; beforeAll(async () => { - const email_addr_json = readFileSync( + compiler.genFromDecomposed( path.join(__dirname, "../circuits/common/subject_all.json"), - "utf8" - ); - const circom = compiler.gen_from_decomposed_memory( - email_addr_json, - "SubjectAllRegex" - ); - writeFileSync( - path.join(__dirname, "../circuits/common/subject_all_regex.circom"), - circom + { + circomFilePath: path.join( + __dirname, + "../circuits/common/subject_all_regex.circom" + ), + templateName: "SubjectAllRegex", + genSubstrs: true, + } ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_subject_all_regex.circom"), @@ -32,14 +30,14 @@ describe("Subject All Regex", () => { it("subject from beginning", async () => { const subjectStr = "subject:This is a test.\r\n"; - const paddedStr = apis.pad_string(subjectStr, 256); + const paddedStr = apis.padString(subjectStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_subject_all_idxes(subjectStr)[0]; + const prefixIdxes = apis.extractSubjectAllIdxes(subjectStr)[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 +49,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.pad_string(subjectStr, 256); + const paddedStr = apis.padString(subjectStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_subject_all_idxes(subjectStr)[0]; + const prefixIdxes = apis.extractSubjectAllIdxes(subjectStr)[0]; for (let idx = 0; idx < 256; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -70,14 +68,14 @@ describe("Subject All Regex", () => { it("subject from beginning and non-English case", async () => { const subjectStr = "subject:これはテストです。\r\n"; - const paddedStr = apis.pad_string(subjectStr, 256); + const paddedStr = apis.padString(subjectStr, 256); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_subject_all_idxes(subjectStr)[0]; + const prefixIdxes = apis.extractSubjectAllIdxes(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 195e838..59c0e96 100644 --- a/packages/circom/tests/timestamp.test.js +++ b/packages/circom/tests/timestamp.test.js @@ -1,28 +1,26 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(600000); describe("Timestamp Regex", () => { let circuit; beforeAll(async () => { - const email_addr_json = readFileSync( + compiler.genFromDecomposed( path.join(__dirname, "../circuits/common/timestamp.json"), - "utf8" - ); - const circom = compiler.gen_from_decomposed_memory( - email_addr_json, - "TimestampRegex" - ); - writeFileSync( - path.join(__dirname, "../circuits/common/timestamp_regex.circom"), - circom + { + circomFilePath: path.join( + __dirname, + "../circuits/common/timestamp_regex.circom" + ), + templateName: "TimestampRegex", + genSubstrs: true, + } ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_timestamp_regex.circom"), @@ -32,14 +30,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.pad_string(signatureField, 1024); + const paddedStr = apis.padString(signatureField, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_timestamp_idxes(signatureField)[0]; + const prefixIdxes = apis.extractTimestampIdxes(signatureField)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -51,14 +49,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.pad_string(signatureField, 1024); + const paddedStr = apis.padString(signatureField, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_timestamp_idxes(signatureField)[0]; + const prefixIdxes = apis.extractTimestampIdxes(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 f0d513e..79c01f9 100644 --- a/packages/circom/tests/to_addr.test.js +++ b/packages/circom/tests/to_addr.test.js @@ -1,62 +1,49 @@ -import circom_tester from "circom_tester"; +const circom_tester = require("circom_tester"); +const wasm_tester = circom_tester.wasm; import * as path from "path"; -import { readFileSync, writeFileSync } from "fs"; -import apis from "../../apis/pkg"; -import compiler from "../../compiler/pkg"; +const apis = require("../../apis"); const option = { include: path.join(__dirname, "../../../node_modules"), }; -const wasm_tester = circom_tester.wasm; +const compiler = require("../../compiler"); jest.setTimeout(600000); describe("To Addr Regex", () => { let circuit; beforeAll(async () => { - { - 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( + 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( __dirname, "../circuits/common/email_addr_with_name_regex.circom" ), - 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 - ); - } + 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, + } + ); circuit = await wasm_tester( path.join(__dirname, "./circuits/test_to_addr_regex.circom"), option @@ -65,14 +52,14 @@ describe("To Addr Regex", () => { it("to field from beginning case 1", async () => { const toStr = "to:adityabisht@gmail.com\r\n"; - const paddedStr = apis.pad_string(toStr, 1024); + const paddedStr = apis.padString(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; + const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -84,14 +71,14 @@ describe("To Addr Regex", () => { it("to field from beginning case 2", async () => { const toStr = "to:Aditya Bisht \r\n"; - const paddedStr = apis.pad_string(toStr, 1024); + const paddedStr = apis.padString(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; + const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -103,14 +90,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.pad_string(toStr, 1024); + const paddedStr = apis.padString(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; + const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -122,14 +109,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.pad_string(toStr, 1024); + const paddedStr = apis.padString(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; + const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -141,14 +128,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.pad_string(toStr, 1024); + const paddedStr = apis.padString(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; + const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -160,14 +147,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.pad_string(toStr, 1024); + const paddedStr = apis.padString(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; + const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -179,14 +166,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.pad_string(toStr, 1024); + const paddedStr = apis.padString(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; + const prefixIdxes = apis.extractToAddrIdxes(toStr)[0]; for (let idx = 0; idx < 1024; ++idx) { if (idx >= prefixIdxes[0] && idx < prefixIdxes[1]) { expect(BigInt(paddedStr[idx])).toEqual(witness[2 + idx]); @@ -198,14 +185,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.pad_string(toStr, 1024); + const paddedStr = apis.padString(toStr, 1024); const circuitInputs = { msg: paddedStr, }; const witness = await circuit.calculateWitness(circuitInputs); await circuit.checkConstraints(witness); expect(1n).toEqual(witness[1]); - const prefixIdxes = apis.extract_to_addr_idxes(toStr)[0]; + const prefixIdxes = apis.extractToAddrIdxes(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 e1a7182..ed0bc8b 100644 --- a/packages/compiler/Cargo.toml +++ b/packages/compiler/Cargo.toml @@ -1,15 +1,15 @@ [package] name = "zk-regex-compiler" -version = "2.0.0" +version = "1.1.0" authors = [ "Javier Su ", "Kata Choi ", "Sora Suegami ", "Yush G ", - "Aditya Bisht ", ] license = "MIT" edition = "2018" +# exclude = ["index.node"] [[bin]] name = "zk-regex" @@ -33,6 +33,12 @@ clap = { version = "=4.2.1", features = ["derive"] } ahash = "=0.8.7" regex-automata = "0.4.5" regex = "1.10.3" -getrandom = { version = "0.2", features = ["js"] } -wasm-bindgen = "0.2" -serde-wasm-bindgen = "0.6.5" + +[dependencies.neon] +version = "0.10" +default-features = false +features = ["napi-6"] + +[features] +default = ["export_neon_main"] +export_neon_main = [] diff --git a/packages/compiler/README.md b/packages/compiler/README.md index 8759458..6c8b132 100644 --- a/packages/compiler/README.md +++ b/packages/compiler/README.md @@ -2,8 +2,12 @@ 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 @@ -20,41 +24,22 @@ If you have already installed the project and only want to run the build, run: $ npm run build ``` -## Compiling zk-regex-compiler to wasm - -### For web usage -Install `wasm-pack` if not already installed - -```sh -cargo install wasm-pack -``` - -Compile the web package +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`. -```sh -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 -``` +## CLI Usage +Please see "Compiler CLI" section in [zk-regex](https://github.com/zkemail/zk-regex/tree/main). -The output package file will be `packages/compiler/pkg/zk-regex-compiler-1.1.1.tgz` +## Exploring zk-regex-compiler -### For tests +After building zk-regex-compiler, you can explore its exports at the Node REPL: ```sh -wasm-pack test --node +$ npm install +$ node +> require('.').hello() +"hello 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: @@ -65,6 +50,8 @@ 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): ``` @@ -81,7 +68,7 @@ Same as [`npm build`](#npm-build) but, builds the module with the [`release`](ht ### `npm test` -Runs the unit tests by calling `wasm-pack test --node`. +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/). ## Project Layout @@ -91,6 +78,7 @@ The directory structure of this project is: zk-regex-compiler/ ├── Cargo.toml ├── README.md +├── index.node ├── package.json ├── src/ | └── lib.rs @@ -105,6 +93,12 @@ 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. @@ -120,3 +114,11 @@ 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 9fa5670..64e4360 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,26 +1,39 @@ { "name": "@zk-email/zk-regex-compiler", - "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.", + "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", "contributors": [ "Javier Su ", "Kata Choi ", "Sora Suegami ", - "Yush G ", - "Aditya Bisht " + "Yush G " ], "repository": { "type": "git", "url": "git+https://github.com/zkemail/zk-regex.git" }, "scripts": { - "build": "cargo build && wasm-pack build --target nodejs --out-dir ./pkg/", + "build": "cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics", "build-debug": "npm run build --", "build-release": "npm run build -- --release", "install": "npm run build-debug", - "install-release": "npm run build-release", - "test": "wasm-pack test --node", - "upload-binary": "wasm-pack publish -t nodejs" + "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" }, - "license": "MIT" -} + "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 diff --git a/packages/compiler/src/circom.rs b/packages/compiler/src/circom.rs index 448c10a..dfb9ac6 100644 --- a/packages/compiler/src/circom.rs +++ b/packages/compiler/src/circom.rs @@ -357,31 +357,22 @@ 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 { - let substrs = self.add_substrs_constraints()?; - write!(circom_file, "{}", substrs)?; + self.add_substrs_constraints(circom_path, circom)?; + } else { + let mut circom_file = File::create(circom_path)?; + write!(circom_file, "{}", circom)?; + circom_file.flush()?; } - 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, - ) -> Result { + circom_path: &PathBuf, + mut circom: String, + ) -> Result<(), CompilerError> { 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"; @@ -436,6 +427,9 @@ impl RegexAndDFA { circom += "\t}\n"; } circom += "}"; - Ok(circom) + let mut circom_file = File::create(circom_path)?; + write!(circom_file, "{}", circom)?; + circom_file.flush()?; + Ok(()) } } diff --git a/packages/compiler/src/lib.rs b/packages/compiler/src/lib.rs index cddab5f..14f6f33 100644 --- a/packages/compiler/src/lib.rs +++ b/packages/compiler/src/lib.rs @@ -2,21 +2,22 @@ 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)] @@ -56,19 +57,19 @@ pub enum SoldityType { Decimal, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct DFAState { r#type: String, state: usize, edges: BTreeMap>, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct DFAGraph { states: Vec, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct RegexAndDFA { // pub max_byte_size: usize, // Original regex string, only here to be printed in generated file to make it more reproducible @@ -77,7 +78,7 @@ pub struct RegexAndDFA { pub substrs_defs: SubstrsDefs, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct SubstrsDefs { pub substr_defs_array: Vec>, pub substr_endpoints_array: Option, BTreeSet)>>, @@ -161,21 +162,6 @@ 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, @@ -219,38 +205,6 @@ 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" { @@ -270,6 +224,14 @@ 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 new file mode 100644 index 0000000..eefc713 --- /dev/null +++ b/packages/compiler/src/node.rs @@ -0,0 +1,102 @@ +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()) +}