diff --git a/circuits/http/machine.circom b/circuits/http/machine.circom index 5f372d5..0c02101 100644 --- a/circuits/http/machine.circom +++ b/circuits/http/machine.circom @@ -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: @@ -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 @@ -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; @@ -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 + ]; } \ No newline at end of file diff --git a/circuits/http/parser.circom b/circuits/http/parser.circom new file mode 100644 index 0000000..981e070 --- /dev/null +++ b/circuits/http/parser.circom @@ -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; + +} \ No newline at end of file diff --git a/circuits/test/http/parser.test.ts b/circuits/test/http/parser.test.ts new file mode 100644 index 0000000..ff88915 --- /dev/null +++ b/circuits/test/http/parser.test.ts @@ -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, + }); + }); + +}); \ No newline at end of file diff --git a/package.json b/package.json index 2734d21..b74cc1a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "web-prover-circuits", "description": "ZK Circuits for WebProofs", - "version": "0.7.0", + "version": "0.7.1", "license": "Apache-2.0", "repository": { "type": "git",