Skip to content

Commit

Permalink
fix: http parser
Browse files Browse the repository at this point in the history
Includes a test to check this works properly
  • Loading branch information
Autoparallel committed Dec 19, 2024
1 parent 7457da0 commit ba27970
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 14 deletions.
35 changes: 21 additions & 14 deletions circuits/http/machine.circom
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,25 @@ template HttpStateUpdate() {

//---------------------------------------------------------------------------------//
// Take current state and CRLF info to update state
signal state[2] <== [parsing_start, parsing_header];
component stateChange = StateChange();
stateChange.readCRLF <== readCRLF;
signal state[3] <== [parsing_start, parsing_header, parsing_field_value];
component stateChange = StateChange();
stateChange.readCRLF <== readCRLF;
stateChange.readCRLFCRLF <== readCRLFCRLF;
stateChange.readSP <== readSP.out;
stateChange.readColon <== readColon.out;
stateChange.state <== state;
stateChange.readSP <== readSP.out;
stateChange.readColon <== readColon.out;
stateChange.state <== state;

component nextState = ArrayAdd(5);
nextState.lhs <== [state[0], state[1], parsing_field_name, parsing_field_value, parsing_body];
nextState.rhs <== stateChange.out;
//---------------------------------------------------------------------------------//

next_parsing_start <== nextState.out[0];
next_parsing_header <== nextState.out[1];
next_parsing_field_name <== nextState.out[2];
next_parsing_start <== nextState.out[0];
next_parsing_header <== nextState.out[1];
next_parsing_field_name <== nextState.out[2];
next_parsing_field_value <== nextState.out[3];
next_parsing_body <== nextState.out[4];
next_line_status <== line_status + readCR.out + readCRLF + readCRLFCRLF - line_status * notCRAndLF;
next_parsing_body <== nextState.out[4];
next_line_status <== line_status + readCR.out + readCRLF + readCRLFCRLF - line_status * notCRAndLF;
}

// TODO:
Expand All @@ -77,7 +77,7 @@ template StateChange() {
signal input readCRLFCRLF;
signal input readSP;
signal input readColon;
signal input state[2];
signal input state[3];
signal output out[5];

// GreaterEqThan(2) because start line can have at most 3 values for request or response
Expand All @@ -97,7 +97,8 @@ template StateChange() {
// disable parsing header on reading CRLF-CRLF
signal disableParsingHeader <== readCRLFCRLF * state[1];
// parsing field value when parsing header and read Colon `:`
signal isParsingFieldValue <== isParsingHeader * readColon;
signal readColonNotInFieldValue <== readColon * (1 - state[2]);
signal isParsingFieldValue <== isParsingHeader * readColonNotInFieldValue;

// parsing body when reading CRLF-CRLF and parsing header
signal enableParsingBody <== readCRLFCRLF * isParsingHeader;
Expand All @@ -107,5 +108,11 @@ template StateChange() {
// parsing_field_name = out[2] = enable header + increment header - parsing field value - parsing body
// parsing_field_value = out[3] = parsing field value - increment parsing header (zeroed every time new header starts)
// parsing_body = out[4] = enable body
out <== [incrementParsingStart - disableParsingStart, enableParsingHeader + incrementParsingHeader - disableParsingHeader, enableParsingHeader + incrementParsingHeader - isParsingFieldValue - enableParsingBody, isParsingFieldValue - incrementParsingHeader, enableParsingBody];
out <== [
incrementParsingStart - disableParsingStart,
enableParsingHeader + incrementParsingHeader - disableParsingHeader,
enableParsingHeader + incrementParsingHeader - isParsingFieldValue - enableParsingBody,
isParsingFieldValue - incrementParsingHeader,
enableParsingBody
];
}
56 changes: 56 additions & 0 deletions circuits/http/parser.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
include "machine.circom";

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

component State[DATA_BYTES];
State[0] = HttpStateUpdate();
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;

log("-------------------------------------------------");
log("byte: ", data[0]);
log("-------------------------------------------------");
log("State[", 0, "].parsing_start =", State[0].parsing_start);
log("State[", 0, "].parsing_header =", State[0].parsing_header);
log("State[", 0, "].parsing_field_name =", State[0].parsing_field_name);
log("State[", 0, "].parsing_field_value =", State[0].parsing_field_value);
log("State[", 0, "].parsing_body =", State[0].parsing_body);
log("State[", 0, "].line_status =", State[0].line_status);
log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");

for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) {
State[data_idx] = HttpStateUpdate();
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;
log("-------------------------------------------------");
log("byte: ", data[data_idx]);
log("-------------------------------------------------");
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");
}

// Verify machine ends in a valid state
State[DATA_BYTES - 1].next_parsing_start === 0;
State[DATA_BYTES - 1].next_parsing_header === 0;
State[DATA_BYTES - 1].next_parsing_field_name === 0;
State[DATA_BYTES - 1].next_parsing_field_value === 0;
State[DATA_BYTES - 1].next_parsing_body === 1;
State[DATA_BYTES - 1].next_line_status === 0;

}
96 changes: 96 additions & 0 deletions circuits/test/http/parser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { circomkit, WitnessTester } from "../common";


const HTTP_BYTES = [
72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 67, 111, 110, 110, 101, 99,
116, 105, 111, 110, 58, 32, 99, 108, 111, 115, 101, 13, 10, 67, 111, 110, 116, 101, 110, 116,
45, 76, 101, 110, 103, 116, 104, 58, 32, 50, 50, 13, 10, 67, 97, 99, 104, 101, 45, 67, 111,
110, 116, 114, 111, 108, 58, 32, 109, 97, 120, 45, 97, 103, 101, 61, 51, 48, 48, 13, 10, 67,
111, 110, 116, 101, 110, 116, 45, 83, 101, 99, 117, 114, 105, 116, 121, 45, 80, 111, 108, 105,
99, 121, 58, 32, 100, 101, 102, 97, 117, 108, 116, 45, 115, 114, 99, 32, 39, 110, 111, 110,
101, 39, 59, 32, 115, 116, 121, 108, 101, 45, 115, 114, 99, 32, 39, 117, 110, 115, 97, 102,
101, 45, 105, 110, 108, 105, 110, 101, 39, 59, 32, 115, 97, 110, 100, 98, 111, 120, 13, 10, 67,
111, 110, 116, 101, 110, 116, 45, 84, 121, 112, 101, 58, 32, 116, 101, 120, 116, 47, 112, 108,
97, 105, 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, 116, 102, 45, 56, 13, 10, 69,
84, 97, 103, 58, 32, 34, 101, 48, 101, 54, 53, 49, 48, 99, 49, 102, 99, 49, 51, 98, 51, 97, 54,
51, 97, 99, 98, 99, 48, 54, 49, 53, 101, 101, 48, 55, 97, 52, 57, 53, 50, 56, 55, 51, 97, 56,
100, 97, 55, 55, 48, 50, 55, 100, 48, 48, 52, 49, 50, 102, 99, 99, 102, 49, 97, 53, 99, 101,
50, 57, 34, 13, 10, 83, 116, 114, 105, 99, 116, 45, 84, 114, 97, 110, 115, 112, 111, 114, 116,
45, 83, 101, 99, 117, 114, 105, 116, 121, 58, 32, 109, 97, 120, 45, 97, 103, 101, 61, 51, 49,
53, 51, 54, 48, 48, 48, 13, 10, 88, 45, 67, 111, 110, 116, 101, 110, 116, 45, 84, 121, 112,
101, 45, 79, 112, 116, 105, 111, 110, 115, 58, 32, 110, 111, 115, 110, 105, 102, 102, 13, 10,
88, 45, 70, 114, 97, 109, 101, 45, 79, 112, 116, 105, 111, 110, 115, 58, 32, 100, 101, 110,
121, 13, 10, 88, 45, 88, 83, 83, 45, 80, 114, 111, 116, 101, 99, 116, 105, 111, 110, 58, 32,
49, 59, 32, 109, 111, 100, 101, 61, 98, 108, 111, 99, 107, 13, 10, 88, 45, 71, 105, 116, 72,
117, 98, 45, 82, 101, 113, 117, 101, 115, 116, 45, 73, 100, 58, 32, 55, 56, 51, 49, 58, 51, 50,
55, 52, 49, 52, 58, 49, 50, 70, 57, 69, 54, 58, 49, 65, 51, 51, 67, 50, 58, 54, 55, 54, 52, 54,
56, 70, 49, 13, 10, 65, 99, 99, 101, 112, 116, 45, 82, 97, 110, 103, 101, 115, 58, 32, 98, 121,
116, 101, 115, 13, 10, 68, 97, 116, 101, 58, 32, 84, 104, 117, 44, 32, 49, 57, 32, 68, 101, 99,
32, 50, 48, 50, 52, 32, 50, 49, 58, 51, 53, 58, 53, 57, 32, 71, 77, 84, 13, 10, 86, 105, 97,
58, 32, 49, 46, 49, 32, 118, 97, 114, 110, 105, 115, 104, 13, 10, 88, 45, 83, 101, 114, 118,
101, 100, 45, 66, 121, 58, 32, 99, 97, 99, 104, 101, 45, 104, 121, 100, 49, 49, 48, 48, 48, 51,
52, 45, 72, 89, 68, 13, 10, 88, 45, 67, 97, 99, 104, 101, 58, 32, 72, 73, 84, 13, 10, 88, 45,
67, 97, 99, 104, 101, 45, 72, 105, 116, 115, 58, 32, 48, 13, 10, 88, 45, 84, 105, 109, 101,
114, 58, 32, 83, 49, 55, 51, 52, 54, 52, 52, 49, 54, 48, 46, 53, 54, 48, 57, 53, 51, 44, 86,
83, 48, 44, 86, 69, 49, 13, 10, 86, 97, 114, 121, 58, 32, 65, 117, 116, 104, 111, 114, 105,
122, 97, 116, 105, 111, 110, 44, 65, 99, 99, 101, 112, 116, 45, 69, 110, 99, 111, 100, 105,
110, 103, 44, 79, 114, 105, 103, 105, 110, 13, 10, 65, 99, 99, 101, 115, 115, 45, 67, 111, 110,
116, 114, 111, 108, 45, 65, 108, 108, 111, 119, 45, 79, 114, 105, 103, 105, 110, 58, 32, 42,
13, 10, 67, 114, 111, 115, 115, 45, 79, 114, 105, 103, 105, 110, 45, 82, 101, 115, 111, 117,
114, 99, 101, 45, 80, 111, 108, 105, 99, 121, 58, 32, 99, 114, 111, 115, 115, 45, 111, 114,
105, 103, 105, 110, 13, 10, 88, 45, 70, 97, 115, 116, 108, 121, 45, 82, 101, 113, 117, 101,
115, 116, 45, 73, 68, 58, 32, 50, 48, 97, 101, 102, 56, 55, 48, 50, 53, 102, 54, 56, 52, 98,
101, 55, 54, 50, 53, 55, 102, 49, 53, 98, 102, 102, 53, 97, 55, 57, 50, 97, 99, 49, 53, 97, 97,
100, 50, 13, 10, 69, 120, 112, 105, 114, 101, 115, 58, 32, 84, 104, 117, 44, 32, 49, 57, 32,
68, 101, 99, 32, 50, 48, 50, 52, 32, 50, 49, 58, 52, 48, 58, 53, 57, 32, 71, 77, 84, 13, 10,
83, 111, 117, 114, 99, 101, 45, 65, 103, 101, 58, 32, 49, 53, 51, 13, 10, 13, 10, 123, 10, 32,
32, 34, 104, 101, 108, 108, 111, 34, 58, 32, 34, 119, 111, 114, 108, 100, 34, 10, 125,
];

// HTTP/1.1 200 OK
// Connection: close
// Content-Length: 22
// Cache-Control: max-age=300
// Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; sandbox
// Content-Type: text/plain; charset=utf-8
// ETag: "e0e6510c1fc13b3a63acbc0615ee07a4952873a8da77027d00412fccf1a5ce29"
// Strict-Transport-Security: max-age=31536000
// X-Content-Type-Options: nosniff
// X-Frame-Options: deny
// X-XSS-Protection: 1; mode=block
// X-GitHub-Request-Id: 7831:327414:12F9E6:1A33C2:676468F1
// Accept-Ranges: bytes
// Date: Thu, 19 Dec 2024 21:35:59 GMT
// Via: 1.1 varnish
// X-Served-By: cache-hyd1100034-HYD
// X-Cache: HIT
// X-Cache-Hits: 0
// X-Timer: S1734644160.560953,VS0,VE1
// Vary: Authorization,Accept-Encoding,Origin
// Access-Control-Allow-Origin: *
// Cross-Origin-Resource-Policy: cross-origin
// X-Fastly-Request-ID: 20aef87025f684be76257f15bff5a792ac15aad2
// Expires: Thu, 19 Dec 2024 21:40:59 GMT
// Source-Age: 153

// {
// "hello": "world"
// }

describe("HTTP Parser", async () => {
let HTTPParser: WitnessTester<["data"], []>;
before(async () => {
HTTPParser = await circomkit.WitnessTester("http_nivc", {
file: "http/parser",
template: "Parser",
params: [HTTP_BYTES.length]
});
});

it("witness: example", async () => {
await HTTPParser.expectPass({
data: HTTP_BYTES,
});
});

});

0 comments on commit ba27970

Please sign in to comment.