From f01c685e344f2e68a51a02dc1408fb0c9fb2976a Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Thu, 29 Aug 2024 15:19:36 -0600 Subject: [PATCH] decent progress on request parse --- circuits.json | 4 +- circuits/http/interpreter.circom | 5 +- circuits/http/parser/language.circom | 2 +- circuits/http/parser/machine.circom | 71 ++++++++++++++++++---------- circuits/http/parser/parser.circom | 40 ++++++++++++++-- examples/http/get_request.http | 6 +-- src/bin/witness.rs | 15 ++++-- 7 files changed, 102 insertions(+), 41 deletions(-) diff --git a/circuits.json b/circuits.json index bd295ac..f1d7ee1 100644 --- a/circuits.json +++ b/circuits.json @@ -72,8 +72,8 @@ ] }, "get_request": { - "file": "parser_http_request/parser", + "file": "http/parser/parser", "template": "Parser", - "params": [158] + "params": [60] } } \ No newline at end of file diff --git a/circuits/http/interpreter.circom b/circuits/http/interpreter.circom index 2f0a55f..68e4a1d 100644 --- a/circuits/http/interpreter.circom +++ b/circuits/http/interpreter.circom @@ -6,8 +6,9 @@ include "../utils/array.circom"; /* TODO: Notes -- - This is a pretty efficient way to simply check what the method used in a request is by checking -the first `DATA_LENGTH` number of bytes. -- Certainly this could be more modular. + the first `DATA_LENGTH` number of bytes. +- Could probably change this to a template that checks if it is one of the given methods + so we don't check them all in one */ template YieldMethod(DATA_LENGTH) { signal input bytes[DATA_LENGTH]; diff --git a/circuits/http/parser/language.circom b/circuits/http/parser/language.circom index a001d86..b6fce6c 100644 --- a/circuits/http/parser/language.circom +++ b/circuits/http/parser/language.circom @@ -14,7 +14,7 @@ template Syntax() { 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 + signal output CLRF[2] <== [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; diff --git a/circuits/http/parser/machine.circom b/circuits/http/parser/machine.circom index ee0cff1..18dc21e 100644 --- a/circuits/http/parser/machine.circom +++ b/circuits/http/parser/machine.circom @@ -1,28 +1,51 @@ 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; +include "../../utils/array.circom"; + +template StateUpdate() { + signal input parsing_start; // Bool flag for if we are in the start line + signal input parsing_header; // Flag + Counter for what header line we are in + signal input parsing_body; + signal input read_clrf; // Bool flag to say whether we just read a CLRF + signal input byte_pair[2]; + + signal output next_parsing_start; + signal output next_parsing_header; + signal output next_parsing_body; + signal output next_read_clrf; + + signal state[3] <== [parsing_start, parsing_header, parsing_body]; + component stateToMask = StateToMask(); + stateToMask.state <== state; + + component Syntax = Syntax(); + + component pairIsCLRF = IsEqualArray(2); + pairIsCLRF.in <== [byte_pair, Syntax.CLRF]; + log("pairIsCLRF: ", pairIsCLRF.out); + + component stateChange = ScalarArrayMul(3); + stateChange.array <== stateToMask.mask; + stateChange.scalar <== pairIsCLRF.out; + log("stateChange[0]: ", stateChange.out[0]); + log("stateChange[1]: ", stateChange.out[1]); + log("stateChange[2]: ", stateChange.out[2]); + + component nextState = ArrayAdd(3); + nextState.lhs <== state; + nextState.rhs <== stateChange.out; + + next_parsing_start <== nextState.out[0]; + next_parsing_header <== nextState.out[1]; + next_parsing_body <== nextState.out[2]; + next_read_clrf <== pairIsCLRF.out; + +} + +template StateToMask() { + signal input state[3]; + signal output mask[3]; + + mask <== [- state[0], state[0] - state[1], state[2]]; } \ No newline at end of file diff --git a/circuits/http/parser/parser.circom b/circuits/http/parser/parser.circom index 9fd9524..7262a35 100644 --- a/circuits/http/parser/parser.circom +++ b/circuits/http/parser/parser.circom @@ -1,6 +1,6 @@ pragma circom 2.1.9; -include "../utils/bytes.circom"; +include "../../utils/bytes.circom"; include "machine.circom"; @@ -16,9 +16,39 @@ template Parser(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]; + // Initialze the parser + component State[DATA_BYTES]; + State[0] = StateUpdate(); + State[0].byte_pair <== [data[0], data[1]]; + State[0].parsing_start <== 1; + State[0].parsing_header <== 0; + State[0].parsing_body <== 0; + State[0].read_clrf <== 0; + + for(var data_idx = 1; data_idx < DATA_BYTES - 1; data_idx++) { + State[data_idx] = StateUpdate(); + State[data_idx].byte_pair <== [data[data_idx], data[data_idx + 1]]; + 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_body <== State[data_idx - 1].next_parsing_body; + State[data_idx].read_clrf <== State[data_idx - 1].next_read_clrf; + + // 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_body ", "= ", State[data_idx].parsing_body); + log("State[", data_idx, "].read_clrf ", "= ", State[data_idx].read_clrf); + log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); } - log("MethodTag: ", ParseMethod.MethodTag); + + // Constrain to have valid JSON (TODO: more is needed) + // State[DATA_BYTES - 1].next_tree_depth === 0; + + // // 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_body ", "= ", State[DATA_BYTES-1].next_parsing_body); + // log("State[", DATA_BYTES, "].read_clrf ", "= ", State[DATA_BYTES-1].next_read_clrf); + // log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + } \ No newline at end of file diff --git a/examples/http/get_request.http b/examples/http/get_request.http index 88eb48d..89257e9 100644 --- a/examples/http/get_request.http +++ b/examples/http/get_request.http @@ -1,5 +1,3 @@ -GET /objectserver/restapi/alerts/status HTTP/1.1 +GET /api HTTP/1.1 Accept: application/json -Authorization: Basic dGVzdHVzZXIwMTpuZXRjb29s -Host: localhost -Connection: keep-alive \ No newline at end of file +Host: localhost \ No newline at end of file diff --git a/src/bin/witness.rs b/src/bin/witness.rs index d3c324f..bacabe0 100644 --- a/src/bin/witness.rs +++ b/src/bin/witness.rs @@ -10,11 +10,11 @@ struct Args { command: Command, /// Output directory (will be created if it doesn't exist) - #[arg(global = true, short, long, default_value = ".")] + #[arg(global = true, long, default_value = ".")] output_dir: PathBuf, /// Output filename (will be created if it doesn't exist) - #[arg(global = true, short, long, default_value = "output.json")] + #[arg(global = true, long, default_value = "output.json")] output_filename: String, } @@ -64,7 +64,16 @@ pub fn main() -> Result<(), Box> { (data, keys_map) } Command::Http { input_file } => { - let data = std::fs::read(input_file)?; + let mut data = std::fs::read(input_file)?; + let mut i = 0; + while i < data.len() { + if data[i] == 10 && (i == 0 || data[i - 1] != 13) { + data.insert(i, 13); + i += 2; + } else { + i += 1; + } + } let keys_map = serde_json::Map::new(); (data, keys_map) }