Skip to content

Commit

Permalink
refactor: organize circuits and begin HTTP parsing (#65)
Browse files Browse the repository at this point in the history
* refactor: circuits

* add HTTP to Rust witness creation

* basic HTTP language file

* parse request method

* Update README.md

* add note on CLRF

* Update get_response.http
  • Loading branch information
Autoparallel authored Aug 28, 2024
1 parent 4473a8b commit 9a44739
Show file tree
Hide file tree
Showing 34 changed files with 237 additions and 137 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ npx circomkit clean extract

All of the above should be ran from repository root.

## Rust Example Witness JSON Creation
To generate example input JSON files for the Circom circuits, you can
```
cargo install --path .
```
to install the `witness` binary.
To get the basic idea, run `witness --help`.
It can process and generate JSON files to be used for the circuits.
For example, if we have a given JSON file we want to parse such as `examples/json/test/example.json` for the `extract` circuit (see `circuits.json`), then we can:
```
witness json --input-file examples/json/test/example.json --output-dir inputs/extract --output-filename input.json
```

For an HTTP request/response, you can generate a JSON input via:
```
witness http --input-file examples/http/get_request.http --output-dir inputs/get_request --output-filename input.json
```
Afterwards, you can run `circomkit compile get_request` then `circomkit witness get_request input`.

## Testing
To test, you can just run
```
Expand Down
37 changes: 21 additions & 16 deletions circuits.json
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
{
"extract": {
"file": "extract",
"template": "Extract",
"file": "parser_json/parser",
"template": "Parser",
"params": [
157,
13
]
},
"value_string": {
"file": "extract",
"template": "Extract",
"file": "parser_json/parser",
"template": "Parser",
"params": [
12,
1
]
},
"value_number": {
"file": "extract",
"template": "Extract",
"file": "parser_json/parser",
"template": "Parser",
"params": [
12,
2
]
},
"value_array": {
"file": "extract",
"template": "Extract",
"file": "parser_json/parser",
"template": "Parser",
"params": [
18,
2
]
},
"value_array_nested": {
"file": "extract",
"template": "Extract",
"file": "parser_json/parser",
"template": "Parser",
"params": [
24,
4
]
},
"value_array_object": {
"file": "extract",
"template": "Extract",
"file": "parser_json/parser",
"template": "Parser",
"params": [
25,
4
]
},
"value_array_object_array": {
"file": "extract",
"template": "Extract",
"file": "parser_json/parser",
"template": "Parser",
"params": [
31,
5
]
},
"value_object": {
"file": "extract",
"template": "Extract",
"file": "parser_json/parser",
"template": "Parser",
"params": [
21,
3
Expand All @@ -70,5 +70,10 @@
787,
10
]
},
"get_request": {
"file": "parser_http_request/parser",
"template": "Parser",
"params": [158]
}
}
49 changes: 49 additions & 0 deletions circuits/parser_http_request/language.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
pragma circom 2.1.9;

// All the possible request methods: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods

template Syntax() {
//-Delimeters---------------------------------------------------------------------------------//
// - ASCII char `:`
signal output COLON <== 58;
// - ASCII char `;`
signal output SEMICOLON <== 59;
// - ASCII char `,`
signal output COMMA <== 44;
// - ASCII char `"`
signal output QUOTE <== 34;
//-White_space--------------------------------------------------------------------------------//
// - ASCII pair: `\r\n`
signal output CLRF <== [13, 10]; // https://www.rfc-editor.org/rfc/rfc2616#section-2.2
// https://www.rfc-editor.org/rfc/rfc7230#section-3.5
// - ASCII char: ` `
signal output SPACE <== 32;
//-Escape-------------------------------------------------------------------------------------//
// - ASCII char: `\`
signal output ESCAPE <== 92;
}

template RequestMethod() {
signal output GET[3] <== [71, 69, 84];
// signal output HEAD[4] <== [72, 69, 65, 68];
signal output POST[4] <== [80, 79, 83, 84];
// signal output PUT <== 3;
// signal output DELETE <== 4;
// signal output CONNECT <== 5;
// signal output OPTIONS <== 6;
// signal output TRACE <== 7;
// signal output PATCH <== 8;
}

// NOTE: Starting at 1 to avoid a false positive with a 0.
template RequestMethodTag() {
signal output GET <== 1;
// signal output HEAD <== 2;
signal output POST <== 3;
// signal output PUT <== 4;
// signal output DELETE <== 5;
// signal output CONNECT <== 6;
// signal output OPTIONS <== 7;
// signal output TRACE <== 8;
// signal output PATCH <== 9;
}
28 changes: 28 additions & 0 deletions circuits/parser_http_request/machine.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
pragma circom 2.1.9;

include "language.circom";
include "../utils/array.circom";

template ParseMethod() {
signal input bytes[7];
signal output MethodTag;

component RequestMethod = RequestMethod();
component RequestMethodTag = RequestMethodTag();

component IsGet = IsEqualArray(3);
for(var byte_idx = 0; byte_idx < 3; byte_idx++) {
IsGet.in[0][byte_idx] <== bytes[byte_idx];
IsGet.in[1][byte_idx] <== RequestMethod.GET[byte_idx];
}
signal TagGet <== IsGet.out * RequestMethodTag.GET;

component IsPost = IsEqualArray(4);
for(var byte_idx = 0; byte_idx < 4; byte_idx++) {
IsPost.in[0][byte_idx] <== bytes[byte_idx];
IsPost.in[1][byte_idx] <== RequestMethod.POST[byte_idx];
}
signal TagPost <== IsPost.out * RequestMethodTag.POST;

MethodTag <== TagGet + TagPost;
}
24 changes: 24 additions & 0 deletions circuits/parser_http_request/parser.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma circom 2.1.9;

include "../utils/bytes.circom";
include "machine.circom";


template Parser(DATA_BYTES) {
signal input data[DATA_BYTES];

signal output Method;

//--------------------------------------------------------------------------------------------//
//-CONSTRAINTS--------------------------------------------------------------------------------//
//--------------------------------------------------------------------------------------------//
component dataASCII = ASCII(DATA_BYTES);
dataASCII.in <== data;
//--------------------------------------------------------------------------------------------//

component ParseMethod = ParseMethod();
for(var byte_idx = 0; byte_idx < 7; byte_idx++) {
ParseMethod.bytes[byte_idx] <== data[byte_idx];
}
log("MethodTag: ", ParseMethod.MethodTag);
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
# `parser`
# `machine`
This module consists of the core parsing components for generating proofs of selective disclosure in JSON.
## Layout
Expand All @@ -23,9 +23,9 @@ Tests for this module are located in the files: `circuits/test/parser/*.test.ts

pragma circom 2.1.9;

include "./utils/array.circom";
include "./utils/bytes.circom";
include "./utils/operators.circom";
include "../utils/array.circom";
include "../utils/bytes.circom";
include "../utils/operators.circom";
include "language.circom";

/*
Expand Down
34 changes: 17 additions & 17 deletions circuits/extract.circom → circuits/parser_json/parser.circom
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
pragma circom 2.1.9;

include "./utils/bytes.circom";
include "parser.circom";
include "../utils/bytes.circom";
include "machine.circom";

template Extract(DATA_BYTES, MAX_STACK_HEIGHT) {
template Parser(DATA_BYTES, MAX_STACK_HEIGHT) {
signal input data[DATA_BYTES];

// TODO: Add assertions on the inputs here!
Expand Down Expand Up @@ -31,23 +31,23 @@ template Extract(DATA_BYTES, MAX_STACK_HEIGHT) {
State[data_idx].parsing_string <== State[data_idx - 1].next_parsing_string;
State[data_idx].parsing_number <== State[data_idx - 1].next_parsing_number;

// Debugging
for(var i = 0; i<MAX_STACK_HEIGHT; i++) {
log("State[", data_idx, "].stack[", i,"] ", "= [",State[data_idx].stack[i][0], "][", State[data_idx].stack[i][1],"]" );
}
log("State[", data_idx, "].parsing_string", "= ", State[data_idx].parsing_string);
log("State[", data_idx, "].parsing_number", "= ", State[data_idx].parsing_number);
log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
// // Debugging
// for(var i = 0; i<MAX_STACK_HEIGHT; i++) {
// log("State[", data_idx, "].stack[", i,"] ", "= [",State[data_idx].stack[i][0], "][", State[data_idx].stack[i][1],"]" );
// }
// log("State[", data_idx, "].parsing_string", "= ", State[data_idx].parsing_string);
// log("State[", data_idx, "].parsing_number", "= ", State[data_idx].parsing_number);
// log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
}

// Constrain to have valid JSON (TODO: more is needed)
// State[DATA_BYTES - 1].next_tree_depth === 0;

// Debugging
for(var i = 0; i < MAX_STACK_HEIGHT; i++) {
log("State[", DATA_BYTES, "].stack[", i,"] ", "= [",State[DATA_BYTES -1].next_stack[i][0], "][", State[DATA_BYTES - 1].next_stack[i][1],"]" );
}
log("State[", DATA_BYTES, "].parsing_string", "= ", State[DATA_BYTES-1].next_parsing_string);
log("State[", DATA_BYTES, "].parsing_number", "= ", State[DATA_BYTES-1].next_parsing_number);
log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
// // Debugging
// for(var i = 0; i < MAX_STACK_HEIGHT; i++) {
// log("State[", DATA_BYTES, "].stack[", i,"] ", "= [",State[DATA_BYTES -1].next_stack[i][0], "][", State[DATA_BYTES - 1].next_stack[i][1],"]" );
// }
// log("State[", DATA_BYTES, "].parsing_string", "= ", State[DATA_BYTES-1].next_parsing_string);
// log("State[", DATA_BYTES, "].parsing_number", "= ", State[DATA_BYTES-1].next_parsing_number);
// log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,9 @@ describe("StateUpdate", () => {
});
}

function generateFailCase(input: any, desc: string) {
const description = generateDescription(input);

it(`(valid) witness: ${description}\n${desc}`, async () => {
await circuit.expectFail(input);
});
}

before(async () => {
circuit = await circomkit.WitnessTester(`StateUpdate`, {
file: "circuits/parser",
file: "circuits/parser_json/machine",
template: "StateUpdate",
params: [4],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ describe("GetTopOfStack", () => {
let circuit: WitnessTester<["stack"], ["value", "pointer"]>;
before(async () => {
circuit = await circomkit.WitnessTester(`GetTopOfStack`, {
file: "circuits/parser",
file: "circuits/parser_json/machine",
template: "GetTopOfStack",
params: [4],
});
Expand Down Expand Up @@ -44,7 +44,7 @@ describe("StateUpdate :: RewriteStack", () => {
>;
before(async () => {
circuit = await circomkit.WitnessTester(`GetTopOfStack`, {
file: "circuits/parser",
file: "circuits/parser_json/machine",
template: "StateUpdate",
params: [4],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe("StateUpdate :: Values", () => {
>;
before(async () => {
circuit = await circomkit.WitnessTester(`GetTopOfStack`, {
file: "circuits/parser",
file: "circuits/parser_json/machine",
template: "StateUpdate",
params: [4],
});
Expand Down
5 changes: 5 additions & 0 deletions examples/http/get_request.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GET /objectserver/restapi/alerts/status HTTP/1.1
Accept: application/json
Authorization: Basic dGVzdHVzZXIwMTpuZXRjb29s
Host: localhost
Connection: keep-alive
5 changes: 5 additions & 0 deletions examples/http/get_response.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 19

{"success":"true"}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
14 changes: 0 additions & 14 deletions json_examples/reddit_response.json

This file was deleted.

7 changes: 0 additions & 7 deletions json_examples/sambhav_example.json

This file was deleted.

Loading

0 comments on commit 9a44739

Please sign in to comment.