diff --git a/Cargo.lock b/Cargo.lock
index f7d2691..06d63c3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -121,6 +121,15 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+[[package]]
+name = "pabuild"
+version = "0.0.0"
+dependencies = [
+ "clap",
+ "serde",
+ "serde_json",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.86"
@@ -278,12 +287,3 @@ name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "wpbuild"
-version = "0.0.0"
-dependencies = [
- "clap",
- "serde",
- "serde_json",
-]
diff --git a/Cargo.toml b/Cargo.toml
index dbfe087..d252b64 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "wpbuild"
+name = "pabuild"
edition = "2021"
[dependencies]
diff --git a/README.md b/README.md
index 6b88400..fc344aa 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
- SPARK
+ Parser Attestor
@@ -16,67 +16,118 @@
## Overview
-SPARK (Succinct Parser Attestation for Reconciliation of Knowledge) is a project focused on implementing parsers and extractors for various data formats using zero-knowledge proofs.
+`parser-attestor` is a project focused on implementing parsers and extractors/selective-disclosure for various data formats inside of zero-knowledge circuits.
## Repository Structure
-- `src/bin`: Binaries
- - `witness`: Used for witness generation
- - `codegen`: Used for generating extractor circuits based on input
- `circuits/`: Current implementation of circuits
- `http`: HTTP parser and extractor
- `json`: JSON parser and extractor
+ - `json` has its own documentation [here](docs/json.md)
- `utils`: Utility circuits
- `test`: Circuit tests
+- `src/`: Rust `pabuild` binary
+ - `pabuild` has its own documentation [here](docs/pabuild.md)
- `examples/`: Reference examples for JSON and HTTP parsers
+Documentation, in general, can be found in the `docs` directory.
+We will add to this over time to make working with `parser-attestor` easier.
+
## Getting Started
### Prerequisites
-To use this repo, you need to install the following:
+To use this repo, you will need to install the following dependencies.
+These instructions should work on Linux/GNU and MacOS, but aren't guaranteed to work on Windows.
-1. `circom` and `snarkjs`:
- ```sh
- git clone https://github.com/iden3/circom.git
- cd circom
- cargo build --release
- cargo install --path circom
- npm install -g snarkjs
+#### Install Rust
+To install Rust, you need to run:
+```sh
+curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+exec $SHELL
+```
+Check this is installed by running:
+```sh
+rustc --version && cargo --version
+```
+to see the path to your Rust compiler and Cargo package manager.
-### Circomkit
-You will need `yarn` on your system (brew, or apt-get or something).
-Then run: `npm install` to get everything else.
+#### Install Circom
+Succinctly, `cd` to a directory of your choosing and run:
+```sh
+git clone https://github.com/iden3/circom.git
+cd circom
+cargo build --release
+cargo install --path circom
+```
+in order to install `circom` globally.
-#### Commands
-To see what you can do, I suggest running:
+#### Install Node
+First, install `nvm` by running:
+```sh
+curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
+exec $SHELL
```
-npx circomkit help
+Now with `nvm` installed, run:
+```sh
+nvm install --lts
+nvm use --lts
+node --version && npm --version
```
-from the repository root.
-#### Compiling and Witnessgen
-For example, to compile the extractor, you can:
+#### Node packages
+From the root of the repository, you can now run:
+```sh
+npm install
```
-npx circomkit compile extract
+which will install all the necessary packages for working with Circom.
+This includes executables `circomkit`, `snarkjs`, and `mocha` which are accessible with Node: `npx`.
+
+##### Circomkit
+This repository uses `circomkit` to manage Circom circuits.
+To see what you can do with `circomkit`, we suggest running:
```
-Then you can do
+npx circomkit help
```
-npx circomkit witness extract witness
+`circomkit` can essentially do everything you would want to do with these Circuits, though we can't guarantee all commands work properly.
+
+**Example:**
+For example, to compile the `json-parser`, you can run the following from the repository root:
```
-And even:
+npx circomkit compile json-parser
```
-npx circomkit prove extract witness
+which implicitly checks the `circuits.json` for an object that points to the circuit's code itself.
+
+If you are having trouble with `circomkit`, consider:
+
+##### SNARKJS
+Likewise, `snarkjs` is used to handle proofs and verification under the hood.
+There is [documentation](https://docs.circom.io/getting-started/compiling-circuits/) on Circom's usage to work with this.
+We suggest starting at that link and carrying through to "Proving circuits with ZK".
+
+##### Mocha
+`mocha` will also be installed from before.
+Running
+```sh
+npx mocha
```
+will run every circuit test.
+To filter tests, you can use the `-g` flag (very helpful!).
-To clean up, just run:
+
+### Install `pabuild`
+From the root of this repository, run:
+```sh
+cargo install --path .
```
-npx circomkit clean extract
+to install the `wpbuild` binary.
+You can see a help menu with the subcommands by:
+```sh
+wpbuild --help
```
+This is our local Rust command line application.
+Please see the [documentation](docs/pabuild.md) for how to use this alongside the other tools.
-All of the above should be ran from repository root.
-
-## Binaries
### Rust Example Witness JSON Creation
To generate example input JSON files for the Circom circuits, run:
@@ -101,111 +152,6 @@ witness http --input-file examples/http/get_request.http --output-dir inputs/get
Afterwards, you can run `circomkit compile get_request` then `circomkit witness get_request input`.
-### Codegen
-
-JSON extractor circuit is generated using rust to handle arbitrary keys and array indices.
-
-Run:
-```bash
-cargo run --bin codegen -- --help
-```
-to get options:
-```
-Usage: codegen [OPTIONS] --json-file
-
-Options:
- -j, --json-file Path to the JSON file
- -o, --output-filename Output circuit file name [default: extractor]
-```
-Takes input 2 arguments:
-- `json-file`: input json file. Examples are located in [codegen](./examples/json/test/codegen/)
-- `output-filename`: circuit filename to save. Located in [circuits/main](./circuits/main/). If not given, defaults to `extractor.circom`.
-
-To test an end-to-end JSON extraction proof:
-- Run codegen to generate circuits. Replace `value_string` with input filename.
- ```bash
- cargo run --bin codegen -- --json-file ./examples/json/test/codegen/value_string.json --output-filename value_string
- ```
-
-- Compile circom circuit using
- ```
- circom ./circuits/main/value_string.circom --r1cs --wasm
- ```
-
-- To use circomkit: add circuit config to [circuits.json](./circuits.json). and input file to [inputs](./inputs/)
-
-- Generate witness:
- ```bash
- node build/json_extract_value_string/json_extract_value_string_js/generate_witness inputs/json_extract_value_string/value_string.json build/json_extract_value_string/witness/
- ```
- or generate using circomkit:
- ```bash
- npx circomkit witness json_extract_value_string value_string
- ```
-
-- create trusted setup:
- ```bash
- npx circomkit setup json_extract_value_string
- # OR
- snarkjs groth16 setup build/json_extract_value_string/json_extract_value_string.r1cs ptau/powersOfTau28_hez_final_14.ptau build/json_extract_value_string/groth16_pkey.zkey
- ```
-
-- create proof:
- ```bash
- npx circomkit prove json_extract_value_string value_string
- # OR
- snarkjs groth16 prove build/json_extract_value_string/groth16_pkey.zkey build/json_extract_value_string/value_string/witness.wtns build/json_extract_value_string/value_string/groth16_proof.json inputs/json_extract_value_string/value_string.json
- ```
-
-- verify proof:
- ```bash
- npx circomkit verify json_extract_value_string value_string
- # OR
- snarkjs groth16 verify build/json_extract_value_string/groth16_vkey.json inputs/json_extract_value_string/value_string.json build/json_extract_value_string/value_string/groth16_proof.json
- ```
-
-## Testing
-To test, you can just run
-```
-npx mocha
-```
-from the repository root.
-
-To run specific tests, use the `-g` flag for `mocha`, e.g., to run any proof described with "State" we can pass:
-```
-npx mocha -g State
-```
-
-> [!NOTE]
-> Currently [search](./circuits/search.circom) circuit isn't working with circomkit, so you might have to compile using circom: `circom circuits/main/search.circom --r1cs --wasm -l node_modules/ -o build/search/`
-
-## (MOSTLY DEPRECATED DUE TO CIRCOMKIT) Running an example
-```
-circom extract.circom --r1cs --wasm
-
-# in rust? circom witness rs
-node extract_js/generate_witness.js extract_js/extract.wasm input.json witness.wtns
-
-##
-# IF YOU NEED A NEW pot (works for all circuits)
-snarkjs powersoftau new bn128 14 pot14_0000.ptau -v
-snarkjs powersoftau contribute pot14_0000.ptau pot14_0001.ptau --name="First contribution" -v
-snarkjs powersoftau prepare phase2 pot14_0001.ptau pot14_final.ptau -v
-##
-
-snarkjs groth16 setup extract.r1cs pot14_final.ptau extract_0000.zkey
-
-snarkjs zkey contribute extract_0000.zkey extract_0001.zkey --name="1st Contributor Name" -v
-
-snarkjs zkey export verificationkey extractor_0001.zkey verification_key.json
-
-# in rust
-snarkjs groth16 prove extractor_0001.zkey witness.wtns proof.json public.json
-
-# in rust
-snarkjs groth16 verify verification_key.json public.json proof.json
-```
-
## Contributing
diff --git a/circuits.json b/circuits.json
index 9139100..09f0948 100644
--- a/circuits.json
+++ b/circuits.json
@@ -1,5 +1,5 @@
{
- "extract": {
+ "json-parser": {
"file": "json/parser/parser",
"template": "Parser",
"params": [
@@ -7,93 +7,11 @@
13
]
},
- "value_string": {
- "file": "json/parser/parser",
- "template": "Parser",
- "params": [
- 12,
- 1
- ]
- },
- "value_number": {
- "file": "json/parser/parser",
- "template": "Parser",
- "params": [
- 12,
- 2
- ]
- },
- "value_array": {
- "file": "json/parser/parser",
- "template": "Parser",
- "params": [
- 18,
- 2
- ]
- },
- "value_array_nested": {
- "file": "json/parser/parser",
- "template": "Parser",
- "params": [
- 24,
- 4
- ]
- },
- "value_array_object": {
- "file": "json/parser/parser",
- "template": "Parser",
- "params": [
- 25,
- 4
- ]
- },
- "value_array_object_array": {
- "file": "json/parser/parser",
- "template": "Parser",
- "params": [
- 31,
- 5
- ]
- },
- "value_object": {
- "file": "json/parser/parser",
- "template": "Parser",
- "params": [
- 21,
- 3
- ]
- },
- "search": {
- "file": "search",
- "template": "SubstringMatch",
- "params": [
- 787,
- 10
- ]
- },
- "get_request": {
+ "http-parser": {
"file": "http/parser/parser",
"template": "Parser",
"params": [
60
]
- },
- "get_response": {
- "file": "http/parser/parser",
- "template": "Parser",
- "params": [
- 89
- ]
- },
- "json_extract_value_string": {
- "file": "main/value_string",
- "template": "ExtractStringValue",
- "params": [
- 12,
- 1,
- 1,
- 0,
- 1
- ]
}
}
\ No newline at end of file
diff --git a/circuits/http/extractor.circom b/circuits/http/extractor.circom
index d6b3dd6..03ad0c2 100644
--- a/circuits/http/extractor.circom
+++ b/circuits/http/extractor.circom
@@ -72,7 +72,7 @@ template ExtractResponse(DATA_BYTES, maxContentLength) {
signal isPrevStartingIndex[DATA_BYTES];
valueStartingIndex[0] <== 0;
isZeroMask[0] <== IsZero()(dataMask[0]);
- for (var i=1 ; i(filename: string): T {
+ const filePath = join(__dirname, "..", "..", "..", "examples", "http", "lockfile", filename);
const jsonString = readFileSync(filePath, 'utf-8');
const jsonData = JSON.parse(jsonString);
return jsonData;
}
-interface HttpData {
- request: Request;
- response: Response;
+function getHeaders(data: Request | Response): [string, string][] {
+ const headers: [string, string][] = [];
+ let i = 1;
+ while (true) {
+ const nameKey = `headerName${i}`;
+ const valueKey = `headerValue${i}`;
+ if (nameKey in data && valueKey in data) {
+ headers.push([data[nameKey], data[valueKey]]);
+ i++;
+ } else {
+ break;
+ }
+ }
+ return headers;
}
interface Request {
method: string,
target: string,
version: string,
- headers: [string, string][],
+ [key: string]: string,
}
interface Response {
version: string,
status: string,
message: string,
- headers: [string, string][],
+ [key: string]: string,
}
function executeCodegen(inputFilename: string, outputFilename: string) {
return new Promise((resolve, reject) => {
- const inputPath = join(__dirname, "..", "..", "..", "examples", "lockfile", inputFilename);
+ const inputPath = join(__dirname, "..", "..", "..", "examples", "http", "lockfile", inputFilename);
- const codegen = spawn("cargo", ["run", "http-lock", "--lockfile", inputPath, "--output-filename", outputFilename]);
+ const codegen = spawn("cargo", ["run", "http", "--lockfile", inputPath, "--output-filename", outputFilename]);
codegen.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
@@ -54,86 +65,184 @@ function executeCodegen(inputFilename: string, outputFilename: string) {
});
}
-describe("HTTP :: Codegen", async () => {
- let circuit: WitnessTester<["data", "beginning", "middle", "final", "header1", "value1", "header2", "value2"], []>;
+describe("HTTP :: Codegen :: Request", async () => {
+ let circuit: WitnessTester<["data", "method", "target", "version", "header1", "value1", "header2", "value2"], []>;
- it("(valid) get_request:", async () => {
- let lockfile = "test.lock";
+ it("(valid) GET:", async () => {
+ let lockfile = "request.lock";
let inputfile = "get_request.http";
// generate extractor circuit using codegen
await executeCodegen(`${lockfile}.json`, lockfile);
- const lockData = await readLockFile(`${lockfile}.json`);
+ const lockData = readLockFile(`${lockfile}.json`);
console.log("lockData: ", JSON.stringify(lockData));
- const input = await readHTTPInputFile(`${inputfile}`).input
+ const input = readHTTPInputFile(`${inputfile}`).input;
- const params = [input.length, lockData.request.method.length, lockData.request.target.length, lockData.request.version.length];
- lockData.request.headers.forEach(header => {
- params.push(header[0].length); // Header name length
- params.push(header[1].length); // Header value length
- console.log("header: ", header[0]);
- console.log("value: ", header[1]);
+ const headers = getHeaders(lockData);
+ const params = [input.length, lockData.method.length, lockData.target.length, lockData.version.length];
+ headers.forEach(header => {
+ params.push(header[0].length);
+ params.push(header[1].length);
});
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${lockfile}`,
- template: "LockHTTP",
+ file: `main/${lockfile}`,
+ template: "LockHTTPRequest",
params: params,
});
console.log("#constraints:", await circuit.getConstraintCount());
// match circuit output to original JSON value
- await circuit.expectPass({
+ const circuitInput: any = {
data: input,
- beginning: toByte(lockData.request.method),
- middle: toByte(lockData.request.target),
- final: toByte(lockData.request.version),
- header1: toByte(lockData.request.headers[0][0]),
- value1: toByte(lockData.request.headers[0][1]),
- header2: toByte(lockData.request.headers[1][0]),
- value2: toByte(lockData.request.headers[1][1])
- },
- {}
- );
+ method: toByte(lockData.method),
+ target: toByte(lockData.target),
+ version: toByte(lockData.version),
+ };
+
+ headers.forEach((header, index) => {
+ circuitInput[`header${index + 1}`] = toByte(header[0]);
+ circuitInput[`value${index + 1}`] = toByte(header[1]);
+ });
+ await circuit.expectPass(circuitInput, {});
});
- it("(invalid) get_request:", async () => {
- let lockfile = "test.lock";
+ it("(invalid) GET:", async () => {
+ let lockfile = "request.lock";
let inputfile = "get_request.http";
// generate extractor circuit using codegen
await executeCodegen(`${lockfile}.json`, lockfile);
- const lockData = await readLockFile(`${lockfile}.json`);
+ const lockData = readLockFile(`${lockfile}.json`);
- const input = await readHTTPInputFile(`${inputfile}`).input
+ const input = readHTTPInputFile(`${inputfile}`).input
- const params = [input.length, lockData.request.method.length, lockData.request.target.length, lockData.request.version.length];
- lockData.request.headers.forEach(header => {
- params.push(header[0].length); // Header name length
- params.push(header[1].length); // Header value length
+ const headers = getHeaders(lockData);
+ const params = [input.length, lockData.method.length, lockData.target.length, lockData.version.length];
+ headers.forEach(header => {
+ params.push(header[0].length);
+ params.push(header[1].length);
});
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${lockfile}`,
- template: "LockHTTP",
+ file: `main/${lockfile}`,
+ template: "LockHTTPRequest",
params: params,
});
console.log("#constraints:", await circuit.getConstraintCount());
- await circuit.expectFail({
- data: input.slice(0),
- beginning: toByte(lockData.request.method),
- middle: toByte(lockData.request.target),
- final: toByte(lockData.request.version),
- header1: toByte(lockData.request.headers[0][0]),
- value1: toByte("/aip"),
- header2: toByte(lockData.request.headers[1][0]),
- value2: toByte(lockData.request.headers[1][1])
+ const circuitInput: any = {
+ data: input,
+ method: toByte(lockData.method),
+ target: toByte(lockData.target),
+ version: toByte(lockData.version),
+ };
+
+ headers.forEach((header, index) => {
+ circuitInput[`header${index + 1}`] = toByte(header[0]);
+ circuitInput[`value${index + 1}`] = toByte(header[1]);
});
+
+ circuitInput.value1 = toByte("/aip");
+ await circuit.expectFail(circuitInput);
});
});
+
+describe("HTTP :: Codegen :: Response", async () => {
+ let circuit: WitnessTester<["data", "version", "status", "message", "header1", "value1", "header2", "value2"], ["body"]>;
+
+ it("(valid) GET:", async () => {
+ let lockfile = "response.lock";
+ let inputfile = "get_response.http";
+
+ // generate extractor circuit using codegen
+ await executeCodegen(`${lockfile}.json`, lockfile);
+
+ const lockData = readLockFile(`${lockfile}.json`);
+ console.log("lockData: ", JSON.stringify(lockData));
+
+ const http = readHTTPInputFile(`${inputfile}`);
+ const input = http.input;
+
+ const headers = getHeaders(lockData);
+
+ const params = [input.length, parseInt(http.headers["Content-Length"]), lockData.version.length, lockData.status.length, lockData.message.length];
+ headers.forEach(header => {
+ params.push(header[0].length);
+ params.push(header[1].length);
+ });
+
+
+ circuit = await circomkit.WitnessTester(`Extract`, {
+ file: `main/${lockfile}`,
+ template: "LockHTTPResponse",
+ params: params,
+ });
+ console.log("#constraints:", await circuit.getConstraintCount());
+
+ // match circuit output to original JSON value
+ const circuitInput: any = {
+ data: input,
+ version: toByte(lockData.version),
+ status: toByte(lockData.status),
+ message: toByte(lockData.message),
+ };
+
+ headers.forEach((header, index) => {
+ circuitInput[`header${index + 1}`] = toByte(header[0]);
+ circuitInput[`value${index + 1}`] = toByte(header[1]);
+ });
+
+
+ await circuit.expectPass(circuitInput, { body: http.bodyBytes });
+ });
+
+ it("(invalid) GET:", async () => {
+ let lockfile = "response.lock";
+ let inputfile = "get_response.http";
+
+ // generate extractor circuit using codegen
+ await executeCodegen(`${lockfile}.json`, lockfile);
+
+ const lockData = readLockFile(`${lockfile}.json`);
+
+ const http = readHTTPInputFile(`${inputfile}`);
+ const input = http.input;
+
+ const headers = getHeaders(lockData);
+
+ const params = [input.length, parseInt(http.headers["Content-Length"]), lockData.version.length, lockData.status.length, lockData.message.length];
+ headers.forEach(header => {
+ params.push(header[0].length);
+ params.push(header[1].length);
+ });
+
+
+ circuit = await circomkit.WitnessTester(`Extract`, {
+ file: `main/${lockfile}`,
+ template: "LockHTTPResponse",
+ params: params,
+ });
+ console.log("#constraints:", await circuit.getConstraintCount());
+
+ const circuitInput: any = {
+ data: input,
+ version: toByte(lockData.version),
+ status: toByte(lockData.status),
+ message: toByte(lockData.message),
+ };
+
+ headers.forEach((header, index) => {
+ circuitInput[`header${index + 1}`] = toByte(header[0]);
+ circuitInput[`value${index + 1}`] = toByte(header[1]);
+ });
+
+ circuitInput.value1 = toByte("/aip");
+ await circuit.expectFail(circuitInput);
+ });
+});
\ No newline at end of file
diff --git a/circuits/test/http/extractor.test.ts b/circuits/test/http/extractor.test.ts
index 6619de4..c69c7a7 100644
--- a/circuits/test/http/extractor.test.ts
+++ b/circuits/test/http/extractor.test.ts
@@ -9,7 +9,7 @@ describe("HTTP :: body Extractor", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`ExtractResponseData`, {
- file: "circuits/http/extractor",
+ file: "http/extractor",
template: "ExtractResponse",
params: [input.length, expected.length],
});
@@ -60,7 +60,7 @@ describe("HTTP :: header Extractor", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`ExtractHeaderValue`, {
- file: "circuits/http/extractor",
+ file: "http/extractor",
template: "ExtractHeaderValue",
params: [input.length, headerName.length, headerValue.length],
});
diff --git a/circuits/test/http/interpreter.test.ts b/circuits/test/http/interpreter.test.ts
index 5c46d95..ac1a330 100644
--- a/circuits/test/http/interpreter.test.ts
+++ b/circuits/test/http/interpreter.test.ts
@@ -9,7 +9,7 @@ describe("HTTP :: Interpreter", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`LockRequestLineData`, {
- file: "circuits/http/interpreter",
+ file: "http/interpreter",
template: "MethodMatch",
params: [input.length, method.length],
});
@@ -24,7 +24,7 @@ describe("HTTP :: Interpreter", async () => {
it(`(invalid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`LockRequestLineData`, {
- file: "circuits/http/interpreter",
+ file: "http/interpreter",
template: "MethodMatch",
params: [input.length, method.length],
});
diff --git a/circuits/test/http/locker.test.ts b/circuits/test/http/locker.test.ts
index 1a67fc1..4969b39 100644
--- a/circuits/test/http/locker.test.ts
+++ b/circuits/test/http/locker.test.ts
@@ -8,7 +8,7 @@ describe("HTTP :: Locker :: Request Line", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`LockStartLine`, {
- file: "circuits/http/locker",
+ file: "http/locker",
template: "LockStartLine",
params: [input.length, beginning.length, middle.length, final.length],
});
@@ -23,7 +23,7 @@ describe("HTTP :: Locker :: Request Line", async () => {
it(`(invalid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`LockStartLine`, {
- file: "circuits/http/locker",
+ file: "http/locker",
template: "LockStartLine",
params: [input.length, beginning.length, middle.length, final.length],
});
@@ -58,7 +58,7 @@ describe("HTTP :: Locker :: Status Line", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`LockStartLine`, {
- file: "circuits/http/locker",
+ file: "http/locker",
template: "LockStartLine",
params: [input.length, beginning.length, middle.length, final.length],
});
@@ -73,7 +73,7 @@ describe("HTTP :: Locker :: Status Line", async () => {
it(`(invalid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`LockStartLine`, {
- file: "circuits/http/locker",
+ file: "http/locker",
template: "LockStartLine",
params: [input.length, beginning.length, middle.length, final.length],
});
@@ -100,7 +100,7 @@ describe("HTTP :: Locker :: Header", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`LockHeader`, {
- file: "circuits/http/locker",
+ file: "http/locker",
template: "LockHeader",
params: [input.length, header.length, value.length],
});
@@ -115,7 +115,7 @@ describe("HTTP :: Locker :: Header", async () => {
it(`(invalid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`LockHeader`, {
- file: "circuits/http/locker",
+ file: "http/locker",
template: "LockHeader",
params: [input.length, header.length, value.length],
});
diff --git a/circuits/test/json/extractor/extractor.test.ts b/circuits/test/json/extractor/extractor.test.ts
index 4d47ea7..9b9b6b3 100644
--- a/circuits/test/json/extractor/extractor.test.ts
+++ b/circuits/test/json/extractor/extractor.test.ts
@@ -5,9 +5,9 @@ import { spawn } from "child_process";
function executeCodegen(inputFilename: string, outputFilename: string) {
return new Promise((resolve, reject) => {
- const inputPath = join(__dirname, "..", "..", "..", "..", "examples", "extractor", inputFilename);
+ const inputPath = join(__dirname, "..", "..", "..", "..", "examples", "json", "lockfile", inputFilename);
- const codegen = spawn("cargo", ["run", "extractor", "--template", inputPath, "--output-filename", outputFilename]);
+ const codegen = spawn("cargo", ["run", "json", "--template", inputPath, "--output-filename", outputFilename]);
codegen.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
@@ -40,7 +40,7 @@ describe("ExtractValue", async () => {
let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, ["k"]);
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${filename}`,
+ file: `main/${filename}`,
template: "ExtractStringValue",
params: [input.length, 1, 1, 0, 1],
});
@@ -60,7 +60,7 @@ describe("ExtractValue", async () => {
let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, ["key2"]);
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${filename}`,
+ file: `main/${filename}`,
template: "ExtractStringValue",
params: [input.length, 1, 4, 0, 3],
});
@@ -75,7 +75,7 @@ describe("ExtractValue", async () => {
let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, ["k"]);
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${filename}`,
+ file: `main/${filename}`,
template: "ExtractNumValue",
params: [input.length, 1, 1, 0, 2],
});
@@ -94,7 +94,7 @@ describe("ExtractValue", async () => {
let [input, keyUnicode, output] = readJSONInputFile("value_array.json", ["b", i]);
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${filename}`,
+ file: `main/${filename}`,
template: "ExtractStringValue",
params: [input.length, 2, 1, 0, i, 1, output.length],
});
@@ -112,7 +112,7 @@ describe("ExtractValue", async () => {
let [input, keyUnicode, output] = readJSONInputFile("value_array.json", ["k", i]);
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${filename}`,
+ file: `main/${filename}`,
template: "ExtractNumValue",
params: [input.length, 2, 1, 0, i, 1, output.length],
});
@@ -131,7 +131,7 @@ describe("ExtractValue", async () => {
let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, ["a", index_0, index_1]);
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${filename}`,
+ file: `main/${filename}`,
template: "ExtractNumValue",
params: [input.length, 3, 1, 0, index_0, 1, index_1, 2, 1],
});
@@ -155,7 +155,7 @@ describe("ExtractValueMultiDepth", () => {
let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, ["e", "e"]);
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${filename}`,
+ file: `main/${filename}`,
template: "ExtractStringValue",
params: [input.length, 3, 1, 0, 1, 1, 1],
});
@@ -183,7 +183,7 @@ describe("ExtractValueArrayObject", () => {
let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, ["a", index_0, "b", index_1]);
circuit = await circomkit.WitnessTester(`Extract`, {
- file: `circuits/main/${filename}`,
+ file: `main/${filename}`,
template: "ExtractNumValue",
params: [input.length, 4, 1, 0, index_0, 1, 1, 2, index_1, 3, 1],
});
diff --git a/circuits/test/json/extractor/interpreter.test.ts b/circuits/test/json/extractor/interpreter.test.ts
index cb2bfd6..26643b1 100644
--- a/circuits/test/json/extractor/interpreter.test.ts
+++ b/circuits/test/json/extractor/interpreter.test.ts
@@ -7,7 +7,7 @@ describe("Interpreter", async () => {
before(async () => {
circuit = await circomkit.WitnessTester(`InsideKey`, {
- file: "circuits/json/interpreter",
+ file: "json/interpreter",
template: "InsideKey",
params: [4],
});
@@ -46,7 +46,7 @@ describe("Interpreter", async () => {
before(async () => {
circuit = await circomkit.WitnessTester(`InsideValue`, {
- file: "circuits/json/interpreter",
+ file: "json/interpreter",
template: "InsideValue",
params: [4],
});
@@ -88,7 +88,7 @@ describe("Interpreter", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`InsideValueAtDepth`, {
- file: "circuits/json/interpreter",
+ file: "json/interpreter",
template: "InsideValueAtDepth",
params: [4, depth],
});
@@ -125,7 +125,7 @@ describe("Interpreter", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`InsideArrayIndex`, {
- file: "circuits/json/interpreter",
+ file: "json/interpreter",
template: "InsideArrayIndex",
params: [4, index],
});
@@ -165,7 +165,7 @@ describe("Interpreter", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`InsideArrayIndexAtDepth`, {
- file: "circuits/json/interpreter",
+ file: "json/interpreter",
template: "InsideArrayIndexAtDepth",
params: [4, index, depth],
});
@@ -199,7 +199,7 @@ describe("Interpreter", async () => {
before(async () => {
circuit = await circomkit.WitnessTester(`NextKVPair`, {
- file: "circuits/json/interpreter",
+ file: "json/interpreter",
template: "NextKVPair",
params: [4],
});
@@ -239,7 +239,7 @@ describe("Interpreter", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`NextKVPairAtDepth`, {
- file: "circuits/json/interpreter",
+ file: "json/interpreter",
template: "NextKVPairAtDepth",
params: [4, depth],
});
@@ -273,7 +273,7 @@ describe("Interpreter", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`KeyMatch`, {
- file: "circuits/json/interpreter",
+ file: "json/interpreter",
template: "KeyMatch",
params: [input.data.length, input.key.length],
});
@@ -314,7 +314,7 @@ describe("Interpreter", async () => {
it(`(valid) witness: ${description} ${desc}`, async () => {
circuit = await circomkit.WitnessTester(`KeyMatchAtDepth`, {
- file: "circuits/json/interpreter",
+ file: "json/interpreter",
template: "KeyMatchAtDepth",
params: [input.data.length, 4, input.key.length, depth],
});
diff --git a/circuits/test/json/parser/parsing_types.test.ts b/circuits/test/json/parser/parsing_types.test.ts
index a5783dc..88d892e 100644
--- a/circuits/test/json/parser/parsing_types.test.ts
+++ b/circuits/test/json/parser/parsing_types.test.ts
@@ -19,7 +19,7 @@ describe("StateUpdate", () => {
before(async () => {
circuit = await circomkit.WitnessTester(`StateUpdate`, {
- file: "circuits/json/parser/machine",
+ file: "json/parser/machine",
template: "StateUpdate",
params: [4],
});
diff --git a/circuits/test/json/parser/stack.test.ts b/circuits/test/json/parser/stack.test.ts
index f719582..860737e 100644
--- a/circuits/test/json/parser/stack.test.ts
+++ b/circuits/test/json/parser/stack.test.ts
@@ -5,7 +5,7 @@ describe("GetTopOfStack", () => {
let circuit: WitnessTester<["stack"], ["value", "pointer"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`GetTopOfStack`, {
- file: "circuits/json/parser/machine",
+ file: "json/parser/machine",
template: "GetTopOfStack",
params: [4],
});
@@ -34,7 +34,7 @@ describe("StateUpdate :: RewriteStack", () => {
>;
before(async () => {
circuit = await circomkit.WitnessTester(`GetTopOfStack`, {
- file: "circuits/json/parser/machine",
+ file: "json/parser/machine",
template: "StateUpdate",
params: [4],
});
diff --git a/circuits/test/json/parser/values.test.ts b/circuits/test/json/parser/values.test.ts
index 2bca379..069525b 100644
--- a/circuits/test/json/parser/values.test.ts
+++ b/circuits/test/json/parser/values.test.ts
@@ -8,7 +8,7 @@ describe("StateUpdate :: Values", () => {
>;
before(async () => {
circuit = await circomkit.WitnessTester(`GetTopOfStack`, {
- file: "circuits/json/parser/machine",
+ file: "json/parser/machine",
template: "StateUpdate",
params: [4],
});
diff --git a/circuits/test/utils/array.test.ts b/circuits/test/utils/array.test.ts
index ae4a42e..c951452 100644
--- a/circuits/test/utils/array.test.ts
+++ b/circuits/test/utils/array.test.ts
@@ -5,7 +5,7 @@ describe("array", () => {
let circuit: WitnessTester<["in"], ["out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`Slice`, {
- file: "circuits/utils/array",
+ file: "utils/array",
template: "Slice",
params: [10, 2, 4],
});
@@ -33,7 +33,7 @@ describe("IsEqualArray", () => {
let circuit: WitnessTester<["in"], ["out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`IsEqualArray`, {
- file: "circuits/utils/array",
+ file: "utils/array",
template: "IsEqualArray",
params: [3],
});
@@ -87,7 +87,7 @@ describe("Contains", () => {
let circuit: WitnessTester<["in", "array"], ["out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`Contains`, {
- file: "circuits/utils/array",
+ file: "utils/array",
template: "Contains",
params: [3],
});
@@ -128,7 +128,7 @@ describe("ArrayAdd", () => {
let circuit: WitnessTester<["lhs", "rhs"], ["out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`ArrayAdd`, {
- file: "circuits/utils/array",
+ file: "utils/array",
template: "ArrayAdd",
params: [3],
});
@@ -148,7 +148,7 @@ describe("ArrayMul", () => {
let circuit: WitnessTester<["lhs", "rhs"], ["out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`ArrayMul`, {
- file: "circuits/utils/array",
+ file: "utils/array",
template: "ArrayMul",
params: [3],
});
@@ -168,7 +168,7 @@ describe("GenericArrayAdd", () => {
let circuit: WitnessTester<["arrays"], ["out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`ArrayAdd`, {
- file: "circuits/utils/array",
+ file: "utils/array",
template: "GenericArrayAdd",
params: [3, 2],
});
diff --git a/circuits/test/utils/bytes.test.ts b/circuits/test/utils/bytes.test.ts
index 5ee55ef..d0690a3 100644
--- a/circuits/test/utils/bytes.test.ts
+++ b/circuits/test/utils/bytes.test.ts
@@ -4,7 +4,7 @@ describe("ASCII", () => {
let circuit: WitnessTester<["in"], ["out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`ASCII`, {
- file: "circuits/utils/bytes",
+ file: "utils/bytes",
template: "ASCII",
params: [13],
});
diff --git a/circuits/test/utils/hash.test.ts b/circuits/test/utils/hash.test.ts
index e834cc7..1661367 100644
--- a/circuits/test/utils/hash.test.ts
+++ b/circuits/test/utils/hash.test.ts
@@ -7,7 +7,7 @@ describe("hash", () => {
before(async () => {
circuit = await circomkit.WitnessTester(`PoseidonModular`, {
- file: "circuits/utils/hash",
+ file: "utils/hash",
template: "PoseidonModular",
params: [16],
});
@@ -30,7 +30,7 @@ describe("hash", () => {
before(async () => {
circuit = await circomkit.WitnessTester(`PoseidonModular`, {
- file: "circuits/utils/hash",
+ file: "utils/hash",
template: "PoseidonModular",
params: [379],
});
diff --git a/circuits/test/utils/operators.test.ts b/circuits/test/utils/operators.test.ts
index 7c82c61..67c0069 100644
--- a/circuits/test/utils/operators.test.ts
+++ b/circuits/test/utils/operators.test.ts
@@ -4,7 +4,7 @@ describe("SwitchArray", () => {
let circuit: WitnessTester<["case", "branches", "vals"], ["match", "out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`SwitchArray`, {
- file: "circuits/utils/operators",
+ file: "utils/operators",
template: "SwitchArray",
params: [3, 2],
});
@@ -59,7 +59,7 @@ describe("Switch", () => {
let circuit: WitnessTester<["case", "branches", "vals"], ["match", "out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`Switch`, {
- file: "circuits/utils/operators",
+ file: "utils/operators",
template: "Switch",
params: [3],
});
@@ -101,7 +101,7 @@ describe("InRange", () => {
let circuit: WitnessTester<["in", "range"], ["out"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`InRange`, {
- file: "circuits/utils/operators",
+ file: "utils/operators",
template: "InRange",
params: [8],
});
diff --git a/circuits/test/utils/search.test.ts b/circuits/test/utils/search.test.ts
index f0938db..e6cbbe1 100644
--- a/circuits/test/utils/search.test.ts
+++ b/circuits/test/utils/search.test.ts
@@ -14,7 +14,7 @@ describe("search", () => {
const hashResult = PoseidonModular(concatenatedInput);
circuit = await circomkit.WitnessTester(`SubstringSearch`, {
- file: "circuits/utils/search",
+ file: "utils/search",
template: "SubstringSearch",
params: [data.length, key.length],
});
@@ -32,7 +32,7 @@ describe("search", () => {
const hashResult = PoseidonModular(concatenatedInput);
circuit = await circomkit.WitnessTester(`SubstringSearch`, {
- file: "circuits/utils/search",
+ file: "utils/search",
template: "SubstringSearch",
params: [data.length, key.length],
});
@@ -51,7 +51,7 @@ describe("search", () => {
const key = [1, 0];
circuit = await circomkit.WitnessTester(`SubstringSearch`, {
- file: "circuits/utils/search",
+ file: "utils/search",
template: "SubstringSearch",
params: [data.length, key.length],
});
@@ -67,7 +67,7 @@ describe("search", () => {
const hashResult = PoseidonModular(concatenatedInput);
circuit = await circomkit.WitnessTester(`SubstringSearch`, {
- file: "circuits/utils/search",
+ file: "utils/search",
template: "SubstringSearch",
params: [witness["data"].length, witness["key"].length],
});
@@ -85,7 +85,7 @@ describe("search", () => {
before(async () => {
circuit = await circomkit.WitnessTester(`SubstringSearch`, {
- file: "circuits/utils/search",
+ file: "utils/search",
template: "SubstringMatchWithIndex",
params: [787, 10],
});
@@ -122,7 +122,7 @@ describe("search", () => {
before(async () => {
circuit = await circomkit.WitnessTester(`SubstringSearch`, {
- file: "circuits/utils/search",
+ file: "utils/search",
template: "SubstringMatch",
params: [787, 10],
});
diff --git a/docs/http.md b/docs/http.md
new file mode 100644
index 0000000..e69de29
diff --git a/docs/pabuild.md b/docs/pabuild.md
new file mode 100644
index 0000000..97191c2
--- /dev/null
+++ b/docs/pabuild.md
@@ -0,0 +1,113 @@
+# `pabuild` CLI Tool
+This repository contains a small Rust CLI tool called `pabuild`.
+
+## Install `pabuild`
+From the root of this repository, run:
+```sh
+cargo install --path .
+```
+to install the `pabuild` binary.
+You can see a help menu with the subcommands by:
+```sh
+pabuild --help
+```
+
+## Witnessgen
+To get the basic idea, run
+```sh
+pabuild witness --help
+```
+It can process and generate JSON files to be used for these circuits.
+
+### Examples
+**JSON Parsing:**
+If we have a given JSON file we want to parse such as [`examples/json/test/example.json`](../examples/json/test/example.json) for the `json-parser` circuit (see [`circuits.json`](../circuits.json)), then we can:
+
+```sh
+pabuild witness json --input-file examples/json/test/example.json --output-dir inputs/json-parser --output-filename input.json json
+```
+
+Afterwards, you can run `npx circomkit compile json-parser` then `circomkit witness json-parser input`.
+
+**HTTP Parsing:**
+If we have a given HTTP request/response (as a file) we want to parse such as [`examples/http/get_request.http`](../examples/http/get_request.http) for the `http-parser` circuit (see `circuits.json`), then we can:
+
+```sh
+pabuild witness http --input-file examples/json/get_request.http --output-dir inputs/http-parser --output-filename input.json http
+```
+
+Afterwards, you can run `npx circomkit compile http-parser` then `circomkit witness http-parser input`.
+
+## Codegen
+
+### JSON Extraction
+JSON extractor circuit is generated using rust to handle arbitrary keys and array indices.
+
+Run:
+```sh
+pabuild json --help
+```
+to get options:
+```
+Usage: pabuild json [OPTIONS] --template
+
+Options:
+ -t, --template Path to the JSON file selective-disclosure template
+ -o, --output-filename Output circuit file name [default: extractor]
+ -d, --debug Optional circuit debug logs
+ -h, --help Print help
+```
+Takes 3 input arguments:
+- `template`: input json file. Examples are located in [extractor](../examples/extractor/).
+ - Should contain only two keys:
+ - `keys`: list of all the keys in the input json
+ - `value_type`: Currently only two value types are supported: `String`,`Number`.
+- `output-filename`: circuit filename to save. Located in [circuits/main](../circuits/main/). If not given, defaults to `extractor.circom`.
+- `debug`: Optional debug logs for parser and extractor output.
+
+To test an end-to-end JSON extraction proof:
+- Run codegen to generate circuits. Replace `value_string` with input filename.
+ ```sh
+ pabuild json --template examples/json/extractor/value_string.json --output-filename value_string
+ ```
+
+- Compile circom circuit using
+ ```
+ circom ./circuits/main/value_string.circom --r1cs --wasm
+ ```
+
+- To use circomkit: add circuit config to [circuits.json](../circuits.json). and input file to [inputs](../inputs/)
+
+- Generate witness:
+ ```bash
+ node build/json_extract_value_string/json_extract_value_string_js/generate_witness inputs/json_extract_value_string/value_string.json build/json_extract_value_string/witness/
+ ```
+ or generate using circomkit:
+ ```bash
+ npx circomkit witness json_extract_value_string value_string
+ ```
+
+- create trusted setup:
+ ```bash
+ npx circomkit setup json_extract_value_string
+ # OR
+ snarkjs groth16 setup build/json_extract_value_string/json_extract_value_string.r1cs ptau/powersOfTau28_hez_final_14.ptau build/json_extract_value_string/groth16_pkey.zkey
+ ```
+
+- create proof:
+ ```bash
+ npx circomkit prove json_extract_value_string value_string
+ # OR
+ snarkjs groth16 prove build/json_extract_value_string/groth16_pkey.zkey build/json_extract_value_string/value_string/witness.wtns build/json_extract_value_string/value_string/groth16_proof.json inputs/json_extract_value_string/value_string.json
+ ```
+
+- verify proof:
+ ```bash
+ npx circomkit verify json_extract_value_string value_string
+ # OR
+ snarkjs groth16 verify build/json_extract_value_string/groth16_vkey.json inputs/json_extract_value_string/value_string.json build/json_extract_value_string/value_string/groth16_proof.json
+ ```
+
+### HTTP Locking and Extraction
+
+TODO
\ No newline at end of file
diff --git a/examples/http/lockfile/request.lock.json b/examples/http/lockfile/request.lock.json
new file mode 100644
index 0000000..7e4935c
--- /dev/null
+++ b/examples/http/lockfile/request.lock.json
@@ -0,0 +1,9 @@
+{
+ "method": "GET",
+ "target": "/api",
+ "version": "HTTP/1.1",
+ "headerName1": "Host",
+ "headerValue1": "localhost",
+ "headerName2": "Accept",
+ "headerValue2": "application/json"
+}
\ No newline at end of file
diff --git a/examples/http/lockfile/response.lock.json b/examples/http/lockfile/response.lock.json
new file mode 100644
index 0000000..cf02dd8
--- /dev/null
+++ b/examples/http/lockfile/response.lock.json
@@ -0,0 +1,7 @@
+{
+ "version": "HTTP/1.1",
+ "status": "200",
+ "message": "OK",
+ "headerName1": "Content-Type",
+ "headerValue1": "application/json"
+}
\ No newline at end of file
diff --git a/examples/extractor/two_keys.json b/examples/json/lockfile/two_keys.json
similarity index 100%
rename from examples/extractor/two_keys.json
rename to examples/json/lockfile/two_keys.json
diff --git a/examples/extractor/value_array_nested.json b/examples/json/lockfile/value_array_nested.json
similarity index 100%
rename from examples/extractor/value_array_nested.json
rename to examples/json/lockfile/value_array_nested.json
diff --git a/examples/extractor/value_array_number.json b/examples/json/lockfile/value_array_number.json
similarity index 100%
rename from examples/extractor/value_array_number.json
rename to examples/json/lockfile/value_array_number.json
diff --git a/examples/extractor/value_array_object.json b/examples/json/lockfile/value_array_object.json
similarity index 100%
rename from examples/extractor/value_array_object.json
rename to examples/json/lockfile/value_array_object.json
diff --git a/examples/extractor/value_array_string.json b/examples/json/lockfile/value_array_string.json
similarity index 100%
rename from examples/extractor/value_array_string.json
rename to examples/json/lockfile/value_array_string.json
diff --git a/examples/extractor/value_number.json b/examples/json/lockfile/value_number.json
similarity index 100%
rename from examples/extractor/value_number.json
rename to examples/json/lockfile/value_number.json
diff --git a/examples/extractor/value_object.json b/examples/json/lockfile/value_object.json
similarity index 100%
rename from examples/extractor/value_object.json
rename to examples/json/lockfile/value_object.json
diff --git a/examples/extractor/value_string.json b/examples/json/lockfile/value_string.json
similarity index 100%
rename from examples/extractor/value_string.json
rename to examples/json/lockfile/value_string.json
diff --git a/examples/lockfile/test.lock.json b/examples/lockfile/test.lock.json
deleted file mode 100644
index e4eada6..0000000
--- a/examples/lockfile/test.lock.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "request": {
- "method": "GET",
- "target": "/api",
- "version": "HTTP/1.1",
- "headers": [
- [
- "Host",
- "localhost"
- ],
- [
- "Accept",
- "application/json"
- ]
- ]
- },
- "response": {
- "version": "HTTP/1.1",
- "status": "200",
- "message": "OK",
- "headers": [
- [
- "Content-Type",
- "application/json"
- ]
- ]
- }
-}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 8c41d03..3265ba4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,16 +10,17 @@
"license": "Apache-2.0",
"dependencies": {
"@zk-email/circuits": "^6.1.1",
- "circomkit": "^0.2.1",
"circomlib": "^2.0.5"
},
"devDependencies": {
"@types/mocha": "^10.0.1",
- "@types/node": "^22.1.0",
- "mocha": "^10.2.0",
- "poseidon-lite": "^0.2.0",
+ "@types/node": "22.5.4",
+ "circomkit": "0.3.0",
+ "mocha": "10.7.3",
+ "poseidon-lite": "0.3.0",
+ "snarkjs": "0.7.4",
"ts-node": "^10.9.1",
- "typescript": "^5.1.3"
+ "typescript": "5.6.2"
}
},
"node_modules/@cspotcode/source-map-support": {
@@ -45,6 +46,7 @@
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/@iden3/binfileutils/-/binfileutils-0.0.11.tgz",
"integrity": "sha512-LylnJoZ0CTdgErnKY8OxohvW4K+p6UHD3sxt+3P9AmMyBQjYR4IpoqoYZZ+9aMj89cmCQ21UvdhndAx04er3NA==",
+ "dev": true,
"license": "GPL-3.0",
"dependencies": {
"fastfile": "0.0.20",
@@ -115,19 +117,20 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "22.1.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz",
- "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==",
+ "version": "22.5.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz",
+ "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~6.13.0"
+ "undici-types": "~6.19.2"
}
},
"node_modules/@types/snarkjs": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/@types/snarkjs/-/snarkjs-0.7.8.tgz",
"integrity": "sha512-x37Jsv1vx6I6RMJdfvYEmDUOLYgzYMecwlk13gniDOcN20xLVe9hy9DlQxWeCPirqpDY/jwugQSqCi2RxehU3g==",
+ "dev": true,
"license": "MIT",
"peer": true
},
@@ -254,6 +257,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": "*"
@@ -269,6 +273,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"possible-typed-array-names": "^1.0.0"
@@ -371,6 +376,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
@@ -403,6 +409,7 @@
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz",
"integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"assertion-error": "^1.1.0",
@@ -437,6 +444,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
"integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"get-func-name": "^2.0.2"
@@ -455,6 +463,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz",
"integrity": "sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==",
+ "dev": true,
"license": "ISC"
},
"node_modules/chokidar": {
@@ -509,6 +518,7 @@
"version": "0.0.19",
"resolved": "https://registry.npmjs.org/circom_tester/-/circom_tester-0.0.19.tgz",
"integrity": "sha512-SNHaBsGxcBH6XsVWfsRbRPA7NF8m8AMKJI9dtJJCFGUtOTT2+zsoIqAwi50z6XCnO4TtjyXq7AeXa1PLHqT0tw==",
+ "dev": true,
"license": "GPL-3.0",
"dependencies": {
"chai": "^4.3.6",
@@ -525,6 +535,7 @@
"version": "0.1.21",
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.21.tgz",
"integrity": "sha512-qTkud630B/GK8y76hnOaaS1aNuF6prfV0dTrkeRsiJKnlP1ryQbP2FWLgDOPqn6aKyaPlam+Z+DTbBhkEzh8dA==",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"ffjavascript": "0.2.56"
@@ -537,6 +548,7 @@
"version": "0.2.56",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.56.tgz",
"integrity": "sha512-em6G5Lrj7ucIqj4TYEgyoHs/j99Urwwqa4+YxEVY2hggnpRimVj+noX5pZQTxI1pvtiekZI4rG65JBf0xraXrg==",
+ "dev": true,
"license": "GPL-3.0",
"dependencies": {
"wasmbuilder": "0.0.16",
@@ -548,6 +560,7 @@
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.5.0.tgz",
"integrity": "sha512-KWz8mZ2Y+6wvn6GGkQo6/ZlKwETdAGohd40Lzpwp5TUZCn6N6O4Az1SuX1rw/qREGL6Im+ycb19suCFE8/xaKA==",
+ "dev": true,
"license": "GPL-3.0",
"dependencies": {
"@iden3/binfileutils": "0.0.11",
@@ -569,15 +582,17 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.0.tgz",
"integrity": "sha512-3e2rbxdujOwaod657gxgmdhZNn+i1qKdHO3Y/bK+8E7bV8ttV/fu5FO4/WLBACF375cK0QDLOP+65Na63qYuWA==",
+ "dev": true,
"license": "GPL-3.0",
"dependencies": {
"wasmbuilder": "0.0.16"
}
},
"node_modules/circomkit": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/circomkit/-/circomkit-0.2.1.tgz",
- "integrity": "sha512-7O8QsOLUq2QvwGMimvWxwdg7OgV33OT7ZBND+81dv3JrVp8ove93yV16jF3TW6XBncSY92/Aka8F4CAi/H9VQw==",
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/circomkit/-/circomkit-0.3.0.tgz",
+ "integrity": "sha512-U9GUKwy24AAdUre0MJ/6KyqZM6q5QRwiNNDLOVKARjuvOaCm6+WZ4hU5felAsdWq4QtZygrc5uKeRzAbJbZANQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"circom_tester": "^0.0.19",
@@ -635,6 +650,7 @@
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
"integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
@@ -695,6 +711,7 @@
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz",
"integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"type-detect": "^4.0.0"
@@ -713,6 +730,7 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
@@ -762,6 +780,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.4"
@@ -774,6 +793,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -883,6 +903,7 @@
"version": "0.2.63",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.63.tgz",
"integrity": "sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A==",
+ "dev": true,
"license": "GPL-3.0",
"dependencies": {
"wasmbuilder": "0.0.16",
@@ -964,12 +985,14 @@
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/fnv-plus/-/fnv-plus-1.3.1.tgz",
"integrity": "sha512-Gz1EvfOneuFfk4yG458dJ3TLJ7gV19q3OM/vVvvHf7eT02Hm1DleB4edsia6ahbKgAYxO9gvyQ1ioWZR+a00Yw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"is-callable": "^1.1.3"
@@ -1001,6 +1024,7 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -1020,6 +1044,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
"integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": "*"
@@ -1029,6 +1054,7 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -1105,6 +1131,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.1.3"
@@ -1126,6 +1153,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
@@ -1138,6 +1166,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -1150,6 +1179,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -1162,6 +1192,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
@@ -1177,6 +1208,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -1220,12 +1252,14 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
"license": "ISC"
},
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.2",
@@ -1255,6 +1289,7 @@
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -1287,6 +1322,7 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"has-tostringtag": "^1.0.0"
@@ -1335,6 +1371,7 @@
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
"integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"which-typed-array": "^1.1.14"
@@ -1457,6 +1494,7 @@
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz",
"integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
@@ -1476,6 +1514,7 @@
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz",
"integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"get-func-name": "^2.0.1"
@@ -1501,9 +1540,9 @@
}
},
"node_modules/mocha": {
- "version": "10.7.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.0.tgz",
- "integrity": "sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA==",
+ "version": "10.7.3",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz",
+ "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1671,6 +1710,7 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": "*"
@@ -1690,9 +1730,9 @@
}
},
"node_modules/poseidon-lite": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/poseidon-lite/-/poseidon-lite-0.2.0.tgz",
- "integrity": "sha512-vivDZnGmz8W4G/GzVA72PXkfYStjilu83rjjUfpL4PueKcC8nfX6hCPh2XhoC5FBgC6y0TA3YuUeUo5YCcNoig==",
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/poseidon-lite/-/poseidon-lite-0.3.0.tgz",
+ "integrity": "sha512-ilJj4MIve4uBEG7SrtPqUUNkvpJ/pLVbndxa0WvebcQqeIhe+h72JR4g0EvwchUzm9sOQDlOjiDNmRAgxNZl4A==",
"dev": true,
"license": "MIT"
},
@@ -1700,6 +1740,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -1717,6 +1758,7 @@
"version": "0.0.41",
"resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.41.tgz",
"integrity": "sha512-Q1WDF3u1vYeAwjHo4YuddkA8Aq0TulbKjmGm99+Atn13Lf5fTsMZBnBV9T741w8iSyPFG6Uh6sapQby77sREqA==",
+ "dev": true,
"license": "GPL-3.0",
"dependencies": {
"@iden3/bigarray": "0.0.2",
@@ -1729,6 +1771,7 @@
"version": "0.2.56",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.56.tgz",
"integrity": "sha512-em6G5Lrj7ucIqj4TYEgyoHs/j99Urwwqa4+YxEVY2hggnpRimVj+noX5pZQTxI1pvtiekZI4rG65JBf0xraXrg==",
+ "dev": true,
"license": "GPL-3.0",
"dependencies": {
"wasmbuilder": "0.0.16",
@@ -1740,6 +1783,7 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.0.tgz",
"integrity": "sha512-3e2rbxdujOwaod657gxgmdhZNn+i1qKdHO3Y/bK+8E7bV8ttV/fu5FO4/WLBACF375cK0QDLOP+65Na63qYuWA==",
+ "dev": true,
"license": "GPL-3.0",
"dependencies": {
"wasmbuilder": "0.0.16"
@@ -1813,6 +1857,7 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
@@ -1956,6 +2001,7 @@
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
"integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=14.14"
@@ -1965,6 +2011,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz",
"integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"tmp": "^0.2.0"
@@ -2059,15 +2106,16 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz",
"integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/typescript": {
- "version": "5.5.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
- "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
+ "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -2085,9 +2133,9 @@
"license": "MIT"
},
"node_modules/undici-types": {
- "version": "6.13.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz",
- "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==",
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true,
"license": "MIT"
},
@@ -2095,6 +2143,7 @@
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
"integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
@@ -2136,6 +2185,7 @@
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
"integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
diff --git a/package.json b/package.json
index 8f55708..4a8cfdb 100644
--- a/package.json
+++ b/package.json
@@ -8,16 +8,17 @@
},
"dependencies": {
"@zk-email/circuits": "^6.1.1",
- "circomkit": "^0.2.1",
"circomlib": "^2.0.5"
},
"devDependencies": {
+ "circomkit": "0.3.0",
+ "snarkjs": "0.7.4",
+ "typescript": "5.6.2",
+ "@types/node": "22.5.4",
+ "mocha": "10.7.3",
"@types/mocha": "^10.0.1",
- "@types/node": "^22.1.0",
- "mocha": "^10.2.0",
- "poseidon-lite": "^0.2.0",
- "ts-node": "^10.9.1",
- "typescript": "^5.1.3"
+ "poseidon-lite": "0.3.0",
+ "ts-node": "^10.9.1"
},
"repository": {
"type": "git",
diff --git a/src/http.rs b/src/http.rs
new file mode 100644
index 0000000..f0cbb65
--- /dev/null
+++ b/src/http.rs
@@ -0,0 +1,453 @@
+use super::*;
+use std::{
+ collections::HashMap,
+ fs::{self, create_dir_all},
+};
+
+#[derive(Serialize, Deserialize)]
+#[serde(untagged)]
+pub enum HttpData {
+ Request(Request),
+ Response(Response),
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Request {
+ method: String,
+ target: String,
+ version: String,
+ #[serde(flatten)]
+ #[serde(deserialize_with = "deserialize_headers")]
+ headers: HashMap,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Response {
+ version: String,
+ status: String,
+ message: String,
+ #[serde(flatten)]
+ #[serde(deserialize_with = "deserialize_headers")]
+ headers: HashMap,
+}
+
+impl HttpData {
+ fn headers(&self) -> HashMap {
+ match self {
+ HttpData::Request(request) => request.headers.clone(),
+ HttpData::Response(response) => response.headers.clone(),
+ }
+ }
+}
+
+impl std::fmt::Debug for HttpData {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ HttpData::Request(req) => req.fmt(f),
+ HttpData::Response(res) => res.fmt(f),
+ }
+ }
+}
+
+fn deserialize_headers<'de, D>(deserializer: D) -> Result, D::Error>
+where
+ D: serde::Deserializer<'de>,
+{
+ let mut map = HashMap::new();
+ let mut temp_map: HashMap = HashMap::deserialize(deserializer)?;
+
+ let mut i = 1;
+ while let (Some(name), Some(value)) = (
+ temp_map.remove(&format!("headerName{}", i)),
+ temp_map.remove(&format!("headerValue{}", i)),
+ ) {
+ map.insert(name, value);
+ i += 1;
+ }
+
+ Ok(map)
+}
+
+const PRAGMA: &str = "pragma circom 2.1.9;\n\n";
+
+fn build_http_circuit(
+ data: HttpData,
+ output_filename: String,
+ debug: bool,
+) -> Result<(), Box> {
+ let mut circuit_buffer = String::new();
+
+ // Dump out the contents of the lockfile used into the circuit
+ circuit_buffer += "/*\n";
+ circuit_buffer += &format!("{:#?}", data);
+ circuit_buffer += "\n*/\n";
+
+ // Version and includes
+ circuit_buffer += PRAGMA;
+ circuit_buffer += "include \"../http/interpreter.circom\";\n";
+ circuit_buffer += "include \"../http/parser/machine.circom\";\n";
+ circuit_buffer += "include \"../utils/bytes.circom\";\n";
+ circuit_buffer += "include \"../utils/search.circom\";\n";
+ circuit_buffer += "include \"circomlib/circuits/gates.circom\";\n";
+ circuit_buffer += "include \"@zk-email/circuits/utils/array.circom\";\n\n";
+
+ {
+ match data {
+ HttpData::Request(_) => {
+ circuit_buffer +=
+ "template LockHTTPRequest(DATA_BYTES, methodLen, targetLen, versionLen";
+ }
+ HttpData::Response(_) => {
+ circuit_buffer +=
+ "template LockHTTPResponse(DATA_BYTES, maxContentLength, versionLen, statusLen, messageLen";
+ }
+ }
+
+ for (i, _header) in data.headers().iter().enumerate() {
+ circuit_buffer += &format!(", headerNameLen{}, headerValueLen{}", i + 1, i + 1);
+ }
+ circuit_buffer += ") {";
+ }
+
+ {
+ circuit_buffer += r#"
+ // Raw HTTP bytestream
+ signal input data[DATA_BYTES];
+"#;
+
+ // Start line signals
+ {
+ match data {
+ HttpData::Request(_) => {
+ circuit_buffer += r#"
+ // Request line attributes
+ signal input method[methodLen];
+ signal input target[targetLen];
+ signal input version[versionLen];
+
+"#;
+ }
+ HttpData::Response(_) => {
+ circuit_buffer += r#"
+ // Status line attributes
+ signal input version[versionLen];
+ signal input status[statusLen];
+ signal input message[messageLen];
+
+"#;
+ }
+ }
+ }
+
+ // Header signals
+ circuit_buffer += " // Header names and values to lock\n";
+ for (i, _header) in data.headers().iter().enumerate() {
+ circuit_buffer += &format!(
+ " signal input header{}[headerNameLen{}];\n",
+ i + 1,
+ i + 1
+ );
+ circuit_buffer += &format!(
+ " signal input value{}[headerValueLen{}];\n",
+ i + 1,
+ i + 1
+ );
+ }
+ }
+
+ // Create an output if circuit is for `Response`
+ {
+ if let HttpData::Response(_) = data {
+ circuit_buffer += r#"
+ // Set up mask bits for where the body of response lies
+ signal output body[maxContentLength];
+
+ signal bodyMask[DATA_BYTES];
+ bodyMask[0] <== 0;
+"#;
+ }
+ }
+
+ // Setup for parsing the start line
+ {
+ match data {
+ HttpData::Request(_) => {
+ circuit_buffer += r#"
+ // Check first method byte
+ signal methodIsEqual[methodLen];
+ methodIsEqual[0] <== IsEqual()([data[0],method[0]]);
+ methodIsEqual[0] === 1;
+
+ // Setup to check target and version bytes
+ signal startLineMask[DATA_BYTES];
+ signal targetMask[DATA_BYTES];
+ signal versionMask[DATA_BYTES];
+
+ var target_start_counter = 1;
+ var target_end_counter = 1;
+ var version_end_counter = 1;
+"#;
+ }
+ HttpData::Response(_) => {
+ circuit_buffer += r#"
+ // Check first version byte
+ signal versionIsEqual[versionLen];
+ versionIsEqual[0] <== IsEqual()([data[0],version[0]]);
+ versionIsEqual[0] === 1;
+
+ // Setup to check status and message bytes
+ signal startLineMask[DATA_BYTES];
+ signal statusMask[DATA_BYTES];
+ signal messageMask[DATA_BYTES];
+
+ var status_start_counter = 1;
+ var status_end_counter = 1;
+ var message_end_counter = 1;
+"#;
+ }
+ }
+ }
+
+ circuit_buffer += r#"
+ component State[DATA_BYTES];
+ State[0] = StateUpdate();
+ State[0].byte <== data[0];
+ State[0].parsing_start <== 1;
+ State[0].parsing_header <== 0;
+ State[0].parsing_field_name <== 0;
+ State[0].parsing_field_value <== 0;
+ State[0].parsing_body <== 0;
+ State[0].line_status <== 0;
+
+"#;
+
+ // Create header match signals
+ {
+ for (i, _header) in data.headers().iter().enumerate() {
+ circuit_buffer += &format!(" signal headerNameValueMatch{}[DATA_BYTES];\n", i + 1);
+ circuit_buffer += &format!(" headerNameValueMatch{}[0] <== 0;\n", i + 1);
+ circuit_buffer += &format!(" var hasMatchedHeaderValue{} = 0;\n\n", i + 1);
+ }
+ }
+
+ // Intro loop
+ {
+ circuit_buffer += r#"
+ for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) {
+ State[data_idx] = StateUpdate();
+ State[data_idx].byte <== data[data_idx];
+ State[data_idx].parsing_start <== State[data_idx - 1].next_parsing_start;
+ State[data_idx].parsing_header <== State[data_idx - 1].next_parsing_header;
+ State[data_idx].parsing_field_name <== State[data_idx-1].next_parsing_field_name;
+ State[data_idx].parsing_field_value <== State[data_idx-1].next_parsing_field_value;
+ State[data_idx].parsing_body <== State[data_idx - 1].next_parsing_body;
+ State[data_idx].line_status <== State[data_idx - 1].next_line_status;
+
+"#;
+ }
+
+ // If parsing a `Response`, create a mask of the body bytes
+ {
+ if let HttpData::Response(_) = data {
+ circuit_buffer += r#"
+ // Mask if parser is in the body of response
+ bodyMask[data_idx] <== data[data_idx] * State[data_idx].next_parsing_body;
+"#;
+ }
+ }
+
+ // Start line matches
+ {
+ match data {
+ HttpData::Request(_) => {
+ circuit_buffer += r#"
+ // Check remaining method bytes
+ if(data_idx < methodLen) {
+ methodIsEqual[data_idx] <== IsEqual()([data[data_idx], method[data_idx]]);
+ methodIsEqual[data_idx] === 1;
+ }
+
+ // Get the target bytes
+ startLineMask[data_idx] <== inStartLine()(State[data_idx].parsing_start);
+ targetMask[data_idx] <== inStartMiddle()(State[data_idx].parsing_start);
+ versionMask[data_idx] <== inStartEnd()(State[data_idx].parsing_start);
+ target_start_counter += startLineMask[data_idx] - targetMask[data_idx] - versionMask[data_idx];
+
+ // Get the version bytes
+ target_end_counter += startLineMask[data_idx] - versionMask[data_idx];
+ version_end_counter += startLineMask[data_idx];
+"#;
+ }
+ HttpData::Response(_) => {
+ circuit_buffer += r#"
+ // Check remaining version bytes
+ if(data_idx < versionLen) {
+ versionIsEqual[data_idx] <== IsEqual()([data[data_idx], version[data_idx]]);
+ versionIsEqual[data_idx] === 1;
+ }
+
+ // Get the status bytes
+ startLineMask[data_idx] <== inStartLine()(State[data_idx].parsing_start);
+ statusMask[data_idx] <== inStartMiddle()(State[data_idx].parsing_start);
+ messageMask[data_idx] <== inStartEnd()(State[data_idx].parsing_start);
+ status_start_counter += startLineMask[data_idx] - statusMask[data_idx] - messageMask[data_idx];
+
+ // Get the message bytes
+ status_end_counter += startLineMask[data_idx] - messageMask[data_idx];
+ message_end_counter += startLineMask[data_idx];
+"#;
+ }
+ }
+ }
+
+ // Header matches
+ {
+ for (i, _header) in data.headers().iter().enumerate() {
+ circuit_buffer += &format!(" headerNameValueMatch{}[data_idx] <== HeaderFieldNameValueMatch(DATA_BYTES, headerNameLen{}, headerValueLen{})(data, header{}, value{}, 100, data_idx);\n", i + 1,i + 1,i + 1,i + 1,i + 1);
+ circuit_buffer += &format!(
+ " hasMatchedHeaderValue{} += headerNameValueMatch{}[data_idx];\n",
+ i + 1,
+ i + 1
+ );
+ }
+ }
+
+ // debugging
+ if debug {
+ circuit_buffer += r#"
+ // Debugging
+ log("State[", data_idx, "].parsing_start ", "= ", State[data_idx].parsing_start);
+ log("State[", data_idx, "].parsing_header ", "= ", State[data_idx].parsing_header);
+ log("State[", data_idx, "].parsing_field_name ", "= ", State[data_idx].parsing_field_name);
+ log("State[", data_idx, "].parsing_field_value", "= ", State[data_idx].parsing_field_value);
+ log("State[", data_idx, "].parsing_body ", "= ", State[data_idx].parsing_body);
+ log("State[", data_idx, "].line_status ", "= ", State[data_idx].line_status);
+ log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+"#;
+ }
+
+ circuit_buffer += " }";
+
+ // debugging
+ if debug {
+ circuit_buffer += r#"
+ // Debugging
+ log("State[", DATA_BYTES, "].parsing_start ", "= ", State[DATA_BYTES-1].next_parsing_start);
+ log("State[", DATA_BYTES, "].parsing_header ", "= ", State[DATA_BYTES-1].next_parsing_header);
+ log("State[", DATA_BYTES, "].parsing_field_name ", "= ", State[DATA_BYTES-1].parsing_field_name);
+ log("State[", DATA_BYTES, "].parsing_field_value", "= ", State[DATA_BYTES-1].parsing_field_value);
+ log("State[", DATA_BYTES, "].parsing_body ", "= ", State[DATA_BYTES-1].next_parsing_body);
+ log("State[", DATA_BYTES, "].line_status ", "= ", State[DATA_BYTES-1].next_line_status);
+ log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+"#;
+ }
+
+ // Get the output body bytes
+ {
+ if let HttpData::Response(_) = data {
+ circuit_buffer += r#"
+ signal bodyStartingIndex[DATA_BYTES];
+ signal isZeroMask[DATA_BYTES];
+ signal isPrevStartingIndex[DATA_BYTES];
+ bodyStartingIndex[0] <== 0;
+ isZeroMask[0] <== IsZero()(bodyMask[0]);
+ for (var i=1 ; i < DATA_BYTES; i++) {
+ isZeroMask[i] <== IsZero()(bodyMask[i]);
+ isPrevStartingIndex[i] <== IsZero()(bodyStartingIndex[i-1]);
+ bodyStartingIndex[i] <== bodyStartingIndex[i-1] + i * (1-isZeroMask[i]) * isPrevStartingIndex[i];
+ }
+
+ body <== SelectSubArray(DATA_BYTES, maxContentLength)(bodyMask, bodyStartingIndex[DATA_BYTES-1]+1, DATA_BYTES - bodyStartingIndex[DATA_BYTES-1]);
+"#;
+ }
+ }
+
+ if debug {
+ circuit_buffer += r#"
+ for(var i = 0; i < maxContentLength; i++) {
+ log("body[", i, "] = ", body[i]);
+ }
+"#;
+ }
+
+ // Verify all start line has matched
+ {
+ match data {
+ HttpData::Request(_) => {
+ circuit_buffer += r#"
+ // Verify method had correct length
+ methodLen === target_start_counter - 1;
+
+ // Check target is correct by substring match and length check
+ // TODO: change r
+ signal targetMatch <== SubstringMatchWithIndex(DATA_BYTES, targetLen)(data, target, 100, target_start_counter);
+ targetMatch === 1;
+ targetLen === target_end_counter - target_start_counter - 1;
+
+ // Check version is correct by substring match and length check
+ // TODO: change r
+ signal versionMatch <== SubstringMatchWithIndex(DATA_BYTES, versionLen)(data, version, 100, target_end_counter);
+ versionMatch === 1;
+ // -2 here for the CRLF
+ versionLen === version_end_counter - target_end_counter - 2;
+"#;
+ }
+ HttpData::Response(_) => {
+ circuit_buffer += r#"
+ // Verify version had correct length
+ versionLen === status_start_counter - 1;
+
+ // Check status is correct by substring match and length check
+ // TODO: change r
+ signal statusMatch <== SubstringMatchWithIndex(DATA_BYTES, statusLen)(data, status, 100, status_start_counter);
+ statusMatch === 1;
+ statusLen === status_end_counter - status_start_counter - 1;
+
+ // Check message is correct by substring match and length check
+ // TODO: change r
+ signal messageMatch <== SubstringMatchWithIndex(DATA_BYTES, messageLen)(data, message, 100, status_end_counter);
+ messageMatch === 1;
+ // -2 here for the CRLF
+ messageLen === message_end_counter - status_end_counter - 2;
+"#;
+ }
+ }
+ }
+
+ // Verify all headers have matched
+ {
+ for (i, _header) in data.headers().iter().enumerate() {
+ circuit_buffer += &format!(" hasMatchedHeaderValue{} === 1;\n", i + 1);
+ }
+ }
+ // End file
+ circuit_buffer += "\n}";
+
+ // write circuits to file
+ let mut file_path = std::env::current_dir()?;
+ file_path.push("circuits");
+ file_path.push("main");
+
+ // create dir if doesn't exist
+ create_dir_all(&file_path)?;
+
+ file_path.push(format!("{}.circom", output_filename));
+
+ fs::write(&file_path, circuit_buffer)?;
+
+ println!("Code generated at: {}", file_path.display());
+
+ Ok(())
+}
+
+// TODO: This needs to codegen a circuit now.
+pub fn http_circuit(args: HttpArgs) -> Result<(), Box> {
+ let data = std::fs::read(&args.lockfile)?;
+
+ let http_data: HttpData = serde_json::from_slice(&data)?;
+
+ build_http_circuit(http_data, args.output_filename, args.debug)?;
+
+ Ok(())
+}
diff --git a/src/http_lock.rs b/src/http_lock.rs
deleted file mode 100644
index 907c8a3..0000000
--- a/src/http_lock.rs
+++ /dev/null
@@ -1,250 +0,0 @@
-use super::*;
-
-#[derive(Debug, Serialize, Deserialize)]
-struct HttpData {
- request: Request,
- response: Response,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-struct Request {
- method: String,
- target: String,
- version: String,
- headers: Vec<(String, String)>,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-struct Response {
- version: String,
- status: String,
- message: String,
- headers: Vec<(String, String)>,
-}
-
-use std::fs::{self, create_dir_all};
-
-const PRAGMA: &str = "pragma circom 2.1.9;\n\n";
-
-fn request_locker_circuit(
- data: HttpData,
- output_filename: String,
-) -> Result<(), Box> {
- let mut circuit_buffer = String::new();
- circuit_buffer += PRAGMA;
- circuit_buffer += "include \"../http/interpreter.circom\";\n";
- circuit_buffer += "include \"../http/parser/machine.circom\";\n";
- circuit_buffer += "include \"../utils/bytes.circom\";\n";
- circuit_buffer += "include \"../utils/search.circom\";\n";
- circuit_buffer += "include \"circomlib/circuits/gates.circom\";\n";
- circuit_buffer += "include \"@zk-email/circuits/utils/array.circom\";\n\n";
-
- // template LockHTTP(DATA_BYTES, beginningLen, middleLen, finalLen, headerNameLen1, headerValueLen1, ...) {
- {
- circuit_buffer += "template LockHTTP(DATA_BYTES, beginningLen, middleLen, finalLen ";
- for (i, _header) in data.request.headers.iter().enumerate() {
- circuit_buffer += &format!(", headerNameLen{}, headerValueLen{}", i + 1, i + 1);
- }
- circuit_buffer += ") {";
- }
-
- /*
- signal input data[DATA_BYTES];
-
- signal input key1[keyLen1];
- signal input key3[keyLen3];
- */
- {
- circuit_buffer += r#"
- signal input data[DATA_BYTES];
-
- // Start line signals
- signal input beginning[beginningLen];
- signal input middle[middleLen];
- signal input final[finalLen];
-
- // Header signals
-"#;
-
- for (i, _header) in data.request.headers.iter().enumerate() {
- circuit_buffer += &format!(
- " signal input header{}[headerNameLen{}];\n",
- i + 1,
- i + 1
- );
- circuit_buffer += &format!(
- " signal input value{}[headerValueLen{}];\n",
- i + 1,
- i + 1
- );
- }
- }
-
- // Setup for parsing the start line
- {
- circuit_buffer += r#"
- // Check first beginning byte
- signal beginningIsEqual[beginningLen];
- beginningIsEqual[0] <== IsEqual()([data[0],beginning[0]]);
- beginningIsEqual[0] === 1;
-
- // Setup to check middle bytes
- signal startLineMask[DATA_BYTES];
- signal middleMask[DATA_BYTES];
- signal finalMask[DATA_BYTES];
-
- var middle_start_counter = 1;
- var middle_end_counter = 1;
- var final_end_counter = 1;
-"#;
- }
-
- circuit_buffer += r#"
- component State[DATA_BYTES];
- State[0] = StateUpdate();
- State[0].byte <== data[0];
- State[0].parsing_start <== 1;
- State[0].parsing_header <== 0;
- State[0].parsing_field_name <== 0;
- State[0].parsing_field_value <== 0;
- State[0].parsing_body <== 0;
- State[0].line_status <== 0;
-
-"#;
-
- // Create header match signals
- {
- for (i, _header) in data.request.headers.iter().enumerate() {
- circuit_buffer += &format!(" signal headerNameValueMatch{}[DATA_BYTES];\n", i + 1);
- circuit_buffer += &format!(" headerNameValueMatch{}[0] <== 0;\n", i + 1);
- circuit_buffer += &format!(" var hasMatchedHeaderValue{} = 0;\n\n", i + 1);
- }
- }
-
- circuit_buffer += r#"
- for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) {
- State[data_idx] = StateUpdate();
- State[data_idx].byte <== data[data_idx];
- State[data_idx].parsing_start <== State[data_idx - 1].next_parsing_start;
- State[data_idx].parsing_header <== State[data_idx - 1].next_parsing_header;
- State[data_idx].parsing_field_name <== State[data_idx-1].next_parsing_field_name;
- State[data_idx].parsing_field_value <== State[data_idx-1].next_parsing_field_value;
- State[data_idx].parsing_body <== State[data_idx - 1].next_parsing_body;
- State[data_idx].line_status <== State[data_idx - 1].next_line_status;
-
-"#;
- // Start line matches
- {
- circuit_buffer += r#"
- // Check remaining beginning bytes
- if(data_idx < beginningLen) {
- beginningIsEqual[data_idx] <== IsEqual()([data[data_idx], beginning[data_idx]]);
- beginningIsEqual[data_idx] === 1;
- }
-
- // Middle
- startLineMask[data_idx] <== inStartLine()(State[data_idx].parsing_start);
- middleMask[data_idx] <== inStartMiddle()(State[data_idx].parsing_start);
- finalMask[data_idx] <== inStartEnd()(State[data_idx].parsing_start);
- middle_start_counter += startLineMask[data_idx] - middleMask[data_idx] - finalMask[data_idx];
- // The end of middle is the start of the final
- middle_end_counter += startLineMask[data_idx] - finalMask[data_idx];
- final_end_counter += startLineMask[data_idx];
-
-"#;
- }
-
- // Header matches
- {
- for (i, _header) in data.request.headers.iter().enumerate() {
- circuit_buffer += &format!(" headerNameValueMatch{}[data_idx] <== HeaderFieldNameValueMatch(DATA_BYTES, headerNameLen{}, headerValueLen{})(data, header{}, value{}, 100, data_idx);\n", i + 1,i + 1,i + 1,i + 1,i + 1);
- circuit_buffer += &format!(
- " hasMatchedHeaderValue{} += headerNameValueMatch{}[data_idx];\n",
- i + 1,
- i + 1
- );
- }
- }
-
- // debugging
- circuit_buffer += r#"
- // Debugging
- log("State[", data_idx, "].parsing_start ", "= ", State[data_idx].parsing_start);
- log("State[", data_idx, "].parsing_header ", "= ", State[data_idx].parsing_header);
- log("State[", data_idx, "].parsing_field_name ", "= ", State[data_idx].parsing_field_name);
- log("State[", data_idx, "].parsing_field_value", "= ", State[data_idx].parsing_field_value);
- log("State[", data_idx, "].parsing_body ", "= ", State[data_idx].parsing_body);
- log("State[", data_idx, "].line_status ", "= ", State[data_idx].line_status);
- log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
-"#;
-
- circuit_buffer += " }";
-
- // debugging
- circuit_buffer += r#"
- // Debugging
- log("State[", DATA_BYTES, "].parsing_start ", "= ", State[DATA_BYTES-1].next_parsing_start);
- log("State[", DATA_BYTES, "].parsing_header ", "= ", State[DATA_BYTES-1].next_parsing_header);
- log("State[", DATA_BYTES, "].parsing_field_name ", "= ", State[DATA_BYTES-1].parsing_field_name);
- log("State[", DATA_BYTES, "].parsing_field_value", "= ", State[DATA_BYTES-1].parsing_field_value);
- log("State[", DATA_BYTES, "].parsing_body ", "= ", State[DATA_BYTES-1].next_parsing_body);
- log("State[", DATA_BYTES, "].line_status ", "= ", State[DATA_BYTES-1].next_line_status);
- log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
-
-"#;
- // Verify all start line has matched
- {
- circuit_buffer += r#"
- // Additionally verify beginning had correct length
- beginningLen === middle_start_counter - 1;
-
- // Check middle is correct by substring match and length check
- // TODO: change r
- signal middleMatch <== SubstringMatchWithIndex(DATA_BYTES, middleLen)(data, middle, 100, middle_start_counter);
- middleMatch === 1;
- middleLen === middle_end_counter - middle_start_counter - 1;
-
- // Check final is correct by substring match and length check
- // TODO: change r
- signal finalMatch <== SubstringMatchWithIndex(DATA_BYTES, finalLen)(data, final, 100, middle_end_counter);
- finalMatch === 1;
- // -2 here for the CRLF
- finalLen === final_end_counter - middle_end_counter - 2;
-"#;
- }
-
- // Verify all headers have matched
- {
- for (i, _header) in data.request.headers.iter().enumerate() {
- circuit_buffer += &format!(" hasMatchedHeaderValue{} === 1;\n", i + 1);
- }
- }
- // End file
- circuit_buffer += "\n}";
-
- // write circuits to file
- let mut file_path = std::env::current_dir()?;
- file_path.push("circuits");
- file_path.push("main");
-
- // create dir if doesn't exist
- create_dir_all(&file_path)?;
-
- file_path.push(format!("{}.circom", output_filename));
-
- fs::write(&file_path, circuit_buffer)?;
-
- println!("Code generated at: {}", file_path.display());
-
- Ok(())
-}
-
-// TODO: This needs to codegen a circuit now.
-pub fn http_lock(args: HttpLockArgs) -> Result<(), Box> {
- let data = std::fs::read(&args.lockfile)?;
- let http_data: HttpData = serde_json::from_slice(&data)?;
-
- request_locker_circuit(http_data, args.output_filename)?;
-
- Ok(())
-}
diff --git a/src/extractor.rs b/src/json.rs
similarity index 88%
rename from src/extractor.rs
rename to src/json.rs
index 7b563cb..7a21e31 100644
--- a/src/extractor.rs
+++ b/src/json.rs
@@ -3,6 +3,8 @@ use std::{
str::FromStr,
};
+use std::collections::HashMap;
+
use super::*;
const PRAGMA: &str = "pragma circom 2.1.9;\n\n";
@@ -23,12 +25,25 @@ pub enum Key {
}
#[derive(Debug, Deserialize)]
-pub struct Data {
+pub struct JsonLockfile {
keys: Vec,
value_type: ValueType,
}
-fn extract_string(data: Data, circuit_buffer: &mut String) {
+impl JsonLockfile {
+ pub fn as_bytes(&self) -> HashMap> {
+ let mut keys = HashMap::>::new();
+ for (i, key) in self.keys.iter().enumerate() {
+ if let Key::String(key) = key {
+ let key_name = format!("key{}", i + 1);
+ keys.insert(key_name, key.as_bytes().to_vec());
+ }
+ }
+ keys
+ }
+}
+
+fn extract_string(data: JsonLockfile, circuit_buffer: &mut String, debug: bool) {
*circuit_buffer += "template ExtractStringValue(DATA_BYTES, MAX_STACK_HEIGHT, ";
for (i, key) in data.keys.iter().enumerate() {
match key {
@@ -78,17 +93,22 @@ fn extract_string(data: Data, circuit_buffer: &mut String) {
}
*circuit_buffer += r#"
- log("value_starting_index", value_starting_index[DATA_BYTES-2]);
- value <== SelectSubArray(DATA_BYTES, maxValueLen)(data, value_starting_index[DATA_BYTES-2]+1, maxValueLen);
+ value <== SelectSubArray(DATA_BYTES, maxValueLen)(data, value_starting_index[DATA_BYTES-2]+1, maxValueLen);"#;
+ if debug {
+ *circuit_buffer += r#"
+ log("value_starting_index", value_starting_index[DATA_BYTES-2]);
for (var i=0 ; i Result<(), Box> {
let mut circuit_buffer = String::new();
+
+ // Dump out the contents of the lockfile used into the circuit
+ circuit_buffer += "/*\n";
+ circuit_buffer += &format!("{:#?}", data);
+ circuit_buffer += "\n*/\n";
+
circuit_buffer += PRAGMA;
circuit_buffer += "include \"../json/interpreter.circom\";\n\n";
@@ -293,7 +326,11 @@ fn parse_json_request(
signal is_value_match[DATA_BYTES];
is_value_match[0] <== 0;
signal value_mask[DATA_BYTES];
- for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) {
+
+ for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) {"#;
+
+ if debug {
+ circuit_buffer += r#"
// Debugging
for(var i = 0; i {
- circuit_buffer += &format!("parsing_object{}_value[data_idx-1], ", i + 1)
+ if debug {
+ circuit_buffer += " // log(\"parsing value:\", ";
+ for (i, key) in data.keys.iter().enumerate() {
+ match key {
+ Key::String(_) => {
+ circuit_buffer += &format!("parsing_object{}_value[data_idx-1], ", i + 1)
+ }
+ Key::Num(_) => {
+ circuit_buffer += &format!("parsing_array{}[data_idx-1], ", i + 1)
+ }
}
- Key::Num(_) => circuit_buffer += &format!("parsing_array{}[data_idx-1], ", i + 1),
}
+ circuit_buffer += "parsing_value[data_idx-1]);\n\n";
}
- circuit_buffer += "parsing_value[data_idx-1]);\n\n";
}
let mut num_objects = 0;
@@ -404,7 +447,9 @@ fn parse_json_request(
circuit_buffer += &format!(" is_key{}_match[data_idx-1] <== KeyMatchAtDepth(DATA_BYTES, MAX_STACK_HEIGHT, keyLen{}, depth{})(data, key{}, r, data_idx-1, parsing_key[data_idx-1], State[data_idx].stack);\n", i+1, i+1, i+1, i+1);
circuit_buffer += &format!(" is_next_pair_at_depth{}[data_idx-1] <== NextKVPairAtDepth(MAX_STACK_HEIGHT, depth{})(State[data_idx].stack, data[data_idx-1]);\n", i+1, i+1);
circuit_buffer += &format!(" is_key{}_match_for_value[data_idx] <== Mux1()([is_key{}_match_for_value[data_idx-1] * (1-is_next_pair_at_depth{}[data_idx-1]), is_key{}_match[data_idx-1] * (1-is_next_pair_at_depth{}[data_idx-1])], is_key{}_match[data_idx-1]);\n", i+1, i+1, i+1, i+1, i+1, i+1);
- circuit_buffer += &format!(" // log(\"is_key{}_match_for_value\", is_key{}_match_for_value[data_idx]);\n\n", i + 1, i + 1);
+ if debug {
+ circuit_buffer += &format!(" // log(\"is_key{}_match_for_value\", is_key{}_match_for_value[data_idx]);\n\n", i + 1, i + 1);
+ }
}
Key::Num(_) => (),
}
@@ -434,24 +479,26 @@ fn parse_json_request(
// debugging and output bytes
{
- circuit_buffer += r#" // log("is_value_match", is_value_match[data_idx]);
-
+ circuit_buffer += r#"
// mask[i] = data[i] * parsing_value[i] * is_key_match_for_value[i]
value_mask[data_idx-1] <== data[data_idx-1] * parsing_value[data_idx-1];
mask[data_idx-1] <== value_mask[data_idx-1] * is_value_match[data_idx];
- log("mask", mask[data_idx-1]);
- log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
- }
+ }"#;
- // Debugging
+ // Debugging
+ if debug {
+ circuit_buffer += r#"
for(var i = 0; i < MAX_STACK_HEIGHT; i++) {
log("State[", DATA_BYTES-1, "].stack[", i,"] ", "= [",State[DATA_BYTES -1].next_stack[i][0], "][", State[DATA_BYTES - 1].next_stack[i][1],"]" );
}
log("State[", DATA_BYTES-1, "].parsing_string", "= ", State[DATA_BYTES-1].next_parsing_string);
log("State[", DATA_BYTES-1, "].parsing_number", "= ", State[DATA_BYTES-1].next_parsing_number);
log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ "#;
+ }
+
+ circuit_buffer += r#"
- // signal value_starting_index[DATA_BYTES];
signal is_zero_mask[DATA_BYTES];
signal is_prev_starting_index[DATA_BYTES];
value_starting_index[0] <== 0;
@@ -468,8 +515,8 @@ fn parse_json_request(
}
match data.value_type {
- ValueType::String => extract_string(data, &mut circuit_buffer),
- ValueType::Number => extract_number(data, &mut circuit_buffer),
+ ValueType::String => extract_string(data, &mut circuit_buffer, debug),
+ ValueType::Number => extract_number(data, &mut circuit_buffer, debug),
}
// write circuits to file
@@ -489,11 +536,11 @@ fn parse_json_request(
Ok(())
}
-pub fn extractor(args: ExtractorArgs) -> Result<(), Box> {
+pub fn json_circuit(args: JsonArgs) -> Result<(), Box> {
let data = std::fs::read(&args.template)?;
- let json_data: Data = serde_json::from_slice(&data)?;
+ let json_data: JsonLockfile = serde_json::from_slice(&data)?;
- parse_json_request(json_data, args.output_filename)?;
+ build_json_circuit(json_data, args.output_filename, args.debug)?;
Ok(())
}
diff --git a/src/main.rs b/src/main.rs
index 2312c5e..5a1757d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,12 +2,12 @@ use clap::{Parser, Subcommand};
use serde::{Deserialize, Serialize};
use std::{error::Error, path::PathBuf};
-pub mod extractor;
-pub mod http_lock;
+pub mod http;
+pub mod json;
pub mod witness;
#[derive(Parser, Debug)]
-#[command(name = "wpbuild")]
+#[command(name = "pabuild")]
pub struct Args {
#[command(subcommand)]
command: Command,
@@ -15,14 +15,15 @@ pub struct Args {
#[derive(Subcommand, Debug)]
pub enum Command {
- Witness(WitnessArgs),
- Extractor(ExtractorArgs),
- HttpLock(HttpLockArgs),
+ ParserWitness(ParserWitnessArgs),
+ ExtractorWitness(ExtractorWitnessArgs),
+ Json(JsonArgs),
+ Http(HttpArgs),
}
#[derive(Parser, Debug)]
-pub struct WitnessArgs {
- #[command(subcommand)]
+pub struct ParserWitnessArgs {
+ #[arg(global = true, value_enum)]
subcommand: WitnessSubcommand,
/// Path to the JSON file
@@ -38,38 +39,69 @@ pub struct WitnessArgs {
output_filename: String,
}
-#[derive(Subcommand, Debug)]
+#[derive(Parser, Debug)]
+pub struct ExtractorWitnessArgs {
+ #[arg(global = true, value_enum)]
+ subcommand: WitnessSubcommand,
+
+ /// Path to the JSON file
+ #[arg(global = true, long)]
+ input_file: PathBuf,
+
+ /// Path to the lockfile
+ #[arg(global = true, long)]
+ lockfile: PathBuf,
+
+ /// Output directory (will be created if it doesn't exist)
+ #[arg(global = true, long, default_value = ".")]
+ output_dir: PathBuf,
+
+ /// Output filename (will be created if it doesn't exist)
+ #[arg(global = true, long, default_value = "output.json")]
+ output_filename: String,
+}
+
+#[derive(clap::ValueEnum, Clone, Debug)]
pub enum WitnessSubcommand {
Json,
Http,
}
#[derive(Parser, Debug)]
-pub struct ExtractorArgs {
- /// Path to the JSON file
- #[arg(long)]
+pub struct JsonArgs {
+ /// Path to the JSON file selective-disclosure template
+ #[arg(long, short)]
template: PathBuf,
/// Output circuit file name
- #[arg(long, default_value = "extractor")]
+ #[arg(long, short, default_value = "extractor")]
output_filename: String,
+
+ /// Optional circuit debug logs
+ #[arg(long, short, action = clap::ArgAction::SetTrue)]
+ debug: bool,
}
#[derive(Parser, Debug)]
-pub struct HttpLockArgs {
+pub struct HttpArgs {
/// Path to the JSON file
#[arg(long)]
lockfile: PathBuf,
/// Output circuit file name
- #[arg(long, default_value = "extractor")]
+ #[arg(long, short, default_value = "extractor")]
output_filename: String,
+
+ /// Optional circuit debug logs
+ #[arg(long, short, action = clap::ArgAction::SetTrue)]
+ debug: bool,
}
pub fn main() -> Result<(), Box> {
match Args::parse().command {
- Command::Extractor(args) => extractor::extractor(args),
- Command::Witness(args) => witness::witness(args),
- Command::HttpLock(args) => http_lock::http_lock(args),
+ Command::ParserWitness(args) => witness::parser_witness(args),
+ Command::Json(args) => json::json_circuit(args),
+ Command::Http(args) => http::http_circuit(args),
+ Command::ExtractorWitness(args) => witness::extractor_witness(args),
}
}
diff --git a/src/witness.rs b/src/witness.rs
index 8375627..522e6c8 100644
--- a/src/witness.rs
+++ b/src/witness.rs
@@ -1,15 +1,42 @@
+use json::JsonLockfile;
+
use super::*;
-use std::io::Write;
+use std::{collections::HashMap, io::Write};
+
+#[derive(serde::Serialize)]
+pub struct Witness {
+ data: Vec,
+}
#[derive(serde::Serialize)]
-pub struct Witness(Vec);
+pub struct ExtractorWitness {
+ data: Vec,
+ keys: HashMap>,
+}
+
+fn print_boxed_output(lines: Vec) {
+ // Determine the maximum length of the lines
+ let max_length = lines.iter().map(|line| line.len()).max().unwrap_or(0);
+
+ // Characters for the box
+ let top_border = format!("┌{}┐", "─".repeat(max_length + 2));
+ let bottom_border = format!("└{}┘", "─".repeat(max_length + 2));
-pub fn witness(args: WitnessArgs) -> Result<(), Box> {
+ // Print the box with content
+ println!("{}", top_border);
+ for line in lines {
+ println!("│ {: Result<(), Box> {
let data = match &args.subcommand {
WitnessSubcommand::Json => std::fs::read(args.input_file)?,
WitnessSubcommand::Http => {
let mut data = std::fs::read(args.input_file)?;
let mut i = 0;
+ // convert LF to CRLF
while i < data.len() {
if data[i] == 10 && (i == 0 || data[i - 1] != 13) {
data.insert(i, 13);
@@ -22,7 +49,7 @@ pub fn witness(args: WitnessArgs) -> Result<(), Box> {
}
};
- let witness = Witness(data.clone());
+ let witness = Witness { data: data.clone() };
if !args.output_dir.exists() {
std::fs::create_dir_all(&args.output_dir)?;
@@ -42,18 +69,53 @@ pub fn witness(args: WitnessArgs) -> Result<(), Box> {
Ok(())
}
-fn print_boxed_output(lines: Vec) {
- // Determine the maximum length of the lines
- let max_length = lines.iter().map(|line| line.len()).max().unwrap_or(0);
+fn read_input_file_as_bytes(
+ file_type: WitnessSubcommand,
+ file_path: PathBuf,
+) -> Result, Box> {
+ match file_type {
+ WitnessSubcommand::Json => Ok(std::fs::read(file_path)?),
+ WitnessSubcommand::Http => {
+ let mut data = std::fs::read(file_path)?;
+ let mut i = 0;
+ // convert LF to CRLF
+ while i < data.len() {
+ if data[i] == 10 && (i == 0 || data[i - 1] != 13) {
+ data.insert(i, 13);
+ i += 2;
+ } else {
+ i += 1;
+ }
+ }
+ Ok(data)
+ }
+ }
+}
+pub fn extractor_witness(args: ExtractorWitnessArgs) -> Result<(), Box> {
+ let input_data = read_input_file_as_bytes(args.subcommand, args.input_file)?;
- // Characters for the box
- let top_border = format!("┌{}┐", "─".repeat(max_length + 2));
- let bottom_border = format!("└{}┘", "─".repeat(max_length + 2));
+ let lockfile_data = std::fs::read(&args.lockfile)?;
+ let lockfile: JsonLockfile = serde_json::from_slice(&lockfile_data)?;
- // Print the box with content
- println!("{}", top_border);
- for line in lines {
- println!("│ {: