Integrate vrm in halo2-regex/tests in email-wallet

This commit is contained in:
SoraSuegami
2023-09-26 07:43:23 +09:00
parent c2d71de3d5
commit 3fa375b1ac
62 changed files with 10665 additions and 1641 deletions

4
.gitignore vendored
View File

@@ -106,3 +106,7 @@ dist
.vscode
build/*
!build/.placeholder
target
index.node

1464
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

9
Cargo.toml Normal file
View File

@@ -0,0 +1,9 @@
[workspace]
members = ["packages/*"]
exclude = ["packages/circom", "test"]
# [patch."https://github.com/stalwartlabs/mail-builder"]
# mail-builder = { version = "0.2.5", git = "https://github.com/stalwartlabs//mail-builder", tag = "0.2.5" }
# [patch."https://github.com/stalwartlabs/mail-parser"]
# mail-parser = { version = "0.8", git = "https://github.com/stalwartlabs//mail-parser", tag = "0.8.0" }

11
babel.config.js Normal file
View File

@@ -0,0 +1,11 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
['@babel/preset-react', { "runtime": "automatic" }],
['jest']
],
plugins: [
'@babel/plugin-transform-modules-commonjs',
]
};

View File

@@ -1,48 +0,0 @@
pragma circom 2.0.3;
include "../node_modules/circomlib/circuits/comparators.circom";
include "../node_modules/circomlib/circuits/gates.circom";
template MultiOROld(n) {
signal input in[n];
signal output out;
component or1;
component or2;
component ors[2];
if (n==1) {
out <== in[0];
} else if (n==2) {
or1 = OR();
or1.a <== in[0];
or1.b <== in[1];
out <== or1.out;
} else {
or2 = OR();
var n1 = n\2;
var n2 = n-n\2;
ors[0] = MultiOR(n1);
ors[1] = MultiOR(n2);
var i;
for (i=0; i<n1; i++) ors[0].in[i] <== in[i];
for (i=0; i<n2; i++) ors[1].in[i] <== in[n1+i];
or2.a <== ors[0].out;
or2.b <== ors[1].out;
out <== or2.out;
}
}
template MultiOR(n) {
signal input in[n];
signal output out;
signal sums[n];
sums[0] <== in[0];
for (var i = 1; i < n; i++) {
sums[i] <== sums[i-1] + in[i];
}
component is_zero = IsZero();
is_zero.in <== sums[n-1];
out <== 1 - is_zero.out;
}

View File

@@ -1,27 +0,0 @@
const generator = require('../compiler/gen');
const program = require('commander');
const unescapeJs = require('unescape-js');
program.version('0.0.1')
.description('A sample CLI program');
program.command('compile <regex> <circuit_name>')
.description('Compile a regular expression into circom circuits')
.action((regex, circuit_name) => {
regex = unescapeJs(regex);
generator.generateCircuit(regex, undefined, circuit_name);
});
program.on('command:*', () => {
console.error(
'Error: Invalid command. See --help for a list of available commands.'
);
process.exit(1);
});
program.parse(process.argv);
if (!process.args.length) {
program.help();
}

View File

@@ -1,258 +0,0 @@
const fs = require('fs');
const path = require('path');
const regexpTree = require('regexp-tree');
const assert = require('assert');
const lexical = require('./lexical');
async function generateCircuit(regex, circuitLibPath, circuitName) {
const ast = regexpTree.parse(`/${regex}/`);
regexpTree.traverse(ast, {
'*': function ({ node }) {
if (node.type === 'CharacterClass') {
throw new Error('CharacterClass not supported');
}
},
});
const graph_json = lexical.compile(regex);
const N = graph_json.length;
// Outgoing nodes
const graph = Array.from({ length: N }, () => ({}));
// Incoming Nodes
const rev_graph = Array.from({ length: N }, () => []);
const accept_nodes = new Set();
for (let i = 0; i < N; i++) {
for (let k in graph_json[i]['edges']) {
//assert len(k) == 1
//assert ord(k) < 128
const v = graph_json[i]['edges'][k];
graph[i][k] = v;
rev_graph[v].push([k, i]);
}
if (graph_json[i]['type'] === 'accept') {
accept_nodes.add(i);
}
}
assert.strictEqual(accept_nodes.size, 1);
let eq_i = 0;
let lt_i = 0;
let and_i = 0;
let multi_or_i = 0;
let lines = [];
lines.push('for (var i = 0; i < num_bytes; i++) {');
assert.strictEqual(accept_nodes.has(0), false);
for (let i = 1; i < N; i++) {
const outputs = [];
for (let [k, prev_i] of rev_graph[i]) {
let vals = new Set(JSON.parse(k));
const eq_outputs = [];
const uppercase = new Set('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''));
const lowercase = new Set('abcdefghijklmnopqrstuvwxyz'.split(''));
const digits = new Set('0123456789'.split(''));
if (new Set([...uppercase].filter((x) => vals.has(x))).size === uppercase.size) {
vals = new Set([...vals].filter((x) => !uppercase.has(x)));
lines.push('\t//UPPERCASE');
lines.push(`\tlt[${lt_i}][i] = LessThan(8);`);
lines.push(`\tlt[${lt_i}][i].in[0] <== 64;`);
lines.push(`\tlt[${lt_i}][i].in[1] <== in[i];`);
lines.push(`\tlt[${lt_i + 1}][i] = LessThan(8);`);
lines.push(`\tlt[${lt_i + 1}][i].in[0] <== in[i];`);
lines.push(`\tlt[${lt_i + 1}][i].in[1] <== 91;`);
lines.push(`\tand[${and_i}][i] = AND();`);
lines.push(`\tand[${and_i}][i].a <== lt[${lt_i}][i].out;`);
lines.push(`\tand[${and_i}][i].b <== lt[${lt_i + 1}][i].out;`);
eq_outputs.push(['and', and_i]);
lt_i += 2;
and_i += 1;
}
if (new Set([...lowercase].filter((x) => vals.has(x))).size === lowercase.size) {
vals = new Set([...vals].filter((x) => !lowercase.has(x)));
lines.push('\t//lowercase');
lines.push(`\tlt[${lt_i}][i] = LessThan(8);`);
lines.push(`\tlt[${lt_i}][i].in[0] <== 96;`);
lines.push(`\tlt[${lt_i}][i].in[1] <== in[i];`);
lines.push(`\tlt[${lt_i + 1}][i] = LessThan(8);`);
lines.push(`\tlt[${lt_i + 1}][i].in[0] <== in[i];`);
lines.push(`\tlt[${lt_i + 1}][i].in[1] <== 123;`);
lines.push(`\tand[${and_i}][i] = AND();`);
lines.push(`\tand[${and_i}][i].a <== lt[${lt_i}][i].out;`);
lines.push(`\tand[${and_i}][i].b <== lt[${lt_i + 1}][i].out;`);
eq_outputs.push(['and', and_i]);
lt_i += 2;
and_i += 1;
}
if (new Set([...digits].filter((x) => vals.has(x))).size === digits.size) {
vals = new Set([...vals].filter((x) => !digits.has(x)));
lines.push('\t//digits');
lines.push(`\tlt[${lt_i}][i] = LessThan(8);`);
lines.push(`\tlt[${lt_i}][i].in[0] <== 47;`);
lines.push(`\tlt[${lt_i}][i].in[1] <== in[i];`);
lines.push(`\tlt[${lt_i + 1}][i] = LessThan(8);`);
lines.push(`\tlt[${lt_i + 1}][i].in[0] <== in[i];`);
lines.push(`\tlt[${lt_i + 1}][i].in[1] <== 58;`);
lines.push(`\tand[${and_i}][i] = AND();`);
lines.push(`\tand[${and_i}][i].a <== lt[${lt_i}][i].out;`);
lines.push(`\tand[${and_i}][i].b <== lt[${lt_i + 1}][i].out;`);
eq_outputs.push(['and', and_i]);
lt_i += 2;
and_i += 1;
}
for (let c of vals) {
assert.strictEqual(c.length, 1);
lines.push(`\t//${c}`);
lines.push(`\teq[${eq_i}][i] = IsEqual();`);
lines.push(`\teq[${eq_i}][i].in[0] <== in[i];`);
lines.push(`\teq[${eq_i}][i].in[1] <== ${c.charCodeAt(0)};`);
eq_outputs.push(['eq', eq_i]);
eq_i += 1;
}
lines.push(`\tand[${and_i}][i] = AND();`);
lines.push(`\tand[${and_i}][i].a <== states[i][${prev_i}];`);
if (eq_outputs.length === 1) {
lines.push(`\tand[${and_i}][i].b <== ${eq_outputs[0][0]}[${eq_outputs[0][1]}][i].out;`);
} else if (eq_outputs.length > 1) {
lines.push(`\tmulti_or[${multi_or_i}][i] = MultiOR(${eq_outputs.length});`);
for (let output_i = 0; output_i < eq_outputs.length; output_i++) {
lines.push(`\tmulti_or[${multi_or_i}][i].in[${output_i}] <== ${eq_outputs[output_i][0]}[${eq_outputs[output_i][1]}][i].out;`);
}
lines.push(`\tand[${and_i}][i].b <== multi_or[${multi_or_i}][i].out;`);
multi_or_i += 1;
}
outputs.push(and_i);
and_i += 1;
}
if (outputs.length === 1) {
lines.push(`\tstates[i+1][${i}] <== and[${outputs[0]}][i].out;`);
} else if (outputs.length > 1) {
lines.push(`\tmulti_or[${multi_or_i}][i] = MultiOR(${outputs.length});`);
for (let output_i = 0; output_i < outputs.length; output_i++) {
lines.push(`\tmulti_or[${multi_or_i}][i].in[${output_i}] <== and[${outputs[output_i]}][i].out;`);
}
lines.push(`\tstates[i+1][${i}] <== multi_or[${multi_or_i}][i].out;`);
multi_or_i += 1;
}
}
lines.push('}');
lines.push('signal final_state_sum[num_bytes+1];');
lines.push(`final_state_sum[0] <== states[0][${N - 1}];`);
lines.push('for (var i = 1; i <= num_bytes; i++) {');
lines.push(`\tfinal_state_sum[i] <== final_state_sum[i-1] + states[i][${N - 1}];`);
lines.push('}');
lines.push('entire_count <== final_state_sum[num_bytes];');
let declarations = [];
if (eq_i > 0) {
declarations.push(`component eq[${eq_i}][num_bytes];`);
}
if (lt_i > 0) {
declarations.push(`component lt[${lt_i}][num_bytes];`);
}
if (and_i > 0) {
declarations.push(`component and[${and_i}][num_bytes];`);
}
if (multi_or_i > 0) {
declarations.push(`component multi_or[${multi_or_i}][num_bytes];`);
}
declarations.push(`signal states[num_bytes+1][${N}];`);
declarations.push('');
let init_code = [];
init_code.push('for (var i = 0; i < num_bytes; i++) {');
init_code.push('\tstates[i][0] <== 1;');
init_code.push('}');
init_code.push(`for (var i = 1; i < ${N}; i++) {`);
init_code.push('\tstates[0][i] <== 0;');
init_code.push('}');
init_code.push('');
// construct the match group indexes
const node_edges = graph_json.map((node) =>
Object.keys(node.edges).map((key) => {
return { [key]: node.edges[key] };
})
);
const node_edges_flat = node_edges.flat();
const node_edges_set = new Set();
node_edges_flat.forEach((node) => {
if (JSON.parse(Object.keys(node)[0]).length > 1) {
node_edges_set.add(Object.values(node)[0]);
}
});
const match_group_indexes = Array.from(node_edges_set).sort((a, b) => a - b);
init_code.push(`var match_group_indexes[${match_group_indexes.length}] = [${match_group_indexes.join(', ')}];`);
const reveal_code = [];
reveal_code.push('signal output reveal[num_bytes];');
reveal_code.push('for (var i = 0; i < num_bytes; i++) {');
reveal_code.push('\treveal[i] <== in[i] * states[i+1][match_group_indexes[group_idx]];');
reveal_code.push('}');
reveal_code.push('');
lines = [...declarations, ...init_code, ...lines, ...reveal_code];
const OUTPUT_HALO2 = true;
if (OUTPUT_HALO2) {
console.log('Logging to halo2 file! Note that this file is not formatted correctly. For the latest spec, see https://github.com/zkemail/halo2-regex');
const f = fs.createWriteStream('halo2_regex_lookup_js.txt');
accept_nodes.forEach((a) => f.write(a + ' '));
f.write('\n');
f.write(match_group_indexes.join(' '));
f.write('\n');
for (let i = 0; i < N; i++) {
const edges = graph_json[i]['edges'];
for (let k in edges) {
const v = edges[k];
for (let val of JSON.parse(k)) {
f.write(`${i} ${v} ${val.charCodeAt(0)}\n`);
}
}
}
}
try {
let tpl = await (await fs.promises.readFile(`${__dirname}/tpl.circom`)).toString();
tpl = tpl.replace('TEMPLATE_NAME_PLACEHOLDER', circuitName || 'Regex');
tpl = tpl.replace('COMPILED_CONTENT_PLACEHOLDER', lines.join('\n\t'));
tpl = tpl.replace(/CIRCUIT_FOLDER/g, circuitLibPath || '../circuits');
tpl = tpl.replace(/\t/g, ' '.repeat(4));
const outputPath = `${__dirname}/../build/${circuitName || 'compiled'}.circom`;
await fs.promises.writeFile(outputPath, tpl);
process.env.VERBOSE && console.log(`Circuit compiled to ${path.normalize(outputPath)}`);
} catch (error) {
console.log(error);
}
}
module.exports = {
generateCircuit,
...lexical,
};

View File

@@ -1,83 +0,0 @@
pragma circom 2.0.3;
include "CIRCUIT_FOLDER/regex_helpers.circom";
template TEMPLATE_NAME_PLACEHOLDER (msg_bytes, reveal_bytes, group_idx) {
signal input msg[msg_bytes];
signal input match_idx;
signal output start_idx;
signal output group_match_count;
signal output entire_count;
signal reveal_shifted_intermediate[reveal_bytes][msg_bytes];
signal output reveal_shifted[reveal_bytes];
var num_bytes = msg_bytes;
signal in[num_bytes];
for (var i = 0; i < msg_bytes; i++) {
in[i] <== msg[i];
}
COMPILED_CONTENT_PLACEHOLDER
// a flag to indicate the start position of the match
var start_index = 0;
// for counting the number of matches
var count = 0;
// lengths to be consistent with states signal
component check_start[num_bytes + 1];
component check_match[num_bytes + 1];
component check_matched_start[num_bytes + 1];
component matched_idx_eq[msg_bytes];
for (var i = 0; i < num_bytes; i++) {
if (i == 0) {
count += states[1][match_group_indexes[group_idx]];
}
else {
check_start[i] = AND();
check_start[i].a <== states[i + 1][match_group_indexes[group_idx]];
check_start[i].b <== 1 - states[i][match_group_indexes[group_idx]];
count += check_start[i].out;
check_match[i] = IsEqual();
check_match[i].in[0] <== count;
check_match[i].in[1] <== match_idx + 1;
check_matched_start[i] = AND();
check_matched_start[i].a <== check_match[i].out;
check_matched_start[i].b <== check_start[i].out;
start_index += check_matched_start[i].out * i;
}
matched_idx_eq[i] = IsEqual();
matched_idx_eq[i].in[0] <== states[i + 1][match_group_indexes[group_idx]] * count;
matched_idx_eq[i].in[1] <== match_idx + 1;
}
component match_start_idx[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
match_start_idx[i] = IsEqual();
match_start_idx[i].in[0] <== i;
match_start_idx[i].in[1] <== start_index;
}
signal reveal_match[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
reveal_match[i] <== matched_idx_eq[i].out * reveal[i];
}
for (var j = 0; j < reveal_bytes; j++) {
reveal_shifted_intermediate[j][j] <== 0;
for (var i = j + 1; i < msg_bytes; i++) {
// This shifts matched string back to the beginning.
reveal_shifted_intermediate[j][i] <== reveal_shifted_intermediate[j][i - 1] + match_start_idx[i-j].out * reveal_match[i];
}
reveal_shifted[j] <== reveal_shifted_intermediate[j][msg_bytes - 1];
}
group_match_count <== count;
start_idx <== start_index;
}

View File

@@ -1,15 +1,15 @@
{
"name": "zk-regex",
"version": "0.0.1",
"private": true,
"description": "zk regex circuit for content attestation",
"main": "index.js",
"directories": {
"test": "test"
},
"main": "node-apis/index.node",
"workspaces": [
"packages/*"
],
"scripts": {
"test": "NODE_OPTIONS=--max_old_space_size=56000 mocha --timeout 600000 'test/**/*.js'",
"lint": "eslint ./",
"compile": "VERBOSE=1 node compiler/cli.js compile"
"test": "yarn workspaces -pt run test",
"lint": "eslint ./"
},
"repository": {
"type": "git",
@@ -28,21 +28,19 @@
"url": "https://github.com/zk-email-verify/zk-regex/issues"
},
"homepage": "https://github.com/zk-email-verify/zk-regex#readme",
"dependencies": {
"circomlib": "^2.0.2",
"commander": "^10.0.0",
"eslint": "^8.34.0",
"regexp-tree": "^0.1.24",
"unescape-js": "^1.1.4"
},
"devDependencies": {
"@types/chai": "^4.3.0",
"@types/expect": "^24.3.0",
"@types/mocha": "^9.0.0",
"chai": "^4.3.4",
"circom_tester": "katat/circom_tester#feat/signal-json",
"mocha": "^9.1.3",
"ts-node": "^10.4.0",
"@babel/core": "^7.22.5",
"@babel/plugin-transform-modules-commonjs": "^7.22.15",
"@babel/preset-env": "^7.22.2",
"@babel/preset-react": "^7.22.0",
"@babel/preset-typescript": "^7.21.5",
"@types/jest": "^29.5.4",
"babel-jest": "^29.5.0",
"babel-preset-jest": "^29.5.0",
"jest": "^29.5.0",
"prettier": "^3.0.0",
"prettier-plugin-solidity": "^1.1.3",
"ts-jest": "^29.1.1",
"typescript": "^4.5.4"
}
}
}

5
packages/apis/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
target
index.node
**/node_modules
**/.DS_Store
npm-debug.log*

24
packages/apis/Cargo.toml Normal file
View File

@@ -0,0 +1,24 @@
[package]
name = "zk-regex-apis"
version = "0.1.0"
license = "MIT"
edition = "2018"
exclude = ["index.node"]
[lib]
crate-type = ["cdylib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
compiler = { package = "zk-regex-compiler", path = "../compiler", default-features = false }
fancy-regex = "0.11.0"
itertools = "0.10.3"
thiserror = "1.0.40"
serde_json = "1.0.95"
[dependencies.neon]
version = "0.10"
default-features = false
features = ["napi-6"]

119
packages/apis/README.md Normal file
View File

@@ -0,0 +1,119 @@
# zk-regex-apis
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).
You can install the project with npm. In the project directory, run:
```sh
$ npm install
```
This fully installs the project, including installing any dependencies and running the build.
## Building zk-regex-apis
If you have already installed the project and only want to run the build, run:
```sh
$ npm run build
```
This command uses the [cargo-cp-artifact](https://github.com/neon-bindings/cargo-cp-artifact) utility to run the Rust build and copy the built library into `./index.node`.
## Exploring zk-regex-apis
After building zk-regex-apis, you can explore its exports at the Node REPL:
```sh
$ npm install
$ node
> require('.').hello()
"hello node"
```
## Available Scripts
In the project directory, you can run:
### `npm install`
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):
```
npm run build -- --feature=beetle
```
#### `npm build-debug`
Alias for `npm build`.
#### `npm build-release`
Same as [`npm build`](#npm-build) but, builds the module with the [`release`](https://doc.rust-lang.org/cargo/reference/profiles.html#release) profile. Release builds will compile slower, but run faster.
### `npm test`
Runs the unit tests by calling `cargo test`. You can learn more about [adding tests to your Rust code](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) from the [Rust book](https://doc.rust-lang.org/book/).
## Project Layout
The directory structure of this project is:
```
zk-regex-apis/
├── Cargo.toml
├── README.md
├── index.node
├── package.json
├── src/
| └── lib.rs
└── target/
```
### Cargo.toml
The Cargo [manifest file](https://doc.rust-lang.org/cargo/reference/manifest.html), which informs the `cargo` command.
### README.md
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.
### src/
The directory tree containing the Rust source code for the project.
### src/lib.rs
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).

View File

@@ -0,0 +1,18 @@
{
"name": "zk-regex-apis",
"version": "0.1.0",
"description": "",
"main": "index.node",
"scripts": {
"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-release",
"test": "cargo test"
},
"author": "",
"license": "MIT",
"devDependencies": {
"cargo-cp-artifact": "^0.1"
}
}

View File

@@ -0,0 +1,216 @@
use fancy_regex::Regex;
use compiler::{DecomposedRegexConfig};
use itertools::Itertools;
use neon::prelude::*;
use thiserror::Error;
use serde_json;
/// Error definitions of the compiler.
#[derive(Error, Debug)]
pub enum ExtractSubstrssError {
#[error("The max length is {} but the input length is {}",.0,.1)]
InvalidInputLen(usize, usize),
#[error("Substring of the entire regex {} is not found in {}",.0,.1)]
SubstringOfEntireNotFound(Regex,String),
#[error("Substring of {} is not found in {}",.0,.1)]
SubstringNotFound(Regex,String),
#[error(transparent)]
RegexError(#[from] fancy_regex::Error),
}
pub fn extract_substr_idxes(
input_str: &str,
regex_config: &DecomposedRegexConfig,
) -> Result<Vec<(usize,usize)>,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();
}
// 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(&regex_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;
}
Ok(public_idxes)
}
pub fn extract_substr_idxes_node(
mut cx: FunctionContext
) -> JsResult<JsArray> {
let input_str = cx.argument::<JsString>(0)?.value(&mut cx);
let regex_config_str = cx.argument::<JsString>(1)?.value(&mut cx);
let regex_config = match serde_json::from_str::<DecomposedRegexConfig>(&regex_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, &regex_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)
}
#[cfg(test)]
mod test {
use compiler::RegexPartConfig;
use super::*;
#[test]
fn test_email_domain_valid() {
let email_addr_regex = DecomposedRegexConfig {
max_byte_size: 256,
parts: vec![
RegexPartConfig {
is_public: false,
regex_def: "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\.|_|%|\\+|-|=)+".to_string(),
max_size: 64,
solidity: None
},
RegexPartConfig {
is_public: false,
regex_def: "@".to_string(),
max_size: 1,
solidity: None
},
RegexPartConfig {
is_public: true,
regex_def: "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\.|-)+".to_string(),
max_size: 255,
solidity: None
}
]
};
let input_str = "suegamisora@gmail.com";
let idxes = extract_substr_idxes(input_str, &email_addr_regex).unwrap();
assert_eq!(idxes, vec![(12,21)]);
}
#[test]
fn test_email_addr_in_subject_valid() {
let email_addr_regex = DecomposedRegexConfig {
max_byte_size: 256,
parts: vec![
RegexPartConfig {
is_public: true,
regex_def: "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\.|_|%|\\+|-|=)+".to_string(),
max_size: 64,
solidity: None
},
RegexPartConfig {
is_public: true,
regex_def: "@".to_string(),
max_size: 1,
solidity: None
},
RegexPartConfig {
is_public: true,
regex_def: "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\.|-)+".to_string(),
max_size: 255,
solidity: None
}
]
};
let input_str = "This is sent for suegamisora@gmail.com";
let idxes = extract_substr_idxes(input_str, &email_addr_regex).unwrap();
assert_eq!(idxes, vec![(17, 28),(28,29),(29, 38)]);
}
#[test]
fn test_code_in_subject_valid() {
let code_regex = DecomposedRegexConfig {
max_byte_size: 1024,
parts: vec![
RegexPartConfig {
is_public: false,
regex_def: "CODE:0x".to_string(),
max_size: 7,
solidity: None
},
RegexPartConfig {
is_public: true,
regex_def: "(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+".to_string(),
max_size: 6,
solidity: None
}
]
};
let input_str = "subject: Email Wallet CODE:0x123abc";
let idxes = extract_substr_idxes(input_str, &code_regex).unwrap();
assert_eq!(idxes, vec![(29, 35)]);
}
#[test]
fn test_timestamp_valid() {
let timestamp_regex = DecomposedRegexConfig {
max_byte_size: 1024,
parts: vec![
RegexPartConfig {
is_public: false,
regex_def: "dkim-signature:".to_string(),
max_size: 10,
solidity: None
},
RegexPartConfig {
is_public: false,
regex_def: "((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)+=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|\"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|\\.|\\/|:|<|=|>|\\?|@|\\[|\\\\|\\]|\\^|_|`|{|\\||}|~| |\t|\n|\r|\\x0b|\\x0c)+; )+t=".to_string(),
max_size: 128,
solidity: None
},
RegexPartConfig {
is_public: true,
regex_def: "(0|1|2|3|4|5|6|7|8|9)+".to_string(),
max_size: 10,
solidity: None
},
RegexPartConfig {
is_public: false,
regex_def: ";".to_string(),
max_size: 1,
solidity: None
},
]
};
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_substr_idxes(input_str, &timestamp_regex).unwrap();
assert_eq!(idxes, vec![(80, 90)]);
}
}

12
packages/apis/src/lib.rs Normal file
View File

@@ -0,0 +1,12 @@
use neon::prelude::*;
pub mod extract_substrs;
pub mod padding;
use extract_substrs::extract_substr_idxes_node;
use padding::pad_string_node;
#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
cx.export_function("extractSubstrIdxes", extract_substr_idxes_node)?;
cx.export_function("padString", pad_string_node)?;
Ok(())
}

View File

@@ -0,0 +1,19 @@
use neon::prelude::*;
pub fn pad_string(str: &str, padded_bytes_size: usize) -> Vec<u8> {
let mut padded_bytes = str.as_bytes().to_vec();
padded_bytes.append(&mut vec![0; padded_bytes_size - padded_bytes.len()]);
padded_bytes
}
pub fn pad_string_node(mut cx: FunctionContext) -> JsResult<JsArray> {
let string = cx.argument::<JsString>(0)?.value(&mut cx);
let padded_bytes_size = cx.argument::<JsNumber>(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)?;
}
Ok(padded_array)
}

View File

@@ -0,0 +1,10 @@
{
"max_byte_size": 512,
"parts": [
{
"is_public": true,
"regex_def": "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\.|_|%|\\+|-|=)+@(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\.|-)+",
"max_size": 256
}
]
}

View File

@@ -0,0 +1,276 @@
pragma circom 2.1.5;
include "zk-regex-circom/circuits/regex_helpers.circom";
template EmailAddrRegex(msg_bytes) {
signal input msg[msg_bytes];
signal output out;
var num_bytes = msg_bytes+1;
signal in[num_bytes];
in[0]<==128;
for (var i = 0; i < msg_bytes; i++) {
in[i+1] <== msg[i];
}
component eq[17][num_bytes];
component lt[24][num_bytes];
component and[17][num_bytes];
component multi_or[6][num_bytes];
signal states[num_bytes+1][4];
component state_changed[num_bytes];
states[0][0] <== 1;
for (var i = 1; i < 4; i++) {
states[0][i] <== 0;
}
for (var i = 0; i < num_bytes; i++) {
state_changed[i] = MultiOR(3);
lt[0][i] = LessThan(8);
lt[0][i].in[0] <== 47;
lt[0][i].in[1] <== in[i];
lt[1][i] = LessThan(8);
lt[1][i].in[0] <== in[i];
lt[1][i].in[1] <== 58;
and[0][i] = AND();
and[0][i].a <== lt[0][i].out;
and[0][i].b <== lt[1][i].out;
lt[2][i] = LessThan(8);
lt[2][i].in[0] <== 64;
lt[2][i].in[1] <== in[i];
lt[3][i] = LessThan(8);
lt[3][i].in[0] <== in[i];
lt[3][i].in[1] <== 91;
and[1][i] = AND();
and[1][i].a <== lt[2][i].out;
and[1][i].b <== lt[3][i].out;
lt[4][i] = LessThan(8);
lt[4][i].in[0] <== 96;
lt[4][i].in[1] <== in[i];
lt[5][i] = LessThan(8);
lt[5][i].in[0] <== in[i];
lt[5][i].in[1] <== 123;
and[2][i] = AND();
and[2][i].a <== lt[4][i].out;
and[2][i].b <== lt[5][i].out;
eq[0][i] = IsEqual();
eq[0][i].in[0] <== in[i];
eq[0][i].in[1] <== 37;
eq[1][i] = IsEqual();
eq[1][i].in[0] <== in[i];
eq[1][i].in[1] <== 43;
eq[2][i] = IsEqual();
eq[2][i].in[0] <== in[i];
eq[2][i].in[1] <== 45;
eq[3][i] = IsEqual();
eq[3][i].in[0] <== in[i];
eq[3][i].in[1] <== 46;
eq[4][i] = IsEqual();
eq[4][i].in[0] <== in[i];
eq[4][i].in[1] <== 61;
eq[5][i] = IsEqual();
eq[5][i].in[0] <== in[i];
eq[5][i].in[1] <== 95;
and[3][i] = AND();
and[3][i].a <== states[i][0];
multi_or[0][i] = MultiOR(9);
multi_or[0][i].in[0] <== and[0][i].out;
multi_or[0][i].in[1] <== and[1][i].out;
multi_or[0][i].in[2] <== and[2][i].out;
multi_or[0][i].in[3] <== eq[0][i].out;
multi_or[0][i].in[4] <== eq[1][i].out;
multi_or[0][i].in[5] <== eq[2][i].out;
multi_or[0][i].in[6] <== eq[3][i].out;
multi_or[0][i].in[7] <== eq[4][i].out;
multi_or[0][i].in[8] <== eq[5][i].out;
and[3][i].b <== multi_or[0][i].out;
lt[6][i] = LessThan(8);
lt[6][i].in[0] <== 47;
lt[6][i].in[1] <== in[i];
lt[7][i] = LessThan(8);
lt[7][i].in[0] <== in[i];
lt[7][i].in[1] <== 58;
and[4][i] = AND();
and[4][i].a <== lt[6][i].out;
and[4][i].b <== lt[7][i].out;
lt[8][i] = LessThan(8);
lt[8][i].in[0] <== 64;
lt[8][i].in[1] <== in[i];
lt[9][i] = LessThan(8);
lt[9][i].in[0] <== in[i];
lt[9][i].in[1] <== 91;
and[5][i] = AND();
and[5][i].a <== lt[8][i].out;
and[5][i].b <== lt[9][i].out;
lt[10][i] = LessThan(8);
lt[10][i].in[0] <== 96;
lt[10][i].in[1] <== in[i];
lt[11][i] = LessThan(8);
lt[11][i].in[0] <== in[i];
lt[11][i].in[1] <== 123;
and[6][i] = AND();
and[6][i].a <== lt[10][i].out;
and[6][i].b <== lt[11][i].out;
eq[6][i] = IsEqual();
eq[6][i].in[0] <== in[i];
eq[6][i].in[1] <== 37;
eq[7][i] = IsEqual();
eq[7][i].in[0] <== in[i];
eq[7][i].in[1] <== 43;
eq[8][i] = IsEqual();
eq[8][i].in[0] <== in[i];
eq[8][i].in[1] <== 45;
eq[9][i] = IsEqual();
eq[9][i].in[0] <== in[i];
eq[9][i].in[1] <== 46;
eq[10][i] = IsEqual();
eq[10][i].in[0] <== in[i];
eq[10][i].in[1] <== 61;
eq[11][i] = IsEqual();
eq[11][i].in[0] <== in[i];
eq[11][i].in[1] <== 95;
and[7][i] = AND();
and[7][i].a <== states[i][1];
multi_or[1][i] = MultiOR(9);
multi_or[1][i].in[0] <== and[4][i].out;
multi_or[1][i].in[1] <== and[5][i].out;
multi_or[1][i].in[2] <== and[6][i].out;
multi_or[1][i].in[3] <== eq[6][i].out;
multi_or[1][i].in[4] <== eq[7][i].out;
multi_or[1][i].in[5] <== eq[8][i].out;
multi_or[1][i].in[6] <== eq[9][i].out;
multi_or[1][i].in[7] <== eq[10][i].out;
multi_or[1][i].in[8] <== eq[11][i].out;
and[7][i].b <== multi_or[1][i].out;
multi_or[2][i] = MultiOR(2);
multi_or[2][i].in[0] <== and[3][i].out;
multi_or[2][i].in[1] <== and[7][i].out;
states[i+1][1] <== multi_or[2][i].out;
state_changed[i].in[0] <== states[i+1][1];
eq[12][i] = IsEqual();
eq[12][i].in[0] <== in[i];
eq[12][i].in[1] <== 64;
and[8][i] = AND();
and[8][i].a <== states[i][1];
and[8][i].b <== eq[12][i].out;
states[i+1][2] <== and[8][i].out;
state_changed[i].in[1] <== states[i+1][2];
lt[12][i] = LessThan(8);
lt[12][i].in[0] <== 47;
lt[12][i].in[1] <== in[i];
lt[13][i] = LessThan(8);
lt[13][i].in[0] <== in[i];
lt[13][i].in[1] <== 58;
and[9][i] = AND();
and[9][i].a <== lt[12][i].out;
and[9][i].b <== lt[13][i].out;
lt[14][i] = LessThan(8);
lt[14][i].in[0] <== 64;
lt[14][i].in[1] <== in[i];
lt[15][i] = LessThan(8);
lt[15][i].in[0] <== in[i];
lt[15][i].in[1] <== 91;
and[10][i] = AND();
and[10][i].a <== lt[14][i].out;
and[10][i].b <== lt[15][i].out;
lt[16][i] = LessThan(8);
lt[16][i].in[0] <== 96;
lt[16][i].in[1] <== in[i];
lt[17][i] = LessThan(8);
lt[17][i].in[0] <== in[i];
lt[17][i].in[1] <== 123;
and[11][i] = AND();
and[11][i].a <== lt[16][i].out;
and[11][i].b <== lt[17][i].out;
eq[13][i] = IsEqual();
eq[13][i].in[0] <== in[i];
eq[13][i].in[1] <== 45;
eq[14][i] = IsEqual();
eq[14][i].in[0] <== in[i];
eq[14][i].in[1] <== 46;
and[12][i] = AND();
and[12][i].a <== states[i][2];
multi_or[3][i] = MultiOR(5);
multi_or[3][i].in[0] <== and[9][i].out;
multi_or[3][i].in[1] <== and[10][i].out;
multi_or[3][i].in[2] <== and[11][i].out;
multi_or[3][i].in[3] <== eq[13][i].out;
multi_or[3][i].in[4] <== eq[14][i].out;
and[12][i].b <== multi_or[3][i].out;
lt[18][i] = LessThan(8);
lt[18][i].in[0] <== 47;
lt[18][i].in[1] <== in[i];
lt[19][i] = LessThan(8);
lt[19][i].in[0] <== in[i];
lt[19][i].in[1] <== 58;
and[13][i] = AND();
and[13][i].a <== lt[18][i].out;
and[13][i].b <== lt[19][i].out;
lt[20][i] = LessThan(8);
lt[20][i].in[0] <== 64;
lt[20][i].in[1] <== in[i];
lt[21][i] = LessThan(8);
lt[21][i].in[0] <== in[i];
lt[21][i].in[1] <== 91;
and[14][i] = AND();
and[14][i].a <== lt[20][i].out;
and[14][i].b <== lt[21][i].out;
lt[22][i] = LessThan(8);
lt[22][i].in[0] <== 96;
lt[22][i].in[1] <== in[i];
lt[23][i] = LessThan(8);
lt[23][i].in[0] <== in[i];
lt[23][i].in[1] <== 123;
and[15][i] = AND();
and[15][i].a <== lt[22][i].out;
and[15][i].b <== lt[23][i].out;
eq[15][i] = IsEqual();
eq[15][i].in[0] <== in[i];
eq[15][i].in[1] <== 45;
eq[16][i] = IsEqual();
eq[16][i].in[0] <== in[i];
eq[16][i].in[1] <== 46;
and[16][i] = AND();
and[16][i].a <== states[i][3];
multi_or[4][i] = MultiOR(5);
multi_or[4][i].in[0] <== and[13][i].out;
multi_or[4][i].in[1] <== and[14][i].out;
multi_or[4][i].in[2] <== and[15][i].out;
multi_or[4][i].in[3] <== eq[15][i].out;
multi_or[4][i].in[4] <== eq[16][i].out;
and[16][i].b <== multi_or[4][i].out;
multi_or[5][i] = MultiOR(2);
multi_or[5][i].in[0] <== and[12][i].out;
multi_or[5][i].in[1] <== and[16][i].out;
states[i+1][3] <== multi_or[5][i].out;
state_changed[i].in[2] <== states[i+1][3];
states[i+1][0] <== 1 - state_changed[i].out;
}
component final_state_result = MultiOR(num_bytes+1);
for (var i = 0; i <= num_bytes; i++) {
final_state_result.in[i] <== states[i][3];
}
out <== final_state_result.out;
signal is_consecutive[msg_bytes+1][2];
is_consecutive[msg_bytes][1] <== 1;
for (var i = 0; i < msg_bytes; i++) {
is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][3] * (1 - is_consecutive[msg_bytes-i][1]) + is_consecutive[msg_bytes-i][1];
is_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];
}
signal is_substr0[msg_bytes][6];
signal is_reveal0[msg_bytes];
signal output reveal0[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr0[i][0] <== 0;
is_substr0[i][1] <== is_substr0[i][0] + states[i+1][1] * states[i+2][2];
is_substr0[i][2] <== is_substr0[i][1] + states[i+1][2] * states[i+2][3];
is_substr0[i][3] <== is_substr0[i][2] + states[i+1][1] * states[i+2][1];
is_substr0[i][4] <== is_substr0[i][3] + states[i+1][0] * states[i+2][1];
is_substr0[i][5] <== is_substr0[i][4] + states[i+1][3] * states[i+2][3];
is_reveal0[i] <== is_substr0[i][5] * is_consecutive[i][1];
reveal0[i] <== in[i+1] * is_reveal0[i];
}
}

View File

@@ -0,0 +1,20 @@
{
"max_byte_size": 256,
"parts": [
{
"is_public": false,
"regex_def": "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\.|_|%|\\+|-|=)+",
"max_size": 64
},
{
"is_public": false,
"regex_def": "@",
"max_size": 1
},
{
"is_public": true,
"regex_def": "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\.|-)+",
"max_size": 255
}
]
}

View File

@@ -0,0 +1,273 @@
pragma circom 2.1.5;
include "zk-regex-circom/circuits/regex_helpers.circom";
template EmailDomainRegex(msg_bytes) {
signal input msg[msg_bytes];
signal output out;
var num_bytes = msg_bytes+1;
signal in[num_bytes];
in[0]<==128;
for (var i = 0; i < msg_bytes; i++) {
in[i+1] <== msg[i];
}
component eq[17][num_bytes];
component lt[24][num_bytes];
component and[17][num_bytes];
component multi_or[6][num_bytes];
signal states[num_bytes+1][4];
component state_changed[num_bytes];
states[0][0] <== 1;
for (var i = 1; i < 4; i++) {
states[0][i] <== 0;
}
for (var i = 0; i < num_bytes; i++) {
state_changed[i] = MultiOR(3);
lt[0][i] = LessThan(8);
lt[0][i].in[0] <== 47;
lt[0][i].in[1] <== in[i];
lt[1][i] = LessThan(8);
lt[1][i].in[0] <== in[i];
lt[1][i].in[1] <== 58;
and[0][i] = AND();
and[0][i].a <== lt[0][i].out;
and[0][i].b <== lt[1][i].out;
lt[2][i] = LessThan(8);
lt[2][i].in[0] <== 64;
lt[2][i].in[1] <== in[i];
lt[3][i] = LessThan(8);
lt[3][i].in[0] <== in[i];
lt[3][i].in[1] <== 91;
and[1][i] = AND();
and[1][i].a <== lt[2][i].out;
and[1][i].b <== lt[3][i].out;
lt[4][i] = LessThan(8);
lt[4][i].in[0] <== 96;
lt[4][i].in[1] <== in[i];
lt[5][i] = LessThan(8);
lt[5][i].in[0] <== in[i];
lt[5][i].in[1] <== 123;
and[2][i] = AND();
and[2][i].a <== lt[4][i].out;
and[2][i].b <== lt[5][i].out;
eq[0][i] = IsEqual();
eq[0][i].in[0] <== in[i];
eq[0][i].in[1] <== 37;
eq[1][i] = IsEqual();
eq[1][i].in[0] <== in[i];
eq[1][i].in[1] <== 43;
eq[2][i] = IsEqual();
eq[2][i].in[0] <== in[i];
eq[2][i].in[1] <== 45;
eq[3][i] = IsEqual();
eq[3][i].in[0] <== in[i];
eq[3][i].in[1] <== 46;
eq[4][i] = IsEqual();
eq[4][i].in[0] <== in[i];
eq[4][i].in[1] <== 61;
eq[5][i] = IsEqual();
eq[5][i].in[0] <== in[i];
eq[5][i].in[1] <== 95;
and[3][i] = AND();
and[3][i].a <== states[i][0];
multi_or[0][i] = MultiOR(9);
multi_or[0][i].in[0] <== and[0][i].out;
multi_or[0][i].in[1] <== and[1][i].out;
multi_or[0][i].in[2] <== and[2][i].out;
multi_or[0][i].in[3] <== eq[0][i].out;
multi_or[0][i].in[4] <== eq[1][i].out;
multi_or[0][i].in[5] <== eq[2][i].out;
multi_or[0][i].in[6] <== eq[3][i].out;
multi_or[0][i].in[7] <== eq[4][i].out;
multi_or[0][i].in[8] <== eq[5][i].out;
and[3][i].b <== multi_or[0][i].out;
lt[6][i] = LessThan(8);
lt[6][i].in[0] <== 47;
lt[6][i].in[1] <== in[i];
lt[7][i] = LessThan(8);
lt[7][i].in[0] <== in[i];
lt[7][i].in[1] <== 58;
and[4][i] = AND();
and[4][i].a <== lt[6][i].out;
and[4][i].b <== lt[7][i].out;
lt[8][i] = LessThan(8);
lt[8][i].in[0] <== 64;
lt[8][i].in[1] <== in[i];
lt[9][i] = LessThan(8);
lt[9][i].in[0] <== in[i];
lt[9][i].in[1] <== 91;
and[5][i] = AND();
and[5][i].a <== lt[8][i].out;
and[5][i].b <== lt[9][i].out;
lt[10][i] = LessThan(8);
lt[10][i].in[0] <== 96;
lt[10][i].in[1] <== in[i];
lt[11][i] = LessThan(8);
lt[11][i].in[0] <== in[i];
lt[11][i].in[1] <== 123;
and[6][i] = AND();
and[6][i].a <== lt[10][i].out;
and[6][i].b <== lt[11][i].out;
eq[6][i] = IsEqual();
eq[6][i].in[0] <== in[i];
eq[6][i].in[1] <== 37;
eq[7][i] = IsEqual();
eq[7][i].in[0] <== in[i];
eq[7][i].in[1] <== 43;
eq[8][i] = IsEqual();
eq[8][i].in[0] <== in[i];
eq[8][i].in[1] <== 45;
eq[9][i] = IsEqual();
eq[9][i].in[0] <== in[i];
eq[9][i].in[1] <== 46;
eq[10][i] = IsEqual();
eq[10][i].in[0] <== in[i];
eq[10][i].in[1] <== 61;
eq[11][i] = IsEqual();
eq[11][i].in[0] <== in[i];
eq[11][i].in[1] <== 95;
and[7][i] = AND();
and[7][i].a <== states[i][1];
multi_or[1][i] = MultiOR(9);
multi_or[1][i].in[0] <== and[4][i].out;
multi_or[1][i].in[1] <== and[5][i].out;
multi_or[1][i].in[2] <== and[6][i].out;
multi_or[1][i].in[3] <== eq[6][i].out;
multi_or[1][i].in[4] <== eq[7][i].out;
multi_or[1][i].in[5] <== eq[8][i].out;
multi_or[1][i].in[6] <== eq[9][i].out;
multi_or[1][i].in[7] <== eq[10][i].out;
multi_or[1][i].in[8] <== eq[11][i].out;
and[7][i].b <== multi_or[1][i].out;
multi_or[2][i] = MultiOR(2);
multi_or[2][i].in[0] <== and[3][i].out;
multi_or[2][i].in[1] <== and[7][i].out;
states[i+1][1] <== multi_or[2][i].out;
state_changed[i].in[0] <== states[i+1][1];
eq[12][i] = IsEqual();
eq[12][i].in[0] <== in[i];
eq[12][i].in[1] <== 64;
and[8][i] = AND();
and[8][i].a <== states[i][1];
and[8][i].b <== eq[12][i].out;
states[i+1][2] <== and[8][i].out;
state_changed[i].in[1] <== states[i+1][2];
lt[12][i] = LessThan(8);
lt[12][i].in[0] <== 47;
lt[12][i].in[1] <== in[i];
lt[13][i] = LessThan(8);
lt[13][i].in[0] <== in[i];
lt[13][i].in[1] <== 58;
and[9][i] = AND();
and[9][i].a <== lt[12][i].out;
and[9][i].b <== lt[13][i].out;
lt[14][i] = LessThan(8);
lt[14][i].in[0] <== 64;
lt[14][i].in[1] <== in[i];
lt[15][i] = LessThan(8);
lt[15][i].in[0] <== in[i];
lt[15][i].in[1] <== 91;
and[10][i] = AND();
and[10][i].a <== lt[14][i].out;
and[10][i].b <== lt[15][i].out;
lt[16][i] = LessThan(8);
lt[16][i].in[0] <== 96;
lt[16][i].in[1] <== in[i];
lt[17][i] = LessThan(8);
lt[17][i].in[0] <== in[i];
lt[17][i].in[1] <== 123;
and[11][i] = AND();
and[11][i].a <== lt[16][i].out;
and[11][i].b <== lt[17][i].out;
eq[13][i] = IsEqual();
eq[13][i].in[0] <== in[i];
eq[13][i].in[1] <== 45;
eq[14][i] = IsEqual();
eq[14][i].in[0] <== in[i];
eq[14][i].in[1] <== 46;
and[12][i] = AND();
and[12][i].a <== states[i][2];
multi_or[3][i] = MultiOR(5);
multi_or[3][i].in[0] <== and[9][i].out;
multi_or[3][i].in[1] <== and[10][i].out;
multi_or[3][i].in[2] <== and[11][i].out;
multi_or[3][i].in[3] <== eq[13][i].out;
multi_or[3][i].in[4] <== eq[14][i].out;
and[12][i].b <== multi_or[3][i].out;
lt[18][i] = LessThan(8);
lt[18][i].in[0] <== 47;
lt[18][i].in[1] <== in[i];
lt[19][i] = LessThan(8);
lt[19][i].in[0] <== in[i];
lt[19][i].in[1] <== 58;
and[13][i] = AND();
and[13][i].a <== lt[18][i].out;
and[13][i].b <== lt[19][i].out;
lt[20][i] = LessThan(8);
lt[20][i].in[0] <== 64;
lt[20][i].in[1] <== in[i];
lt[21][i] = LessThan(8);
lt[21][i].in[0] <== in[i];
lt[21][i].in[1] <== 91;
and[14][i] = AND();
and[14][i].a <== lt[20][i].out;
and[14][i].b <== lt[21][i].out;
lt[22][i] = LessThan(8);
lt[22][i].in[0] <== 96;
lt[22][i].in[1] <== in[i];
lt[23][i] = LessThan(8);
lt[23][i].in[0] <== in[i];
lt[23][i].in[1] <== 123;
and[15][i] = AND();
and[15][i].a <== lt[22][i].out;
and[15][i].b <== lt[23][i].out;
eq[15][i] = IsEqual();
eq[15][i].in[0] <== in[i];
eq[15][i].in[1] <== 45;
eq[16][i] = IsEqual();
eq[16][i].in[0] <== in[i];
eq[16][i].in[1] <== 46;
and[16][i] = AND();
and[16][i].a <== states[i][3];
multi_or[4][i] = MultiOR(5);
multi_or[4][i].in[0] <== and[13][i].out;
multi_or[4][i].in[1] <== and[14][i].out;
multi_or[4][i].in[2] <== and[15][i].out;
multi_or[4][i].in[3] <== eq[15][i].out;
multi_or[4][i].in[4] <== eq[16][i].out;
and[16][i].b <== multi_or[4][i].out;
multi_or[5][i] = MultiOR(2);
multi_or[5][i].in[0] <== and[12][i].out;
multi_or[5][i].in[1] <== and[16][i].out;
states[i+1][3] <== multi_or[5][i].out;
state_changed[i].in[2] <== states[i+1][3];
states[i+1][0] <== 1 - state_changed[i].out;
}
component final_state_result = MultiOR(num_bytes+1);
for (var i = 0; i <= num_bytes; i++) {
final_state_result.in[i] <== states[i][3];
}
out <== final_state_result.out;
signal is_consecutive[msg_bytes+1][2];
is_consecutive[msg_bytes][1] <== 1;
for (var i = 0; i < msg_bytes; i++) {
is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][3] * (1 - is_consecutive[msg_bytes-i][1]) + is_consecutive[msg_bytes-i][1];
is_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];
}
signal is_substr0[msg_bytes][3];
signal is_reveal0[msg_bytes];
signal output reveal0[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr0[i][0] <== 0;
is_substr0[i][1] <== is_substr0[i][0] + states[i+1][2] * states[i+2][3];
is_substr0[i][2] <== is_substr0[i][1] + states[i+1][3] * states[i+2][3];
is_reveal0[i] <== is_substr0[i][2] * is_consecutive[i][1];
reveal0[i] <== in[i+1] * is_reveal0[i];
}
}

View File

@@ -0,0 +1,25 @@
{
"max_byte_size": 1024,
"parts": [
{
"is_public": false,
"regex_def": "((\r\n)|^)from:",
"max_size": 7
},
{
"is_public": false,
"regex_def": "((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|\\.|\"| |@)+<)?",
"max_size": 256
},
{
"is_public": true,
"regex_def": "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|\\.|-)+@(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|\\.|-)+",
"max_size": 256
},
{
"is_public": false,
"regex_def": ">?\r\n",
"max_size": 3
}
]
}

View File

@@ -0,0 +1,759 @@
pragma circom 2.1.5;
include "zk-regex-circom/circuits/regex_helpers.circom";
template FromAddrRegex(msg_bytes) {
signal input msg[msg_bytes];
signal output out;
var num_bytes = msg_bytes+1;
signal in[num_bytes];
in[0]<==128;
for (var i = 0; i < msg_bytes; i++) {
in[i+1] <== msg[i];
}
component eq[61][num_bytes];
component lt[54][num_bytes];
component and[65][num_bytes];
component multi_or[23][num_bytes];
signal states[num_bytes+1][19];
component state_changed[num_bytes];
states[0][0] <== 1;
for (var i = 1; i < 19; i++) {
states[0][i] <== 0;
}
for (var i = 0; i < num_bytes; i++) {
state_changed[i] = MultiOR(18);
lt[0][i] = LessThan(8);
lt[0][i].in[0] <== 47;
lt[0][i].in[1] <== in[i];
lt[1][i] = LessThan(8);
lt[1][i].in[0] <== in[i];
lt[1][i].in[1] <== 58;
and[0][i] = AND();
and[0][i].a <== lt[0][i].out;
and[0][i].b <== lt[1][i].out;
lt[2][i] = LessThan(8);
lt[2][i].in[0] <== 64;
lt[2][i].in[1] <== in[i];
lt[3][i] = LessThan(8);
lt[3][i].in[0] <== in[i];
lt[3][i].in[1] <== 91;
and[1][i] = AND();
and[1][i].a <== lt[2][i].out;
and[1][i].b <== lt[3][i].out;
lt[4][i] = LessThan(8);
lt[4][i].in[0] <== 96;
lt[4][i].in[1] <== in[i];
lt[5][i] = LessThan(8);
lt[5][i].in[0] <== in[i];
lt[5][i].in[1] <== 123;
and[2][i] = AND();
and[2][i].a <== lt[4][i].out;
and[2][i].b <== lt[5][i].out;
eq[0][i] = IsEqual();
eq[0][i].in[0] <== in[i];
eq[0][i].in[1] <== 46;
eq[1][i] = IsEqual();
eq[1][i].in[0] <== in[i];
eq[1][i].in[1] <== 95;
and[3][i] = AND();
and[3][i].a <== states[i][1];
multi_or[0][i] = MultiOR(5);
multi_or[0][i].in[0] <== and[0][i].out;
multi_or[0][i].in[1] <== and[1][i].out;
multi_or[0][i].in[2] <== and[2][i].out;
multi_or[0][i].in[3] <== eq[0][i].out;
multi_or[0][i].in[4] <== eq[1][i].out;
and[3][i].b <== multi_or[0][i].out;
lt[6][i] = LessThan(8);
lt[6][i].in[0] <== 47;
lt[6][i].in[1] <== in[i];
lt[7][i] = LessThan(8);
lt[7][i].in[0] <== in[i];
lt[7][i].in[1] <== 58;
and[4][i] = AND();
and[4][i].a <== lt[6][i].out;
and[4][i].b <== lt[7][i].out;
lt[8][i] = LessThan(8);
lt[8][i].in[0] <== 64;
lt[8][i].in[1] <== in[i];
lt[9][i] = LessThan(8);
lt[9][i].in[0] <== in[i];
lt[9][i].in[1] <== 91;
and[5][i] = AND();
and[5][i].a <== lt[8][i].out;
and[5][i].b <== lt[9][i].out;
lt[10][i] = LessThan(8);
lt[10][i].in[0] <== 96;
lt[10][i].in[1] <== in[i];
lt[11][i] = LessThan(8);
lt[11][i].in[0] <== in[i];
lt[11][i].in[1] <== 123;
and[6][i] = AND();
and[6][i].a <== lt[10][i].out;
and[6][i].b <== lt[11][i].out;
eq[2][i] = IsEqual();
eq[2][i].in[0] <== in[i];
eq[2][i].in[1] <== 46;
eq[3][i] = IsEqual();
eq[3][i].in[0] <== in[i];
eq[3][i].in[1] <== 95;
and[7][i] = AND();
and[7][i].a <== states[i][13];
multi_or[1][i] = MultiOR(5);
multi_or[1][i].in[0] <== and[4][i].out;
multi_or[1][i].in[1] <== and[5][i].out;
multi_or[1][i].in[2] <== and[6][i].out;
multi_or[1][i].in[3] <== eq[2][i].out;
multi_or[1][i].in[4] <== eq[3][i].out;
and[7][i].b <== multi_or[1][i].out;
multi_or[2][i] = MultiOR(2);
multi_or[2][i].in[0] <== and[3][i].out;
multi_or[2][i].in[1] <== and[7][i].out;
states[i+1][1] <== multi_or[2][i].out;
state_changed[i].in[0] <== states[i+1][1];
eq[4][i] = IsEqual();
eq[4][i].in[0] <== in[i];
eq[4][i].in[1] <== 13;
and[8][i] = AND();
and[8][i].a <== states[i][0];
and[8][i].b <== eq[4][i].out;
eq[5][i] = IsEqual();
eq[5][i].in[0] <== in[i];
eq[5][i].in[1] <== 13;
and[9][i] = AND();
and[9][i].a <== states[i][4];
and[9][i].b <== eq[5][i].out;
multi_or[3][i] = MultiOR(2);
multi_or[3][i].in[0] <== and[8][i].out;
multi_or[3][i].in[1] <== and[9][i].out;
states[i+1][2] <== multi_or[3][i].out;
state_changed[i].in[1] <== states[i+1][2];
eq[6][i] = IsEqual();
eq[6][i].in[0] <== in[i];
eq[6][i].in[1] <== 32;
eq[7][i] = IsEqual();
eq[7][i].in[0] <== in[i];
eq[7][i].in[1] <== 34;
and[10][i] = AND();
and[10][i].a <== states[i][1];
multi_or[4][i] = MultiOR(2);
multi_or[4][i].in[0] <== eq[6][i].out;
multi_or[4][i].in[1] <== eq[7][i].out;
and[10][i].b <== multi_or[4][i].out;
lt[12][i] = LessThan(8);
lt[12][i].in[0] <== 47;
lt[12][i].in[1] <== in[i];
lt[13][i] = LessThan(8);
lt[13][i].in[0] <== in[i];
lt[13][i].in[1] <== 58;
and[11][i] = AND();
and[11][i].a <== lt[12][i].out;
and[11][i].b <== lt[13][i].out;
lt[14][i] = LessThan(8);
lt[14][i].in[0] <== 64;
lt[14][i].in[1] <== in[i];
lt[15][i] = LessThan(8);
lt[15][i].in[0] <== in[i];
lt[15][i].in[1] <== 91;
and[12][i] = AND();
and[12][i].a <== lt[14][i].out;
and[12][i].b <== lt[15][i].out;
lt[16][i] = LessThan(8);
lt[16][i].in[0] <== 96;
lt[16][i].in[1] <== in[i];
lt[17][i] = LessThan(8);
lt[17][i].in[0] <== in[i];
lt[17][i].in[1] <== 123;
and[13][i] = AND();
and[13][i].a <== lt[16][i].out;
and[13][i].b <== lt[17][i].out;
eq[8][i] = IsEqual();
eq[8][i].in[0] <== in[i];
eq[8][i].in[1] <== 32;
eq[9][i] = IsEqual();
eq[9][i].in[0] <== in[i];
eq[9][i].in[1] <== 34;
eq[10][i] = IsEqual();
eq[10][i].in[0] <== in[i];
eq[10][i].in[1] <== 46;
eq[11][i] = IsEqual();
eq[11][i].in[0] <== in[i];
eq[11][i].in[1] <== 64;
eq[12][i] = IsEqual();
eq[12][i].in[0] <== in[i];
eq[12][i].in[1] <== 95;
and[14][i] = AND();
and[14][i].a <== states[i][3];
multi_or[5][i] = MultiOR(8);
multi_or[5][i].in[0] <== and[11][i].out;
multi_or[5][i].in[1] <== and[12][i].out;
multi_or[5][i].in[2] <== and[13][i].out;
multi_or[5][i].in[3] <== eq[8][i].out;
multi_or[5][i].in[4] <== eq[9][i].out;
multi_or[5][i].in[5] <== eq[10][i].out;
multi_or[5][i].in[6] <== eq[11][i].out;
multi_or[5][i].in[7] <== eq[12][i].out;
and[14][i].b <== multi_or[5][i].out;
eq[13][i] = IsEqual();
eq[13][i].in[0] <== in[i];
eq[13][i].in[1] <== 32;
eq[14][i] = IsEqual();
eq[14][i].in[0] <== in[i];
eq[14][i].in[1] <== 34;
eq[15][i] = IsEqual();
eq[15][i].in[0] <== in[i];
eq[15][i].in[1] <== 64;
and[15][i] = AND();
and[15][i].a <== states[i][12];
multi_or[6][i] = MultiOR(3);
multi_or[6][i].in[0] <== eq[13][i].out;
multi_or[6][i].in[1] <== eq[14][i].out;
multi_or[6][i].in[2] <== eq[15][i].out;
and[15][i].b <== multi_or[6][i].out;
eq[16][i] = IsEqual();
eq[16][i].in[0] <== in[i];
eq[16][i].in[1] <== 32;
eq[17][i] = IsEqual();
eq[17][i].in[0] <== in[i];
eq[17][i].in[1] <== 34;
eq[18][i] = IsEqual();
eq[18][i].in[0] <== in[i];
eq[18][i].in[1] <== 64;
and[16][i] = AND();
and[16][i].a <== states[i][13];
multi_or[7][i] = MultiOR(3);
multi_or[7][i].in[0] <== eq[16][i].out;
multi_or[7][i].in[1] <== eq[17][i].out;
multi_or[7][i].in[2] <== eq[18][i].out;
and[16][i].b <== multi_or[7][i].out;
eq[19][i] = IsEqual();
eq[19][i].in[0] <== in[i];
eq[19][i].in[1] <== 32;
eq[20][i] = IsEqual();
eq[20][i].in[0] <== in[i];
eq[20][i].in[1] <== 34;
eq[21][i] = IsEqual();
eq[21][i].in[0] <== in[i];
eq[21][i].in[1] <== 64;
and[17][i] = AND();
and[17][i].a <== states[i][15];
multi_or[8][i] = MultiOR(3);
multi_or[8][i].in[0] <== eq[19][i].out;
multi_or[8][i].in[1] <== eq[20][i].out;
multi_or[8][i].in[2] <== eq[21][i].out;
and[17][i].b <== multi_or[8][i].out;
multi_or[9][i] = MultiOR(5);
multi_or[9][i].in[0] <== and[10][i].out;
multi_or[9][i].in[1] <== and[14][i].out;
multi_or[9][i].in[2] <== and[15][i].out;
multi_or[9][i].in[3] <== and[16][i].out;
multi_or[9][i].in[4] <== and[17][i].out;
states[i+1][3] <== multi_or[9][i].out;
state_changed[i].in[2] <== states[i+1][3];
eq[22][i] = IsEqual();
eq[22][i].in[0] <== in[i];
eq[22][i].in[1] <== 128;
and[18][i] = AND();
and[18][i].a <== states[i][0];
and[18][i].b <== eq[22][i].out;
eq[23][i] = IsEqual();
eq[23][i].in[0] <== in[i];
eq[23][i].in[1] <== 10;
and[19][i] = AND();
and[19][i].a <== states[i][2];
and[19][i].b <== eq[23][i].out;
multi_or[10][i] = MultiOR(2);
multi_or[10][i].in[0] <== and[18][i].out;
multi_or[10][i].in[1] <== and[19][i].out;
states[i+1][4] <== multi_or[10][i].out;
state_changed[i].in[3] <== states[i+1][4];
eq[24][i] = IsEqual();
eq[24][i].in[0] <== in[i];
eq[24][i].in[1] <== 60;
and[20][i] = AND();
and[20][i].a <== states[i][1];
and[20][i].b <== eq[24][i].out;
eq[25][i] = IsEqual();
eq[25][i].in[0] <== in[i];
eq[25][i].in[1] <== 60;
and[21][i] = AND();
and[21][i].a <== states[i][3];
and[21][i].b <== eq[25][i].out;
eq[26][i] = IsEqual();
eq[26][i].in[0] <== in[i];
eq[26][i].in[1] <== 60;
and[22][i] = AND();
and[22][i].a <== states[i][12];
and[22][i].b <== eq[26][i].out;
eq[27][i] = IsEqual();
eq[27][i].in[0] <== in[i];
eq[27][i].in[1] <== 60;
and[23][i] = AND();
and[23][i].a <== states[i][15];
and[23][i].b <== eq[27][i].out;
multi_or[11][i] = MultiOR(4);
multi_or[11][i].in[0] <== and[20][i].out;
multi_or[11][i].in[1] <== and[21][i].out;
multi_or[11][i].in[2] <== and[22][i].out;
multi_or[11][i].in[3] <== and[23][i].out;
states[i+1][5] <== multi_or[11][i].out;
state_changed[i].in[4] <== states[i+1][5];
eq[28][i] = IsEqual();
eq[28][i].in[0] <== in[i];
eq[28][i].in[1] <== 102;
and[24][i] = AND();
and[24][i].a <== states[i][4];
and[24][i].b <== eq[28][i].out;
states[i+1][6] <== and[24][i].out;
state_changed[i].in[5] <== states[i+1][6];
eq[29][i] = IsEqual();
eq[29][i].in[0] <== in[i];
eq[29][i].in[1] <== 45;
and[25][i] = AND();
and[25][i].a <== states[i][1];
and[25][i].b <== eq[29][i].out;
lt[18][i] = LessThan(8);
lt[18][i].in[0] <== 47;
lt[18][i].in[1] <== in[i];
lt[19][i] = LessThan(8);
lt[19][i].in[0] <== in[i];
lt[19][i].in[1] <== 58;
and[26][i] = AND();
and[26][i].a <== lt[18][i].out;
and[26][i].b <== lt[19][i].out;
lt[20][i] = LessThan(8);
lt[20][i].in[0] <== 64;
lt[20][i].in[1] <== in[i];
lt[21][i] = LessThan(8);
lt[21][i].in[0] <== in[i];
lt[21][i].in[1] <== 91;
and[27][i] = AND();
and[27][i].a <== lt[20][i].out;
and[27][i].b <== lt[21][i].out;
lt[22][i] = LessThan(8);
lt[22][i].in[0] <== 96;
lt[22][i].in[1] <== in[i];
lt[23][i] = LessThan(8);
lt[23][i].in[0] <== in[i];
lt[23][i].in[1] <== 123;
and[28][i] = AND();
and[28][i].a <== lt[22][i].out;
and[28][i].b <== lt[23][i].out;
eq[30][i] = IsEqual();
eq[30][i].in[0] <== in[i];
eq[30][i].in[1] <== 45;
eq[31][i] = IsEqual();
eq[31][i].in[0] <== in[i];
eq[31][i].in[1] <== 46;
eq[32][i] = IsEqual();
eq[32][i].in[0] <== in[i];
eq[32][i].in[1] <== 95;
and[29][i] = AND();
and[29][i].a <== states[i][5];
multi_or[12][i] = MultiOR(6);
multi_or[12][i].in[0] <== and[26][i].out;
multi_or[12][i].in[1] <== and[27][i].out;
multi_or[12][i].in[2] <== and[28][i].out;
multi_or[12][i].in[3] <== eq[30][i].out;
multi_or[12][i].in[4] <== eq[31][i].out;
multi_or[12][i].in[5] <== eq[32][i].out;
and[29][i].b <== multi_or[12][i].out;
lt[24][i] = LessThan(8);
lt[24][i].in[0] <== 47;
lt[24][i].in[1] <== in[i];
lt[25][i] = LessThan(8);
lt[25][i].in[0] <== in[i];
lt[25][i].in[1] <== 58;
and[30][i] = AND();
and[30][i].a <== lt[24][i].out;
and[30][i].b <== lt[25][i].out;
lt[26][i] = LessThan(8);
lt[26][i].in[0] <== 64;
lt[26][i].in[1] <== in[i];
lt[27][i] = LessThan(8);
lt[27][i].in[0] <== in[i];
lt[27][i].in[1] <== 91;
and[31][i] = AND();
and[31][i].a <== lt[26][i].out;
and[31][i].b <== lt[27][i].out;
lt[28][i] = LessThan(8);
lt[28][i].in[0] <== 96;
lt[28][i].in[1] <== in[i];
lt[29][i] = LessThan(8);
lt[29][i].in[0] <== in[i];
lt[29][i].in[1] <== 123;
and[32][i] = AND();
and[32][i].a <== lt[28][i].out;
and[32][i].b <== lt[29][i].out;
eq[33][i] = IsEqual();
eq[33][i].in[0] <== in[i];
eq[33][i].in[1] <== 45;
eq[34][i] = IsEqual();
eq[34][i].in[0] <== in[i];
eq[34][i].in[1] <== 46;
eq[35][i] = IsEqual();
eq[35][i].in[0] <== in[i];
eq[35][i].in[1] <== 95;
and[33][i] = AND();
and[33][i].a <== states[i][7];
multi_or[13][i] = MultiOR(6);
multi_or[13][i].in[0] <== and[30][i].out;
multi_or[13][i].in[1] <== and[31][i].out;
multi_or[13][i].in[2] <== and[32][i].out;
multi_or[13][i].in[3] <== eq[33][i].out;
multi_or[13][i].in[4] <== eq[34][i].out;
multi_or[13][i].in[5] <== eq[35][i].out;
and[33][i].b <== multi_or[13][i].out;
eq[36][i] = IsEqual();
eq[36][i].in[0] <== in[i];
eq[36][i].in[1] <== 45;
and[34][i] = AND();
and[34][i].a <== states[i][13];
and[34][i].b <== eq[36][i].out;
multi_or[14][i] = MultiOR(4);
multi_or[14][i].in[0] <== and[25][i].out;
multi_or[14][i].in[1] <== and[29][i].out;
multi_or[14][i].in[2] <== and[33][i].out;
multi_or[14][i].in[3] <== and[34][i].out;
states[i+1][7] <== multi_or[14][i].out;
state_changed[i].in[6] <== states[i+1][7];
eq[37][i] = IsEqual();
eq[37][i].in[0] <== in[i];
eq[37][i].in[1] <== 114;
and[35][i] = AND();
and[35][i].a <== states[i][6];
and[35][i].b <== eq[37][i].out;
states[i+1][8] <== and[35][i].out;
state_changed[i].in[7] <== states[i+1][8];
eq[38][i] = IsEqual();
eq[38][i].in[0] <== in[i];
eq[38][i].in[1] <== 64;
and[36][i] = AND();
and[36][i].a <== states[i][7];
and[36][i].b <== eq[38][i].out;
states[i+1][9] <== and[36][i].out;
state_changed[i].in[8] <== states[i+1][9];
eq[39][i] = IsEqual();
eq[39][i].in[0] <== in[i];
eq[39][i].in[1] <== 111;
and[37][i] = AND();
and[37][i].a <== states[i][8];
and[37][i].b <== eq[39][i].out;
states[i+1][10] <== and[37][i].out;
state_changed[i].in[9] <== states[i+1][10];
eq[40][i] = IsEqual();
eq[40][i].in[0] <== in[i];
eq[40][i].in[1] <== 109;
and[38][i] = AND();
and[38][i].a <== states[i][10];
and[38][i].b <== eq[40][i].out;
states[i+1][11] <== and[38][i].out;
state_changed[i].in[10] <== states[i+1][11];
eq[41][i] = IsEqual();
eq[41][i].in[0] <== in[i];
eq[41][i].in[1] <== 64;
and[39][i] = AND();
and[39][i].a <== states[i][1];
and[39][i].b <== eq[41][i].out;
states[i+1][12] <== and[39][i].out;
state_changed[i].in[11] <== states[i+1][12];
eq[42][i] = IsEqual();
eq[42][i].in[0] <== in[i];
eq[42][i].in[1] <== 58;
and[40][i] = AND();
and[40][i].a <== states[i][11];
and[40][i].b <== eq[42][i].out;
states[i+1][13] <== and[40][i].out;
state_changed[i].in[12] <== states[i+1][13];
lt[30][i] = LessThan(8);
lt[30][i].in[0] <== 47;
lt[30][i].in[1] <== in[i];
lt[31][i] = LessThan(8);
lt[31][i].in[0] <== in[i];
lt[31][i].in[1] <== 58;
and[41][i] = AND();
and[41][i].a <== lt[30][i].out;
and[41][i].b <== lt[31][i].out;
lt[32][i] = LessThan(8);
lt[32][i].in[0] <== 64;
lt[32][i].in[1] <== in[i];
lt[33][i] = LessThan(8);
lt[33][i].in[0] <== in[i];
lt[33][i].in[1] <== 91;
and[42][i] = AND();
and[42][i].a <== lt[32][i].out;
and[42][i].b <== lt[33][i].out;
lt[34][i] = LessThan(8);
lt[34][i].in[0] <== 96;
lt[34][i].in[1] <== in[i];
lt[35][i] = LessThan(8);
lt[35][i].in[0] <== in[i];
lt[35][i].in[1] <== 123;
and[43][i] = AND();
and[43][i].a <== lt[34][i].out;
and[43][i].b <== lt[35][i].out;
eq[43][i] = IsEqual();
eq[43][i].in[0] <== in[i];
eq[43][i].in[1] <== 45;
eq[44][i] = IsEqual();
eq[44][i].in[0] <== in[i];
eq[44][i].in[1] <== 46;
eq[45][i] = IsEqual();
eq[45][i].in[0] <== in[i];
eq[45][i].in[1] <== 95;
and[44][i] = AND();
and[44][i].a <== states[i][9];
multi_or[15][i] = MultiOR(6);
multi_or[15][i].in[0] <== and[41][i].out;
multi_or[15][i].in[1] <== and[42][i].out;
multi_or[15][i].in[2] <== and[43][i].out;
multi_or[15][i].in[3] <== eq[43][i].out;
multi_or[15][i].in[4] <== eq[44][i].out;
multi_or[15][i].in[5] <== eq[45][i].out;
and[44][i].b <== multi_or[15][i].out;
eq[46][i] = IsEqual();
eq[46][i].in[0] <== in[i];
eq[46][i].in[1] <== 45;
and[45][i] = AND();
and[45][i].a <== states[i][12];
and[45][i].b <== eq[46][i].out;
lt[36][i] = LessThan(8);
lt[36][i].in[0] <== 47;
lt[36][i].in[1] <== in[i];
lt[37][i] = LessThan(8);
lt[37][i].in[0] <== in[i];
lt[37][i].in[1] <== 58;
and[46][i] = AND();
and[46][i].a <== lt[36][i].out;
and[46][i].b <== lt[37][i].out;
lt[38][i] = LessThan(8);
lt[38][i].in[0] <== 64;
lt[38][i].in[1] <== in[i];
lt[39][i] = LessThan(8);
lt[39][i].in[0] <== in[i];
lt[39][i].in[1] <== 91;
and[47][i] = AND();
and[47][i].a <== lt[38][i].out;
and[47][i].b <== lt[39][i].out;
lt[40][i] = LessThan(8);
lt[40][i].in[0] <== 96;
lt[40][i].in[1] <== in[i];
lt[41][i] = LessThan(8);
lt[41][i].in[0] <== in[i];
lt[41][i].in[1] <== 123;
and[48][i] = AND();
and[48][i].a <== lt[40][i].out;
and[48][i].b <== lt[41][i].out;
eq[47][i] = IsEqual();
eq[47][i].in[0] <== in[i];
eq[47][i].in[1] <== 45;
eq[48][i] = IsEqual();
eq[48][i].in[0] <== in[i];
eq[48][i].in[1] <== 46;
eq[49][i] = IsEqual();
eq[49][i].in[0] <== in[i];
eq[49][i].in[1] <== 95;
and[49][i] = AND();
and[49][i].a <== states[i][14];
multi_or[16][i] = MultiOR(6);
multi_or[16][i].in[0] <== and[46][i].out;
multi_or[16][i].in[1] <== and[47][i].out;
multi_or[16][i].in[2] <== and[48][i].out;
multi_or[16][i].in[3] <== eq[47][i].out;
multi_or[16][i].in[4] <== eq[48][i].out;
multi_or[16][i].in[5] <== eq[49][i].out;
and[49][i].b <== multi_or[16][i].out;
eq[50][i] = IsEqual();
eq[50][i].in[0] <== in[i];
eq[50][i].in[1] <== 45;
and[50][i] = AND();
and[50][i].a <== states[i][15];
and[50][i].b <== eq[50][i].out;
multi_or[17][i] = MultiOR(4);
multi_or[17][i].in[0] <== and[44][i].out;
multi_or[17][i].in[1] <== and[45][i].out;
multi_or[17][i].in[2] <== and[49][i].out;
multi_or[17][i].in[3] <== and[50][i].out;
states[i+1][14] <== multi_or[17][i].out;
state_changed[i].in[13] <== states[i+1][14];
lt[42][i] = LessThan(8);
lt[42][i].in[0] <== 47;
lt[42][i].in[1] <== in[i];
lt[43][i] = LessThan(8);
lt[43][i].in[0] <== in[i];
lt[43][i].in[1] <== 58;
and[51][i] = AND();
and[51][i].a <== lt[42][i].out;
and[51][i].b <== lt[43][i].out;
lt[44][i] = LessThan(8);
lt[44][i].in[0] <== 64;
lt[44][i].in[1] <== in[i];
lt[45][i] = LessThan(8);
lt[45][i].in[0] <== in[i];
lt[45][i].in[1] <== 91;
and[52][i] = AND();
and[52][i].a <== lt[44][i].out;
and[52][i].b <== lt[45][i].out;
lt[46][i] = LessThan(8);
lt[46][i].in[0] <== 96;
lt[46][i].in[1] <== in[i];
lt[47][i] = LessThan(8);
lt[47][i].in[0] <== in[i];
lt[47][i].in[1] <== 123;
and[53][i] = AND();
and[53][i].a <== lt[46][i].out;
and[53][i].b <== lt[47][i].out;
eq[51][i] = IsEqual();
eq[51][i].in[0] <== in[i];
eq[51][i].in[1] <== 46;
eq[52][i] = IsEqual();
eq[52][i].in[0] <== in[i];
eq[52][i].in[1] <== 95;
and[54][i] = AND();
and[54][i].a <== states[i][12];
multi_or[18][i] = MultiOR(5);
multi_or[18][i].in[0] <== and[51][i].out;
multi_or[18][i].in[1] <== and[52][i].out;
multi_or[18][i].in[2] <== and[53][i].out;
multi_or[18][i].in[3] <== eq[51][i].out;
multi_or[18][i].in[4] <== eq[52][i].out;
and[54][i].b <== multi_or[18][i].out;
lt[48][i] = LessThan(8);
lt[48][i].in[0] <== 47;
lt[48][i].in[1] <== in[i];
lt[49][i] = LessThan(8);
lt[49][i].in[0] <== in[i];
lt[49][i].in[1] <== 58;
and[55][i] = AND();
and[55][i].a <== lt[48][i].out;
and[55][i].b <== lt[49][i].out;
lt[50][i] = LessThan(8);
lt[50][i].in[0] <== 64;
lt[50][i].in[1] <== in[i];
lt[51][i] = LessThan(8);
lt[51][i].in[0] <== in[i];
lt[51][i].in[1] <== 91;
and[56][i] = AND();
and[56][i].a <== lt[50][i].out;
and[56][i].b <== lt[51][i].out;
lt[52][i] = LessThan(8);
lt[52][i].in[0] <== 96;
lt[52][i].in[1] <== in[i];
lt[53][i] = LessThan(8);
lt[53][i].in[0] <== in[i];
lt[53][i].in[1] <== 123;
and[57][i] = AND();
and[57][i].a <== lt[52][i].out;
and[57][i].b <== lt[53][i].out;
eq[53][i] = IsEqual();
eq[53][i].in[0] <== in[i];
eq[53][i].in[1] <== 46;
eq[54][i] = IsEqual();
eq[54][i].in[0] <== in[i];
eq[54][i].in[1] <== 95;
and[58][i] = AND();
and[58][i].a <== states[i][15];
multi_or[19][i] = MultiOR(5);
multi_or[19][i].in[0] <== and[55][i].out;
multi_or[19][i].in[1] <== and[56][i].out;
multi_or[19][i].in[2] <== and[57][i].out;
multi_or[19][i].in[3] <== eq[53][i].out;
multi_or[19][i].in[4] <== eq[54][i].out;
and[58][i].b <== multi_or[19][i].out;
multi_or[20][i] = MultiOR(2);
multi_or[20][i].in[0] <== and[54][i].out;
multi_or[20][i].in[1] <== and[58][i].out;
states[i+1][15] <== multi_or[20][i].out;
state_changed[i].in[14] <== states[i+1][15];
eq[55][i] = IsEqual();
eq[55][i].in[0] <== in[i];
eq[55][i].in[1] <== 13;
and[59][i] = AND();
and[59][i].a <== states[i][14];
and[59][i].b <== eq[55][i].out;
eq[56][i] = IsEqual();
eq[56][i].in[0] <== in[i];
eq[56][i].in[1] <== 13;
and[60][i] = AND();
and[60][i].a <== states[i][15];
and[60][i].b <== eq[56][i].out;
eq[57][i] = IsEqual();
eq[57][i].in[0] <== in[i];
eq[57][i].in[1] <== 13;
and[61][i] = AND();
and[61][i].a <== states[i][17];
and[61][i].b <== eq[57][i].out;
multi_or[21][i] = MultiOR(3);
multi_or[21][i].in[0] <== and[59][i].out;
multi_or[21][i].in[1] <== and[60][i].out;
multi_or[21][i].in[2] <== and[61][i].out;
states[i+1][16] <== multi_or[21][i].out;
state_changed[i].in[15] <== states[i+1][16];
eq[58][i] = IsEqual();
eq[58][i].in[0] <== in[i];
eq[58][i].in[1] <== 62;
and[62][i] = AND();
and[62][i].a <== states[i][14];
and[62][i].b <== eq[58][i].out;
eq[59][i] = IsEqual();
eq[59][i].in[0] <== in[i];
eq[59][i].in[1] <== 62;
and[63][i] = AND();
and[63][i].a <== states[i][15];
and[63][i].b <== eq[59][i].out;
multi_or[22][i] = MultiOR(2);
multi_or[22][i].in[0] <== and[62][i].out;
multi_or[22][i].in[1] <== and[63][i].out;
states[i+1][17] <== multi_or[22][i].out;
state_changed[i].in[16] <== states[i+1][17];
eq[60][i] = IsEqual();
eq[60][i].in[0] <== in[i];
eq[60][i].in[1] <== 10;
and[64][i] = AND();
and[64][i].a <== states[i][16];
and[64][i].b <== eq[60][i].out;
states[i+1][18] <== and[64][i].out;
state_changed[i].in[17] <== states[i+1][18];
states[i+1][0] <== 1 - state_changed[i].out;
}
component final_state_result = MultiOR(num_bytes+1);
for (var i = 0; i <= num_bytes; i++) {
final_state_result.in[i] <== states[i][18];
}
out <== final_state_result.out;
signal is_consecutive[msg_bytes+1][2];
is_consecutive[msg_bytes][1] <== 1;
for (var i = 0; i < msg_bytes; i++) {
is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][18] * (1 - is_consecutive[msg_bytes-i][1]) + is_consecutive[msg_bytes-i][1];
is_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];
}
signal is_substr0[msg_bytes][15];
signal is_reveal0[msg_bytes];
signal output reveal0[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr0[i][0] <== 0;
is_substr0[i][1] <== is_substr0[i][0] + states[i+1][9] * states[i+2][14];
is_substr0[i][2] <== is_substr0[i][1] + states[i+1][1] * states[i+2][1];
is_substr0[i][3] <== is_substr0[i][2] + states[i+1][14] * states[i+2][14];
is_substr0[i][4] <== is_substr0[i][3] + states[i+1][1] * states[i+2][12];
is_substr0[i][5] <== is_substr0[i][4] + states[i+1][12] * states[i+2][15];
is_substr0[i][6] <== is_substr0[i][5] + states[i+1][12] * states[i+2][14];
is_substr0[i][7] <== is_substr0[i][6] + states[i+1][15] * states[i+2][14];
is_substr0[i][8] <== is_substr0[i][7] + states[i+1][13] * states[i+2][1];
is_substr0[i][9] <== is_substr0[i][8] + states[i+1][7] * states[i+2][9];
is_substr0[i][10] <== is_substr0[i][9] + states[i+1][15] * states[i+2][15];
is_substr0[i][11] <== is_substr0[i][10] + states[i+1][5] * states[i+2][7];
is_substr0[i][12] <== is_substr0[i][11] + states[i+1][7] * states[i+2][7];
is_substr0[i][13] <== is_substr0[i][12] + states[i+1][13] * states[i+2][7];
is_substr0[i][14] <== is_substr0[i][13] + states[i+1][1] * states[i+2][7];
is_reveal0[i] <== is_substr0[i][14] * is_consecutive[i][1];
reveal0[i] <== in[i+1] * is_reveal0[i];
}
}

View File

@@ -0,0 +1,20 @@
{
"max_byte_size": 1024,
"parts": [
{
"is_public": false,
"regex_def": "((\r\n)|^)subject:",
"max_size": 10
},
{
"is_public": true,
"regex_def": "(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|\"|#|\\$|%|&|\\'|\\(|\\)|\\*|\\+|,|-|\\.|/|:|;|<|=|>|\\?|@|[|\\\\|]|\\^|_|`|{|\\||}|~| |\t)+",
"max_size": 1024
},
{
"is_public": false,
"regex_def": "\r\n",
"max_size": 2
}
]
}

View File

@@ -0,0 +1,338 @@
pragma circom 2.1.5;
include "zk-regex-circom/circuits/regex_helpers.circom";
template SubjectAllRegex(msg_bytes) {
signal input msg[msg_bytes];
signal output out;
var num_bytes = msg_bytes+1;
signal in[num_bytes];
in[0]<==128;
for (var i = 0; i < msg_bytes; i++) {
in[i+1] <== msg[i];
}
component eq[48][num_bytes];
component lt[4][num_bytes];
component and[18][num_bytes];
component multi_or[5][num_bytes];
signal states[num_bytes+1][14];
component state_changed[num_bytes];
states[0][0] <== 1;
for (var i = 1; i < 14; i++) {
states[0][i] <== 0;
}
for (var i = 0; i < num_bytes; i++) {
state_changed[i] = MultiOR(13);
lt[0][i] = LessThan(8);
lt[0][i].in[0] <== 47;
lt[0][i].in[1] <== in[i];
lt[1][i] = LessThan(8);
lt[1][i].in[0] <== in[i];
lt[1][i].in[1] <== 127;
and[0][i] = AND();
and[0][i].a <== lt[0][i].out;
and[0][i].b <== lt[1][i].out;
eq[0][i] = IsEqual();
eq[0][i].in[0] <== in[i];
eq[0][i].in[1] <== 9;
eq[1][i] = IsEqual();
eq[1][i].in[0] <== in[i];
eq[1][i].in[1] <== 32;
eq[2][i] = IsEqual();
eq[2][i].in[0] <== in[i];
eq[2][i].in[1] <== 33;
eq[3][i] = IsEqual();
eq[3][i].in[0] <== in[i];
eq[3][i].in[1] <== 34;
eq[4][i] = IsEqual();
eq[4][i].in[0] <== in[i];
eq[4][i].in[1] <== 35;
eq[5][i] = IsEqual();
eq[5][i].in[0] <== in[i];
eq[5][i].in[1] <== 36;
eq[6][i] = IsEqual();
eq[6][i].in[0] <== in[i];
eq[6][i].in[1] <== 37;
eq[7][i] = IsEqual();
eq[7][i].in[0] <== in[i];
eq[7][i].in[1] <== 38;
eq[8][i] = IsEqual();
eq[8][i].in[0] <== in[i];
eq[8][i].in[1] <== 39;
eq[9][i] = IsEqual();
eq[9][i].in[0] <== in[i];
eq[9][i].in[1] <== 40;
eq[10][i] = IsEqual();
eq[10][i].in[0] <== in[i];
eq[10][i].in[1] <== 41;
eq[11][i] = IsEqual();
eq[11][i].in[0] <== in[i];
eq[11][i].in[1] <== 42;
eq[12][i] = IsEqual();
eq[12][i].in[0] <== in[i];
eq[12][i].in[1] <== 43;
eq[13][i] = IsEqual();
eq[13][i].in[0] <== in[i];
eq[13][i].in[1] <== 44;
eq[14][i] = IsEqual();
eq[14][i].in[0] <== in[i];
eq[14][i].in[1] <== 45;
eq[15][i] = IsEqual();
eq[15][i].in[0] <== in[i];
eq[15][i].in[1] <== 46;
eq[16][i] = IsEqual();
eq[16][i].in[0] <== in[i];
eq[16][i].in[1] <== 47;
and[1][i] = AND();
and[1][i].a <== states[i][1];
multi_or[0][i] = MultiOR(18);
multi_or[0][i].in[0] <== and[0][i].out;
multi_or[0][i].in[1] <== eq[0][i].out;
multi_or[0][i].in[2] <== eq[1][i].out;
multi_or[0][i].in[3] <== eq[2][i].out;
multi_or[0][i].in[4] <== eq[3][i].out;
multi_or[0][i].in[5] <== eq[4][i].out;
multi_or[0][i].in[6] <== eq[5][i].out;
multi_or[0][i].in[7] <== eq[6][i].out;
multi_or[0][i].in[8] <== eq[7][i].out;
multi_or[0][i].in[9] <== eq[8][i].out;
multi_or[0][i].in[10] <== eq[9][i].out;
multi_or[0][i].in[11] <== eq[10][i].out;
multi_or[0][i].in[12] <== eq[11][i].out;
multi_or[0][i].in[13] <== eq[12][i].out;
multi_or[0][i].in[14] <== eq[13][i].out;
multi_or[0][i].in[15] <== eq[14][i].out;
multi_or[0][i].in[16] <== eq[15][i].out;
multi_or[0][i].in[17] <== eq[16][i].out;
and[1][i].b <== multi_or[0][i].out;
lt[2][i] = LessThan(8);
lt[2][i].in[0] <== 47;
lt[2][i].in[1] <== in[i];
lt[3][i] = LessThan(8);
lt[3][i].in[0] <== in[i];
lt[3][i].in[1] <== 127;
and[2][i] = AND();
and[2][i].a <== lt[2][i].out;
and[2][i].b <== lt[3][i].out;
eq[17][i] = IsEqual();
eq[17][i].in[0] <== in[i];
eq[17][i].in[1] <== 9;
eq[18][i] = IsEqual();
eq[18][i].in[0] <== in[i];
eq[18][i].in[1] <== 32;
eq[19][i] = IsEqual();
eq[19][i].in[0] <== in[i];
eq[19][i].in[1] <== 33;
eq[20][i] = IsEqual();
eq[20][i].in[0] <== in[i];
eq[20][i].in[1] <== 34;
eq[21][i] = IsEqual();
eq[21][i].in[0] <== in[i];
eq[21][i].in[1] <== 35;
eq[22][i] = IsEqual();
eq[22][i].in[0] <== in[i];
eq[22][i].in[1] <== 36;
eq[23][i] = IsEqual();
eq[23][i].in[0] <== in[i];
eq[23][i].in[1] <== 37;
eq[24][i] = IsEqual();
eq[24][i].in[0] <== in[i];
eq[24][i].in[1] <== 38;
eq[25][i] = IsEqual();
eq[25][i].in[0] <== in[i];
eq[25][i].in[1] <== 39;
eq[26][i] = IsEqual();
eq[26][i].in[0] <== in[i];
eq[26][i].in[1] <== 40;
eq[27][i] = IsEqual();
eq[27][i].in[0] <== in[i];
eq[27][i].in[1] <== 41;
eq[28][i] = IsEqual();
eq[28][i].in[0] <== in[i];
eq[28][i].in[1] <== 42;
eq[29][i] = IsEqual();
eq[29][i].in[0] <== in[i];
eq[29][i].in[1] <== 43;
eq[30][i] = IsEqual();
eq[30][i].in[0] <== in[i];
eq[30][i].in[1] <== 44;
eq[31][i] = IsEqual();
eq[31][i].in[0] <== in[i];
eq[31][i].in[1] <== 45;
eq[32][i] = IsEqual();
eq[32][i].in[0] <== in[i];
eq[32][i].in[1] <== 46;
eq[33][i] = IsEqual();
eq[33][i].in[0] <== in[i];
eq[33][i].in[1] <== 47;
and[3][i] = AND();
and[3][i].a <== states[i][13];
multi_or[1][i] = MultiOR(18);
multi_or[1][i].in[0] <== and[2][i].out;
multi_or[1][i].in[1] <== eq[17][i].out;
multi_or[1][i].in[2] <== eq[18][i].out;
multi_or[1][i].in[3] <== eq[19][i].out;
multi_or[1][i].in[4] <== eq[20][i].out;
multi_or[1][i].in[5] <== eq[21][i].out;
multi_or[1][i].in[6] <== eq[22][i].out;
multi_or[1][i].in[7] <== eq[23][i].out;
multi_or[1][i].in[8] <== eq[24][i].out;
multi_or[1][i].in[9] <== eq[25][i].out;
multi_or[1][i].in[10] <== eq[26][i].out;
multi_or[1][i].in[11] <== eq[27][i].out;
multi_or[1][i].in[12] <== eq[28][i].out;
multi_or[1][i].in[13] <== eq[29][i].out;
multi_or[1][i].in[14] <== eq[30][i].out;
multi_or[1][i].in[15] <== eq[31][i].out;
multi_or[1][i].in[16] <== eq[32][i].out;
multi_or[1][i].in[17] <== eq[33][i].out;
and[3][i].b <== multi_or[1][i].out;
multi_or[2][i] = MultiOR(2);
multi_or[2][i].in[0] <== and[1][i].out;
multi_or[2][i].in[1] <== and[3][i].out;
states[i+1][1] <== multi_or[2][i].out;
state_changed[i].in[0] <== states[i+1][1];
eq[34][i] = IsEqual();
eq[34][i].in[0] <== in[i];
eq[34][i].in[1] <== 13;
and[4][i] = AND();
and[4][i].a <== states[i][0];
and[4][i].b <== eq[34][i].out;
eq[35][i] = IsEqual();
eq[35][i].in[0] <== in[i];
eq[35][i].in[1] <== 13;
and[5][i] = AND();
and[5][i].a <== states[i][3];
and[5][i].b <== eq[35][i].out;
multi_or[3][i] = MultiOR(2);
multi_or[3][i].in[0] <== and[4][i].out;
multi_or[3][i].in[1] <== and[5][i].out;
states[i+1][2] <== multi_or[3][i].out;
state_changed[i].in[1] <== states[i+1][2];
eq[36][i] = IsEqual();
eq[36][i].in[0] <== in[i];
eq[36][i].in[1] <== 128;
and[6][i] = AND();
and[6][i].a <== states[i][0];
and[6][i].b <== eq[36][i].out;
eq[37][i] = IsEqual();
eq[37][i].in[0] <== in[i];
eq[37][i].in[1] <== 10;
and[7][i] = AND();
and[7][i].a <== states[i][2];
and[7][i].b <== eq[37][i].out;
multi_or[4][i] = MultiOR(2);
multi_or[4][i].in[0] <== and[6][i].out;
multi_or[4][i].in[1] <== and[7][i].out;
states[i+1][3] <== multi_or[4][i].out;
state_changed[i].in[2] <== states[i+1][3];
eq[38][i] = IsEqual();
eq[38][i].in[0] <== in[i];
eq[38][i].in[1] <== 13;
and[8][i] = AND();
and[8][i].a <== states[i][1];
and[8][i].b <== eq[38][i].out;
states[i+1][4] <== and[8][i].out;
state_changed[i].in[3] <== states[i+1][4];
eq[39][i] = IsEqual();
eq[39][i].in[0] <== in[i];
eq[39][i].in[1] <== 115;
and[9][i] = AND();
and[9][i].a <== states[i][3];
and[9][i].b <== eq[39][i].out;
states[i+1][5] <== and[9][i].out;
state_changed[i].in[4] <== states[i+1][5];
eq[40][i] = IsEqual();
eq[40][i].in[0] <== in[i];
eq[40][i].in[1] <== 117;
and[10][i] = AND();
and[10][i].a <== states[i][5];
and[10][i].b <== eq[40][i].out;
states[i+1][6] <== and[10][i].out;
state_changed[i].in[5] <== states[i+1][6];
eq[41][i] = IsEqual();
eq[41][i].in[0] <== in[i];
eq[41][i].in[1] <== 98;
and[11][i] = AND();
and[11][i].a <== states[i][6];
and[11][i].b <== eq[41][i].out;
states[i+1][7] <== and[11][i].out;
state_changed[i].in[6] <== states[i+1][7];
eq[42][i] = IsEqual();
eq[42][i].in[0] <== in[i];
eq[42][i].in[1] <== 10;
and[12][i] = AND();
and[12][i].a <== states[i][4];
and[12][i].b <== eq[42][i].out;
states[i+1][8] <== and[12][i].out;
state_changed[i].in[7] <== states[i+1][8];
eq[43][i] = IsEqual();
eq[43][i].in[0] <== in[i];
eq[43][i].in[1] <== 106;
and[13][i] = AND();
and[13][i].a <== states[i][7];
and[13][i].b <== eq[43][i].out;
states[i+1][9] <== and[13][i].out;
state_changed[i].in[8] <== states[i+1][9];
eq[44][i] = IsEqual();
eq[44][i].in[0] <== in[i];
eq[44][i].in[1] <== 101;
and[14][i] = AND();
and[14][i].a <== states[i][9];
and[14][i].b <== eq[44][i].out;
states[i+1][10] <== and[14][i].out;
state_changed[i].in[9] <== states[i+1][10];
eq[45][i] = IsEqual();
eq[45][i].in[0] <== in[i];
eq[45][i].in[1] <== 99;
and[15][i] = AND();
and[15][i].a <== states[i][10];
and[15][i].b <== eq[45][i].out;
states[i+1][11] <== and[15][i].out;
state_changed[i].in[10] <== states[i+1][11];
eq[46][i] = IsEqual();
eq[46][i].in[0] <== in[i];
eq[46][i].in[1] <== 116;
and[16][i] = AND();
and[16][i].a <== states[i][11];
and[16][i].b <== eq[46][i].out;
states[i+1][12] <== and[16][i].out;
state_changed[i].in[11] <== states[i+1][12];
eq[47][i] = IsEqual();
eq[47][i].in[0] <== in[i];
eq[47][i].in[1] <== 58;
and[17][i] = AND();
and[17][i].a <== states[i][12];
and[17][i].b <== eq[47][i].out;
states[i+1][13] <== and[17][i].out;
state_changed[i].in[12] <== states[i+1][13];
states[i+1][0] <== 1 - state_changed[i].out;
}
component final_state_result = MultiOR(num_bytes+1);
for (var i = 0; i <= num_bytes; i++) {
final_state_result.in[i] <== states[i][8];
}
out <== final_state_result.out;
signal is_consecutive[msg_bytes+1][2];
is_consecutive[msg_bytes][1] <== 1;
for (var i = 0; i < msg_bytes; i++) {
is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][8] * (1 - is_consecutive[msg_bytes-i][1]) + is_consecutive[msg_bytes-i][1];
is_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];
}
signal is_substr0[msg_bytes][3];
signal is_reveal0[msg_bytes];
signal output reveal0[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr0[i][0] <== 0;
is_substr0[i][1] <== is_substr0[i][0] + states[i+1][13] * states[i+2][1];
is_substr0[i][2] <== is_substr0[i][1] + states[i+1][1] * states[i+2][1];
is_reveal0[i] <== is_substr0[i][2] * is_consecutive[i][1];
reveal0[i] <== in[i+1] * is_reveal0[i];
}
}

View File

@@ -0,0 +1,891 @@
pragma circom 2.1.5;
include "zk-regex-circom/circuits/regex_helpers.circom";
template TimestampRegex(msg_bytes) {
signal input msg[msg_bytes];
signal output out;
var num_bytes = msg_bytes+1;
signal in[num_bytes];
in[0]<==128;
for (var i = 0; i < msg_bytes; i++) {
in[i+1] <== msg[i];
}
component eq[147][num_bytes];
component lt[22][num_bytes];
component and[43][num_bytes];
component multi_or[9][num_bytes];
signal states[num_bytes+1][25];
component state_changed[num_bytes];
states[0][0] <== 1;
for (var i = 1; i < 25; i++) {
states[0][i] <== 0;
}
for (var i = 0; i < num_bytes; i++) {
state_changed[i] = MultiOR(24);
lt[0][i] = LessThan(8);
lt[0][i].in[0] <== 96;
lt[0][i].in[1] <== in[i];
lt[1][i] = LessThan(8);
lt[1][i].in[0] <== in[i];
lt[1][i].in[1] <== 123;
and[0][i] = AND();
and[0][i].a <== lt[0][i].out;
and[0][i].b <== lt[1][i].out;
and[1][i] = AND();
and[1][i].a <== states[i][1];
and[1][i].b <== and[0][i].out;
eq[0][i] = IsEqual();
eq[0][i].in[0] <== in[i];
eq[0][i].in[1] <== 97;
eq[1][i] = IsEqual();
eq[1][i].in[0] <== in[i];
eq[1][i].in[1] <== 98;
eq[2][i] = IsEqual();
eq[2][i].in[0] <== in[i];
eq[2][i].in[1] <== 99;
eq[3][i] = IsEqual();
eq[3][i].in[0] <== in[i];
eq[3][i].in[1] <== 100;
eq[4][i] = IsEqual();
eq[4][i].in[0] <== in[i];
eq[4][i].in[1] <== 101;
eq[5][i] = IsEqual();
eq[5][i].in[0] <== in[i];
eq[5][i].in[1] <== 102;
eq[6][i] = IsEqual();
eq[6][i].in[0] <== in[i];
eq[6][i].in[1] <== 103;
eq[7][i] = IsEqual();
eq[7][i].in[0] <== in[i];
eq[7][i].in[1] <== 104;
eq[8][i] = IsEqual();
eq[8][i].in[0] <== in[i];
eq[8][i].in[1] <== 105;
eq[9][i] = IsEqual();
eq[9][i].in[0] <== in[i];
eq[9][i].in[1] <== 106;
eq[10][i] = IsEqual();
eq[10][i].in[0] <== in[i];
eq[10][i].in[1] <== 107;
eq[11][i] = IsEqual();
eq[11][i].in[0] <== in[i];
eq[11][i].in[1] <== 108;
eq[12][i] = IsEqual();
eq[12][i].in[0] <== in[i];
eq[12][i].in[1] <== 109;
eq[13][i] = IsEqual();
eq[13][i].in[0] <== in[i];
eq[13][i].in[1] <== 110;
eq[14][i] = IsEqual();
eq[14][i].in[0] <== in[i];
eq[14][i].in[1] <== 111;
eq[15][i] = IsEqual();
eq[15][i].in[0] <== in[i];
eq[15][i].in[1] <== 112;
eq[16][i] = IsEqual();
eq[16][i].in[0] <== in[i];
eq[16][i].in[1] <== 113;
eq[17][i] = IsEqual();
eq[17][i].in[0] <== in[i];
eq[17][i].in[1] <== 114;
eq[18][i] = IsEqual();
eq[18][i].in[0] <== in[i];
eq[18][i].in[1] <== 115;
eq[19][i] = IsEqual();
eq[19][i].in[0] <== in[i];
eq[19][i].in[1] <== 117;
eq[20][i] = IsEqual();
eq[20][i].in[0] <== in[i];
eq[20][i].in[1] <== 118;
eq[21][i] = IsEqual();
eq[21][i].in[0] <== in[i];
eq[21][i].in[1] <== 119;
eq[22][i] = IsEqual();
eq[22][i].in[0] <== in[i];
eq[22][i].in[1] <== 120;
eq[23][i] = IsEqual();
eq[23][i].in[0] <== in[i];
eq[23][i].in[1] <== 121;
eq[24][i] = IsEqual();
eq[24][i].in[0] <== in[i];
eq[24][i].in[1] <== 122;
and[2][i] = AND();
and[2][i].a <== states[i][14];
multi_or[0][i] = MultiOR(25);
multi_or[0][i].in[0] <== eq[0][i].out;
multi_or[0][i].in[1] <== eq[1][i].out;
multi_or[0][i].in[2] <== eq[2][i].out;
multi_or[0][i].in[3] <== eq[3][i].out;
multi_or[0][i].in[4] <== eq[4][i].out;
multi_or[0][i].in[5] <== eq[5][i].out;
multi_or[0][i].in[6] <== eq[6][i].out;
multi_or[0][i].in[7] <== eq[7][i].out;
multi_or[0][i].in[8] <== eq[8][i].out;
multi_or[0][i].in[9] <== eq[9][i].out;
multi_or[0][i].in[10] <== eq[10][i].out;
multi_or[0][i].in[11] <== eq[11][i].out;
multi_or[0][i].in[12] <== eq[12][i].out;
multi_or[0][i].in[13] <== eq[13][i].out;
multi_or[0][i].in[14] <== eq[14][i].out;
multi_or[0][i].in[15] <== eq[15][i].out;
multi_or[0][i].in[16] <== eq[16][i].out;
multi_or[0][i].in[17] <== eq[17][i].out;
multi_or[0][i].in[18] <== eq[18][i].out;
multi_or[0][i].in[19] <== eq[19][i].out;
multi_or[0][i].in[20] <== eq[20][i].out;
multi_or[0][i].in[21] <== eq[21][i].out;
multi_or[0][i].in[22] <== eq[22][i].out;
multi_or[0][i].in[23] <== eq[23][i].out;
multi_or[0][i].in[24] <== eq[24][i].out;
and[2][i].b <== multi_or[0][i].out;
lt[2][i] = LessThan(8);
lt[2][i].in[0] <== 96;
lt[2][i].in[1] <== in[i];
lt[3][i] = LessThan(8);
lt[3][i].in[0] <== in[i];
lt[3][i].in[1] <== 123;
and[3][i] = AND();
and[3][i].a <== lt[2][i].out;
and[3][i].b <== lt[3][i].out;
and[4][i] = AND();
and[4][i].a <== states[i][16];
and[4][i].b <== and[3][i].out;
lt[4][i] = LessThan(8);
lt[4][i].in[0] <== 96;
lt[4][i].in[1] <== in[i];
lt[5][i] = LessThan(8);
lt[5][i].in[0] <== in[i];
lt[5][i].in[1] <== 123;
and[5][i] = AND();
and[5][i].a <== lt[4][i].out;
and[5][i].b <== lt[5][i].out;
and[6][i] = AND();
and[6][i].a <== states[i][22];
and[6][i].b <== and[5][i].out;
multi_or[1][i] = MultiOR(4);
multi_or[1][i].in[0] <== and[1][i].out;
multi_or[1][i].in[1] <== and[2][i].out;
multi_or[1][i].in[2] <== and[4][i].out;
multi_or[1][i].in[3] <== and[6][i].out;
states[i+1][1] <== multi_or[1][i].out;
state_changed[i].in[0] <== states[i+1][1];
eq[25][i] = IsEqual();
eq[25][i].in[0] <== in[i];
eq[25][i].in[1] <== 61;
and[7][i] = AND();
and[7][i].a <== states[i][1];
and[7][i].b <== eq[25][i].out;
states[i+1][2] <== and[7][i].out;
state_changed[i].in[1] <== states[i+1][2];
eq[26][i] = IsEqual();
eq[26][i].in[0] <== in[i];
eq[26][i].in[1] <== 100;
and[8][i] = AND();
and[8][i].a <== states[i][0];
and[8][i].b <== eq[26][i].out;
states[i+1][3] <== and[8][i].out;
state_changed[i].in[2] <== states[i+1][3];
lt[6][i] = LessThan(8);
lt[6][i].in[0] <== 47;
lt[6][i].in[1] <== in[i];
lt[7][i] = LessThan(8);
lt[7][i].in[0] <== in[i];
lt[7][i].in[1] <== 58;
and[9][i] = AND();
and[9][i].a <== lt[6][i].out;
and[9][i].b <== lt[7][i].out;
lt[8][i] = LessThan(8);
lt[8][i].in[0] <== 64;
lt[8][i].in[1] <== in[i];
lt[9][i] = LessThan(8);
lt[9][i].in[0] <== in[i];
lt[9][i].in[1] <== 127;
and[10][i] = AND();
and[10][i].a <== lt[8][i].out;
and[10][i].b <== lt[9][i].out;
eq[27][i] = IsEqual();
eq[27][i].in[0] <== in[i];
eq[27][i].in[1] <== 9;
eq[28][i] = IsEqual();
eq[28][i].in[0] <== in[i];
eq[28][i].in[1] <== 10;
eq[29][i] = IsEqual();
eq[29][i].in[0] <== in[i];
eq[29][i].in[1] <== 13;
eq[30][i] = IsEqual();
eq[30][i].in[0] <== in[i];
eq[30][i].in[1] <== 32;
eq[31][i] = IsEqual();
eq[31][i].in[0] <== in[i];
eq[31][i].in[1] <== 33;
eq[32][i] = IsEqual();
eq[32][i].in[0] <== in[i];
eq[32][i].in[1] <== 34;
eq[33][i] = IsEqual();
eq[33][i].in[0] <== in[i];
eq[33][i].in[1] <== 35;
eq[34][i] = IsEqual();
eq[34][i].in[0] <== in[i];
eq[34][i].in[1] <== 36;
eq[35][i] = IsEqual();
eq[35][i].in[0] <== in[i];
eq[35][i].in[1] <== 37;
eq[36][i] = IsEqual();
eq[36][i].in[0] <== in[i];
eq[36][i].in[1] <== 38;
eq[37][i] = IsEqual();
eq[37][i].in[0] <== in[i];
eq[37][i].in[1] <== 39;
eq[38][i] = IsEqual();
eq[38][i].in[0] <== in[i];
eq[38][i].in[1] <== 40;
eq[39][i] = IsEqual();
eq[39][i].in[0] <== in[i];
eq[39][i].in[1] <== 41;
eq[40][i] = IsEqual();
eq[40][i].in[0] <== in[i];
eq[40][i].in[1] <== 42;
eq[41][i] = IsEqual();
eq[41][i].in[0] <== in[i];
eq[41][i].in[1] <== 43;
eq[42][i] = IsEqual();
eq[42][i].in[0] <== in[i];
eq[42][i].in[1] <== 44;
eq[43][i] = IsEqual();
eq[43][i].in[0] <== in[i];
eq[43][i].in[1] <== 45;
eq[44][i] = IsEqual();
eq[44][i].in[0] <== in[i];
eq[44][i].in[1] <== 46;
eq[45][i] = IsEqual();
eq[45][i].in[0] <== in[i];
eq[45][i].in[1] <== 47;
eq[46][i] = IsEqual();
eq[46][i].in[0] <== in[i];
eq[46][i].in[1] <== 58;
eq[47][i] = IsEqual();
eq[47][i].in[0] <== in[i];
eq[47][i].in[1] <== 60;
eq[48][i] = IsEqual();
eq[48][i].in[0] <== in[i];
eq[48][i].in[1] <== 61;
eq[49][i] = IsEqual();
eq[49][i].in[0] <== in[i];
eq[49][i].in[1] <== 62;
eq[50][i] = IsEqual();
eq[50][i].in[0] <== in[i];
eq[50][i].in[1] <== 63;
eq[51][i] = IsEqual();
eq[51][i].in[0] <== in[i];
eq[51][i].in[1] <== 64;
and[11][i] = AND();
and[11][i].a <== states[i][2];
multi_or[2][i] = MultiOR(27);
multi_or[2][i].in[0] <== and[9][i].out;
multi_or[2][i].in[1] <== and[10][i].out;
multi_or[2][i].in[2] <== eq[27][i].out;
multi_or[2][i].in[3] <== eq[28][i].out;
multi_or[2][i].in[4] <== eq[29][i].out;
multi_or[2][i].in[5] <== eq[30][i].out;
multi_or[2][i].in[6] <== eq[31][i].out;
multi_or[2][i].in[7] <== eq[32][i].out;
multi_or[2][i].in[8] <== eq[33][i].out;
multi_or[2][i].in[9] <== eq[34][i].out;
multi_or[2][i].in[10] <== eq[35][i].out;
multi_or[2][i].in[11] <== eq[36][i].out;
multi_or[2][i].in[12] <== eq[37][i].out;
multi_or[2][i].in[13] <== eq[38][i].out;
multi_or[2][i].in[14] <== eq[39][i].out;
multi_or[2][i].in[15] <== eq[40][i].out;
multi_or[2][i].in[16] <== eq[41][i].out;
multi_or[2][i].in[17] <== eq[42][i].out;
multi_or[2][i].in[18] <== eq[43][i].out;
multi_or[2][i].in[19] <== eq[44][i].out;
multi_or[2][i].in[20] <== eq[45][i].out;
multi_or[2][i].in[21] <== eq[46][i].out;
multi_or[2][i].in[22] <== eq[47][i].out;
multi_or[2][i].in[23] <== eq[48][i].out;
multi_or[2][i].in[24] <== eq[49][i].out;
multi_or[2][i].in[25] <== eq[50][i].out;
multi_or[2][i].in[26] <== eq[51][i].out;
and[11][i].b <== multi_or[2][i].out;
lt[10][i] = LessThan(8);
lt[10][i].in[0] <== 47;
lt[10][i].in[1] <== in[i];
lt[11][i] = LessThan(8);
lt[11][i].in[0] <== in[i];
lt[11][i].in[1] <== 58;
and[12][i] = AND();
and[12][i].a <== lt[10][i].out;
and[12][i].b <== lt[11][i].out;
lt[12][i] = LessThan(8);
lt[12][i].in[0] <== 64;
lt[12][i].in[1] <== in[i];
lt[13][i] = LessThan(8);
lt[13][i].in[0] <== in[i];
lt[13][i].in[1] <== 127;
and[13][i] = AND();
and[13][i].a <== lt[12][i].out;
and[13][i].b <== lt[13][i].out;
eq[52][i] = IsEqual();
eq[52][i].in[0] <== in[i];
eq[52][i].in[1] <== 9;
eq[53][i] = IsEqual();
eq[53][i].in[0] <== in[i];
eq[53][i].in[1] <== 10;
eq[54][i] = IsEqual();
eq[54][i].in[0] <== in[i];
eq[54][i].in[1] <== 13;
eq[55][i] = IsEqual();
eq[55][i].in[0] <== in[i];
eq[55][i].in[1] <== 32;
eq[56][i] = IsEqual();
eq[56][i].in[0] <== in[i];
eq[56][i].in[1] <== 33;
eq[57][i] = IsEqual();
eq[57][i].in[0] <== in[i];
eq[57][i].in[1] <== 34;
eq[58][i] = IsEqual();
eq[58][i].in[0] <== in[i];
eq[58][i].in[1] <== 35;
eq[59][i] = IsEqual();
eq[59][i].in[0] <== in[i];
eq[59][i].in[1] <== 36;
eq[60][i] = IsEqual();
eq[60][i].in[0] <== in[i];
eq[60][i].in[1] <== 37;
eq[61][i] = IsEqual();
eq[61][i].in[0] <== in[i];
eq[61][i].in[1] <== 38;
eq[62][i] = IsEqual();
eq[62][i].in[0] <== in[i];
eq[62][i].in[1] <== 39;
eq[63][i] = IsEqual();
eq[63][i].in[0] <== in[i];
eq[63][i].in[1] <== 40;
eq[64][i] = IsEqual();
eq[64][i].in[0] <== in[i];
eq[64][i].in[1] <== 41;
eq[65][i] = IsEqual();
eq[65][i].in[0] <== in[i];
eq[65][i].in[1] <== 42;
eq[66][i] = IsEqual();
eq[66][i].in[0] <== in[i];
eq[66][i].in[1] <== 43;
eq[67][i] = IsEqual();
eq[67][i].in[0] <== in[i];
eq[67][i].in[1] <== 44;
eq[68][i] = IsEqual();
eq[68][i].in[0] <== in[i];
eq[68][i].in[1] <== 45;
eq[69][i] = IsEqual();
eq[69][i].in[0] <== in[i];
eq[69][i].in[1] <== 46;
eq[70][i] = IsEqual();
eq[70][i].in[0] <== in[i];
eq[70][i].in[1] <== 47;
eq[71][i] = IsEqual();
eq[71][i].in[0] <== in[i];
eq[71][i].in[1] <== 58;
eq[72][i] = IsEqual();
eq[72][i].in[0] <== in[i];
eq[72][i].in[1] <== 60;
eq[73][i] = IsEqual();
eq[73][i].in[0] <== in[i];
eq[73][i].in[1] <== 61;
eq[74][i] = IsEqual();
eq[74][i].in[0] <== in[i];
eq[74][i].in[1] <== 62;
eq[75][i] = IsEqual();
eq[75][i].in[0] <== in[i];
eq[75][i].in[1] <== 63;
eq[76][i] = IsEqual();
eq[76][i].in[0] <== in[i];
eq[76][i].in[1] <== 64;
and[14][i] = AND();
and[14][i].a <== states[i][4];
multi_or[3][i] = MultiOR(27);
multi_or[3][i].in[0] <== and[12][i].out;
multi_or[3][i].in[1] <== and[13][i].out;
multi_or[3][i].in[2] <== eq[52][i].out;
multi_or[3][i].in[3] <== eq[53][i].out;
multi_or[3][i].in[4] <== eq[54][i].out;
multi_or[3][i].in[5] <== eq[55][i].out;
multi_or[3][i].in[6] <== eq[56][i].out;
multi_or[3][i].in[7] <== eq[57][i].out;
multi_or[3][i].in[8] <== eq[58][i].out;
multi_or[3][i].in[9] <== eq[59][i].out;
multi_or[3][i].in[10] <== eq[60][i].out;
multi_or[3][i].in[11] <== eq[61][i].out;
multi_or[3][i].in[12] <== eq[62][i].out;
multi_or[3][i].in[13] <== eq[63][i].out;
multi_or[3][i].in[14] <== eq[64][i].out;
multi_or[3][i].in[15] <== eq[65][i].out;
multi_or[3][i].in[16] <== eq[66][i].out;
multi_or[3][i].in[17] <== eq[67][i].out;
multi_or[3][i].in[18] <== eq[68][i].out;
multi_or[3][i].in[19] <== eq[69][i].out;
multi_or[3][i].in[20] <== eq[70][i].out;
multi_or[3][i].in[21] <== eq[71][i].out;
multi_or[3][i].in[22] <== eq[72][i].out;
multi_or[3][i].in[23] <== eq[73][i].out;
multi_or[3][i].in[24] <== eq[74][i].out;
multi_or[3][i].in[25] <== eq[75][i].out;
multi_or[3][i].in[26] <== eq[76][i].out;
and[14][i].b <== multi_or[3][i].out;
lt[14][i] = LessThan(8);
lt[14][i].in[0] <== 64;
lt[14][i].in[1] <== in[i];
lt[15][i] = LessThan(8);
lt[15][i].in[0] <== in[i];
lt[15][i].in[1] <== 127;
and[15][i] = AND();
and[15][i].a <== lt[14][i].out;
and[15][i].b <== lt[15][i].out;
eq[77][i] = IsEqual();
eq[77][i].in[0] <== in[i];
eq[77][i].in[1] <== 9;
eq[78][i] = IsEqual();
eq[78][i].in[0] <== in[i];
eq[78][i].in[1] <== 10;
eq[79][i] = IsEqual();
eq[79][i].in[0] <== in[i];
eq[79][i].in[1] <== 13;
eq[80][i] = IsEqual();
eq[80][i].in[0] <== in[i];
eq[80][i].in[1] <== 32;
eq[81][i] = IsEqual();
eq[81][i].in[0] <== in[i];
eq[81][i].in[1] <== 33;
eq[82][i] = IsEqual();
eq[82][i].in[0] <== in[i];
eq[82][i].in[1] <== 34;
eq[83][i] = IsEqual();
eq[83][i].in[0] <== in[i];
eq[83][i].in[1] <== 35;
eq[84][i] = IsEqual();
eq[84][i].in[0] <== in[i];
eq[84][i].in[1] <== 36;
eq[85][i] = IsEqual();
eq[85][i].in[0] <== in[i];
eq[85][i].in[1] <== 37;
eq[86][i] = IsEqual();
eq[86][i].in[0] <== in[i];
eq[86][i].in[1] <== 38;
eq[87][i] = IsEqual();
eq[87][i].in[0] <== in[i];
eq[87][i].in[1] <== 39;
eq[88][i] = IsEqual();
eq[88][i].in[0] <== in[i];
eq[88][i].in[1] <== 40;
eq[89][i] = IsEqual();
eq[89][i].in[0] <== in[i];
eq[89][i].in[1] <== 41;
eq[90][i] = IsEqual();
eq[90][i].in[0] <== in[i];
eq[90][i].in[1] <== 42;
eq[91][i] = IsEqual();
eq[91][i].in[0] <== in[i];
eq[91][i].in[1] <== 43;
eq[92][i] = IsEqual();
eq[92][i].in[0] <== in[i];
eq[92][i].in[1] <== 44;
eq[93][i] = IsEqual();
eq[93][i].in[0] <== in[i];
eq[93][i].in[1] <== 45;
eq[94][i] = IsEqual();
eq[94][i].in[0] <== in[i];
eq[94][i].in[1] <== 46;
eq[95][i] = IsEqual();
eq[95][i].in[0] <== in[i];
eq[95][i].in[1] <== 47;
eq[96][i] = IsEqual();
eq[96][i].in[0] <== in[i];
eq[96][i].in[1] <== 58;
eq[97][i] = IsEqual();
eq[97][i].in[0] <== in[i];
eq[97][i].in[1] <== 60;
eq[98][i] = IsEqual();
eq[98][i].in[0] <== in[i];
eq[98][i].in[1] <== 61;
eq[99][i] = IsEqual();
eq[99][i].in[0] <== in[i];
eq[99][i].in[1] <== 62;
eq[100][i] = IsEqual();
eq[100][i].in[0] <== in[i];
eq[100][i].in[1] <== 63;
eq[101][i] = IsEqual();
eq[101][i].in[0] <== in[i];
eq[101][i].in[1] <== 64;
and[16][i] = AND();
and[16][i].a <== states[i][18];
multi_or[4][i] = MultiOR(26);
multi_or[4][i].in[0] <== and[15][i].out;
multi_or[4][i].in[1] <== eq[77][i].out;
multi_or[4][i].in[2] <== eq[78][i].out;
multi_or[4][i].in[3] <== eq[79][i].out;
multi_or[4][i].in[4] <== eq[80][i].out;
multi_or[4][i].in[5] <== eq[81][i].out;
multi_or[4][i].in[6] <== eq[82][i].out;
multi_or[4][i].in[7] <== eq[83][i].out;
multi_or[4][i].in[8] <== eq[84][i].out;
multi_or[4][i].in[9] <== eq[85][i].out;
multi_or[4][i].in[10] <== eq[86][i].out;
multi_or[4][i].in[11] <== eq[87][i].out;
multi_or[4][i].in[12] <== eq[88][i].out;
multi_or[4][i].in[13] <== eq[89][i].out;
multi_or[4][i].in[14] <== eq[90][i].out;
multi_or[4][i].in[15] <== eq[91][i].out;
multi_or[4][i].in[16] <== eq[92][i].out;
multi_or[4][i].in[17] <== eq[93][i].out;
multi_or[4][i].in[18] <== eq[94][i].out;
multi_or[4][i].in[19] <== eq[95][i].out;
multi_or[4][i].in[20] <== eq[96][i].out;
multi_or[4][i].in[21] <== eq[97][i].out;
multi_or[4][i].in[22] <== eq[98][i].out;
multi_or[4][i].in[23] <== eq[99][i].out;
multi_or[4][i].in[24] <== eq[100][i].out;
multi_or[4][i].in[25] <== eq[101][i].out;
and[16][i].b <== multi_or[4][i].out;
lt[16][i] = LessThan(8);
lt[16][i].in[0] <== 64;
lt[16][i].in[1] <== in[i];
lt[17][i] = LessThan(8);
lt[17][i].in[0] <== in[i];
lt[17][i].in[1] <== 127;
and[17][i] = AND();
and[17][i].a <== lt[16][i].out;
and[17][i].b <== lt[17][i].out;
eq[102][i] = IsEqual();
eq[102][i].in[0] <== in[i];
eq[102][i].in[1] <== 9;
eq[103][i] = IsEqual();
eq[103][i].in[0] <== in[i];
eq[103][i].in[1] <== 10;
eq[104][i] = IsEqual();
eq[104][i].in[0] <== in[i];
eq[104][i].in[1] <== 13;
eq[105][i] = IsEqual();
eq[105][i].in[0] <== in[i];
eq[105][i].in[1] <== 32;
eq[106][i] = IsEqual();
eq[106][i].in[0] <== in[i];
eq[106][i].in[1] <== 33;
eq[107][i] = IsEqual();
eq[107][i].in[0] <== in[i];
eq[107][i].in[1] <== 34;
eq[108][i] = IsEqual();
eq[108][i].in[0] <== in[i];
eq[108][i].in[1] <== 35;
eq[109][i] = IsEqual();
eq[109][i].in[0] <== in[i];
eq[109][i].in[1] <== 36;
eq[110][i] = IsEqual();
eq[110][i].in[0] <== in[i];
eq[110][i].in[1] <== 37;
eq[111][i] = IsEqual();
eq[111][i].in[0] <== in[i];
eq[111][i].in[1] <== 38;
eq[112][i] = IsEqual();
eq[112][i].in[0] <== in[i];
eq[112][i].in[1] <== 39;
eq[113][i] = IsEqual();
eq[113][i].in[0] <== in[i];
eq[113][i].in[1] <== 40;
eq[114][i] = IsEqual();
eq[114][i].in[0] <== in[i];
eq[114][i].in[1] <== 41;
eq[115][i] = IsEqual();
eq[115][i].in[0] <== in[i];
eq[115][i].in[1] <== 42;
eq[116][i] = IsEqual();
eq[116][i].in[0] <== in[i];
eq[116][i].in[1] <== 43;
eq[117][i] = IsEqual();
eq[117][i].in[0] <== in[i];
eq[117][i].in[1] <== 44;
eq[118][i] = IsEqual();
eq[118][i].in[0] <== in[i];
eq[118][i].in[1] <== 45;
eq[119][i] = IsEqual();
eq[119][i].in[0] <== in[i];
eq[119][i].in[1] <== 46;
eq[120][i] = IsEqual();
eq[120][i].in[0] <== in[i];
eq[120][i].in[1] <== 47;
eq[121][i] = IsEqual();
eq[121][i].in[0] <== in[i];
eq[121][i].in[1] <== 58;
eq[122][i] = IsEqual();
eq[122][i].in[0] <== in[i];
eq[122][i].in[1] <== 60;
eq[123][i] = IsEqual();
eq[123][i].in[0] <== in[i];
eq[123][i].in[1] <== 61;
eq[124][i] = IsEqual();
eq[124][i].in[0] <== in[i];
eq[124][i].in[1] <== 62;
eq[125][i] = IsEqual();
eq[125][i].in[0] <== in[i];
eq[125][i].in[1] <== 63;
eq[126][i] = IsEqual();
eq[126][i].in[0] <== in[i];
eq[126][i].in[1] <== 64;
and[18][i] = AND();
and[18][i].a <== states[i][23];
multi_or[5][i] = MultiOR(26);
multi_or[5][i].in[0] <== and[17][i].out;
multi_or[5][i].in[1] <== eq[102][i].out;
multi_or[5][i].in[2] <== eq[103][i].out;
multi_or[5][i].in[3] <== eq[104][i].out;
multi_or[5][i].in[4] <== eq[105][i].out;
multi_or[5][i].in[5] <== eq[106][i].out;
multi_or[5][i].in[6] <== eq[107][i].out;
multi_or[5][i].in[7] <== eq[108][i].out;
multi_or[5][i].in[8] <== eq[109][i].out;
multi_or[5][i].in[9] <== eq[110][i].out;
multi_or[5][i].in[10] <== eq[111][i].out;
multi_or[5][i].in[11] <== eq[112][i].out;
multi_or[5][i].in[12] <== eq[113][i].out;
multi_or[5][i].in[13] <== eq[114][i].out;
multi_or[5][i].in[14] <== eq[115][i].out;
multi_or[5][i].in[15] <== eq[116][i].out;
multi_or[5][i].in[16] <== eq[117][i].out;
multi_or[5][i].in[17] <== eq[118][i].out;
multi_or[5][i].in[18] <== eq[119][i].out;
multi_or[5][i].in[19] <== eq[120][i].out;
multi_or[5][i].in[20] <== eq[121][i].out;
multi_or[5][i].in[21] <== eq[122][i].out;
multi_or[5][i].in[22] <== eq[123][i].out;
multi_or[5][i].in[23] <== eq[124][i].out;
multi_or[5][i].in[24] <== eq[125][i].out;
multi_or[5][i].in[25] <== eq[126][i].out;
and[18][i].b <== multi_or[5][i].out;
multi_or[6][i] = MultiOR(4);
multi_or[6][i].in[0] <== and[11][i].out;
multi_or[6][i].in[1] <== and[14][i].out;
multi_or[6][i].in[2] <== and[16][i].out;
multi_or[6][i].in[3] <== and[18][i].out;
states[i+1][4] <== multi_or[6][i].out;
state_changed[i].in[3] <== states[i+1][4];
eq[127][i] = IsEqual();
eq[127][i].in[0] <== in[i];
eq[127][i].in[1] <== 107;
and[19][i] = AND();
and[19][i].a <== states[i][3];
and[19][i].b <== eq[127][i].out;
states[i+1][5] <== and[19][i].out;
state_changed[i].in[4] <== states[i+1][5];
eq[128][i] = IsEqual();
eq[128][i].in[0] <== in[i];
eq[128][i].in[1] <== 105;
and[20][i] = AND();
and[20][i].a <== states[i][5];
and[20][i].b <== eq[128][i].out;
states[i+1][6] <== and[20][i].out;
state_changed[i].in[5] <== states[i+1][6];
eq[129][i] = IsEqual();
eq[129][i].in[0] <== in[i];
eq[129][i].in[1] <== 109;
and[21][i] = AND();
and[21][i].a <== states[i][6];
and[21][i].b <== eq[129][i].out;
states[i+1][7] <== and[21][i].out;
state_changed[i].in[6] <== states[i+1][7];
eq[130][i] = IsEqual();
eq[130][i].in[0] <== in[i];
eq[130][i].in[1] <== 45;
and[22][i] = AND();
and[22][i].a <== states[i][7];
and[22][i].b <== eq[130][i].out;
states[i+1][8] <== and[22][i].out;
state_changed[i].in[7] <== states[i+1][8];
eq[131][i] = IsEqual();
eq[131][i].in[0] <== in[i];
eq[131][i].in[1] <== 115;
and[23][i] = AND();
and[23][i].a <== states[i][8];
and[23][i].b <== eq[131][i].out;
states[i+1][9] <== and[23][i].out;
state_changed[i].in[8] <== states[i+1][9];
eq[132][i] = IsEqual();
eq[132][i].in[0] <== in[i];
eq[132][i].in[1] <== 59;
and[24][i] = AND();
and[24][i].a <== states[i][4];
and[24][i].b <== eq[132][i].out;
states[i+1][10] <== and[24][i].out;
state_changed[i].in[9] <== states[i+1][10];
eq[133][i] = IsEqual();
eq[133][i].in[0] <== in[i];
eq[133][i].in[1] <== 105;
and[25][i] = AND();
and[25][i].a <== states[i][9];
and[25][i].b <== eq[133][i].out;
states[i+1][11] <== and[25][i].out;
state_changed[i].in[10] <== states[i+1][11];
eq[134][i] = IsEqual();
eq[134][i].in[0] <== in[i];
eq[134][i].in[1] <== 103;
and[26][i] = AND();
and[26][i].a <== states[i][11];
and[26][i].b <== eq[134][i].out;
states[i+1][12] <== and[26][i].out;
state_changed[i].in[11] <== states[i+1][12];
eq[135][i] = IsEqual();
eq[135][i].in[0] <== in[i];
eq[135][i].in[1] <== 110;
and[27][i] = AND();
and[27][i].a <== states[i][12];
and[27][i].b <== eq[135][i].out;
states[i+1][13] <== and[27][i].out;
state_changed[i].in[12] <== states[i+1][13];
eq[136][i] = IsEqual();
eq[136][i].in[0] <== in[i];
eq[136][i].in[1] <== 32;
and[28][i] = AND();
and[28][i].a <== states[i][10];
and[28][i].b <== eq[136][i].out;
eq[137][i] = IsEqual();
eq[137][i].in[0] <== in[i];
eq[137][i].in[1] <== 32;
and[29][i] = AND();
and[29][i].a <== states[i][24];
and[29][i].b <== eq[137][i].out;
multi_or[7][i] = MultiOR(2);
multi_or[7][i].in[0] <== and[28][i].out;
multi_or[7][i].in[1] <== and[29][i].out;
states[i+1][14] <== multi_or[7][i].out;
state_changed[i].in[13] <== states[i+1][14];
eq[138][i] = IsEqual();
eq[138][i].in[0] <== in[i];
eq[138][i].in[1] <== 97;
and[30][i] = AND();
and[30][i].a <== states[i][13];
and[30][i].b <== eq[138][i].out;
states[i+1][15] <== and[30][i].out;
state_changed[i].in[14] <== states[i+1][15];
eq[139][i] = IsEqual();
eq[139][i].in[0] <== in[i];
eq[139][i].in[1] <== 116;
and[31][i] = AND();
and[31][i].a <== states[i][14];
and[31][i].b <== eq[139][i].out;
states[i+1][16] <== and[31][i].out;
state_changed[i].in[15] <== states[i+1][16];
eq[140][i] = IsEqual();
eq[140][i].in[0] <== in[i];
eq[140][i].in[1] <== 116;
and[32][i] = AND();
and[32][i].a <== states[i][15];
and[32][i].b <== eq[140][i].out;
states[i+1][17] <== and[32][i].out;
state_changed[i].in[16] <== states[i+1][17];
eq[141][i] = IsEqual();
eq[141][i].in[0] <== in[i];
eq[141][i].in[1] <== 61;
and[33][i] = AND();
and[33][i].a <== states[i][16];
and[33][i].b <== eq[141][i].out;
states[i+1][18] <== and[33][i].out;
state_changed[i].in[17] <== states[i+1][18];
eq[142][i] = IsEqual();
eq[142][i].in[0] <== in[i];
eq[142][i].in[1] <== 117;
and[34][i] = AND();
and[34][i].a <== states[i][17];
and[34][i].b <== eq[142][i].out;
states[i+1][19] <== and[34][i].out;
state_changed[i].in[18] <== states[i+1][19];
eq[143][i] = IsEqual();
eq[143][i].in[0] <== in[i];
eq[143][i].in[1] <== 114;
and[35][i] = AND();
and[35][i].a <== states[i][19];
and[35][i].b <== eq[143][i].out;
states[i+1][20] <== and[35][i].out;
state_changed[i].in[19] <== states[i+1][20];
eq[144][i] = IsEqual();
eq[144][i].in[0] <== in[i];
eq[144][i].in[1] <== 101;
and[36][i] = AND();
and[36][i].a <== states[i][20];
and[36][i].b <== eq[144][i].out;
states[i+1][21] <== and[36][i].out;
state_changed[i].in[20] <== states[i+1][21];
eq[145][i] = IsEqual();
eq[145][i].in[0] <== in[i];
eq[145][i].in[1] <== 58;
and[37][i] = AND();
and[37][i].a <== states[i][21];
and[37][i].b <== eq[145][i].out;
states[i+1][22] <== and[37][i].out;
state_changed[i].in[21] <== states[i+1][22];
lt[18][i] = LessThan(8);
lt[18][i].in[0] <== 47;
lt[18][i].in[1] <== in[i];
lt[19][i] = LessThan(8);
lt[19][i].in[0] <== in[i];
lt[19][i].in[1] <== 58;
and[38][i] = AND();
and[38][i].a <== lt[18][i].out;
and[38][i].b <== lt[19][i].out;
and[39][i] = AND();
and[39][i].a <== states[i][18];
and[39][i].b <== and[38][i].out;
lt[20][i] = LessThan(8);
lt[20][i].in[0] <== 47;
lt[20][i].in[1] <== in[i];
lt[21][i] = LessThan(8);
lt[21][i].in[0] <== in[i];
lt[21][i].in[1] <== 58;
and[40][i] = AND();
and[40][i].a <== lt[20][i].out;
and[40][i].b <== lt[21][i].out;
and[41][i] = AND();
and[41][i].a <== states[i][23];
and[41][i].b <== and[40][i].out;
multi_or[8][i] = MultiOR(2);
multi_or[8][i].in[0] <== and[39][i].out;
multi_or[8][i].in[1] <== and[41][i].out;
states[i+1][23] <== multi_or[8][i].out;
state_changed[i].in[22] <== states[i+1][23];
eq[146][i] = IsEqual();
eq[146][i].in[0] <== in[i];
eq[146][i].in[1] <== 59;
and[42][i] = AND();
and[42][i].a <== states[i][23];
and[42][i].b <== eq[146][i].out;
states[i+1][24] <== and[42][i].out;
state_changed[i].in[23] <== states[i+1][24];
states[i+1][0] <== 1 - state_changed[i].out;
}
component final_state_result = MultiOR(num_bytes+1);
for (var i = 0; i <= num_bytes; i++) {
final_state_result.in[i] <== states[i][24];
}
out <== final_state_result.out;
signal is_consecutive[msg_bytes+1][2];
is_consecutive[msg_bytes][1] <== 1;
for (var i = 0; i < msg_bytes; i++) {
is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][24] * (1 - is_consecutive[msg_bytes-i][1]) + is_consecutive[msg_bytes-i][1];
is_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];
}
signal is_substr0[msg_bytes][3];
signal is_reveal0[msg_bytes];
signal output reveal0[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr0[i][0] <== 0;
is_substr0[i][1] <== is_substr0[i][0] + states[i+1][23] * states[i+2][23];
is_substr0[i][2] <== is_substr0[i][1] + states[i+1][18] * states[i+2][23];
is_reveal0[i] <== is_substr0[i][2] * is_consecutive[i][1];
reveal0[i] <== in[i+1] * is_reveal0[i];
}
}

View File

@@ -0,0 +1,25 @@
{
"max_byte_size": 1024,
"parts": [
{
"is_public": false,
"regex_def": "dkim-signature:",
"max_size": 15
},
{
"is_public": false,
"regex_def": "((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)+=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|\"|#|$|%|&|\\'|\\(|\\)|\\*|\\+|,|-|\\.|\\/|:|<|=|>|\\?|@|\\[|\\\\|\\]|\\^|_|`|{|\\||}|~| |\t|\n|\r|\\x0b|\\x0c)+; )+t=",
"max_size": 128
},
{
"is_public": true,
"regex_def": "(0|1|2|3|4|5|6|7|8|9)+",
"max_size": 10
},
{
"is_public": false,
"regex_def": ";",
"max_size": 1
}
]
}

View File

@@ -0,0 +1,865 @@
pragma circom 2.1.5;
include "zk-regex-circom/circuits/regex_helpers.circom";
template TimestampRegex(msg_bytes) {
signal input msg[msg_bytes];
signal output out;
var num_bytes = msg_bytes+1;
signal in[num_bytes];
in[0]<==128;
for (var i = 0; i < msg_bytes; i++) {
in[i+1] <== msg[i];
}
component eq[147][num_bytes];
component lt[18][num_bytes];
component and[39][num_bytes];
component multi_or[9][num_bytes];
signal states[num_bytes+1][25];
component state_changed[num_bytes];
states[0][0] <== 1;
for (var i = 1; i < 25; i++) {
states[0][i] <== 0;
}
for (var i = 0; i < num_bytes; i++) {
state_changed[i] = MultiOR(24);
eq[0][i] = IsEqual();
eq[0][i].in[0] <== in[i];
eq[0][i].in[1] <== 97;
eq[1][i] = IsEqual();
eq[1][i].in[0] <== in[i];
eq[1][i].in[1] <== 98;
eq[2][i] = IsEqual();
eq[2][i].in[0] <== in[i];
eq[2][i].in[1] <== 99;
eq[3][i] = IsEqual();
eq[3][i].in[0] <== in[i];
eq[3][i].in[1] <== 100;
eq[4][i] = IsEqual();
eq[4][i].in[0] <== in[i];
eq[4][i].in[1] <== 101;
eq[5][i] = IsEqual();
eq[5][i].in[0] <== in[i];
eq[5][i].in[1] <== 102;
eq[6][i] = IsEqual();
eq[6][i].in[0] <== in[i];
eq[6][i].in[1] <== 103;
eq[7][i] = IsEqual();
eq[7][i].in[0] <== in[i];
eq[7][i].in[1] <== 104;
eq[8][i] = IsEqual();
eq[8][i].in[0] <== in[i];
eq[8][i].in[1] <== 105;
eq[9][i] = IsEqual();
eq[9][i].in[0] <== in[i];
eq[9][i].in[1] <== 106;
eq[10][i] = IsEqual();
eq[10][i].in[0] <== in[i];
eq[10][i].in[1] <== 107;
eq[11][i] = IsEqual();
eq[11][i].in[0] <== in[i];
eq[11][i].in[1] <== 108;
eq[12][i] = IsEqual();
eq[12][i].in[0] <== in[i];
eq[12][i].in[1] <== 109;
eq[13][i] = IsEqual();
eq[13][i].in[0] <== in[i];
eq[13][i].in[1] <== 110;
eq[14][i] = IsEqual();
eq[14][i].in[0] <== in[i];
eq[14][i].in[1] <== 111;
eq[15][i] = IsEqual();
eq[15][i].in[0] <== in[i];
eq[15][i].in[1] <== 112;
eq[16][i] = IsEqual();
eq[16][i].in[0] <== in[i];
eq[16][i].in[1] <== 113;
eq[17][i] = IsEqual();
eq[17][i].in[0] <== in[i];
eq[17][i].in[1] <== 114;
eq[18][i] = IsEqual();
eq[18][i].in[0] <== in[i];
eq[18][i].in[1] <== 115;
eq[19][i] = IsEqual();
eq[19][i].in[0] <== in[i];
eq[19][i].in[1] <== 117;
eq[20][i] = IsEqual();
eq[20][i].in[0] <== in[i];
eq[20][i].in[1] <== 118;
eq[21][i] = IsEqual();
eq[21][i].in[0] <== in[i];
eq[21][i].in[1] <== 119;
eq[22][i] = IsEqual();
eq[22][i].in[0] <== in[i];
eq[22][i].in[1] <== 120;
eq[23][i] = IsEqual();
eq[23][i].in[0] <== in[i];
eq[23][i].in[1] <== 121;
eq[24][i] = IsEqual();
eq[24][i].in[0] <== in[i];
eq[24][i].in[1] <== 122;
and[0][i] = AND();
and[0][i].a <== states[i][13];
multi_or[0][i] = MultiOR(25);
multi_or[0][i].in[0] <== eq[0][i].out;
multi_or[0][i].in[1] <== eq[1][i].out;
multi_or[0][i].in[2] <== eq[2][i].out;
multi_or[0][i].in[3] <== eq[3][i].out;
multi_or[0][i].in[4] <== eq[4][i].out;
multi_or[0][i].in[5] <== eq[5][i].out;
multi_or[0][i].in[6] <== eq[6][i].out;
multi_or[0][i].in[7] <== eq[7][i].out;
multi_or[0][i].in[8] <== eq[8][i].out;
multi_or[0][i].in[9] <== eq[9][i].out;
multi_or[0][i].in[10] <== eq[10][i].out;
multi_or[0][i].in[11] <== eq[11][i].out;
multi_or[0][i].in[12] <== eq[12][i].out;
multi_or[0][i].in[13] <== eq[13][i].out;
multi_or[0][i].in[14] <== eq[14][i].out;
multi_or[0][i].in[15] <== eq[15][i].out;
multi_or[0][i].in[16] <== eq[16][i].out;
multi_or[0][i].in[17] <== eq[17][i].out;
multi_or[0][i].in[18] <== eq[18][i].out;
multi_or[0][i].in[19] <== eq[19][i].out;
multi_or[0][i].in[20] <== eq[20][i].out;
multi_or[0][i].in[21] <== eq[21][i].out;
multi_or[0][i].in[22] <== eq[22][i].out;
multi_or[0][i].in[23] <== eq[23][i].out;
multi_or[0][i].in[24] <== eq[24][i].out;
and[0][i].b <== multi_or[0][i].out;
lt[0][i] = LessThan(8);
lt[0][i].in[0] <== 96;
lt[0][i].in[1] <== in[i];
lt[1][i] = LessThan(8);
lt[1][i].in[0] <== in[i];
lt[1][i].in[1] <== 123;
and[1][i] = AND();
and[1][i].a <== lt[0][i].out;
and[1][i].b <== lt[1][i].out;
and[2][i] = AND();
and[2][i].a <== states[i][23];
and[2][i].b <== and[1][i].out;
multi_or[1][i] = MultiOR(2);
multi_or[1][i].in[0] <== and[0][i].out;
multi_or[1][i].in[1] <== and[2][i].out;
states[i+1][1] <== multi_or[1][i].out;
state_changed[i].in[0] <== states[i+1][1];
eq[25][i] = IsEqual();
eq[25][i].in[0] <== in[i];
eq[25][i].in[1] <== 61;
and[3][i] = AND();
and[3][i].a <== states[i][1];
and[3][i].b <== eq[25][i].out;
states[i+1][2] <== and[3][i].out;
state_changed[i].in[1] <== states[i+1][2];
lt[2][i] = LessThan(8);
lt[2][i].in[0] <== 47;
lt[2][i].in[1] <== in[i];
lt[3][i] = LessThan(8);
lt[3][i].in[0] <== in[i];
lt[3][i].in[1] <== 58;
and[4][i] = AND();
and[4][i].a <== lt[2][i].out;
and[4][i].b <== lt[3][i].out;
lt[4][i] = LessThan(8);
lt[4][i].in[0] <== 64;
lt[4][i].in[1] <== in[i];
lt[5][i] = LessThan(8);
lt[5][i].in[0] <== in[i];
lt[5][i].in[1] <== 127;
and[5][i] = AND();
and[5][i].a <== lt[4][i].out;
and[5][i].b <== lt[5][i].out;
eq[26][i] = IsEqual();
eq[26][i].in[0] <== in[i];
eq[26][i].in[1] <== 9;
eq[27][i] = IsEqual();
eq[27][i].in[0] <== in[i];
eq[27][i].in[1] <== 10;
eq[28][i] = IsEqual();
eq[28][i].in[0] <== in[i];
eq[28][i].in[1] <== 13;
eq[29][i] = IsEqual();
eq[29][i].in[0] <== in[i];
eq[29][i].in[1] <== 32;
eq[30][i] = IsEqual();
eq[30][i].in[0] <== in[i];
eq[30][i].in[1] <== 33;
eq[31][i] = IsEqual();
eq[31][i].in[0] <== in[i];
eq[31][i].in[1] <== 34;
eq[32][i] = IsEqual();
eq[32][i].in[0] <== in[i];
eq[32][i].in[1] <== 35;
eq[33][i] = IsEqual();
eq[33][i].in[0] <== in[i];
eq[33][i].in[1] <== 36;
eq[34][i] = IsEqual();
eq[34][i].in[0] <== in[i];
eq[34][i].in[1] <== 37;
eq[35][i] = IsEqual();
eq[35][i].in[0] <== in[i];
eq[35][i].in[1] <== 38;
eq[36][i] = IsEqual();
eq[36][i].in[0] <== in[i];
eq[36][i].in[1] <== 39;
eq[37][i] = IsEqual();
eq[37][i].in[0] <== in[i];
eq[37][i].in[1] <== 40;
eq[38][i] = IsEqual();
eq[38][i].in[0] <== in[i];
eq[38][i].in[1] <== 41;
eq[39][i] = IsEqual();
eq[39][i].in[0] <== in[i];
eq[39][i].in[1] <== 42;
eq[40][i] = IsEqual();
eq[40][i].in[0] <== in[i];
eq[40][i].in[1] <== 43;
eq[41][i] = IsEqual();
eq[41][i].in[0] <== in[i];
eq[41][i].in[1] <== 44;
eq[42][i] = IsEqual();
eq[42][i].in[0] <== in[i];
eq[42][i].in[1] <== 45;
eq[43][i] = IsEqual();
eq[43][i].in[0] <== in[i];
eq[43][i].in[1] <== 46;
eq[44][i] = IsEqual();
eq[44][i].in[0] <== in[i];
eq[44][i].in[1] <== 47;
eq[45][i] = IsEqual();
eq[45][i].in[0] <== in[i];
eq[45][i].in[1] <== 58;
eq[46][i] = IsEqual();
eq[46][i].in[0] <== in[i];
eq[46][i].in[1] <== 60;
eq[47][i] = IsEqual();
eq[47][i].in[0] <== in[i];
eq[47][i].in[1] <== 61;
eq[48][i] = IsEqual();
eq[48][i].in[0] <== in[i];
eq[48][i].in[1] <== 62;
eq[49][i] = IsEqual();
eq[49][i].in[0] <== in[i];
eq[49][i].in[1] <== 63;
eq[50][i] = IsEqual();
eq[50][i].in[0] <== in[i];
eq[50][i].in[1] <== 64;
and[6][i] = AND();
and[6][i].a <== states[i][2];
multi_or[2][i] = MultiOR(27);
multi_or[2][i].in[0] <== and[4][i].out;
multi_or[2][i].in[1] <== and[5][i].out;
multi_or[2][i].in[2] <== eq[26][i].out;
multi_or[2][i].in[3] <== eq[27][i].out;
multi_or[2][i].in[4] <== eq[28][i].out;
multi_or[2][i].in[5] <== eq[29][i].out;
multi_or[2][i].in[6] <== eq[30][i].out;
multi_or[2][i].in[7] <== eq[31][i].out;
multi_or[2][i].in[8] <== eq[32][i].out;
multi_or[2][i].in[9] <== eq[33][i].out;
multi_or[2][i].in[10] <== eq[34][i].out;
multi_or[2][i].in[11] <== eq[35][i].out;
multi_or[2][i].in[12] <== eq[36][i].out;
multi_or[2][i].in[13] <== eq[37][i].out;
multi_or[2][i].in[14] <== eq[38][i].out;
multi_or[2][i].in[15] <== eq[39][i].out;
multi_or[2][i].in[16] <== eq[40][i].out;
multi_or[2][i].in[17] <== eq[41][i].out;
multi_or[2][i].in[18] <== eq[42][i].out;
multi_or[2][i].in[19] <== eq[43][i].out;
multi_or[2][i].in[20] <== eq[44][i].out;
multi_or[2][i].in[21] <== eq[45][i].out;
multi_or[2][i].in[22] <== eq[46][i].out;
multi_or[2][i].in[23] <== eq[47][i].out;
multi_or[2][i].in[24] <== eq[48][i].out;
multi_or[2][i].in[25] <== eq[49][i].out;
multi_or[2][i].in[26] <== eq[50][i].out;
and[6][i].b <== multi_or[2][i].out;
lt[6][i] = LessThan(8);
lt[6][i].in[0] <== 47;
lt[6][i].in[1] <== in[i];
lt[7][i] = LessThan(8);
lt[7][i].in[0] <== in[i];
lt[7][i].in[1] <== 58;
and[7][i] = AND();
and[7][i].a <== lt[6][i].out;
and[7][i].b <== lt[7][i].out;
lt[8][i] = LessThan(8);
lt[8][i].in[0] <== 64;
lt[8][i].in[1] <== in[i];
lt[9][i] = LessThan(8);
lt[9][i].in[0] <== in[i];
lt[9][i].in[1] <== 127;
and[8][i] = AND();
and[8][i].a <== lt[8][i].out;
and[8][i].b <== lt[9][i].out;
eq[51][i] = IsEqual();
eq[51][i].in[0] <== in[i];
eq[51][i].in[1] <== 9;
eq[52][i] = IsEqual();
eq[52][i].in[0] <== in[i];
eq[52][i].in[1] <== 10;
eq[53][i] = IsEqual();
eq[53][i].in[0] <== in[i];
eq[53][i].in[1] <== 13;
eq[54][i] = IsEqual();
eq[54][i].in[0] <== in[i];
eq[54][i].in[1] <== 32;
eq[55][i] = IsEqual();
eq[55][i].in[0] <== in[i];
eq[55][i].in[1] <== 33;
eq[56][i] = IsEqual();
eq[56][i].in[0] <== in[i];
eq[56][i].in[1] <== 34;
eq[57][i] = IsEqual();
eq[57][i].in[0] <== in[i];
eq[57][i].in[1] <== 35;
eq[58][i] = IsEqual();
eq[58][i].in[0] <== in[i];
eq[58][i].in[1] <== 36;
eq[59][i] = IsEqual();
eq[59][i].in[0] <== in[i];
eq[59][i].in[1] <== 37;
eq[60][i] = IsEqual();
eq[60][i].in[0] <== in[i];
eq[60][i].in[1] <== 38;
eq[61][i] = IsEqual();
eq[61][i].in[0] <== in[i];
eq[61][i].in[1] <== 39;
eq[62][i] = IsEqual();
eq[62][i].in[0] <== in[i];
eq[62][i].in[1] <== 40;
eq[63][i] = IsEqual();
eq[63][i].in[0] <== in[i];
eq[63][i].in[1] <== 41;
eq[64][i] = IsEqual();
eq[64][i].in[0] <== in[i];
eq[64][i].in[1] <== 42;
eq[65][i] = IsEqual();
eq[65][i].in[0] <== in[i];
eq[65][i].in[1] <== 43;
eq[66][i] = IsEqual();
eq[66][i].in[0] <== in[i];
eq[66][i].in[1] <== 44;
eq[67][i] = IsEqual();
eq[67][i].in[0] <== in[i];
eq[67][i].in[1] <== 45;
eq[68][i] = IsEqual();
eq[68][i].in[0] <== in[i];
eq[68][i].in[1] <== 46;
eq[69][i] = IsEqual();
eq[69][i].in[0] <== in[i];
eq[69][i].in[1] <== 47;
eq[70][i] = IsEqual();
eq[70][i].in[0] <== in[i];
eq[70][i].in[1] <== 58;
eq[71][i] = IsEqual();
eq[71][i].in[0] <== in[i];
eq[71][i].in[1] <== 60;
eq[72][i] = IsEqual();
eq[72][i].in[0] <== in[i];
eq[72][i].in[1] <== 61;
eq[73][i] = IsEqual();
eq[73][i].in[0] <== in[i];
eq[73][i].in[1] <== 62;
eq[74][i] = IsEqual();
eq[74][i].in[0] <== in[i];
eq[74][i].in[1] <== 63;
eq[75][i] = IsEqual();
eq[75][i].in[0] <== in[i];
eq[75][i].in[1] <== 64;
and[9][i] = AND();
and[9][i].a <== states[i][3];
multi_or[3][i] = MultiOR(27);
multi_or[3][i].in[0] <== and[7][i].out;
multi_or[3][i].in[1] <== and[8][i].out;
multi_or[3][i].in[2] <== eq[51][i].out;
multi_or[3][i].in[3] <== eq[52][i].out;
multi_or[3][i].in[4] <== eq[53][i].out;
multi_or[3][i].in[5] <== eq[54][i].out;
multi_or[3][i].in[6] <== eq[55][i].out;
multi_or[3][i].in[7] <== eq[56][i].out;
multi_or[3][i].in[8] <== eq[57][i].out;
multi_or[3][i].in[9] <== eq[58][i].out;
multi_or[3][i].in[10] <== eq[59][i].out;
multi_or[3][i].in[11] <== eq[60][i].out;
multi_or[3][i].in[12] <== eq[61][i].out;
multi_or[3][i].in[13] <== eq[62][i].out;
multi_or[3][i].in[14] <== eq[63][i].out;
multi_or[3][i].in[15] <== eq[64][i].out;
multi_or[3][i].in[16] <== eq[65][i].out;
multi_or[3][i].in[17] <== eq[66][i].out;
multi_or[3][i].in[18] <== eq[67][i].out;
multi_or[3][i].in[19] <== eq[68][i].out;
multi_or[3][i].in[20] <== eq[69][i].out;
multi_or[3][i].in[21] <== eq[70][i].out;
multi_or[3][i].in[22] <== eq[71][i].out;
multi_or[3][i].in[23] <== eq[72][i].out;
multi_or[3][i].in[24] <== eq[73][i].out;
multi_or[3][i].in[25] <== eq[74][i].out;
multi_or[3][i].in[26] <== eq[75][i].out;
and[9][i].b <== multi_or[3][i].out;
lt[10][i] = LessThan(8);
lt[10][i].in[0] <== 64;
lt[10][i].in[1] <== in[i];
lt[11][i] = LessThan(8);
lt[11][i].in[0] <== in[i];
lt[11][i].in[1] <== 127;
and[10][i] = AND();
and[10][i].a <== lt[10][i].out;
and[10][i].b <== lt[11][i].out;
eq[76][i] = IsEqual();
eq[76][i].in[0] <== in[i];
eq[76][i].in[1] <== 9;
eq[77][i] = IsEqual();
eq[77][i].in[0] <== in[i];
eq[77][i].in[1] <== 10;
eq[78][i] = IsEqual();
eq[78][i].in[0] <== in[i];
eq[78][i].in[1] <== 13;
eq[79][i] = IsEqual();
eq[79][i].in[0] <== in[i];
eq[79][i].in[1] <== 32;
eq[80][i] = IsEqual();
eq[80][i].in[0] <== in[i];
eq[80][i].in[1] <== 33;
eq[81][i] = IsEqual();
eq[81][i].in[0] <== in[i];
eq[81][i].in[1] <== 34;
eq[82][i] = IsEqual();
eq[82][i].in[0] <== in[i];
eq[82][i].in[1] <== 35;
eq[83][i] = IsEqual();
eq[83][i].in[0] <== in[i];
eq[83][i].in[1] <== 36;
eq[84][i] = IsEqual();
eq[84][i].in[0] <== in[i];
eq[84][i].in[1] <== 37;
eq[85][i] = IsEqual();
eq[85][i].in[0] <== in[i];
eq[85][i].in[1] <== 38;
eq[86][i] = IsEqual();
eq[86][i].in[0] <== in[i];
eq[86][i].in[1] <== 39;
eq[87][i] = IsEqual();
eq[87][i].in[0] <== in[i];
eq[87][i].in[1] <== 40;
eq[88][i] = IsEqual();
eq[88][i].in[0] <== in[i];
eq[88][i].in[1] <== 41;
eq[89][i] = IsEqual();
eq[89][i].in[0] <== in[i];
eq[89][i].in[1] <== 42;
eq[90][i] = IsEqual();
eq[90][i].in[0] <== in[i];
eq[90][i].in[1] <== 43;
eq[91][i] = IsEqual();
eq[91][i].in[0] <== in[i];
eq[91][i].in[1] <== 44;
eq[92][i] = IsEqual();
eq[92][i].in[0] <== in[i];
eq[92][i].in[1] <== 45;
eq[93][i] = IsEqual();
eq[93][i].in[0] <== in[i];
eq[93][i].in[1] <== 46;
eq[94][i] = IsEqual();
eq[94][i].in[0] <== in[i];
eq[94][i].in[1] <== 47;
eq[95][i] = IsEqual();
eq[95][i].in[0] <== in[i];
eq[95][i].in[1] <== 58;
eq[96][i] = IsEqual();
eq[96][i].in[0] <== in[i];
eq[96][i].in[1] <== 60;
eq[97][i] = IsEqual();
eq[97][i].in[0] <== in[i];
eq[97][i].in[1] <== 61;
eq[98][i] = IsEqual();
eq[98][i].in[0] <== in[i];
eq[98][i].in[1] <== 62;
eq[99][i] = IsEqual();
eq[99][i].in[0] <== in[i];
eq[99][i].in[1] <== 63;
eq[100][i] = IsEqual();
eq[100][i].in[0] <== in[i];
eq[100][i].in[1] <== 64;
and[11][i] = AND();
and[11][i].a <== states[i][16];
multi_or[4][i] = MultiOR(26);
multi_or[4][i].in[0] <== and[10][i].out;
multi_or[4][i].in[1] <== eq[76][i].out;
multi_or[4][i].in[2] <== eq[77][i].out;
multi_or[4][i].in[3] <== eq[78][i].out;
multi_or[4][i].in[4] <== eq[79][i].out;
multi_or[4][i].in[5] <== eq[80][i].out;
multi_or[4][i].in[6] <== eq[81][i].out;
multi_or[4][i].in[7] <== eq[82][i].out;
multi_or[4][i].in[8] <== eq[83][i].out;
multi_or[4][i].in[9] <== eq[84][i].out;
multi_or[4][i].in[10] <== eq[85][i].out;
multi_or[4][i].in[11] <== eq[86][i].out;
multi_or[4][i].in[12] <== eq[87][i].out;
multi_or[4][i].in[13] <== eq[88][i].out;
multi_or[4][i].in[14] <== eq[89][i].out;
multi_or[4][i].in[15] <== eq[90][i].out;
multi_or[4][i].in[16] <== eq[91][i].out;
multi_or[4][i].in[17] <== eq[92][i].out;
multi_or[4][i].in[18] <== eq[93][i].out;
multi_or[4][i].in[19] <== eq[94][i].out;
multi_or[4][i].in[20] <== eq[95][i].out;
multi_or[4][i].in[21] <== eq[96][i].out;
multi_or[4][i].in[22] <== eq[97][i].out;
multi_or[4][i].in[23] <== eq[98][i].out;
multi_or[4][i].in[24] <== eq[99][i].out;
multi_or[4][i].in[25] <== eq[100][i].out;
and[11][i].b <== multi_or[4][i].out;
lt[12][i] = LessThan(8);
lt[12][i].in[0] <== 64;
lt[12][i].in[1] <== in[i];
lt[13][i] = LessThan(8);
lt[13][i].in[0] <== in[i];
lt[13][i].in[1] <== 127;
and[12][i] = AND();
and[12][i].a <== lt[12][i].out;
and[12][i].b <== lt[13][i].out;
eq[101][i] = IsEqual();
eq[101][i].in[0] <== in[i];
eq[101][i].in[1] <== 9;
eq[102][i] = IsEqual();
eq[102][i].in[0] <== in[i];
eq[102][i].in[1] <== 10;
eq[103][i] = IsEqual();
eq[103][i].in[0] <== in[i];
eq[103][i].in[1] <== 13;
eq[104][i] = IsEqual();
eq[104][i].in[0] <== in[i];
eq[104][i].in[1] <== 32;
eq[105][i] = IsEqual();
eq[105][i].in[0] <== in[i];
eq[105][i].in[1] <== 33;
eq[106][i] = IsEqual();
eq[106][i].in[0] <== in[i];
eq[106][i].in[1] <== 34;
eq[107][i] = IsEqual();
eq[107][i].in[0] <== in[i];
eq[107][i].in[1] <== 35;
eq[108][i] = IsEqual();
eq[108][i].in[0] <== in[i];
eq[108][i].in[1] <== 36;
eq[109][i] = IsEqual();
eq[109][i].in[0] <== in[i];
eq[109][i].in[1] <== 37;
eq[110][i] = IsEqual();
eq[110][i].in[0] <== in[i];
eq[110][i].in[1] <== 38;
eq[111][i] = IsEqual();
eq[111][i].in[0] <== in[i];
eq[111][i].in[1] <== 39;
eq[112][i] = IsEqual();
eq[112][i].in[0] <== in[i];
eq[112][i].in[1] <== 40;
eq[113][i] = IsEqual();
eq[113][i].in[0] <== in[i];
eq[113][i].in[1] <== 41;
eq[114][i] = IsEqual();
eq[114][i].in[0] <== in[i];
eq[114][i].in[1] <== 42;
eq[115][i] = IsEqual();
eq[115][i].in[0] <== in[i];
eq[115][i].in[1] <== 43;
eq[116][i] = IsEqual();
eq[116][i].in[0] <== in[i];
eq[116][i].in[1] <== 44;
eq[117][i] = IsEqual();
eq[117][i].in[0] <== in[i];
eq[117][i].in[1] <== 45;
eq[118][i] = IsEqual();
eq[118][i].in[0] <== in[i];
eq[118][i].in[1] <== 46;
eq[119][i] = IsEqual();
eq[119][i].in[0] <== in[i];
eq[119][i].in[1] <== 47;
eq[120][i] = IsEqual();
eq[120][i].in[0] <== in[i];
eq[120][i].in[1] <== 58;
eq[121][i] = IsEqual();
eq[121][i].in[0] <== in[i];
eq[121][i].in[1] <== 60;
eq[122][i] = IsEqual();
eq[122][i].in[0] <== in[i];
eq[122][i].in[1] <== 61;
eq[123][i] = IsEqual();
eq[123][i].in[0] <== in[i];
eq[123][i].in[1] <== 62;
eq[124][i] = IsEqual();
eq[124][i].in[0] <== in[i];
eq[124][i].in[1] <== 63;
eq[125][i] = IsEqual();
eq[125][i].in[0] <== in[i];
eq[125][i].in[1] <== 64;
and[13][i] = AND();
and[13][i].a <== states[i][21];
multi_or[5][i] = MultiOR(26);
multi_or[5][i].in[0] <== and[12][i].out;
multi_or[5][i].in[1] <== eq[101][i].out;
multi_or[5][i].in[2] <== eq[102][i].out;
multi_or[5][i].in[3] <== eq[103][i].out;
multi_or[5][i].in[4] <== eq[104][i].out;
multi_or[5][i].in[5] <== eq[105][i].out;
multi_or[5][i].in[6] <== eq[106][i].out;
multi_or[5][i].in[7] <== eq[107][i].out;
multi_or[5][i].in[8] <== eq[108][i].out;
multi_or[5][i].in[9] <== eq[109][i].out;
multi_or[5][i].in[10] <== eq[110][i].out;
multi_or[5][i].in[11] <== eq[111][i].out;
multi_or[5][i].in[12] <== eq[112][i].out;
multi_or[5][i].in[13] <== eq[113][i].out;
multi_or[5][i].in[14] <== eq[114][i].out;
multi_or[5][i].in[15] <== eq[115][i].out;
multi_or[5][i].in[16] <== eq[116][i].out;
multi_or[5][i].in[17] <== eq[117][i].out;
multi_or[5][i].in[18] <== eq[118][i].out;
multi_or[5][i].in[19] <== eq[119][i].out;
multi_or[5][i].in[20] <== eq[120][i].out;
multi_or[5][i].in[21] <== eq[121][i].out;
multi_or[5][i].in[22] <== eq[122][i].out;
multi_or[5][i].in[23] <== eq[123][i].out;
multi_or[5][i].in[24] <== eq[124][i].out;
multi_or[5][i].in[25] <== eq[125][i].out;
and[13][i].b <== multi_or[5][i].out;
multi_or[6][i] = MultiOR(4);
multi_or[6][i].in[0] <== and[6][i].out;
multi_or[6][i].in[1] <== and[9][i].out;
multi_or[6][i].in[2] <== and[11][i].out;
multi_or[6][i].in[3] <== and[13][i].out;
states[i+1][3] <== multi_or[6][i].out;
state_changed[i].in[2] <== states[i+1][3];
eq[126][i] = IsEqual();
eq[126][i].in[0] <== in[i];
eq[126][i].in[1] <== 100;
and[14][i] = AND();
and[14][i].a <== states[i][0];
and[14][i].b <== eq[126][i].out;
states[i+1][4] <== and[14][i].out;
state_changed[i].in[3] <== states[i+1][4];
eq[127][i] = IsEqual();
eq[127][i].in[0] <== in[i];
eq[127][i].in[1] <== 107;
and[15][i] = AND();
and[15][i].a <== states[i][4];
and[15][i].b <== eq[127][i].out;
states[i+1][5] <== and[15][i].out;
state_changed[i].in[4] <== states[i+1][5];
eq[128][i] = IsEqual();
eq[128][i].in[0] <== in[i];
eq[128][i].in[1] <== 105;
and[16][i] = AND();
and[16][i].a <== states[i][5];
and[16][i].b <== eq[128][i].out;
states[i+1][6] <== and[16][i].out;
state_changed[i].in[5] <== states[i+1][6];
eq[129][i] = IsEqual();
eq[129][i].in[0] <== in[i];
eq[129][i].in[1] <== 109;
and[17][i] = AND();
and[17][i].a <== states[i][6];
and[17][i].b <== eq[129][i].out;
states[i+1][7] <== and[17][i].out;
state_changed[i].in[6] <== states[i+1][7];
eq[130][i] = IsEqual();
eq[130][i].in[0] <== in[i];
eq[130][i].in[1] <== 45;
and[18][i] = AND();
and[18][i].a <== states[i][7];
and[18][i].b <== eq[130][i].out;
states[i+1][8] <== and[18][i].out;
state_changed[i].in[7] <== states[i+1][8];
eq[131][i] = IsEqual();
eq[131][i].in[0] <== in[i];
eq[131][i].in[1] <== 59;
and[19][i] = AND();
and[19][i].a <== states[i][3];
and[19][i].b <== eq[131][i].out;
states[i+1][9] <== and[19][i].out;
state_changed[i].in[8] <== states[i+1][9];
eq[132][i] = IsEqual();
eq[132][i].in[0] <== in[i];
eq[132][i].in[1] <== 115;
and[20][i] = AND();
and[20][i].a <== states[i][8];
and[20][i].b <== eq[132][i].out;
states[i+1][10] <== and[20][i].out;
state_changed[i].in[9] <== states[i+1][10];
eq[133][i] = IsEqual();
eq[133][i].in[0] <== in[i];
eq[133][i].in[1] <== 105;
and[21][i] = AND();
and[21][i].a <== states[i][10];
and[21][i].b <== eq[133][i].out;
states[i+1][11] <== and[21][i].out;
state_changed[i].in[10] <== states[i+1][11];
eq[134][i] = IsEqual();
eq[134][i].in[0] <== in[i];
eq[134][i].in[1] <== 103;
and[22][i] = AND();
and[22][i].a <== states[i][11];
and[22][i].b <== eq[134][i].out;
states[i+1][12] <== and[22][i].out;
state_changed[i].in[11] <== states[i+1][12];
eq[135][i] = IsEqual();
eq[135][i].in[0] <== in[i];
eq[135][i].in[1] <== 32;
and[23][i] = AND();
and[23][i].a <== states[i][9];
and[23][i].b <== eq[135][i].out;
eq[136][i] = IsEqual();
eq[136][i].in[0] <== in[i];
eq[136][i].in[1] <== 32;
and[24][i] = AND();
and[24][i].a <== states[i][24];
and[24][i].b <== eq[136][i].out;
multi_or[7][i] = MultiOR(2);
multi_or[7][i].in[0] <== and[23][i].out;
multi_or[7][i].in[1] <== and[24][i].out;
states[i+1][13] <== multi_or[7][i].out;
state_changed[i].in[12] <== states[i+1][13];
eq[137][i] = IsEqual();
eq[137][i].in[0] <== in[i];
eq[137][i].in[1] <== 110;
and[25][i] = AND();
and[25][i].a <== states[i][12];
and[25][i].b <== eq[137][i].out;
states[i+1][14] <== and[25][i].out;
state_changed[i].in[13] <== states[i+1][14];
eq[138][i] = IsEqual();
eq[138][i].in[0] <== in[i];
eq[138][i].in[1] <== 116;
and[26][i] = AND();
and[26][i].a <== states[i][13];
and[26][i].b <== eq[138][i].out;
states[i+1][15] <== and[26][i].out;
state_changed[i].in[14] <== states[i+1][15];
eq[139][i] = IsEqual();
eq[139][i].in[0] <== in[i];
eq[139][i].in[1] <== 61;
and[27][i] = AND();
and[27][i].a <== states[i][15];
and[27][i].b <== eq[139][i].out;
states[i+1][16] <== and[27][i].out;
state_changed[i].in[15] <== states[i+1][16];
eq[140][i] = IsEqual();
eq[140][i].in[0] <== in[i];
eq[140][i].in[1] <== 97;
and[28][i] = AND();
and[28][i].a <== states[i][14];
and[28][i].b <== eq[140][i].out;
states[i+1][17] <== and[28][i].out;
state_changed[i].in[16] <== states[i+1][17];
eq[141][i] = IsEqual();
eq[141][i].in[0] <== in[i];
eq[141][i].in[1] <== 116;
and[29][i] = AND();
and[29][i].a <== states[i][17];
and[29][i].b <== eq[141][i].out;
states[i+1][18] <== and[29][i].out;
state_changed[i].in[17] <== states[i+1][18];
eq[142][i] = IsEqual();
eq[142][i].in[0] <== in[i];
eq[142][i].in[1] <== 117;
and[30][i] = AND();
and[30][i].a <== states[i][18];
and[30][i].b <== eq[142][i].out;
states[i+1][19] <== and[30][i].out;
state_changed[i].in[18] <== states[i+1][19];
eq[143][i] = IsEqual();
eq[143][i].in[0] <== in[i];
eq[143][i].in[1] <== 114;
and[31][i] = AND();
and[31][i].a <== states[i][19];
and[31][i].b <== eq[143][i].out;
states[i+1][20] <== and[31][i].out;
state_changed[i].in[19] <== states[i+1][20];
lt[14][i] = LessThan(8);
lt[14][i].in[0] <== 47;
lt[14][i].in[1] <== in[i];
lt[15][i] = LessThan(8);
lt[15][i].in[0] <== in[i];
lt[15][i].in[1] <== 58;
and[32][i] = AND();
and[32][i].a <== lt[14][i].out;
and[32][i].b <== lt[15][i].out;
and[33][i] = AND();
and[33][i].a <== states[i][16];
and[33][i].b <== and[32][i].out;
lt[16][i] = LessThan(8);
lt[16][i].in[0] <== 47;
lt[16][i].in[1] <== in[i];
lt[17][i] = LessThan(8);
lt[17][i].in[0] <== in[i];
lt[17][i].in[1] <== 58;
and[34][i] = AND();
and[34][i].a <== lt[16][i].out;
and[34][i].b <== lt[17][i].out;
and[35][i] = AND();
and[35][i].a <== states[i][21];
and[35][i].b <== and[34][i].out;
multi_or[8][i] = MultiOR(2);
multi_or[8][i].in[0] <== and[33][i].out;
multi_or[8][i].in[1] <== and[35][i].out;
states[i+1][21] <== multi_or[8][i].out;
state_changed[i].in[20] <== states[i+1][21];
eq[144][i] = IsEqual();
eq[144][i].in[0] <== in[i];
eq[144][i].in[1] <== 101;
and[36][i] = AND();
and[36][i].a <== states[i][20];
and[36][i].b <== eq[144][i].out;
states[i+1][22] <== and[36][i].out;
state_changed[i].in[21] <== states[i+1][22];
eq[145][i] = IsEqual();
eq[145][i].in[0] <== in[i];
eq[145][i].in[1] <== 58;
and[37][i] = AND();
and[37][i].a <== states[i][22];
and[37][i].b <== eq[145][i].out;
states[i+1][23] <== and[37][i].out;
state_changed[i].in[22] <== states[i+1][23];
eq[146][i] = IsEqual();
eq[146][i].in[0] <== in[i];
eq[146][i].in[1] <== 59;
and[38][i] = AND();
and[38][i].a <== states[i][21];
and[38][i].b <== eq[146][i].out;
states[i+1][24] <== and[38][i].out;
state_changed[i].in[23] <== states[i+1][24];
states[i+1][0] <== 1 - state_changed[i].out;
}
component final_state_result = MultiOR(num_bytes+1);
for (var i = 0; i <= num_bytes; i++) {
final_state_result.in[i] <== states[i][24];
}
out <== final_state_result.out;
signal is_consecutive[msg_bytes+1][2];
is_consecutive[msg_bytes][1] <== 1;
for (var i = 0; i < msg_bytes; i++) {
is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][24] * (1 - is_consecutive[msg_bytes-i][1]) + is_consecutive[msg_bytes-i][1];
is_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];
}
signal is_substr0[msg_bytes][3];
signal is_reveal0[msg_bytes];
signal output reveal0[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr0[i][0] <== 0;
is_substr0[i][1] <== is_substr0[i][0] + states[i+1][21] * states[i+2][21];
is_substr0[i][2] <== is_substr0[i][1] + states[i+1][16] * states[i+2][21];
is_reveal0[i] <== is_substr0[i][2] * is_consecutive[i][1];
reveal0[i] <== in[i+1] * is_reveal0[i];
}
}

View File

@@ -0,0 +1,48 @@
pragma circom 2.0.3;
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/gates.circom";
// template MultiOROld(n) {
// signal input in[n];
// signal output out;
// component or1;
// component or2;
// component ors[2];
// if (n==1) {
// out <== in[0];
// } else if (n==2) {
// or1 = OR();
// or1.a <== in[0];
// or1.b <== in[1];
// out <== or1.out;
// } else {
// or2 = OR();
// var n1 = n\2;
// var n2 = n-n\2;
// ors[0] = MultiOR(n1);
// ors[1] = MultiOR(n2);
// var i;
// for (i=0; i<n1; i++) ors[0].in[i] <== in[i];
// for (i=0; i<n2; i++) ors[1].in[i] <== in[n1+i];
// or2.a <== ors[0].out;
// or2.b <== ors[1].out;
// out <== or2.out;
// }
// }
template MultiOR(n) {
signal input in[n];
signal output out;
signal sums[n];
sums[0] <== in[0];
for (var i = 1; i < n; i++) {
sums[i] <== sums[i-1] + in[i];
}
component is_zero = IsZero();
is_zero.in <== sums[n-1];
out <== 1 - is_zero.out;
}

View File

@@ -0,0 +1,35 @@
{
"name": "zk-regex-circom",
"version": "1.0.0",
"license": "MIT",
"scripts": {
"test": "jest"
},
"dependencies": {
"commander": "^11.0.0",
"snarkjs": "^0.7.0"
},
"devDependencies": {
"@types/jest": "^29.5.4",
"chai": "^4.3.7",
"circom_tester": "^0.0.19",
"circomlib": "^2.0.5",
"circomlibjs": "^0.1.2",
"ffjavascript": "^0.2.59",
"jest": "^29.5.0",
"mocha": "^10.2.0",
"ts-jest": "^29.1.1",
"typescript": "^4.8.3"
},
"babel": {
"presets": [
[
"@babel/preset-env"
],
"@babel/preset-typescript",
[
"jest"
]
]
}
}

View File

@@ -0,0 +1,180 @@
pragma circom 2.1.5;
include "zk-regex-circom/circuits/regex_helpers.circom";
template SimpleRegex(msg_bytes) {
signal input msg[msg_bytes];
signal output out;
var num_bytes = msg_bytes+1;
signal in[num_bytes];
in[0]<==128;
for (var i = 0; i < msg_bytes; i++) {
in[i+1] <== msg[i];
}
component eq[14][num_bytes];
component and[11][num_bytes];
component multi_or[5][num_bytes];
signal states[num_bytes+1][10];
component state_changed[num_bytes];
states[0][0] <== 1;
for (var i = 1; i < 10; i++) {
states[0][i] <== 0;
}
for (var i = 0; i < num_bytes; i++) {
state_changed[i] = MultiOR(9);
eq[0][i] = IsEqual();
eq[0][i].in[0] <== in[i];
eq[0][i].in[1] <== 49;
and[0][i] = AND();
and[0][i].a <== states[i][0];
and[0][i].b <== eq[0][i].out;
states[i+1][1] <== and[0][i].out;
state_changed[i].in[0] <== states[i+1][1];
eq[1][i] = IsEqual();
eq[1][i].in[0] <== in[i];
eq[1][i].in[1] <== 61;
and[1][i] = AND();
and[1][i].a <== states[i][1];
and[1][i].b <== eq[1][i].out;
states[i+1][2] <== and[1][i].out;
state_changed[i].in[1] <== states[i+1][2];
eq[2][i] = IsEqual();
eq[2][i].in[0] <== in[i];
eq[2][i].in[1] <== 97;
eq[3][i] = IsEqual();
eq[3][i].in[0] <== in[i];
eq[3][i].in[1] <== 98;
and[2][i] = AND();
and[2][i].a <== states[i][2];
multi_or[0][i] = MultiOR(2);
multi_or[0][i].in[0] <== eq[2][i].out;
multi_or[0][i].in[1] <== eq[3][i].out;
and[2][i].b <== multi_or[0][i].out;
states[i+1][3] <== and[2][i].out;
state_changed[i].in[2] <== states[i+1][3];
eq[4][i] = IsEqual();
eq[4][i].in[0] <== in[i];
eq[4][i].in[1] <== 32;
and[3][i] = AND();
and[3][i].a <== states[i][3];
and[3][i].b <== eq[4][i].out;
states[i+1][4] <== and[3][i].out;
state_changed[i].in[3] <== states[i+1][4];
eq[5][i] = IsEqual();
eq[5][i].in[0] <== in[i];
eq[5][i].in[1] <== 50;
and[4][i] = AND();
and[4][i].a <== states[i][4];
and[4][i].b <== eq[5][i].out;
eq[6][i] = IsEqual();
eq[6][i].in[0] <== in[i];
eq[6][i].in[1] <== 50;
and[5][i] = AND();
and[5][i].a <== states[i][8];
and[5][i].b <== eq[6][i].out;
multi_or[1][i] = MultiOR(2);
multi_or[1][i].in[0] <== and[4][i].out;
multi_or[1][i].in[1] <== and[5][i].out;
states[i+1][5] <== multi_or[1][i].out;
state_changed[i].in[4] <== states[i+1][5];
eq[7][i] = IsEqual();
eq[7][i].in[0] <== in[i];
eq[7][i].in[1] <== 61;
and[6][i] = AND();
and[6][i].a <== states[i][5];
and[6][i].b <== eq[7][i].out;
states[i+1][6] <== and[6][i].out;
state_changed[i].in[5] <== states[i+1][6];
eq[8][i] = IsEqual();
eq[8][i].in[0] <== in[i];
eq[8][i].in[1] <== 98;
eq[9][i] = IsEqual();
eq[9][i].in[0] <== in[i];
eq[9][i].in[1] <== 99;
and[7][i] = AND();
and[7][i].a <== states[i][6];
multi_or[2][i] = MultiOR(2);
multi_or[2][i].in[0] <== eq[8][i].out;
multi_or[2][i].in[1] <== eq[9][i].out;
and[7][i].b <== multi_or[2][i].out;
eq[10][i] = IsEqual();
eq[10][i].in[0] <== in[i];
eq[10][i].in[1] <== 98;
eq[11][i] = IsEqual();
eq[11][i].in[0] <== in[i];
eq[11][i].in[1] <== 99;
and[8][i] = AND();
and[8][i].a <== states[i][7];
multi_or[3][i] = MultiOR(2);
multi_or[3][i].in[0] <== eq[10][i].out;
multi_or[3][i].in[1] <== eq[11][i].out;
and[8][i].b <== multi_or[3][i].out;
multi_or[4][i] = MultiOR(2);
multi_or[4][i].in[0] <== and[7][i].out;
multi_or[4][i].in[1] <== and[8][i].out;
states[i+1][7] <== multi_or[4][i].out;
state_changed[i].in[6] <== states[i+1][7];
eq[12][i] = IsEqual();
eq[12][i].in[0] <== in[i];
eq[12][i].in[1] <== 32;
and[9][i] = AND();
and[9][i].a <== states[i][7];
and[9][i].b <== eq[12][i].out;
states[i+1][8] <== and[9][i].out;
state_changed[i].in[7] <== states[i+1][8];
eq[13][i] = IsEqual();
eq[13][i].in[0] <== in[i];
eq[13][i].in[1] <== 100;
and[10][i] = AND();
and[10][i].a <== states[i][8];
and[10][i].b <== eq[13][i].out;
states[i+1][9] <== and[10][i].out;
state_changed[i].in[8] <== states[i+1][9];
states[i+1][0] <== 1 - state_changed[i].out;
}
component final_state_result = MultiOR(num_bytes+1);
for (var i = 0; i <= num_bytes; i++) {
final_state_result.in[i] <== states[i][9];
}
out <== final_state_result.out;
signal is_consecutive[msg_bytes+1][2];
is_consecutive[msg_bytes][1] <== 1;
for (var i = 0; i < msg_bytes; i++) {
is_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][9] * (1 - is_consecutive[msg_bytes-i][1]) + is_consecutive[msg_bytes-i][1];
is_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];
}
signal is_substr0[msg_bytes][2];
signal is_reveal0[msg_bytes];
signal output reveal0[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr0[i][0] <== 0;
is_substr0[i][1] <== is_substr0[i][0] + states[i+1][2] * states[i+2][3];
is_reveal0[i] <== is_substr0[i][1] * is_consecutive[i][1];
reveal0[i] <== in[i+1] * is_reveal0[i];
}
signal is_substr1[msg_bytes][3];
signal is_reveal1[msg_bytes];
signal output reveal1[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr1[i][0] <== 0;
is_substr1[i][1] <== is_substr1[i][0] + states[i+1][7] * states[i+2][7];
is_substr1[i][2] <== is_substr1[i][1] + states[i+1][6] * states[i+2][7];
is_reveal1[i] <== is_substr1[i][2] * is_consecutive[i][1];
reveal1[i] <== in[i+1] * is_reveal1[i];
}
signal is_substr2[msg_bytes][2];
signal is_reveal2[msg_bytes];
signal output reveal2[msg_bytes];
for (var i = 0; i < msg_bytes; i++) {
is_substr2[i][0] <== 0;
is_substr2[i][1] <== is_substr2[i][0] + states[i+1][8] * states[i+2][9];
is_reveal2[i] <== is_substr2[i][1] * is_consecutive[i][1];
reveal2[i] <== in[i+1] * is_reveal2[i];
}
}

View File

@@ -0,0 +1,26 @@
{
"transitions": [
[
[
2,
3
]
],
[
[
6,
7
],
[
7,
7
]
],
[
[
8,
9
]
]
]
}

View File

@@ -0,0 +1,3 @@
include "../../circuits/common/email_addr_regex.circom";
component main = EmailAddrRegex(256);

View File

@@ -0,0 +1,3 @@
include "../../circuits/common/email_domain_regex.circom";
component main = EmailDomainRegex(256);

View File

@@ -0,0 +1,3 @@
include "../../circuits/common/from_addr_regex.circom";
component main = FromAddrRegex(1024);

View File

@@ -0,0 +1,3 @@
include "./simple_regex.circom";
// 1=(a|b) (2=(b|c)+ )+d
component main = SimpleRegex(64);

View File

@@ -0,0 +1,3 @@
include "../../circuits/common/subject_all_regex.circom";
component main = SubjectAllRegex(256);

View File

@@ -0,0 +1,3 @@
include "../../circuits/common/timestamp_regex.circom";
component main = TimestampRegex(1024);

View File

@@ -0,0 +1,49 @@
const ff = require('ffjavascript');
const stringifyBigInts = ff.utils.stringifyBigInts;
const circom_tester = require("circom_tester");
const wasm_tester = circom_tester.wasm;
import * as path from "path";
const p = "21888242871839275222246405745257275088548364400416034343698204186575808495617";
const field = new ff.F1Field(p);
const apis = require("../../apis");
const option = {
include: path.join(__dirname, "../../../node_modules")
};
import { readFileSync } from "fs";
jest.setTimeout(120000);
describe("Email Address Regex", () => {
it("only an email address", async () => {
const emailAddr = "suegamisora@gmail.com";
const paddedEmailAddr = apis.padString(emailAddr, 256);
const circuitInputs = {
msg: paddedEmailAddr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_email_addr_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
expect(1n).toEqual(witness[1]);
for (let idx = 0; idx < emailAddr.length; ++idx) {
expect(BigInt(paddedEmailAddr[idx])).toEqual(witness[2 + idx]);
}
});
it("with a prefix", async () => {
const prefix = "subject:";
const emailAddr = "suegamisora@gmail.com";
const string = prefix + emailAddr;
console.log(string);
const paddedStr = apis.padString(string, 256);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_email_addr_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
expect(1n).toEqual(witness[1]);
const prefixIdx = apis.extractSubstrIdxes(string, readFileSync(path.join(__dirname, "../circuits/common/email_addr.json"), "utf8"))[0][0];
for (let idx = 0; idx < emailAddr.length; ++idx) {
expect(BigInt(paddedStr[prefixIdx + idx])).toEqual(witness[2 + prefixIdx + idx]);
}
});
});

View File

@@ -0,0 +1,35 @@
const ff = require('ffjavascript');
const stringifyBigInts = ff.utils.stringifyBigInts;
const circom_tester = require("circom_tester");
const wasm_tester = circom_tester.wasm;
import * as path from "path";
const p = "21888242871839275222246405745257275088548364400416034343698204186575808495617";
const field = new ff.F1Field(p);
const apis = require("../../apis");
const option = {
include: path.join(__dirname, "../../../node_modules")
};
import { readFileSync } from "fs";
jest.setTimeout(120000);
describe("Email Domain Regex", () => {
it("test a regex of an email domain", async () => {
const emailAddr = "suegamisora@gmail.com";
const paddedEmailAddr = apis.padString(emailAddr, 256);
const revealed = "gmail.com";
const circuitInputs = {
msg: paddedEmailAddr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_email_domain_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
expect(1n).toEqual(witness[1]);
for (let idx = 0; idx < 12; ++idx) {
expect(0n).toEqual(witness[2 + idx]);
}
const prefixIdx = apis.extractSubstrIdxes(emailAddr, readFileSync(path.join(__dirname, "../circuits/common/email_domain.json"), "utf8"))[0][0];
for (let idx = 0; idx < revealed.length; ++idx) {
expect(BigInt(paddedEmailAddr[prefixIdx + idx])).toEqual(witness[2 + prefixIdx + idx]);
}
});
});

View File

@@ -0,0 +1,90 @@
const ff = require('ffjavascript');
const stringifyBigInts = ff.utils.stringifyBigInts;
const circom_tester = require("circom_tester");
const wasm_tester = circom_tester.wasm;
import * as path from "path";
const p = "21888242871839275222246405745257275088548364400416034343698204186575808495617";
const field = new ff.F1Field(p);
const apis = require("../../apis");
const option = {
include: path.join(__dirname, "../../../node_modules")
};
import { readFileSync } from "fs";
jest.setTimeout(120000);
describe("From Addr Regex", () => {
it("from field from beginning case 1", async () => {
const fromStr = "from:suegamisora@gmail.com\r\n";
const revealed = "suegamisora@gmail.com";
const paddedStr = apis.padString(fromStr, 1024);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_from_addr_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const prefixIdx = apis.extractSubstrIdxes(fromStr, readFileSync(path.join(__dirname, "../circuits/common/from_addr.json"), "utf8"))[0][0];
for (let idx = 0; idx < revealed.length; ++idx) {
expect(BigInt(paddedStr[prefixIdx + idx])).toEqual(witness[2 + prefixIdx + idx]);
}
});
it("from field from beginning case 2", async () => {
const fromStr = "from:Sora Suegami <suegamisora@gmail.com>\r\n";
const revealed = "suegamisora@gmail.com";
// const prefixLen = "from:Sora Suegami <".length;
const paddedStr = apis.padString(fromStr, 1024);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_from_addr_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const prefixIdx = apis.extractSubstrIdxes(fromStr, readFileSync(path.join(__dirname, "../circuits/common/from_addr.json"), "utf8"))[0][0];
for (let idx = 0; idx < revealed.length; ++idx) {
expect(BigInt(paddedStr[prefixIdx + idx])).toEqual(witness[2 + prefixIdx + idx]);
}
});
it("from field after new line case 1", async () => {
const fromStr = "dummy\r\nfrom:suegamisora@gmail.com\r\n";
const revealed = "suegamisora@gmail.com";
// const prefixLen = "dummy\r\nfrom:".length;
const paddedStr = apis.padString(fromStr, 1024);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_from_addr_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const prefixIdx = apis.extractSubstrIdxes(fromStr, readFileSync(path.join(__dirname, "../circuits/common/from_addr.json"), "utf8"))[0][0];
for (let idx = 0; idx < revealed.length; ++idx) {
expect(BigInt(paddedStr[prefixIdx + idx])).toEqual(witness[2 + prefixIdx + idx]);
}
});
it("from field after new line case 2", async () => {
const fromStr = "dummy\r\nfrom:Sora Suegami <suegamisora@gmail.com>\r\n";
const revealed = "suegamisora@gmail.com";
// const prefixLen = "dummy\r\nfrom:Sora Suegami <".length;
const paddedStr = apis.padString(fromStr, 1024);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_from_addr_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const prefixIdx = apis.extractSubstrIdxes(fromStr, readFileSync(path.join(__dirname, "../circuits/common/from_addr.json"), "utf8"))[0][0];
for (let idx = 0; idx < revealed.length; ++idx) {
expect(BigInt(paddedStr[prefixIdx + idx])).toEqual(witness[2 + prefixIdx + idx]);
}
});
});

View File

@@ -0,0 +1,84 @@
const ff = require('ffjavascript');
const stringifyBigInts = ff.utils.stringifyBigInts;
const circom_tester = require("circom_tester");
const wasm_tester = circom_tester.wasm;
import * as path from "path";
const p = "21888242871839275222246405745257275088548364400416034343698204186575808495617";
const field = new ff.F1Field(p);
const apis = require("../../apis");
const option = {
include: path.join(__dirname, "../../../node_modules")
};
jest.setTimeout(120000);
describe("Simple Regex", () => {
it("case 1", async () => {
const input = "1=a 2=b d";
const paddedStr = apis.padString(input, 64);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_simple_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const revealedIdx = [[2], [6], [8]];
for (let substr_idx = 0; substr_idx < 3; ++substr_idx) {
for (let idx = 0; idx < 64; ++idx) {
if (revealedIdx[substr_idx].includes(idx)) {
expect(BigInt(paddedStr[idx])).toEqual(witness[2 + 64 * substr_idx + idx]);
} else {
expect(0n).toEqual(witness[2 + 64 * substr_idx + idx]);
}
}
}
});
it("case 2", async () => {
const input = "1=a 2=b 2=bc 2=c d";
const paddedStr = apis.padString(input, 64);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_simple_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const revealedIdx = [[2], [6, 10, 11, 15], [17]];
for (let substr_idx = 0; substr_idx < 3; ++substr_idx) {
for (let idx = 0; idx < 64; ++idx) {
if (revealedIdx[substr_idx].includes(idx)) {
expect(BigInt(paddedStr[idx])).toEqual(witness[2 + 64 * substr_idx + idx]);
} else {
expect(0n).toEqual(witness[2 + 64 * substr_idx + idx]);
}
}
}
});
it("case 3", async () => {
const input = "1=a 2=b 2=bc 2=c da 1=a 2=cb 2=c 2=b dd";
const paddedStr = apis.padString(input, 64);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_simple_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
expect(1n).toEqual(witness[1]);
const revealedIdx = [[2, 22], [6, 10, 11, 15, 26, 27, 31, 35], [17, 37]];
for (let substr_idx = 0; substr_idx < 3; ++substr_idx) {
for (let idx = 0; idx < 64; ++idx) {
if (revealedIdx[substr_idx].includes(idx)) {
expect(BigInt(paddedStr[idx])).toEqual(witness[2 + 64 * substr_idx + idx]);
} else {
expect(0n).toEqual(witness[2 + 64 * substr_idx + idx]);
}
}
}
});
});

View File

@@ -0,0 +1,54 @@
const ff = require('ffjavascript');
const stringifyBigInts = ff.utils.stringifyBigInts;
const circom_tester = require("circom_tester");
const wasm_tester = circom_tester.wasm;
import * as path from "path";
const p = "21888242871839275222246405745257275088548364400416034343698204186575808495617";
const field = new ff.F1Field(p);
const apis = require("../../apis");
const option = {
include: path.join(__dirname, "../../../node_modules")
};
import { readFileSync } from "fs";
jest.setTimeout(120000);
describe("Subject All Regex", () => {
it("subject from beginning", async () => {
const subjectStr = "subject:This is a test.\r\n";
const revealed = "This is a test.";
// const prefixLen = "subject:".length;
const paddedStr = apis.padString(subjectStr, 256);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_subject_all_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const prefixIdx = apis.extractSubstrIdxes(subjectStr, readFileSync(path.join(__dirname, "../circuits/common/subject_all.json"), "utf8"))[0][0];
for (let idx = 0; idx < revealed.length; ++idx) {
expect(BigInt(paddedStr[prefixIdx + idx])).toEqual(witness[2 + prefixIdx + idx]);
}
});
it("subject after new line", async () => {
const subjectStr = "dummy\r\nsubject:This is a test.\r\n";
const revealed = "This is a test.";
// const prefixLen = "dummy\r\nsubject:".length;
const paddedStr = apis.padString(subjectStr, 256);
console.log(paddedStr);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_subject_all_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
// console.log(witness);
expect(1n).toEqual(witness[1]);
const prefixIdx = apis.extractSubstrIdxes(subjectStr, readFileSync(path.join(__dirname, "../circuits/common/subject_all.json"), "utf8"))[0][0];
for (let idx = 0; idx < revealed.length; ++idx) {
expect(BigInt(paddedStr[prefixIdx + idx])).toEqual(witness[2 + prefixIdx + idx]);
}
});
});

View File

@@ -0,0 +1,32 @@
const ff = require('ffjavascript');
const stringifyBigInts = ff.utils.stringifyBigInts;
const circom_tester = require("circom_tester");
const wasm_tester = circom_tester.wasm;
import * as path from "path";
import { readFileSync } from "fs";
const p = "21888242871839275222246405745257275088548364400416034343698204186575808495617";
const field = new ff.F1Field(p);
const apis = require("../../apis");
const option = {
include: path.join(__dirname, "../../../node_modules")
};
jest.setTimeout(120000);
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 revealed = "1694989812";
const paddedStr = apis.padString(signatureField, 1024);
const circuitInputs = {
msg: paddedStr,
};
const circuit = await wasm_tester(path.join(__dirname, "./circuits/test_timestamp_regex.circom"), option);
const witness = await circuit.calculateWitness(circuitInputs);
await circuit.checkConstraints(witness);
expect(1n).toEqual(witness[1]);
const timestampIdx = apis.extractSubstrIdxes(signatureField, readFileSync(path.join(__dirname, "../circuits/common/timestamp.json"), "utf8"))[0][0];
for (let idx = 0; idx < revealed.length; ++idx) {
expect(BigInt(paddedStr[timestampIdx + idx])).toEqual(witness[2 + timestampIdx + idx]);
}
});
});

View File

@@ -0,0 +1,38 @@
[package]
name = "zk-regex-compiler"
version = "0.1.0"
authors = ["Sora Suegami"]
license = "MIT"
edition = "2018"
# exclude = ["index.node"]
[[bin]]
name = "zk-regex"
path = "src/bin/compiler.rs"
[lib]
crate-type = ["rlib", "cdylib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tabbycat = { version = "0.1", features = ["attributes"], optional = true }
fancy-regex = "0.11.0"
petgraph = "0.6.3"
graph-cycles = "0.1.0"
thiserror = "1.0.40"
serde_json = "1.0.95"
serde = { version = "1.0.159", features = ["derive"] }
js-sandbox = { version = "0.2.0-rc.1", git = "https://github.com/Bromeon/js-sandbox.git", rev = "cd256ef" }
itertools = "0.10.3"
clap = { version = "=4.2.1", features = ["derive"] }
[dependencies.neon]
version = "0.10"
default-features = false
features = ["napi-6"]
optional = true
[features]
default = ["node"]
node = ["neon"]

119
packages/compiler/README.md Normal file
View File

@@ -0,0 +1,119 @@
# zk-regex-apis
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).
You can install the project with npm. In the project directory, run:
```sh
$ npm install
```
This fully installs the project, including installing any dependencies and running the build.
## Building zk-regex-apis
If you have already installed the project and only want to run the build, run:
```sh
$ npm run build
```
This command uses the [cargo-cp-artifact](https://github.com/neon-bindings/cargo-cp-artifact) utility to run the Rust build and copy the built library into `./index.node`.
## Exploring zk-regex-apis
After building zk-regex-apis, you can explore its exports at the Node REPL:
```sh
$ npm install
$ node
> require('.').hello()
"hello node"
```
## Available Scripts
In the project directory, you can run:
### `npm install`
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):
```
npm run build -- --feature=beetle
```
#### `npm build-debug`
Alias for `npm build`.
#### `npm build-release`
Same as [`npm build`](#npm-build) but, builds the module with the [`release`](https://doc.rust-lang.org/cargo/reference/profiles.html#release) profile. Release builds will compile slower, but run faster.
### `npm test`
Runs the unit tests by calling `cargo test`. You can learn more about [adding tests to your Rust code](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) from the [Rust book](https://doc.rust-lang.org/book/).
## Project Layout
The directory structure of this project is:
```
zk-regex-apis/
├── Cargo.toml
├── README.md
├── index.node
├── package.json
├── src/
| └── lib.rs
└── target/
```
### Cargo.toml
The Cargo [manifest file](https://doc.rust-lang.org/cargo/reference/manifest.html), which informs the `cargo` command.
### README.md
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.
### src/
The directory tree containing the Rust source code for the project.
### src/lib.rs
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).

View File

@@ -0,0 +1,18 @@
{
"name": "zk-regex-compiler",
"version": "0.1.0",
"description": "",
"main": "index.node",
"scripts": {
"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-release",
"test": "cargo test"
},
"author": "",
"license": "MIT",
"devDependencies": {
"cargo-cp-artifact": "^0.1"
}
}

View File

@@ -0,0 +1,125 @@
use std::{
fs::File,
path::{Path, PathBuf},
};
use clap::{Parser, Subcommand};
use itertools::Itertools;
use zk_regex_compiler::*;
#[derive(Parser, Debug, Clone)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Debug, Subcommand, Clone)]
enum Commands {
Decomposed {
#[arg(short, long)]
decomposed_regex_path: String,
#[arg(short, long)]
halo2_dir_path: Option<String>,
#[arg(long)]
circom_file_path: Option<String>,
#[arg(long)]
circom_template_name: Option<String>,
#[arg(short, long)]
gen_substrs: Option<bool>,
},
Raw {
#[arg(short, long)]
raw_regex: String,
#[arg(short, long)]
max_bytes: usize,
#[arg(short, long)]
substrs_json_path: Option<String>,
#[arg(short, long)]
halo2_dir_path: Option<String>,
#[arg(long)]
circom_file_path: Option<String>,
#[arg(long)]
circom_template_name: Option<String>,
#[arg(short, long)]
gen_substrs: Option<bool>,
},
}
fn main() {
let cli = Cli::parse();
match cli.command {
Commands::Decomposed {
decomposed_regex_path,
halo2_dir_path,
circom_file_path,
circom_template_name,
gen_substrs,
} => {
gen_from_decomposed(
&decomposed_regex_path,
halo2_dir_path.as_ref().map(|s| s.as_str()),
circom_file_path.as_ref().map(|s| s.as_str()),
circom_template_name.as_ref().map(|s| s.as_str()),
gen_substrs,
);
}
Commands::Raw {
raw_regex,
max_bytes,
substrs_json_path,
halo2_dir_path,
circom_file_path,
circom_template_name,
gen_substrs,
} => {
gen_from_raw(
&raw_regex,
max_bytes,
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()),
circom_template_name.as_ref().map(|s| s.as_str()),
gen_substrs,
);
} // Commands::GenHalo2Texts {
// decomposed_regex_path,
// allstr_file_path,
// substrs_dir_path,
// } => {
// let regex_decomposed: DecomposedRegexConfig =
// serde_json::from_reader(File::open(decomposed_regex_path).unwrap()).unwrap();
// let num_public_part = regex_decomposed
// .parts
// .iter()
// .filter(|part| part.is_public)
// .collect_vec()
// .len();
// let substr_file_pathes = (0..num_public_part)
// .map(|idx| {
// PathBuf::new()
// .join(&substrs_dir_path)
// .join(&format!("substr{}.txt", idx))
// })
// .collect_vec();
// regex_decomposed
// .gen_regex_files(
// &Path::new(&allstr_file_path).to_path_buf(),
// &substr_file_pathes,
// )
// .unwrap();
// }
// Commands::GenCircom {
// decomposed_regex_path,
// circom_file_path,
// template_name,
// } => {
// let regex_decomposed: DecomposedRegexConfig =
// serde_json::from_reader(File::open(decomposed_regex_path).unwrap()).unwrap();
// let circom_path = PathBuf::from(circom_file_path);
// regex_decomposed
// .gen_circom(&circom_path, &template_name)
// .unwrap();
// }
}
}

View File

@@ -0,0 +1,83 @@
use super::CompilerError;
use crate::get_accepted_state;
use crate::js_caller::*;
use crate::RegexAndDFA;
// use crate::{AllstrRegexDef, SubstrRegexDef};
use fancy_regex::Regex;
use itertools::Itertools;
use petgraph::prelude::*;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::io::BufWriter;
use std::io::Write;
use std::path::PathBuf;
use std::{collections::HashMap, fs::File};
use thiserror::Error;
impl RegexAndDFA {
pub fn gen_circom(
&self,
circom_path: &PathBuf,
template_name: &str,
gen_substrs: bool,
) -> Result<(), CompilerError> {
let all_regex = String::new();
let circom = gen_circom_allstr(&self.dfa_val, template_name)?;
if gen_substrs {
self.add_substrs_constraints(circom_path, circom)?;
}
Ok(())
}
pub fn add_substrs_constraints(
&self,
circom_path: &PathBuf,
mut circom: String,
) -> Result<(), CompilerError> {
let accepted_state =
get_accepted_state(&self.dfa_val).ok_or(JsCallerError::NoAcceptedState)?;
circom += "\n";
circom += "\tsignal is_consecutive[msg_bytes+1][2];\n";
circom += "\tis_consecutive[msg_bytes][1] <== 1;\n";
circom += "\tfor (var i = 0; i < msg_bytes; i++) {\n";
circom += &format!("\t\tis_consecutive[msg_bytes-1-i][0] <== states[num_bytes-i][{}] * (1 - is_consecutive[msg_bytes-i][1]) + is_consecutive[msg_bytes-i][1];\n",accepted_state);
circom += "\t\tis_consecutive[msg_bytes-1-i][1] <== state_changed[msg_bytes-i].out * is_consecutive[msg_bytes-1-i][0];\n";
circom += "\t}\n";
let substr_defs_array = &self.substrs_defs.substr_defs_array;
for (idx, defs) in substr_defs_array.into_iter().enumerate() {
let num_defs = defs.len();
circom += &format!("\tsignal is_substr{}[msg_bytes][{}];\n", idx, num_defs + 1);
circom += &format!("\tsignal is_reveal{}[msg_bytes];\n", idx);
circom += &format!("\tsignal output reveal{}[msg_bytes];\n", idx);
circom += "\tfor (var i = 0; i < msg_bytes; i++) {\n";
circom += &format!("\t\tis_substr{}[i][0] <== 0;\n", idx);
for (j, (cur, next)) in defs.iter().enumerate() {
circom += &format!(
"\t\tis_substr{}[i][{}] <== is_substr{}[i][{}] + ",
idx,
j + 1,
idx,
j
);
circom += &format!("states[i+1][{}] * states[i+2][{}];\n", cur, next);
// if j != defs.len() - 1 {
// circom += " + ";
// } else {
// circom += ";\n";
// }
}
circom += &format!(
"\t\tis_reveal{}[i] <== is_substr{}[i][{}] * is_consecutive[i][1];\n",
idx, idx, num_defs
);
circom += &format!("\t\treveal{}[i] <== in[i+1] * is_reveal{}[i];\n", idx, idx);
circom += "\t}\n";
}
circom += "}";
let mut circom_file = File::create(circom_path)?;
write!(circom_file, "{}", circom)?;
circom_file.flush()?;
Ok(())
}
}

View File

@@ -0,0 +1,233 @@
function genCircomAllstr(graph_json, template_name) {
const N = graph_json.length;
// const graph = Array(N).fill({});
const rev_graph = [];
const to_init_graph = [];
let init_going_state = null;
for (let i = 0; i < N; i++) {
rev_graph.push({});
to_init_graph.push([]);
}
let accept_nodes = new Set();
for (let i = 0; i < N; i++) {
for (let k in graph_json[i]["edges"]) {
const v = graph_json[i]["edges"][k];
rev_graph[v][i] = Array.from(JSON.parse(k)).map(c => c.charCodeAt());
if (i == 0) {
const index = rev_graph[v][i].indexOf(94);
if (index != -1) {
init_going_state = v;
rev_graph[v][i][index] = 128;
}
for (let j = 0; j < rev_graph[v][i].length; j++) {
if (rev_graph[v][i][j] == 128) {
continue;
}
to_init_graph[v].push(rev_graph[v][i][j]);
}
}
}
if (graph_json[i]["type"] == "accept") {
accept_nodes.add(i);
}
}
if (init_going_state != null) {
for (const [going_state, chars] of Object.entries(to_init_graph)) {
if (chars.length == 0) {
continue;
}
if (rev_graph[going_state][init_going_state] == null) {
rev_graph[going_state][init_going_state] = [];
}
rev_graph[going_state][init_going_state] = rev_graph[going_state][init_going_state].concat(chars);
}
}
if (accept_nodes[0] != null) {
throw new Error("accept node must not be 0");
}
accept_nodes = [...accept_nodes];
if (accept_nodes.length != 1) {
throw new Error("the size of accept nodes must be one");
}
let eq_i = 0;
let lt_i = 0;
let and_i = 0;
let multi_or_i = 0;
let lines = [];
lines.push("\tfor (var i = 0; i < num_bytes; i++) {");
const uppercase = new Set(Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZ").map(c => c.charCodeAt()));
const lowercase = new Set(Array.from("abcdefghijklmnopqrstuvwxyz").map(c => c.charCodeAt()));
const digits = new Set(Array.from("0123456789").map(c => c.charCodeAt()));
const symbols1 = new Set([":", ";", "<", "=", ">", "?", "@"].map(c => c.charCodeAt()));
const symbols2 = new Set(["[", "\\", "]", "^", "_", "`"].map(c => c.charCodeAt()));
const symbols3 = new Set(["{", "|", "}", "~"].map(c => c.charCodeAt()));
lines.push(`\t\tstate_changed[i] = MultiOR(${N - 1});`);
for (let i = 1; i < N; i++) {
const outputs = [];
for (let prev_i of Object.keys(rev_graph[i])) {
const k = rev_graph[i][prev_i];
const eq_outputs = [];
const vals = new Set(k);
if (vals.size == 0) {
continue;
}
const min_maxs = [];
for (let subsets of [
[digits, 47, 58],
[symbols1, 57, 65],
[uppercase, 64, 91],
[symbols2, 90, 97],
[lowercase, 96, 123],
[symbols3, 122, 127]
]) {
const subset = subsets[0];
const min = subsets[1];
const max = subsets[2];
if (vals.isSuperset(subset)) {
vals.difference(subset);
if (min_maxs.length == 0) {
min_maxs.push([min, max]);
} else {
const last = min_maxs[min_maxs.length - 1];
if (last[1] - 1 == min) {
min_maxs[min_maxs.length - 1][1] = max;
} else {
min_maxs.push([min, max]);
}
}
}
}
for (let min_max of min_maxs) {
lines.push(`\t\tlt[${lt_i}][i] = LessThan(8);`);
lines.push(`\t\tlt[${lt_i}][i].in[0] <== ${min_max[0]};`);
lines.push(`\t\tlt[${lt_i}][i].in[1] <== in[i];`);
lines.push(`\t\tlt[${lt_i + 1}][i] = LessThan(8);`);
lines.push(`\t\tlt[${lt_i + 1}][i].in[0] <== in[i];`);
lines.push(`\t\tlt[${lt_i + 1}][i].in[1] <== ${min_max[1]};`);
lines.push(`\t\tand[${and_i}][i] = AND();`);
lines.push(`\t\tand[${and_i}][i].a <== lt[${lt_i}][i].out;`);
lines.push(`\t\tand[${and_i}][i].b <== lt[${lt_i + 1}][i].out;`);
eq_outputs.push(['and', and_i]);
lt_i += 2
and_i += 1
}
for (let code of vals) {
lines.push(`\t\teq[${eq_i}][i] = IsEqual();`);
lines.push(`\t\teq[${eq_i}][i].in[0] <== in[i];`);
lines.push(`\t\teq[${eq_i}][i].in[1] <== ${code};`);
eq_outputs.push(['eq', eq_i]);
eq_i += 1
}
lines.push(`\t\tand[${and_i}][i] = AND();`);
lines.push(`\t\tand[${and_i}][i].a <== states[i][${prev_i}];`);
if (eq_outputs.length == 1) {
lines.push(`\t\tand[${and_i}][i].b <== ${eq_outputs[0][0]}[${eq_outputs[0][1]}][i].out;`);
} else if (eq_outputs.length > 1) {
lines.push(`\t\tmulti_or[${multi_or_i}][i] = MultiOR(${eq_outputs.length});`);
for (let output_i = 0; output_i < eq_outputs.length; output_i++) {
lines.push(`\t\tmulti_or[${multi_or_i}][i].in[${output_i}] <== ${eq_outputs[output_i][0]}[${eq_outputs[output_i][1]}][i].out;`);
}
lines.push(`\t\tand[${and_i}][i].b <== multi_or[${multi_or_i}][i].out;`);
multi_or_i += 1
}
outputs.push(and_i);
and_i += 1;
}
if (outputs.length == 1) {
lines.push(`\t\tstates[i+1][${i}] <== and[${outputs[0]}][i].out;`);
} else if (outputs.length > 1) {
lines.push(`\t\tmulti_or[${multi_or_i}][i] = MultiOR(${outputs.length});`);
for (let output_i = 0; output_i < outputs.length; output_i++) {
lines.push(`\t\tmulti_or[${multi_or_i}][i].in[${output_i}] <== and[${outputs[output_i]}][i].out;`);
}
lines.push(`\t\tstates[i+1][${i}] <== multi_or[${multi_or_i}][i].out;`);
multi_or_i += 1
}
lines.push(`\t\tstate_changed[i].in[${i - 1}] <== states[i+1][${i}];`);
}
lines.push(`\t\tstates[i+1][0] <== 1 - state_changed[i].out;`);
lines.push("\t}");
const declarations = [];
declarations.push(`pragma circom 2.1.5;\n`);
declarations.push(`include "zk-regex-circom/circuits/regex_helpers.circom";\n`);
// declarations.push(`pragma circom 2.1.5;\ninclude "@zk-email/circuits/regexes/regex_helpers.circom";\n`);
declarations.push(`template ${template_name}(msg_bytes) {`);
declarations.push(`\tsignal input msg[msg_bytes];`);
declarations.push(`\tsignal output out;\n`);
declarations.push(`\tvar num_bytes = msg_bytes+1;`);
declarations.push(`\tsignal in[num_bytes];`);
declarations.push(`\tin[0]<==128;`);
declarations.push(`\tfor (var i = 0; i < msg_bytes; i++) {`);
declarations.push(`\t\tin[i+1] <== msg[i];`);
declarations.push(`\t}\n`);
if (eq_i > 0) {
declarations.push(`\tcomponent eq[${eq_i}][num_bytes];`);
}
if (lt_i > 0) {
declarations.push(`\tcomponent lt[${lt_i}][num_bytes];`);
}
if (and_i > 0) {
declarations.push(`\tcomponent and[${and_i}][num_bytes];`);
}
if (multi_or_i > 0) {
declarations.push(`\tcomponent multi_or[${multi_or_i}][num_bytes];`);
}
declarations.push(`\tsignal states[num_bytes+1][${N}];`);
declarations.push(`\tcomponent state_changed[num_bytes];`);
declarations.push("");
const init_code = [];
init_code.push(`\tstates[0][0] <== 1;`);
init_code.push(`\tfor (var i = 1; i < ${N}; i++) {`);
init_code.push(`\t\tstates[0][i] <== 0;`);
init_code.push("\t}");
init_code.push("");
lines = declarations.concat(init_code).concat(lines);
const accept_node = accept_nodes[0];
const accept_lines = [""];
accept_lines.push("\tcomponent final_state_result = MultiOR(num_bytes+1);");
accept_lines.push("\tfor (var i = 0; i <= num_bytes; i++) {");
accept_lines.push(`\t\tfinal_state_result.in[i] <== states[i][${accept_node}];`);
accept_lines.push("\t}");
accept_lines.push("\tout <== final_state_result.out;");
lines = lines.concat(accept_lines);
let string = lines.reduce((res, line) => res + line + "\n", "");
return string;
}
Set.prototype.isSuperset = function (subset) {
if (this.size == 0) {
return false;
}
for (var elem of subset) {
if (!this.has(elem)) {
return false;
}
}
return true;
}
Set.prototype.difference = function (setB) {
for (let elem of setB) {
this.delete(elem)
}
}

View File

@@ -0,0 +1,104 @@
use crate::js_caller::*;
use crate::*;
use fancy_regex::Regex;
use itertools::Itertools;
use petgraph::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashSet;
use std::io::BufWriter;
use std::io::Write;
use std::iter::FromIterator;
use std::path::PathBuf;
use std::{collections::HashMap, fs::File};
use thiserror::Error;
impl RegexAndDFA {
pub fn gen_halo2_tables(
&self,
allstr_file_path: &PathBuf,
substr_file_pathes: &[PathBuf],
gen_substrs: bool,
) -> Result<(), CompilerError> {
let regex_text = self.dfa_to_regex_def_text()?;
let mut regex_file = File::create(allstr_file_path)?;
write!(regex_file, "{}", regex_text)?;
regex_file.flush()?;
if !gen_substrs {
return Ok(());
}
let substr_endpoints_array = self.substrs_defs.substr_endpoints_array.as_ref().unwrap();
let max_bytes = self.substrs_defs.max_bytes.as_ref().unwrap();
for (idx, defs) in self.substrs_defs.substr_defs_array.iter().enumerate() {
let mut writer = BufWriter::new(File::create(&substr_file_pathes[idx])?);
let max_size = max_bytes[idx];
writer.write_fmt(format_args!("{}\n", &max_size))?;
writer.write_fmt(format_args!("0\n{}\n", self.max_byte_size - 1))?;
let mut starts_str = "".to_string();
let starts = substr_endpoints_array[idx]
.0
.iter()
.sorted_by(|a, b| a.cmp(b));
for start in starts {
starts_str += &format!("{} ", start);
}
writer.write_fmt(format_args!("{}\n", starts_str))?;
let mut ends_str = "".to_string();
let ends = substr_endpoints_array[idx]
.1
.iter()
.sorted_by(|a, b| a.cmp(b));
for end in ends {
ends_str += &format!("{} ", end);
}
writer.write_fmt(format_args!("{}\n", ends_str))?;
let mut defs = defs.iter().collect::<Vec<&(usize, usize)>>();
defs.sort_by(|a, b| {
let start_cmp = a.0.cmp(&b.0);
let end_cmp = a.1.cmp(&b.1);
if start_cmp == std::cmp::Ordering::Equal {
end_cmp
} else {
start_cmp
}
});
for (cur, next) in defs.iter() {
writer.write_fmt(format_args!("{} {}\n", cur, next))?;
}
}
Ok(())
}
pub fn dfa_to_regex_def_text(&self) -> Result<String, JsCallerError> {
let accepted_state =
get_accepted_state(&self.dfa_val).ok_or(JsCallerError::NoAcceptedState)?;
let max_state = get_max_state(&self.dfa_val)?;
let mut text = "0\n".to_string();
text += &format!("{}\n", accepted_state.to_string());
text += &format!("{}\n", max_state.to_string());
for (i, val) in self.dfa_val.iter().enumerate() {
for (key, next_node_val) in val["edges"]
.as_object()
.ok_or(JsCallerError::InvalidEdges(val["edges"].clone()))?
.iter()
{
let key_list: Vec<String> = serde_json::from_str(&key)?;
for key_char in key_list.iter() {
let key_char: char = key_char.chars().collect::<Vec<char>>()[0];
let next_node = next_node_val
.as_u64()
.ok_or(JsCallerError::InvalidNodeValue(next_node_val.clone()))?
as usize;
// println!("i {} next {} char {}", i, next_node, key_char as u8);
text += &format!(
"{} {} {}\n",
i.to_string(),
next_node.to_string(),
(key_char as u8).to_string()
);
}
}
}
Ok(text)
}
}

View File

@@ -0,0 +1,55 @@
use std::collections::HashMap;
use js_sandbox::{AnyError, JsError, Script};
use petgraph::prelude::*;
use serde_json::Value;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum JsCallerError {
#[error("Edges {0} are not object")]
InvalidEdges(Value),
#[error("node value {0} is not u64")]
InvalidNodeValue(Value),
#[error("No accepted state")]
NoAcceptedState,
#[error(transparent)]
JsError(#[from] JsError),
#[error(transparent)]
JsonError(#[from] serde_json::Error),
}
pub fn catch_all_regex_str() -> Result<String, JsCallerError> {
let code: &'static str = include_str!("regex.js");
let mut script = Script::from_string(code)?;
let result: String = script.call("catchAllRegexStr", ())?;
Ok(result)
}
pub fn text_context_prefix() -> Result<String, JsCallerError> {
let code: &'static str = include_str!("regex.js");
let mut script = Script::from_string(code)?;
let result: String = script.call("textContextPrefix", ())?;
Ok(result)
}
// pub fn format_regex_printable(regex: &str) -> Result<String, JsCallerError> {
// let code: &'static str = include_str!("regex.js");
// let mut script = Script::from_string(code)?;
// let result: String = script.call("formatRegexPrintable", (regex,))?;
// Ok(result)
// }
pub fn regex_to_dfa(regex: &str) -> Result<Vec<Value>, JsCallerError> {
let code: &'static str = include_str!("regex.js");
let mut script = Script::from_string(code)?;
let result: String = script.call("regexToDfa", (regex,))?;
Ok(serde_json::from_str(&result)?)
}
pub fn gen_circom_allstr(graph: &[Value], template_name: &str) -> Result<String, JsCallerError> {
let code: &'static str = include_str!("gen_circom.js");
let mut script = Script::from_string(code)?;
let result: String = script.call("genCircomAllstr", (graph, template_name))?;
Ok(result)
}

View File

@@ -0,0 +1,470 @@
use std::iter::FromIterator;
use std::{collections::HashMap, fs::File};
pub mod circom;
pub mod halo2;
pub mod js_caller;
#[cfg(feature = "node")]
pub mod node;
#[cfg(feature = "node")]
use crate::node::*;
#[cfg(feature = "node")]
use neon;
use crate::js_caller::*;
use fancy_regex::Regex;
use itertools::Itertools;
use petgraph::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashSet;
use std::path::PathBuf;
use thiserror::Error;
/// Error definitions of the compiler.
#[derive(Error, Debug)]
pub enum CompilerError {
#[error("No edge from {:?} to {:?} in the graph",.0,.1)]
NoEdge(NodeIndex<usize>, NodeIndex<usize>),
#[error(transparent)]
JsCallerError(#[from] JsCallerError),
#[error(transparent)]
IoError(#[from] std::io::Error),
#[error(transparent)]
RegexError(#[from] fancy_regex::Error),
}
/// A configuration of decomposed regexes.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DecomposedRegexConfig {
/// Maximum byte size of the input string.
pub max_byte_size: usize,
/// A vector of decomposed regexes.
pub parts: Vec<RegexPartConfig>,
}
/// Decomposed regex part.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegexPartConfig {
/// A flag indicating whether the substring matching with `regex_def` should be exposed.
pub is_public: bool,
/// A regex string.
pub regex_def: String,
/// Maximum byte size of the substring in this part.
pub max_size: usize,
/// (Optional) A solidity type of the substring in this part, e.g., "String", "Int", "Decimal".
pub solidity: Option<SoldityType>,
}
/// Solidity type of the substring.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum SoldityType {
String,
Uint,
Decimal,
}
#[derive(Debug, Clone)]
pub struct RegexAndDFA {
pub max_byte_size: usize,
pub all_regex: String,
pub dfa_val: Vec<Value>,
pub substrs_defs: SubstrsDefs,
}
#[derive(Debug, Clone)]
pub struct SubstrsDefs {
pub substr_defs_array: Vec<HashSet<(usize, usize)>>,
pub substr_endpoints_array: Option<Vec<(HashSet<usize>, HashSet<usize>)>>,
pub max_bytes: Option<Vec<usize>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubstrsDefsJson {
pub transitions: Vec<Vec<(usize, usize)>>,
}
impl DecomposedRegexConfig {
pub fn to_regex_and_dfa(&self) -> Result<RegexAndDFA, CompilerError> {
let mut all_regex = String::new();
let part_configs = &self.parts;
for config in part_configs.iter() {
all_regex += &config.regex_def;
}
let dfa_val = regex_to_dfa(&all_regex)?;
let substrs_defs = self.extract_substr_ids(&dfa_val)?;
Ok(RegexAndDFA {
max_byte_size: self.max_byte_size,
all_regex,
dfa_val,
substrs_defs,
})
}
pub fn extract_substr_ids(&self, dfa_val: &[Value]) -> Result<SubstrsDefs, CompilerError> {
let part_configs = &self.parts;
let mut graph = Graph::<bool, String, Directed, usize>::with_capacity(0, 0);
let max_state = get_max_state(dfa_val)?;
add_graph_nodes(dfa_val, &mut graph, None, max_state)?;
let accepted_state = get_accepted_state(dfa_val).ok_or(JsCallerError::NoAcceptedState)?;
let accepted_state_index = NodeIndex::from(accepted_state);
let mut pathes = Vec::<Vec<NodeIndex<usize>>>::new();
let mut stack = Vec::<(NodeIndex<usize>, Vec<NodeIndex<usize>>)>::new();
stack.push((accepted_state_index, vec![accepted_state_index]));
let mut self_nodes = HashSet::new();
let mut self_nodes_char = HashMap::new();
for state in 0..=max_state {
let node = NodeIndex::from(state);
if let Some(edge) = graph.find_edge(node, node) {
let str = graph.edge_weight(edge).unwrap().as_str();
let bytes = str.as_bytes();
self_nodes_char.insert(node.index(), bytes[0]);
}
}
while stack.len() != 0 {
let (node, path) = stack.pop().unwrap();
let mut parents = graph.neighbors(node).detach();
while let Some((edge, parent)) = parents.next(&graph) {
if parent.index() == node.index() {
self_nodes.insert(node.index());
graph.remove_edge(edge).unwrap();
continue;
}
if !path.contains(&parent) {
if parent.index() == 0 {
pathes.push(path.to_vec());
continue;
}
stack.push((parent, vec![path.clone(), vec![parent]].concat()));
}
}
}
let mut public_config_indexes: Vec<usize> = vec![];
let mut part_regexes = vec![];
for (idx, config) in part_configs.iter().enumerate() {
if config.is_public {
public_config_indexes.push(idx);
}
if idx == 0 {
let regex_def = config.regex_def.replace("^", "\\^");
part_regexes.push(Regex::new(&regex_def)?);
} else {
let pre_regex = part_regexes[idx - 1].to_string();
part_regexes.push(Regex::new(&(pre_regex + &config.regex_def))?);
}
}
let num_public_parts = public_config_indexes.len();
let mut substr_defs_array = (0..num_public_parts)
.map(|_| HashSet::<(usize, usize)>::new())
.collect_vec();
let mut substr_endpoints_array = (0..num_public_parts)
.map(|_| (HashSet::<usize>::new(), HashSet::<usize>::new()))
.collect_vec();
for path in pathes.iter_mut() {
let n = path.len();
path.append(&mut vec![NodeIndex::from(0)]);
let edges = (0..n)
.map(|idx| {
graph
.find_edge(path[idx], path[idx + 1])
.ok_or(CompilerError::NoEdge(path[idx], path[idx + 1]))
})
.collect::<Result<Vec<EdgeIndex<usize>>, CompilerError>>()?;
let string_vec = edges
.iter()
.map(|edge| graph.edge_weight(*edge).unwrap().as_str())
.collect::<Vec<&str>>();
let path_states = path
.into_iter()
.rev()
.map(|node| node.index())
.collect::<Vec<usize>>();
let path_strs = string_vec
.iter()
.rev()
.map(|s| s.to_string())
.collect::<Vec<String>>();
let substr_states = self.get_substr_defs_from_path(
&path_states,
&path_strs,
&part_regexes,
&public_config_indexes,
)?;
for (substr_idx, (path_states, substr)) in substr_states.into_iter().enumerate() {
let defs = &mut substr_defs_array[substr_idx];
substr_endpoints_array[substr_idx].0.insert(path_states[0]);
substr_endpoints_array[substr_idx]
.1
.insert(path_states[path_states.len() - 1]);
for path_idx in 0..(path_states.len() - 1) {
defs.insert((path_states[path_idx], path_states[path_idx + 1]));
if self_nodes.contains(&path_states[path_idx]) {
defs.insert((path_states[path_idx], path_states[path_idx]));
}
for pre_path_idx in 0..=path_idx {
if graph
.find_edge(
NodeIndex::from(path_states[pre_path_idx]),
NodeIndex::from(path_states[path_idx + 1]),
)
.is_some()
{
defs.insert((path_states[path_idx + 1], path_states[pre_path_idx]));
}
}
}
if self_nodes.contains(&path_states[path_states.len() - 1]) {
let part_index = public_config_indexes[substr_idx];
let part_regex = &part_regexes[part_index];
let byte = self_nodes_char[&path_states[path_states.len() - 1]];
let substr = substr + &(byte as char).to_string();
if part_regex.is_match(&substr).unwrap() {
defs.insert((
path_states[path_states.len() - 1],
path_states[path_states.len() - 1],
));
}
}
}
}
let max_bytes = public_config_indexes
.iter()
.map(|idx| self.parts[*idx].max_size)
.collect_vec();
let substrs_defs = SubstrsDefs {
substr_defs_array,
substr_endpoints_array: Some(substr_endpoints_array),
max_bytes: Some(max_bytes),
};
Ok(substrs_defs)
}
fn get_substr_defs_from_path(
&self,
path_states: &[usize],
path_strs: &[String],
part_regexes: &[Regex],
public_config_indexes: &[usize],
) -> Result<Vec<(Vec<usize>, String)>, CompilerError> {
debug_assert_eq!(path_states.len(), path_strs.len() + 1);
let mut concat_str = String::new();
for str in path_strs.into_iter() {
let first_chars = str.as_bytes();
concat_str += &(first_chars[0] as char).to_string();
}
let index_ends = part_regexes
.iter()
.map(|regex| {
let found = regex.find(&concat_str).unwrap().unwrap();
if found.start() == found.end() {
found.end() + 1
} else {
found.end()
}
})
.collect_vec();
let mut substr_results = vec![];
for index in public_config_indexes.iter() {
let start = if *index == 0 {
0
} else {
index_ends[index - 1]
};
let end = index_ends[*index];
substr_results.push((
path_states[(start)..=end].to_vec(),
concat_str[0..=(end - 1)].to_string(),
));
}
Ok(substr_results)
}
}
impl RegexAndDFA {
pub fn from_regex_str_and_substr_defs(
max_byte_size: usize,
regex_str: &str,
substrs_defs_json: SubstrsDefsJson,
) -> Result<RegexAndDFA, CompilerError> {
let dfa_val = regex_to_dfa(regex_str)?;
let substr_defs_array = substrs_defs_json
.transitions
.into_iter()
.map(|transitions_array| HashSet::<(usize, usize)>::from_iter(transitions_array))
.collect_vec();
let substrs_defs = SubstrsDefs {
substr_defs_array,
substr_endpoints_array: None,
max_bytes: None,
};
Ok(RegexAndDFA {
max_byte_size,
all_regex: regex_str.to_string(),
dfa_val,
substrs_defs,
})
}
}
pub fn gen_from_decomposed(
decomposed_regex_path: &str,
halo2_dir_path: Option<&str>,
circom_file_path: Option<&str>,
circom_template_name: Option<&str>,
gen_substrs: Option<bool>,
) {
let decomposed_regex_config: DecomposedRegexConfig =
serde_json::from_reader(File::open(decomposed_regex_path).unwrap()).unwrap();
let regex_and_dfa = decomposed_regex_config
.to_regex_and_dfa()
.expect("failed to convert the decomposed regex to dfa");
let gen_substrs = gen_substrs.unwrap_or(true);
if let Some(halo2_dir_path) = halo2_dir_path {
let halo2_dir_path = PathBuf::from(halo2_dir_path);
let allstr_file_path = halo2_dir_path.join("allstr.txt");
let mut num_public_parts = 0usize;
for part in decomposed_regex_config.parts.iter() {
if part.is_public {
num_public_parts += 1;
}
}
let substr_file_pathes = (0..num_public_parts)
.map(|idx| halo2_dir_path.join(format!("substr_{}.txt", idx)))
.collect_vec();
regex_and_dfa
.gen_halo2_tables(&allstr_file_path, &substr_file_pathes, gen_substrs)
.expect("failed to generate halo2 tables");
}
if let Some(circom_file_path) = circom_file_path {
let circom_file_path = PathBuf::from(circom_file_path);
let circom_template_name = circom_template_name
.expect("circom template name must be specified if circom file path is specified");
regex_and_dfa
.gen_circom(&circom_file_path, &circom_template_name, gen_substrs)
.expect("failed to generate circom");
}
}
pub fn gen_from_raw(
raw_regex: &str,
max_bytes: usize,
substrs_json_path: Option<&str>,
halo2_dir_path: Option<&str>,
circom_file_path: Option<&str>,
circom_template_name: Option<&str>,
gen_substrs: Option<bool>,
) {
let substrs_defs_json = if let Some(substrs_json_path) = substrs_json_path {
let substrs_json_path = PathBuf::from(substrs_json_path);
let substrs_defs_json: SubstrsDefsJson =
serde_json::from_reader(File::open(substrs_json_path).unwrap()).unwrap();
substrs_defs_json
} else {
SubstrsDefsJson {
transitions: vec![vec![]],
}
};
let num_public_parts = substrs_defs_json.transitions.len();
let regex_and_dfa =
RegexAndDFA::from_regex_str_and_substr_defs(max_bytes, raw_regex, substrs_defs_json)
.expect("failed to convert the raw regex and state transitions to dfa");
let gen_substrs = gen_substrs.unwrap_or(true);
if let Some(halo2_dir_path) = halo2_dir_path {
let halo2_dir_path = PathBuf::from(halo2_dir_path);
let allstr_file_path = halo2_dir_path.join("allstr.txt");
let substr_file_pathes = (0..num_public_parts)
.map(|idx| halo2_dir_path.join(format!("substr_{}.txt", idx)))
.collect_vec();
regex_and_dfa
.gen_halo2_tables(&allstr_file_path, &substr_file_pathes, gen_substrs)
.expect("failed to generate halo2 tables");
}
if let Some(circom_file_path) = circom_file_path {
let circom_file_path = PathBuf::from(circom_file_path);
let circom_template_name = circom_template_name
.expect("circom template name must be specified if circom file path is specified");
regex_and_dfa
.gen_circom(&circom_file_path, &circom_template_name, gen_substrs)
.expect("failed to generate circom");
}
}
pub(crate) fn get_accepted_state(dfa_val: &[Value]) -> Option<usize> {
for i in 0..dfa_val.len() {
if dfa_val[i]["type"] == "accept" {
return Some(i as usize);
}
}
None
}
pub(crate) fn get_max_state(dfa_val: &[Value]) -> Result<usize, JsCallerError> {
let mut max_state = 0;
for (i, val) in dfa_val.iter().enumerate() {
for (_, next_node_val) in val["edges"]
.as_object()
.ok_or(JsCallerError::InvalidEdges(val["edges"].clone()))?
.iter()
{
let next_node = next_node_val
.as_u64()
.ok_or(JsCallerError::InvalidNodeValue(next_node_val.clone()))?
as usize;
if next_node > max_state {
max_state = next_node;
}
}
}
Ok(max_state)
}
pub(crate) fn add_graph_nodes(
dfa_val: &[Value],
graph: &mut Graph<bool, String, Directed, usize>,
last_max_state: Option<usize>,
next_max_state: usize,
) -> Result<(), JsCallerError> {
let first_new_state = match last_max_state {
Some(v) => v + 1,
None => 0,
};
for idx in first_new_state..=next_max_state {
graph.add_node(idx == next_max_state);
}
for (i, val) in dfa_val.iter().enumerate() {
for (key, next_node_val) in val["edges"]
.as_object()
.ok_or(JsCallerError::InvalidEdges(val["edges"].clone()))?
.iter()
{
let next_node = next_node_val
.as_u64()
.ok_or(JsCallerError::InvalidNodeValue(next_node_val.clone()))?
as usize;
if let Some(max) = last_max_state {
if i <= max && next_node <= max {
continue;
}
}
let key_list: Vec<String> = serde_json::from_str(&key)?;
let mut key_str = String::new();
for key_char in key_list.iter() {
assert!(key_char.len() == 1);
key_str += key_char;
}
graph.add_edge(NodeIndex::from(next_node), NodeIndex::from(i), key_str);
}
}
Ok(())
}
#[cfg(feature = "node")]
#[neon::main]
fn main(mut cx: neon::prelude::ModuleContext) -> neon::prelude::NeonResult<()> {
cx.export_function("genFromDecomposed", gen_from_decomposed_node)?;
Ok(())
}

View File

@@ -0,0 +1,35 @@
use crate::gen_from_decomposed;
use neon::prelude::*;
pub(crate) fn gen_from_decomposed_node(mut cx: FunctionContext) -> JsResult<JsNull> {
let decomposed_regex_path = cx.argument::<JsString>(0)?.value(&mut cx);
let halo2_dir_path = cx.argument_opt(1).map(|v| {
v.to_string(&mut cx)
.expect("halo2_dir_path must be null or string")
.value(&mut cx)
});
let circom_file_path = cx.argument_opt(2).map(|v| {
v.to_string(&mut cx)
.expect("circom_file_path must be null or string")
.value(&mut cx)
});
let circom_template_name = cx.argument_opt(3).map(|v| {
v.to_string(&mut cx)
.expect("circom_template_name must be null or string")
.value(&mut cx)
});
let gen_substrs = cx.argument_opt(4).map(|v| {
v.as_value(&mut cx)
.downcast::<JsBoolean, _>(&mut cx)
.expect("gen_substrs must be null or boolean")
.value(&mut cx)
});
gen_from_decomposed(
&decomposed_regex_path,
halo2_dir_path.as_ref().map(|s| s.as_str()),
circom_file_path.as_ref().map(|s| s.as_str()),
circom_template_name.as_ref().map(|s| s.as_str()),
gen_substrs,
);
Ok(cx.null())
}

View File

@@ -1,6 +1,15 @@
/* eslint-disable no-prototype-builtins */
/*jslint browser: true*/
// const a2z_nosep = "abcdefghijklmnopqrstuvwxyz";
// const A2Z_nosep = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// const a2f_nosep = "abcdef";
// const A2F_nosep = "ABCDEF";
// const r0to9_nosep = "0123456789";
// const escapeMap = { n: "\n", r: "\r", t: "\t", v: "\v", f: "\f" };
// const whitespace = Object.values(escapeMap);
// const slash_s = whitespace.join("|");
/**
* Try parsing simple regular expression to syntax tree.
*
@@ -26,7 +35,7 @@ function parseRegex(text) {
var i,
sub,
last = 0,
node = {'begin': begin, 'end': end},
node = { 'begin': begin, 'end': end },
virNode,
tempNode,
stack = 0,
@@ -86,7 +95,7 @@ function parseRegex(text) {
if (parts.length === 0) {
return 'Error: unexpected * at ' + (begin + i) + '.';
}
tempNode = {'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1};
tempNode = { 'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1 };
tempNode.type = 'star';
tempNode.sub = parts[parts.length - 1];
parts[parts.length - 1] = tempNode;
@@ -94,10 +103,10 @@ function parseRegex(text) {
if (parts.length === 0) {
return 'Error: unexpected + at ' + (begin + i) + '.';
}
virNode = {'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1};
virNode = { 'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1 };
virNode.type = 'star';
virNode.sub = parts[parts.length - 1];
tempNode = {'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1};
tempNode = { 'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1 };
tempNode.type = 'cat';
tempNode.parts = [parts[parts.length - 1], virNode];
parts[parts.length - 1] = tempNode;
@@ -105,24 +114,24 @@ function parseRegex(text) {
if (parts.length === 0) {
return 'Error: unexpected + at ' + (begin + i) + '.';
}
virNode = {'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1};
virNode = { 'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1 };
virNode.type = 'empty';
virNode.sub = parts[parts.length - 1];
tempNode = {'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1};
tempNode = { 'begin': parts[parts.length - 1].begin, 'end': parts[parts.length - 1].end + 1 };
tempNode.type = 'or';
tempNode.parts = [parts[parts.length - 1], virNode];
parts[parts.length - 1] = tempNode;
} else if (text[i] === 'ϵ') {
tempNode = {'begin': begin + i, 'end': begin + i + 1};
tempNode = { 'begin': begin + i, 'end': begin + i + 1 };
tempNode.type = 'empty';
parts.push(tempNode);
} else if (Array.isArray(text[i])) {
tempNode = {'begin': begin + i, 'end': begin + i + 1};
tempNode = { 'begin': begin + i, 'end': begin + i + 1 };
tempNode.type = 'text';
tempNode.text = text[i][0];
parts.push(tempNode);
} else {
tempNode = {'begin': begin + i, 'end': begin + i + 1};
tempNode = { 'begin': begin + i, 'end': begin + i + 1 };
tempNode.type = 'text';
tempNode.text = text[i];
parts.push(tempNode);
@@ -141,7 +150,7 @@ function parseRegex(text) {
let i = 0;
while (i < text.length) {
if (text[i] == '\\') {
new_text.push([text[i+1]]);
new_text.push([text[i + 1]]);
i += 2;
} else {
new_text.push(text[i]);
@@ -166,36 +175,36 @@ function regexToNfa(text) {
count += 1;
}
switch (node.type) {
case 'empty':
start.edges.push(['ϵ', end]);
break;
case 'text':
start.edges.push([node.text, end]);
break;
case 'cat':
last = start;
for (i = 0; i < node.parts.length - 1; i += 1) {
temp = {'type': '', 'edges': []};
count = generateGraph(node.parts[i], last, temp, count);
last = temp;
}
count = generateGraph(node.parts[node.parts.length - 1], last, end, count);
break;
case 'or':
for (i = 0; i < node.parts.length; i += 1) {
tempStart = {'type': '', 'edges': []};
tempEnd = {'type': '', 'edges': [['ϵ', end]]};
case 'empty':
start.edges.push(['ϵ', end]);
break;
case 'text':
start.edges.push([node.text, end]);
break;
case 'cat':
last = start;
for (i = 0; i < node.parts.length - 1; i += 1) {
temp = { 'type': '', 'edges': [] };
count = generateGraph(node.parts[i], last, temp, count);
last = temp;
}
count = generateGraph(node.parts[node.parts.length - 1], last, end, count);
break;
case 'or':
for (i = 0; i < node.parts.length; i += 1) {
tempStart = { 'type': '', 'edges': [] };
tempEnd = { 'type': '', 'edges': [['ϵ', end]] };
start.edges.push(['ϵ', tempStart]);
count = generateGraph(node.parts[i], tempStart, tempEnd, count);
}
break;
case 'star':
tempStart = { 'type': '', 'edges': [] };
tempEnd = { 'type': '', 'edges': [['ϵ', tempStart], ['ϵ', end]] };
start.edges.push(['ϵ', tempStart]);
count = generateGraph(node.parts[i], tempStart, tempEnd, count);
}
break;
case 'star':
tempStart = {'type': '', 'edges': []};
tempEnd = {'type': '', 'edges': [['ϵ', tempStart], ['ϵ', end]]};
start.edges.push(['ϵ', tempStart]);
start.edges.push(['ϵ', end]);
count = generateGraph(node.sub, tempStart, tempEnd, count);
break;
start.edges.push(['ϵ', end]);
count = generateGraph(node.sub, tempStart, tempEnd, count);
break;
}
if (!end.hasOwnProperty('id')) {
end.id = count;
@@ -204,8 +213,8 @@ function regexToNfa(text) {
return count;
}
var ast = parseRegex(text),
start = {'type': 'start', 'edges': []},
accept = {'type': 'accept', 'edges': []};
start = { 'type': 'start', 'edges': [] },
accept = { 'type': 'accept', 'edges': [] };
if (typeof ast === 'string') {
return ast;
}
@@ -532,20 +541,14 @@ function toNature(col) {
// '(\r\n|\x80)(to|from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>?\r\n';
// let regex = '(\r\n|\x80)(to|from):((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9| |_|.|"|@|-)+<)?(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-)+@(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-)+>?\r\n';
const key_chars = '(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)';
const catch_all = '(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|;|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\n|\r|\x0b|\x0c)';
const catch_all_without_semicolon = '(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\n|\r|\x0b|\x0c)';
const base_64 = '(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\+|/|=)';
const word_char = '(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_)';
// const key_chars = '(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)';
// const catch_all = '(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|;|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\n|\r|\x0b|\x0c)';
// const catch_all_without_semicolon = '(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\n|\r|\x0b|\x0c)';
// const base_64 = '(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\+|/|=)';
// const word_char = '(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_)';
function compile(regex) {
// let regex = `\r\ndkim-signature:(${key_chars}=${catch_all_without_semicolon}+; )+bh=${base_64}+; `;
// console.log(regex);
// console.log(Buffer.from(regex).toString('base64'));
// let regex = 'hello(0|1|2|3|4|5|6|7|8|9)+world';
function regexToDfa(regex) {
let nfa = regexToNfa(regex);
let dfa = minDfa(nfaToDfa(nfa));
@@ -582,20 +585,45 @@ function compile(regex) {
curr.edges = {};
for (let j = 0; j < symbols.length; j += 1) {
if (nodes[i].trans.hasOwnProperty(symbols[j])) {
curr.edges[symbols[j]] = nodes[i].trans[symbols[j]].nature-1;
curr.edges[symbols[j]] = nodes[i].trans[symbols[j]].nature - 1;
}
}
graph[nodes[i].nature-1] = curr;
graph[nodes[i].nature - 1] = curr;
}
return graph;
return JSON.stringify(graph);
}
module.exports = {
compile,
key_chars,
base_64,
word_char,
catch_all,
catch_all_without_semicolon,
};
function catchAllRegexStr() {
return "(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|\"|#|$|%|&|'|\\(|\\)|\\*|\\+|,|-|.|/|:|;|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\n|\r|\x0b|\x0c)";
}
function catchAllWithoutRNRegexStr() {
return "(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|\"|#|$|%|&|'|\\(|\\)|\\*|\\+|,|-|.|/|:|;|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\x0b|\x0c)";
}
function textContextPrefix() {
return `Content-Type: text/plain; charset="UTF-8"\r\n\r\n`;
}
// function formatRegexPrintable(s) {
// const escaped_string_json = JSON.stringify(s);
// const escaped_string = escaped_string_json.slice(1, escaped_string_json.length - 1);
// return escaped_string
// .replaceAll("\\\\\\\\", "\\")
// .replaceAll("\\\\", "\\")
// .replaceAll("/", "\\/")
// .replaceAll("\u000b", "\\♥")
// .replaceAll("^", "\\^")
// .replaceAll("$", "\\$")
// .replaceAll("|[|", "|\\[|")
// .replaceAll("|]|", "|\\]|")
// .replaceAll("|.|", "|\\.|")
// .replaceAll("|$|", "|\\$|")
// .replaceAll("|^|", "|\\^|");
// }
// module.exports = {
// regexToDfa
// };

View File

@@ -1,10 +0,0 @@
pragma circom 2.0.2;
include "../../build/compiled.circom";
component main {
public [
msg,
match_idx
]
} = Regex(1536, 44, 0);

View File

@@ -1,10 +0,0 @@
pragma circom 2.0.2;
include "../../build/compiled.circom";
component main {
public [
msg,
match_idx
]
} = Regex(1536, 44, 1);

View File

@@ -1,10 +0,0 @@
pragma circom 2.0.2;
include "../../build/compiled.circom";
component main {
public [
msg,
match_idx
]
} = Regex(1536, 44, 2);

View File

@@ -1,10 +0,0 @@
pragma circom 2.0.2;
include "../../build/compiled.circom";
component main {
public [
msg,
match_idx
]
} = Regex(1536, 44, 3);

View File

@@ -1,7 +0,0 @@
Date: Sat, 24 Dec 2022 07:12:37 +0000
from: Twitter <verify@twitter.com>
to: test <test@test.com>
Subject: Password reset request
MIME-Version: 1.0
Content-Type: multipart/alternative;

View File

@@ -1,214 +0,0 @@
const fs = require('fs');
const {expect} = require('chai');
const path = require('path');
const circom_tester = require('circom_tester');
const generator = require('../compiler/gen');
const wasm_tester = circom_tester.wasm;
describe('regex compiler tests', function () {
[
[
['1=(a|b) (2=(b|c)+ )+d', 0],
[
[
'1 entire match and 1st sub-group match',
convertMsg('1=a 2=b 2=bc 2=c d'),
0,
(signals) => {
expect(signals.main.entire_count).to.equal(1n);
expect(signals.main.group_match_count).to.equal(1n);
expect(signals.main.start_idx).to.equal(2n);
const expected_reveal = encodeString('a');
assert_reveal(signals, expected_reveal);
}
],
]
],
[
['1=(a|b) (2=(b|c)+ )+d', 1],
[
[
'1 entire match and 1st sub-group match',
convertMsg('1=a 2=b 2=bc 2=c d'),
0,
(signals) => {
expect(signals.main.entire_count).to.equal(1n);
expect(signals.main.group_match_count).to.equal(3n);
expect(signals.main.start_idx).to.equal(6n);
const expected_reveal = encodeString('b');
assert_reveal(signals, expected_reveal);
}
],
[
'1 entire match and 2nd sub-group match',
convertMsg('1=a 2=b 2=bc 2=c d'),
1,
(signals) => {
expect(signals.main.entire_count).to.equal(1n);
expect(signals.main.group_match_count).to.equal(3n);
expect(signals.main.start_idx).to.equal(10n);
const expected_reveal = encodeString('bc');
assert_reveal(signals, expected_reveal);
}
],
[
'1 entire match and 3rd sub-group match',
convertMsg('1=a 2=b 2=bc 2=c d'),
2,
(signals) => {
expect(signals.main.entire_count).to.equal(1n);
expect(signals.main.group_match_count).to.equal(3n);
expect(signals.main.start_idx).to.equal(15n);
const expected_reveal = encodeString('c');
assert_reveal(signals, expected_reveal);
}
],
[
'0 entire match and 2 group matches',
convertMsg('1=a 2=b 2=bc 2=e d'),
1,
(signals) => {
expect(signals.main.entire_count).to.equal(0n);
expect(signals.main.group_match_count).to.equal(2n);
}
],
[
'2 entire match and 2nd sub-group match',
convertMsg('1=a 2=b 2=bc 2=c da 1=a 2=cb 2=c 2=b dd'),
1,
(signals) => {
expect(signals.main.entire_count).to.equal(2n);
expect(signals.main.group_match_count).to.equal(6n);
expect(signals.main.start_idx).to.equal(10n);
const expected_reveal = encodeString('bc');
assert_reveal(signals, expected_reveal);
}
],
// todo TOFIX
// [
// '1 entire match and 1+ group matches with no trails behind the last group',
// convertMsg(`1=a 2=b 2=bc 2=c `),
// [`1=(a|b) (2=(b|c)+ )+`, 1, 1],
// (signals) => {
// for (let i = 0; i < signals.main.states.length; i++) {
// console.log(signals.main.states[i][8])
// }
// expect(signals.main.entire_count).to.equal(1n)
// expect(signals.main.group_match_count).to.equal(3n)
// expect(signals.main.start_idx).to.equal(10n)
// const expected_reveal = 'bc'.split('').map((x) => BigInt(x.charCodeAt(0)))
// assert_reveal(signals, expected_reveal);
// }
// ],
]
],
[
['(\r\n|\x80)(to|from):((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9| |_|.|"|@|-)+<)?(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-)+@(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-)+>?\r\n', 2],
[
[
'from to email header',
convertMsg(fs.readFileSync(path.join(__dirname, 'header.fixture.txt'), 'utf8')),
0,
(signals) => {
expect(signals.main.entire_count).to.equal(2n);
expect(signals.main.group_match_count).to.equal(2n);
expect(signals.main.start_idx).to.equal(54n);
const expected_reveal = encodeString('verify');
assert_reveal(signals, expected_reveal);
}
],
]
],
[
['dkim-signature:((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|\\/|:|<|=|>|\\?|@|\\[|\\\\|\\]|^|_|`|{|\\||}|~| |\t|\n' +
'|\r|\x0B|\f)+; )+bh=(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\+|\\/|=)+; ', 2],
[
[
'assert body hash',
convertMsg('\r\ndkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=twitter.com; s=dkim-201406; t=1671865957; bh=hEMyi6n9V0N6aGtz3lEc6fQBlZRVUok/tkwpRCmrnaa=; h=Date:From:To:Subject:MIME-Version:Content-Type:Message-ID; b='),
0,
(signals) => {
expect(signals.main.entire_count).to.equal(1n);
expect(signals.main.group_match_count).to.equal(1n);
const expected_reveal = encodeString('hEMyi6n9V0N6aGtz3lEc6fQBlZRVUok/tkwpRCmrnaa=');
assert_reveal(signals, expected_reveal);
}
]
]
],
]
.forEach((regexSuite) => {
const regex = regexSuite[0][0];
const group_idx = regexSuite[0][1];
const tests = regexSuite[1];
const testCircomFile = `test_regex_compiler_group_${group_idx}.circom`;
let circuit;
describe(`/${regex}/ > group idx: ${group_idx} > ${testCircomFile}`, () => {
before(async function () {
await generator.generateCircuit(
regex,
'../circuits'
);
circuit = await wasm_tester(
path.join(__dirname, 'circuits', testCircomFile),
{recompile: process.env.NO_COMPILE ? false : true, output: `${__dirname}/../build/`, O: 0}
);
});
tests.forEach((test) => {
const name = test[0];
const content = test[1];
const match_idx = test[2];
const checkSignals = test[3];
describe(name, () => {
it('checks witness', async function() {
let witness = await circuit.calculateWitness({msg: content, match_idx});
const signals = await circuit.getJSONOutput('main', witness);
checkSignals(signals);
await circuit.checkConstraints(witness);
});
});
});
});
});
describe('exceptions', () => {
it('character class not supported', async () => {
try {
await generator.generateCircuit(
'[a-z]',
'../circuits'
);
}
catch (e) {
expect(e.message).to.equal('CharacterClass not supported');
return;
}
expect.fail('should have thrown');
});
});
});
function encodeString(str) {
return str.split('').map((x) => BigInt(x.charCodeAt(0)));
}
function convertMsg(msg, maxLen = 1536) {
let msgEncoded = msg.split('').map((x) => x.charCodeAt(0));
while (msgEncoded.length < maxLen) {
msgEncoded.push(0);
}
msgEncoded = msgEncoded.map((x) => `${x}`);
return msgEncoded;
}
function assert_reveal(signals, expected_reveal) {
for (let m in signals.main.reveal_shifted) {
const value = signals.main.reveal_shifted[m];
if (expected_reveal[m]) {
expect(value).to.equal(expected_reveal[m]);
}
}
}

View File

@@ -1,218 +0,0 @@
const fs = require('fs');
import { expect } from 'chai';
const path = require('path')
const circom_tester = require('circom_tester');
const generator = require('../compiler/gen')
const wasm_tester = circom_tester.wasm;
describe("regex compiler tests", function () {
[
[
[`1=(a|b) (2=(b|c)+ )+d`, 0],
[
[
'1 entire match and 1st sub-group match',
convertMsg(`1=a 2=b 2=bc 2=c d`),
0,
(signals: any) => {
expect(signals.main.entire_count).to.equal(1n)
expect(signals.main.group_match_count).to.equal(1n)
expect(signals.main.start_idx).to.equal(2n)
const expected_reveal = encodeString('a')
assert_reveal(signals, expected_reveal);
}
],
]
],
[
[`1=(a|b) (2=(b|c)+ )+d`, 1],
[
[
'1 entire match and 1st sub-group match',
convertMsg(`1=a 2=b 2=bc 2=c d`),
0,
(signals: any) => {
expect(signals.main.entire_count).to.equal(1n)
expect(signals.main.group_match_count).to.equal(3n)
expect(signals.main.start_idx).to.equal(6n)
const expected_reveal = encodeString('b')
assert_reveal(signals, expected_reveal);
}
],
[
'1 entire match and 2nd sub-group match',
convertMsg(`1=a 2=b 2=bc 2=c d`),
1,
(signals: any) => {
expect(signals.main.entire_count).to.equal(1n)
expect(signals.main.group_match_count).to.equal(3n)
expect(signals.main.start_idx).to.equal(10n)
const expected_reveal = encodeString('bc')
assert_reveal(signals, expected_reveal);
}
],
[
'1 entire match and 3rd sub-group match',
convertMsg(`1=a 2=b 2=bc 2=c d`),
2,
(signals: any) => {
expect(signals.main.entire_count).to.equal(1n)
expect(signals.main.group_match_count).to.equal(3n)
expect(signals.main.start_idx).to.equal(15n)
const expected_reveal = encodeString('c')
assert_reveal(signals, expected_reveal);
}
],
[
'0 entire match and 2 group matches',
convertMsg(`1=a 2=b 2=bc 2=e d`),
1,
(signals: any) => {
expect(signals.main.entire_count).to.equal(0n)
expect(signals.main.group_match_count).to.equal(2n)
}
],
[
'2 entire match and 2nd sub-group match',
convertMsg(`1=a 2=b 2=bc 2=c da 1=a 2=cb 2=c 2=b dd`),
1,
(signals: any) => {
expect(signals.main.entire_count).to.equal(2n)
expect(signals.main.group_match_count).to.equal(6n)
expect(signals.main.start_idx).to.equal(10n)
const expected_reveal = encodeString('bc')
assert_reveal(signals, expected_reveal);
}
],
// todo TOFIX
// [
// '1 entire match and 1+ group matches with no trails behind the last group',
// convertMsg(`1=a 2=b 2=bc 2=c `),
// [`1=(a|b) (2=(b|c)+ )+`, 1, 1],
// (signals: any) => {
// for (let i = 0; i < signals.main.states.length; i++) {
// console.log(signals.main.states[i][8])
// }
// expect(signals.main.entire_count).to.equal(1n)
// expect(signals.main.group_match_count).to.equal(3n)
// expect(signals.main.start_idx).to.equal(10n)
// const expected_reveal = 'bc'.split('').map((x: any) => BigInt(x.charCodeAt(0)))
// assert_reveal(signals, expected_reveal);
// }
// ],
]
],
[
['(\r\n|\x80)(to|from):((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9| |_|.|"|@|-)+<)?(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-)+@(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-)+>?\r\n', 2],
[
[
'from to email header',
convertMsg(fs.readFileSync(path.join(__dirname, 'header.fixture.txt'), 'utf8')),
0,
(signals: any) => {
expect(signals.main.entire_count).to.equal(2n)
expect(signals.main.group_match_count).to.equal(2n)
expect(signals.main.start_idx).to.equal(54n)
const expected_reveal = encodeString('verify')
assert_reveal(signals, expected_reveal);
}
],
]
],
[
['dkim-signature:((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|\\/|:|<|=|>|\\?|@|\\[|\\\\|\\]|^|_|`|{|\\||}|~| |\t|\n' +
'|\r|\x0B|\f)+; )+bh=(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\+|\\/|=)+; ', 2],
[
[
'assert body hash',
convertMsg("\r\ndkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=twitter.com; s=dkim-201406; t=1671865957; bh=hEMyi6n9V0N6aGtz3lEc6fQBlZRVUok/tkwpRCmrnaa=; h=Date:From:To:Subject:MIME-Version:Content-Type:Message-ID; b="),
0,
(signals: any) => {
expect(signals.main.entire_count).to.equal(1n)
expect(signals.main.group_match_count).to.equal(1n)
const expected_reveal = encodeString('hEMyi6n9V0N6aGtz3lEc6fQBlZRVUok/tkwpRCmrnaa=')
assert_reveal(signals, expected_reveal);
}
]
]
],
]
.forEach((regexSuite: any) => {
const regex = regexSuite[0][0]
const group_idx = regexSuite[0][1]
const tests: any = regexSuite[1]
const testCircomFile = `test_regex_compiler_group_${group_idx}.circom`
let circuit: any;
describe(`/${regex}/ > group idx: ${group_idx} > ${testCircomFile}`, () => {
before(async function () {
await generator.generateCircuit(
regex,
'../circuits'
)
circuit = await wasm_tester(
path.join(__dirname, "circuits", testCircomFile),
{recompile: process.env.NO_COMPILE ? false : true, output: `${__dirname}/../build/`, O: 0}
);
});
tests.forEach((test: any) => {
//@ts-ignore
const name: string = test[0]
//@ts-ignore
const content: string = test[1]
//@ts-ignore
const match_idx: number = test[2]
//@ts-ignore
const checkSignals: Function = test[3]
describe(name, () => {
it('checks witness', async function() {
let witness = await circuit.calculateWitness({msg: content, match_idx});
const signals = await circuit.getJSONOutput('main', witness);
checkSignals(signals)
await circuit.checkConstraints(witness);
});
});
})
});
})
describe('exceptions', () => {
it('character class not supported', async () => {
try {
await generator.generateCircuit(
'[a-z]',
'../circuits'
)
}
catch (e: any) {
expect(e.message).to.equal('CharacterClass not supported')
return
}
expect.fail('should have thrown')
});
});
});
function encodeString(str: string) {
return str.split('').map((x: any) => BigInt(x.charCodeAt(0)));
}
function convertMsg(msg: string, maxLen: number = 1536) {
let msgEncoded = msg.split('').map((x: any) => x.charCodeAt(0));
while (msgEncoded.length < maxLen) {
msgEncoded.push(0);
}
msgEncoded = msgEncoded.map((x: any) => `${x}`);
return msgEncoded;
}
function assert_reveal(signals: any, expected_reveal: bigint[]) {
for (let m in signals.main.reveal_shifted) {
const value = signals.main.reveal_shifted[m];
if (expected_reveal[m as any]) {
expect(value).to.equal(expected_reveal[m as any]);
}
}
}

3879
yarn.lock

File diff suppressed because it is too large Load Diff