From 0f4d3e8e3a47380b13d70f2e5a86e5a17d2a95c3 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Thu, 29 Aug 2024 16:08:37 -0600 Subject: [PATCH] feat: very basic HTTP parsing --- circuits.json | 5 ++ circuits/http/parser/language.circom | 9 ++-- circuits/http/parser/machine.circom | 71 +++++++++++++++++++--------- circuits/http/parser/parser.circom | 27 +++++------ 4 files changed, 72 insertions(+), 40 deletions(-) diff --git a/circuits.json b/circuits.json index f1d7ee1..d254c67 100644 --- a/circuits.json +++ b/circuits.json @@ -75,5 +75,10 @@ "file": "http/parser/parser", "template": "Parser", "params": [60] + }, + "get_response": { + "file": "http/parser/parser", + "template": "Parser", + "params": [89] } } \ No newline at end of file diff --git a/circuits/http/parser/language.circom b/circuits/http/parser/language.circom index b6fce6c..b8e3fa6 100644 --- a/circuits/http/parser/language.circom +++ b/circuits/http/parser/language.circom @@ -13,9 +13,12 @@ template Syntax() { // - ASCII char `"` signal output QUOTE <== 34; //-White_space--------------------------------------------------------------------------------// - // - ASCII pair: `\r\n` - 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 + // https://www.rfc-editor.org/rfc/rfc2616#section-2.2 + // https://www.rfc-editor.org/rfc/rfc7230#section-3.5 + // - ASCII char `\r` + signal output CL <== 13; + // - ASCII char `\n` + signal output RF <== 10; // - ASCII char: ` ` signal output SPACE <== 32; //-Escape-------------------------------------------------------------------------------------// diff --git a/circuits/http/parser/machine.circom b/circuits/http/parser/machine.circom index 18dc21e..16540a9 100644 --- a/circuits/http/parser/machine.circom +++ b/circuits/http/parser/machine.circom @@ -7,45 +7,72 @@ 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 input line_status; // Flag that counts up to 4 to read a double CLRF + signal input byte; 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; + signal output next_line_status; component Syntax = Syntax(); - component pairIsCLRF = IsEqualArray(2); - pairIsCLRF.in <== [byte_pair, Syntax.CLRF]; - log("pairIsCLRF: ", pairIsCLRF.out); + //---------------------------------------------------------------------------------// + // Check if what we just read is a CL / RF + component readCL = IsEqual(); + readCL.in <== [byte, Syntax.CL]; + component readRF = IsEqual(); + readRF.in <== [byte, Syntax.RF]; + + signal notCLAndRF <== (1 - readCL.out) * (1 - readRF.out); + //---------------------------------------------------------------------------------// + + //---------------------------------------------------------------------------------// + // Check if we had read previously CL / RF or multiple + component prevReadCL = IsEqual(); + prevReadCL.in <== [line_status, 1]; + log("prevReadCL: ", prevReadCL.out); + component prevReadCLRF = IsEqual(); + prevReadCLRF.in <== [line_status, 2]; + log("prevReadCLRF: ", prevReadCLRF.out); + component prevReadCLRFCL = IsEqual(); + prevReadCLRFCL.in <== [line_status, 3]; + log("prevReadCLRFCL: ", prevReadCLRFCL.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]); + signal readCLRF <== prevReadCL.out * readRF.out; + log("readCLRF: ", readCLRF); + signal readCLRFCLRF <== prevReadCLRFCL.out * readRF.out; + log("readCLRFCLRF: ", readCLRFCLRF); + //---------------------------------------------------------------------------------// + + //---------------------------------------------------------------------------------// + // Take current state and CLRF info to update state + signal state[3] <== [parsing_start, parsing_header, parsing_body]; + component stateChange = StateChange(); + stateChange.readCLRF <== readCLRF; + stateChange.readCLRFCLRF <== readCLRFCLRF; + stateChange.state <== state; component nextState = ArrayAdd(3); nextState.lhs <== state; nextState.rhs <== stateChange.out; + //---------------------------------------------------------------------------------// - next_parsing_start <== nextState.out[0]; + next_parsing_start <== nextState.out[0]; next_parsing_header <== nextState.out[1]; - next_parsing_body <== nextState.out[2]; - next_read_clrf <== pairIsCLRF.out; + next_parsing_body <== nextState.out[2]; + next_line_status <== line_status + readCL.out + readCLRF + readCLRFCLRF - line_status * notCLAndRF; } -template StateToMask() { +template StateChange() { + signal input readCLRF; + signal input readCLRFCLRF; signal input state[3]; - signal output mask[3]; + signal output out[3]; + + signal disableParsingStart <== readCLRF * state[0]; + signal disableParsingHeader <== readCLRFCLRF * state[1]; - mask <== [- state[0], state[0] - state[1], state[2]]; + out <== [-disableParsingStart, disableParsingStart - disableParsingHeader, disableParsingHeader]; } \ No newline at end of file diff --git a/circuits/http/parser/parser.circom b/circuits/http/parser/parser.circom index 7262a35..487fb63 100644 --- a/circuits/http/parser/parser.circom +++ b/circuits/http/parser/parser.circom @@ -19,36 +19,33 @@ template Parser(DATA_BYTES) { // Initialze the parser component State[DATA_BYTES]; State[0] = StateUpdate(); - State[0].byte_pair <== [data[0], data[1]]; + State[0].byte <== data[0]; State[0].parsing_start <== 1; State[0].parsing_header <== 0; State[0].parsing_body <== 0; - State[0].read_clrf <== 0; + State[0].line_status <== 0; - for(var data_idx = 1; data_idx < DATA_BYTES - 1; data_idx++) { + for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { State[data_idx] = StateUpdate(); - State[data_idx].byte_pair <== [data[data_idx], data[data_idx + 1]]; + 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_body <== State[data_idx - 1].next_parsing_body; - State[data_idx].read_clrf <== State[data_idx - 1].next_read_clrf; + State[data_idx].line_status <== State[data_idx - 1].next_line_status; // 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("State[", data_idx, "].line_status ", "= ", State[data_idx].line_status); log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); } - // 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"); + // 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, "].line_status ", "= ", State[DATA_BYTES-1].next_line_status); + log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); } \ No newline at end of file