From 38e9370f4ba72b007195ff97c7e1ff9800d08184 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Tue, 5 Nov 2024 14:50:17 -0700 Subject: [PATCH 1/9] reduce AES public io --- builds/target_1024b/aes_gctr_nivc_1024b.circom | 3 +-- builds/target_256b/aes_gctr_nivc_256b.circom | 6 ------ builds/target_256b/http_body_mask_256b.circom | 6 ------ builds/target_256b/http_lock_header_256b.circom | 5 ----- .../http_parse_and_lock_start_line_256b.circom | 5 ----- builds/target_256b/json_extract_value_256b.circom | 5 ----- .../target_256b/json_mask_array_index_256b.circom | 5 ----- builds/target_256b/json_mask_object_256b.circom | 5 ----- builds/target_256b/json_parse_256b.circom | 6 ------ builds/target_512b/aes_gctr_nivc_512b.circom | 3 +-- circuits/aes-gcm/nivc/aes-gctr-nivc.circom | 9 +++------ circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts | 14 ++++++-------- package.json | 2 +- 13 files changed, 12 insertions(+), 62 deletions(-) delete mode 100644 builds/target_256b/aes_gctr_nivc_256b.circom delete mode 100644 builds/target_256b/http_body_mask_256b.circom delete mode 100644 builds/target_256b/http_lock_header_256b.circom delete mode 100644 builds/target_256b/http_parse_and_lock_start_line_256b.circom delete mode 100644 builds/target_256b/json_extract_value_256b.circom delete mode 100644 builds/target_256b/json_mask_array_index_256b.circom delete mode 100644 builds/target_256b/json_mask_object_256b.circom delete mode 100644 builds/target_256b/json_parse_256b.circom diff --git a/builds/target_1024b/aes_gctr_nivc_1024b.circom b/builds/target_1024b/aes_gctr_nivc_1024b.circom index ae0ccf2..a48234a 100644 --- a/builds/target_1024b/aes_gctr_nivc_1024b.circom +++ b/builds/target_1024b/aes_gctr_nivc_1024b.circom @@ -2,5 +2,4 @@ pragma circom 2.1.9; include "../../circuits/aes-gcm/nivc/aes-gctr-nivc.circom"; -// the circomkit tests become unhappy when there is a main. -component main { public [step_in] } = AESGCTRFOLD(1024, 10); \ No newline at end of file +component main { public [step_in] } = AESGCTRFOLD(1024); \ No newline at end of file diff --git a/builds/target_256b/aes_gctr_nivc_256b.circom b/builds/target_256b/aes_gctr_nivc_256b.circom deleted file mode 100644 index 478c4b2..0000000 --- a/builds/target_256b/aes_gctr_nivc_256b.circom +++ /dev/null @@ -1,6 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/aes-gcm/nivc/aes-gctr-nivc.circom"; - -// the circomkit tests become unhappy when there is a main. -component main { public [step_in] } = AESGCTRFOLD(256, 10); \ No newline at end of file diff --git a/builds/target_256b/http_body_mask_256b.circom b/builds/target_256b/http_body_mask_256b.circom deleted file mode 100644 index cb65ee5..0000000 --- a/builds/target_256b/http_body_mask_256b.circom +++ /dev/null @@ -1,6 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/http/nivc/body_mask.circom"; - -component main { public [step_in] } = HTTPMaskBodyNIVC(256, 10); - diff --git a/builds/target_256b/http_lock_header_256b.circom b/builds/target_256b/http_lock_header_256b.circom deleted file mode 100644 index 892e013..0000000 --- a/builds/target_256b/http_lock_header_256b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/http/nivc/lock_header.circom"; - -component main { public [step_in] } = LockHeader(256, 10, 50, 100); \ No newline at end of file diff --git a/builds/target_256b/http_parse_and_lock_start_line_256b.circom b/builds/target_256b/http_parse_and_lock_start_line_256b.circom deleted file mode 100644 index 00411e1..0000000 --- a/builds/target_256b/http_parse_and_lock_start_line_256b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/http/nivc/parse_and_lock_start_line.circom"; - -component main { public [step_in] } = ParseAndLockStartLine(256, 10, 50, 200, 50); \ No newline at end of file diff --git a/builds/target_256b/json_extract_value_256b.circom b/builds/target_256b/json_extract_value_256b.circom deleted file mode 100644 index da8db1f..0000000 --- a/builds/target_256b/json_extract_value_256b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/extractor.circom"; - -component main { public [step_in] } = MaskExtractFinal(256, 10, 50); \ No newline at end of file diff --git a/builds/target_256b/json_mask_array_index_256b.circom b/builds/target_256b/json_mask_array_index_256b.circom deleted file mode 100644 index 83ebb08..0000000 --- a/builds/target_256b/json_mask_array_index_256b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/masker.circom"; - -component main { public [step_in] } = JsonMaskArrayIndexNIVC(256, 10); \ No newline at end of file diff --git a/builds/target_256b/json_mask_object_256b.circom b/builds/target_256b/json_mask_object_256b.circom deleted file mode 100644 index b6bb1ef..0000000 --- a/builds/target_256b/json_mask_object_256b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/masker.circom"; - -component main { public [step_in] } = JsonMaskObjectNIVC(256, 10, 10); diff --git a/builds/target_256b/json_parse_256b.circom b/builds/target_256b/json_parse_256b.circom deleted file mode 100644 index c0f5e8c..0000000 --- a/builds/target_256b/json_parse_256b.circom +++ /dev/null @@ -1,6 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/parse.circom"; - -component main { public [step_in] } = JsonParseNIVC(256, 10); - diff --git a/builds/target_512b/aes_gctr_nivc_512b.circom b/builds/target_512b/aes_gctr_nivc_512b.circom index 07939ff..f863572 100644 --- a/builds/target_512b/aes_gctr_nivc_512b.circom +++ b/builds/target_512b/aes_gctr_nivc_512b.circom @@ -2,5 +2,4 @@ pragma circom 2.1.9; include "../../circuits/aes-gcm/nivc/aes-gctr-nivc.circom"; -// the circomkit tests become unhappy when there is a main. -component main { public [step_in] } = AESGCTRFOLD(512, 10); \ No newline at end of file +component main { public [step_in] } = AESGCTRFOLD(512); \ No newline at end of file diff --git a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom index aa866f3..bae0890 100644 --- a/circuits/aes-gcm/nivc/aes-gctr-nivc.circom +++ b/circuits/aes-gcm/nivc/aes-gctr-nivc.circom @@ -5,13 +5,12 @@ include "../../utils/array.circom"; // Compute AES-GCTR -template AESGCTRFOLD(DATA_BYTES, MAX_STACK_HEIGHT) { +template AESGCTRFOLD(DATA_BYTES) { // ------------------------------------------------------------------------------------------------------------------ // // ~~ Set sizes at compile time ~~ assert(DATA_BYTES % 16 == 0); - // Total number of variables in the parser for each byte of data - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + // Value for accumulating both plaintext and ciphertext as well as counter + var TOTAL_BYTES_ACROSS_NIVC = 2 * DATA_BYTES + 4; // ------------------------------------------------------------------------------------------------------------------ // @@ -75,8 +74,6 @@ template AESGCTRFOLD(DATA_BYTES, MAX_STACK_HEIGHT) { step_out[i] <== nextTexts.outSecond[i - DATA_BYTES]; } else if(i < 2 * DATA_BYTES + 4) { step_out[i] <== aes.counter[i - (2 * DATA_BYTES)]; - } else { - step_out[i] <== 0; } } } diff --git a/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts b/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts index 6ebd2bb..88e361e 100644 --- a/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts +++ b/circuits/test/aes-gcm/nivc/aes-gctr-nivc.test.ts @@ -2,20 +2,18 @@ import { assert } from "chai"; import { WitnessTester } from "circomkit"; import { circomkit } from "../../common"; -const MAX_STACK_HEIGHT = 0; - describe("aes-gctr-nivc", () => { let circuit_one_block: WitnessTester<["key", "iv", "plainText", "aad", "step_in"], ["step_out"]>; const DATA_BYTES_0 = 16; - const TOTAL_BYTES_ACROSS_NIVC_0 = DATA_BYTES_0 * (MAX_STACK_HEIGHT + 2 + 1) + 1; + const TOTAL_BYTES_ACROSS_NIVC_0 = 2 * DATA_BYTES_0 + 4; it("all correct for self generated single zero pt block case", async () => { circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { file: "aes-gcm/nivc/aes-gctr-nivc", template: "AESGCTRFOLD", - params: [DATA_BYTES_0, MAX_STACK_HEIGHT], // input len is 16 bytes + params: [DATA_BYTES_0], // input len is 16 bytes }); let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; @@ -40,7 +38,7 @@ describe("aes-gctr-nivc", () => { circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { file: "aes-gcm/nivc/aes-gctr-nivc", template: "AESGCTRFOLD", - params: [DATA_BYTES_0, MAX_STACK_HEIGHT], // input len is 16 bytes + params: [DATA_BYTES_0], // input len is 16 bytes }); let key = [0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31]; @@ -63,7 +61,7 @@ describe("aes-gctr-nivc", () => { }); const DATA_BYTES_1 = 32; - const TOTAL_BYTES_ACROSS_NIVC_1 = DATA_BYTES_1 * (MAX_STACK_HEIGHT + 2 + 1) + 1; + const TOTAL_BYTES_ACROSS_NIVC_1 = DATA_BYTES_1 * 2 + 4; let zero_block = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; @@ -79,7 +77,7 @@ describe("aes-gctr-nivc", () => { circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { file: "aes-gcm/nivc/aes-gctr-nivc", template: "AESGCTRFOLD", - params: [DATA_BYTES_1, MAX_STACK_HEIGHT], // input len is 32 bytes + params: [DATA_BYTES_1], // input len is 32 bytes }); const counter = [0x00, 0x00, 0x00, 0x01]; @@ -98,7 +96,7 @@ describe("aes-gctr-nivc", () => { circuit_one_block = await circomkit.WitnessTester("aes-gcm-fold", { file: "aes-gcm/nivc/aes-gctr-nivc", template: "AESGCTRFOLD", - params: [DATA_BYTES_1, MAX_STACK_HEIGHT], // input len is 32 bytes + params: [DATA_BYTES_1], // input len is 32 bytes }); const counter = [0x00, 0x00, 0x00, 0x02]; diff --git a/package.json b/package.json index 8834711..13e5752 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "web-prover-circuits", "description": "ZK Circuits for WebProofs", - "version": "0.2.7", + "version": "0.3.0", "license": "Apache-2.0", "repository": { "type": "git", From dfd572141cccda089671a22d6ccadbf139c65930 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Tue, 5 Nov 2024 14:59:56 -0700 Subject: [PATCH 2/9] reduce HTTP start line public io --- ...ttp_parse_and_lock_start_line_1024b.circom | 2 +- ...http_parse_and_lock_start_line_512b.circom | 2 +- .../nivc/parse_and_lock_start_line.circom | 48 +++++-------------- .../nivc/parse_and_lock_start_line.test.ts | 6 +-- 4 files changed, 15 insertions(+), 43 deletions(-) diff --git a/builds/target_1024b/http_parse_and_lock_start_line_1024b.circom b/builds/target_1024b/http_parse_and_lock_start_line_1024b.circom index d55f32c..b70daa1 100644 --- a/builds/target_1024b/http_parse_and_lock_start_line_1024b.circom +++ b/builds/target_1024b/http_parse_and_lock_start_line_1024b.circom @@ -2,4 +2,4 @@ pragma circom 2.1.9; include "../../circuits/http/nivc/parse_and_lock_start_line.circom"; -component main { public [step_in] } = ParseAndLockStartLine(1024, 10, 50, 200, 50); \ No newline at end of file +component main { public [step_in] } = ParseAndLockStartLine(1024, 50, 200, 50); \ No newline at end of file diff --git a/builds/target_512b/http_parse_and_lock_start_line_512b.circom b/builds/target_512b/http_parse_and_lock_start_line_512b.circom index f88d411..6463e4c 100644 --- a/builds/target_512b/http_parse_and_lock_start_line_512b.circom +++ b/builds/target_512b/http_parse_and_lock_start_line_512b.circom @@ -2,4 +2,4 @@ pragma circom 2.1.9; include "../../circuits/http/nivc/parse_and_lock_start_line.circom"; -component main { public [step_in] } = ParseAndLockStartLine(512, 10, 50, 200, 50); \ No newline at end of file +component main { public [step_in] } = ParseAndLockStartLine(512, 50, 200, 50); \ No newline at end of file diff --git a/circuits/http/nivc/parse_and_lock_start_line.circom b/circuits/http/nivc/parse_and_lock_start_line.circom index f1c1c53..afa1d3a 100644 --- a/circuits/http/nivc/parse_and_lock_start_line.circom +++ b/circuits/http/nivc/parse_and_lock_start_line.circom @@ -6,40 +6,22 @@ include "../../utils/bytes.circom"; // TODO: Note that TOTAL_BYTES will match what we have for AESGCMFOLD step_out // I have not gone through to double check the sizes of everything yet. -template ParseAndLockStartLine(DATA_BYTES, MAX_STACK_HEIGHT, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH) { +template ParseAndLockStartLine(DATA_BYTES, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH) { // ------------------------------------------------------------------------------------------------------------------ // // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - // var AES_BYTES = DATA_BYTES + 50; // TODO: Might be wrong, but good enough for now - /* 5 is for the variables: - next_parsing_start - next_parsing_header - next_parsing_field_name - next_parsing_field_value - State[i].next_parsing_body - */ - var TOTAL_BYTES_HTTP_STATE = DATA_BYTES * (5 + 1); // data + parser vars - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; // AES ct/pt + ctr // ------------------------------------------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------------ // - // ~ Unravel from previous NIVC step ~ - // Read in from previous NIVC step (JsonParseNIVC) signal input step_in[TOTAL_BYTES_ACROSS_NIVC]; signal output step_out[TOTAL_BYTES_ACROSS_NIVC]; + // Get the plaintext signal data[DATA_BYTES]; for (var i = 0 ; i < DATA_BYTES ; i++) { - // data[i] <== step_in[50 + i]; // THIS WAS OFFSET FOR AES, WHICH WE NEED TO TAKE INTO ACCOUNT data[i] <== step_in[i]; } - // // TODO: check if these needs to here or not - // DON'T THINK WE NEED THIS SINCE AES SHOULD OUTPUT ASCII OR FAIL - // component dataASCII = ASCII(DATA_BYTES); - // dataASCII.in <== data; - signal input beginning[MAX_BEGINNING_LENGTH]; signal input beginning_length; signal input middle[MAX_MIDDLE_LENGTH]; @@ -114,21 +96,13 @@ template ParseAndLockStartLine(DATA_BYTES, MAX_STACK_HEIGHT, MAX_BEGINNING_LENGT final_length === final_end_counter - middle_end_counter - 2; // ------------------------------------------------------------------------------------------------------------------ // - // ~ Write out to next NIVC step (Lock Header) - for (var i = 0 ; i < DATA_BYTES ; i++) { - // add plaintext http input to step_out - // step_out[i] <== step_in[50 + i]; // AGAIN, NEED TO ACCOUNT FOR AES VARIABLES POSSIBLY - step_out[i] <== step_in[i]; - - // add parser state - step_out[DATA_BYTES + i * 5] <== State[i].next_parsing_start; - step_out[DATA_BYTES + i * 5 + 1] <== State[i].next_parsing_header; - step_out[DATA_BYTES + i * 5 + 2] <== State[i].next_parsing_field_name; - step_out[DATA_BYTES + i * 5 + 3] <== State[i].next_parsing_field_value; - step_out[DATA_BYTES + i * 5 + 4] <== State[i].next_parsing_body; - } - // Pad remaining with zeros - for (var i = TOTAL_BYTES_HTTP_STATE ; i < TOTAL_BYTES_ACROSS_NIVC ; i++ ) { - step_out[i] <== 0; + // write out the pt again + for (var i = 0 ; i < TOTAL_BYTES_ACROSS_NIVC ; i++) { + // add plaintext http input to step_out and ignore the ciphertext + if(i < DATA_BYTES) { + step_out[i] <== step_in[i]; + } else { + step_out[i] <== 0; + } } } diff --git a/circuits/test/http/nivc/parse_and_lock_start_line.test.ts b/circuits/test/http/nivc/parse_and_lock_start_line.test.ts index c52000a..c843c6d 100644 --- a/circuits/test/http/nivc/parse_and_lock_start_line.test.ts +++ b/circuits/test/http/nivc/parse_and_lock_start_line.test.ts @@ -5,9 +5,7 @@ describe("HTTPParseAndLockStartLine", async () => { let httpParseAndLockStartLineCircuit: WitnessTester<["step_in", "beginning", "beginning_length", "middle", "middle_length", "final", "final_length"], ["step_out"]>; const DATA_BYTES = 320; - const MAX_STACK_HEIGHT = 5; - const PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; const MAX_BEGINNING_LENGTH = 10; const MAX_MIDDLE_LENGTH = 50; @@ -17,7 +15,7 @@ describe("HTTPParseAndLockStartLine", async () => { httpParseAndLockStartLineCircuit = await circomkit.WitnessTester(`ParseAndLockStartLine`, { file: "http/nivc/parse_and_lock_start_line", template: "ParseAndLockStartLine", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], + params: [DATA_BYTES, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], }); console.log("#constraints:", await httpParseAndLockStartLineCircuit.getConstraintCount()); }); From 28a6ef754b499b81601838aff6795cd3d399e1fb Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Tue, 5 Nov 2024 15:15:32 -0700 Subject: [PATCH 3/9] reduce HTTP lock header public io --- .../http_lock_header_1024b.circom | 2 +- .../target_512b/http_lock_header_512b.circom | 2 +- circuits/http/nivc/lock_header.circom | 87 ++++++++++++------- circuits/test/http/nivc/lock_header.test.ts | 8 +- 4 files changed, 60 insertions(+), 39 deletions(-) diff --git a/builds/target_1024b/http_lock_header_1024b.circom b/builds/target_1024b/http_lock_header_1024b.circom index fc3d5b3..de4863d 100644 --- a/builds/target_1024b/http_lock_header_1024b.circom +++ b/builds/target_1024b/http_lock_header_1024b.circom @@ -2,4 +2,4 @@ pragma circom 2.1.9; include "../../circuits/http/nivc/lock_header.circom"; -component main { public [step_in] } = LockHeader(1024, 10, 50, 100); \ No newline at end of file +component main { public [step_in] } = LockHeader(1024, 50, 100); \ No newline at end of file diff --git a/builds/target_512b/http_lock_header_512b.circom b/builds/target_512b/http_lock_header_512b.circom index 02d9dc9..5017fe0 100644 --- a/builds/target_512b/http_lock_header_512b.circom +++ b/builds/target_512b/http_lock_header_512b.circom @@ -2,4 +2,4 @@ pragma circom 2.1.9; include "../../circuits/http/nivc/lock_header.circom"; -component main { public [step_in] } = LockHeader(512, 10, 50, 100); \ No newline at end of file +component main { public [step_in] } = LockHeader(512, 50, 100); \ No newline at end of file diff --git a/circuits/http/nivc/lock_header.circom b/circuits/http/nivc/lock_header.circom index 9affcb4..8b9e430 100644 --- a/circuits/http/nivc/lock_header.circom +++ b/circuits/http/nivc/lock_header.circom @@ -1,41 +1,70 @@ pragma circom 2.1.9; +include "../parser/machine.circom"; include "../interpreter.circom"; include "../../utils/array.circom"; include "circomlib/circuits/comparators.circom"; // TODO: should use a MAX_HEADER_NAME_LENGTH and a MAX_HEADER_VALUE_LENGTH -template LockHeader(DATA_BYTES, MAX_STACK_HEIGHT, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH) { +template LockHeader(DATA_BYTES, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH) { // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - /* 5 is for the variables: - next_parsing_start - next_parsing_header - next_parsing_field_name - next_parsing_field_value - State[i].next_parsing_body - */ - var TOTAL_BYTES_HTTP_STATE = DATA_BYTES * (5 + 1); // data + parser vars - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; // aes pt/ct + ctr // ------------------------------------------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------------ // - // ~ Unravel from previous NIVC step ~ - // Read in from previous NIVC step (HttpParseAndLockStartLine or HTTPLockHeader) signal input step_in[TOTAL_BYTES_ACROSS_NIVC]; signal output step_out[TOTAL_BYTES_ACROSS_NIVC]; + // get the plaintext signal data[DATA_BYTES]; for (var i = 0 ; i < DATA_BYTES ; i++) { data[i] <== step_in[i]; } + + // ------------------------------------------------------------------------------------------------------------------ // + // PARSE + // Initialze the parser + 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; + + // TODO (autoparallel): Redundant as fuck, but I'm doing this quickly sorry. I don't think this actually adds constraints signal httpParserState[DATA_BYTES * 5]; - for (var i = 0 ; i < DATA_BYTES * 5 ; i++) { - httpParserState[i] <== step_in[DATA_BYTES + i]; + + + var middle_start_counter = 1; + var middle_end_counter = 1; + var final_end_counter = 1; + 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; + } + // ------------------------------------------------------------------------------------------------------------------ // + + + // TODO (autoparallel): again bad + // Get those redundant variables + for(var i = 0 ; i < DATA_BYTES ; i++) { + httpParserState[i * 5] <== State[i].next_parsing_start; + httpParserState[i * 5 + 1] <== State[i].next_parsing_header; + httpParserState[i * 5 + 2] <== State[i].next_parsing_field_name; + httpParserState[i * 5 + 3] <== State[i].next_parsing_field_value; + httpParserState[i * 5 + 4] <== State[i].next_parsing_body; } + // TODO: Better naming for these variables signal input header[MAX_HEADER_NAME_LENGTH]; signal input headerNameLength; @@ -55,22 +84,16 @@ template LockHeader(DATA_BYTES, MAX_STACK_HEIGHT, MAX_HEADER_NAME_LENGTH, MAX_HE parsingHeader === 1; // ------------------------------------------------------------------------------------------------------------------ // - // ~ Write out to next NIVC step - for (var i = 0 ; i < DATA_BYTES ; i++) { - // add plaintext http input to step_out - step_out[i] <== step_in[i]; - - // add parser state - step_out[DATA_BYTES + i * 5] <== step_in[DATA_BYTES + i * 5]; - step_out[DATA_BYTES + i * 5 + 1] <== step_in[DATA_BYTES + i * 5 + 1]; - step_out[DATA_BYTES + i * 5 + 2] <== step_in[DATA_BYTES + i * 5 + 2]; - step_out[DATA_BYTES + i * 5 + 3] <== step_in[DATA_BYTES + i * 5 + 3]; - step_out[DATA_BYTES + i * 5 + 4] <== step_in[DATA_BYTES + i * 5 + 4]; - } - // Pad remaining with zeros - for (var i = TOTAL_BYTES_HTTP_STATE ; i < TOTAL_BYTES_ACROSS_NIVC ; i++ ) { - step_out[i] <== 0; + // write out the pt again + for (var i = 0 ; i < TOTAL_BYTES_ACROSS_NIVC ; i++) { + // add plaintext http input to step_out and ignore the ciphertext + if(i < DATA_BYTES) { + step_out[i] <== step_in[i]; + } else { + step_out[i] <== 0; + } } + } // TODO: Handrolled template that I haven't tested YOLO. diff --git a/circuits/test/http/nivc/lock_header.test.ts b/circuits/test/http/nivc/lock_header.test.ts index 295c2b4..06eae58 100644 --- a/circuits/test/http/nivc/lock_header.test.ts +++ b/circuits/test/http/nivc/lock_header.test.ts @@ -6,9 +6,7 @@ describe("HTTPLockHeader", async () => { let lockHeaderCircuit: WitnessTester<["step_in", "header", "headerNameLength", "value", "headerValueLength"], ["step_out"]>; const DATA_BYTES = 320; - const MAX_STACK_HEIGHT = 5; - const PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; const MAX_BEGINNING_LENGTH = 10; const MAX_MIDDLE_LENGTH = 50; @@ -20,14 +18,14 @@ describe("HTTPLockHeader", async () => { httpParseAndLockStartLineCircuit = await circomkit.WitnessTester(`ParseAndLockStartLine`, { file: "http/nivc/parse_and_lock_start_line", template: "ParseAndLockStartLine", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], + params: [DATA_BYTES, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], }); console.log("#constraints:", await httpParseAndLockStartLineCircuit.getConstraintCount()); lockHeaderCircuit = await circomkit.WitnessTester(`LockHeader`, { file: "http/nivc/lock_header", template: "LockHeader", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH], + params: [DATA_BYTES, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH], }); console.log("#constraints:", await lockHeaderCircuit.getConstraintCount()); }); From f480e6f4d5c139684986a2672533f4a9bfe6a090 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Tue, 5 Nov 2024 15:26:15 -0700 Subject: [PATCH 4/9] reduce HTTP body mask public io --- .../target_1024b/http_body_mask_1024b.circom | 2 +- builds/target_512b/http_body_mask_512b.circom | 2 +- circuits/http/nivc/body_mask.circom | 50 +++++++++++++------ circuits/test/http/nivc/body_mask.test.ts | 10 ++-- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/builds/target_1024b/http_body_mask_1024b.circom b/builds/target_1024b/http_body_mask_1024b.circom index ea474a2..8309267 100644 --- a/builds/target_1024b/http_body_mask_1024b.circom +++ b/builds/target_1024b/http_body_mask_1024b.circom @@ -2,5 +2,5 @@ pragma circom 2.1.9; include "../../circuits/http/nivc/body_mask.circom"; -component main { public [step_in] } = HTTPMaskBodyNIVC(1024, 10); +component main { public [step_in] } = HTTPMaskBodyNIVC(1024); diff --git a/builds/target_512b/http_body_mask_512b.circom b/builds/target_512b/http_body_mask_512b.circom index ffb3b7e..dea77d1 100644 --- a/builds/target_512b/http_body_mask_512b.circom +++ b/builds/target_512b/http_body_mask_512b.circom @@ -2,5 +2,5 @@ pragma circom 2.1.9; include "../../circuits/http/nivc/body_mask.circom"; -component main { public [step_in] } = HTTPMaskBodyNIVC(512, 10); +component main { public [step_in] } = HTTPMaskBodyNIVC(512); diff --git a/circuits/http/nivc/body_mask.circom b/circuits/http/nivc/body_mask.circom index 5ac67f9..d4b46f2 100644 --- a/circuits/http/nivc/body_mask.circom +++ b/circuits/http/nivc/body_mask.circom @@ -1,13 +1,10 @@ pragma circom 2.1.9; -include "../interpreter.circom"; +include "../parser/machine.circom"; -template HTTPMaskBodyNIVC(DATA_BYTES, MAX_STACK_HEIGHT) { +template HTTPMaskBodyNIVC(DATA_BYTES) { // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; // aes ct/pt + ctr // ------------------------------------------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------------ // @@ -17,20 +14,45 @@ template HTTPMaskBodyNIVC(DATA_BYTES, MAX_STACK_HEIGHT) { signal output step_out[TOTAL_BYTES_ACROSS_NIVC]; signal data[DATA_BYTES]; - signal parsing_body[DATA_BYTES]; + // signal parsing_body[DATA_BYTES]; for (var i = 0 ; i < DATA_BYTES ; i++) { data[i] <== step_in[i]; - parsing_body[i] <== step_in[DATA_BYTES + i * 5 + 4]; // `parsing_body` stored in every 5th slot of step_in/out + // parsing_body[i] <== step_in[DATA_BYTES + i * 5 + 4]; // `parsing_body` stored in every 5th slot of step_in/out } // ------------------------------------------------------------------------------------------------------------------ // - // ~ Write out to next NIVC step - for (var i = 0 ; i < DATA_BYTES ; i++) { - step_out[i] <== data[i] * parsing_body[i]; + // PARSE + // Initialze the parser + 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; + + 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; } - // Write out padded with zeros - for (var i = DATA_BYTES ; i < TOTAL_BYTES_ACROSS_NIVC ; i++) { - step_out[i] <== 0; + // ------------------------------------------------------------------------------------------------------------------ // + + // ------------------------------------------------------------------------------------------------------------------ // + // ~ Write out to next NIVC step + for (var i = 0 ; i < TOTAL_BYTES_ACROSS_NIVC ; i++) { + if(i < DATA_BYTES) { + step_out[i] <== data[i] * State[i].next_parsing_body; + } else { + step_out[i] <== 0; + } } } diff --git a/circuits/test/http/nivc/body_mask.test.ts b/circuits/test/http/nivc/body_mask.test.ts index ae3f206..6c5e5b6 100644 --- a/circuits/test/http/nivc/body_mask.test.ts +++ b/circuits/test/http/nivc/body_mask.test.ts @@ -42,9 +42,7 @@ describe("NIVC_HTTP", async () => { let bodyMaskCircuit: WitnessTester<["step_in"], ["step_out"]>; const DATA_BYTES = 320; - const MAX_STACK_HEIGHT = 5; - const PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; const MAX_HEADER_NAME_LENGTH = 20; const MAX_HEADER_VALUE_LENGTH = 35; @@ -60,21 +58,21 @@ describe("NIVC_HTTP", async () => { httpParseAndLockStartLineCircuit = await circomkit.WitnessTester(`ParseAndLockStartLine`, { file: "http/nivc/parse_and_lock_start_line", template: "ParseAndLockStartLine", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], + params: [DATA_BYTES, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], }); console.log("#constraints:", await httpParseAndLockStartLineCircuit.getConstraintCount()); lockHeaderCircuit = await circomkit.WitnessTester(`LockHeader`, { file: "http/nivc/lock_header", template: "LockHeader", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH], + params: [DATA_BYTES, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH], }); console.log("#constraints:", await lockHeaderCircuit.getConstraintCount()); bodyMaskCircuit = await circomkit.WitnessTester(`BodyMask`, { file: "http/nivc/body_mask", template: "HTTPMaskBodyNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], + params: [DATA_BYTES], }); console.log("#constraints:", await bodyMaskCircuit.getConstraintCount()); }); From 26e976bb797c631aaa08138f0175a00e28ece10a Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Tue, 5 Nov 2024 15:31:53 -0700 Subject: [PATCH 5/9] rm unneeded json parse NIVC --- builds/target_1024b/json_parse_1024b.circom | 6 ------ builds/target_512b/json_parse_512b.circom | 6 ------ 2 files changed, 12 deletions(-) delete mode 100644 builds/target_1024b/json_parse_1024b.circom delete mode 100644 builds/target_512b/json_parse_512b.circom diff --git a/builds/target_1024b/json_parse_1024b.circom b/builds/target_1024b/json_parse_1024b.circom deleted file mode 100644 index 4538d31..0000000 --- a/builds/target_1024b/json_parse_1024b.circom +++ /dev/null @@ -1,6 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/parse.circom"; - -component main { public [step_in] } = JsonParseNIVC(1024, 10); - diff --git a/builds/target_512b/json_parse_512b.circom b/builds/target_512b/json_parse_512b.circom deleted file mode 100644 index a48a10b..0000000 --- a/builds/target_512b/json_parse_512b.circom +++ /dev/null @@ -1,6 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/parse.circom"; - -component main { public [step_in] } = JsonParseNIVC(512, 10); - From 503ccc3e8344eccffa73d38043a9446ad4fcd6ac Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Tue, 5 Nov 2024 15:56:08 -0700 Subject: [PATCH 6/9] reduce JSON NIVC public io --- circuits/json/nivc/extractor.circom | 5 +- circuits/json/nivc/masker.circom | 259 +++++++------------- circuits/json/nivc/parse.circom | 61 ----- circuits/test/json/nivc/masker_nivc.test.ts | 14 +- 4 files changed, 98 insertions(+), 241 deletions(-) delete mode 100644 circuits/json/nivc/parse.circom diff --git a/circuits/json/nivc/extractor.circom b/circuits/json/nivc/extractor.circom index e0a86e7..95220ab 100644 --- a/circuits/json/nivc/extractor.circom +++ b/circuits/json/nivc/extractor.circom @@ -5,11 +5,8 @@ include "@zk-email/circuits/utils/array.circom"; template MaskExtractFinal(DATA_BYTES, MAX_STACK_HEIGHT, MAX_VALUE_LENGTH) { // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data assert(MAX_STACK_HEIGHT >= 2); - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; // aes pt/ct + ctr // ------------------------------------------------------------------------------------------------------------------ // signal input step_in[TOTAL_BYTES_ACROSS_NIVC]; signal output step_out[TOTAL_BYTES_ACROSS_NIVC]; diff --git a/circuits/json/nivc/masker.circom b/circuits/json/nivc/masker.circom index 66dbf81..97f1114 100644 --- a/circuits/json/nivc/masker.circom +++ b/circuits/json/nivc/masker.circom @@ -1,217 +1,148 @@ pragma circom 2.1.9; include "../interpreter.circom"; -include "../../utils/array.circom"; template JsonMaskObjectNIVC(DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH) { // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - assert(MAX_STACK_HEIGHT >= 2); - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + assert(MAX_STACK_HEIGHT >= 2); // TODO (autoparallel): idk if we need this now + var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; // aes ct/pt + ctr // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Unravel from previous NIVC step ~ - // Read in from previous NIVC step (JsonParseNIVC) signal input step_in[TOTAL_BYTES_ACROSS_NIVC]; signal output step_out[TOTAL_BYTES_ACROSS_NIVC]; - // Grab the raw data bytes from the `step_in` variable - var paddedDataLen = DATA_BYTES + MAX_KEY_LENGTH + 1; - signal data[paddedDataLen]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - data[i] <== step_in[i]; - } - for (var i = 0 ; i < MAX_KEY_LENGTH + 1 ; i++) { - data[DATA_BYTES + i] <== 0; - } - - // Decode the encoded data in `step_in` back into parser variables - signal stack[DATA_BYTES][MAX_STACK_HEIGHT + 1][2]; - signal parsingData[DATA_BYTES][2]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - for (var j = 0 ; j < MAX_STACK_HEIGHT + 1 ; j++) { - if (j < MAX_STACK_HEIGHT) { - stack[i][j][0] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2]; - stack[i][j][1] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2 + 1]; - } else { - // Add one extra stack element without doing this while parsing. - // Stack under/overflow caught in parsing. - stack[i][j][0] <== 0; - stack[i][j][1] <== 0; - } - - } - parsingData[i][0] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2]; - parsingData[i][1] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2 + 1]; - } - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Object masking ~ - // Key data to use to point to which object to extract + // Declaration of signals. + signal data[DATA_BYTES]; signal input key[MAX_KEY_LENGTH]; signal input keyLen; - // Signals to detect if we are parsing a key or value with initial setup - signal parsing_key[DATA_BYTES]; - signal parsing_value[DATA_BYTES]; + for(var i = 0 ; i < DATA_BYTES ; i++) { + data[i] <== step_in[i]; + } - // Flags at each byte to indicate if we are matching correct key and in subsequent value - signal is_key_match[DATA_BYTES]; - signal is_value_match[DATA_BYTES]; + // Constraints. + signal value_starting_index[DATA_BYTES - MAX_KEY_LENGTH]; + // flag determining whether this byte is matched value + signal is_value_match[DATA_BYTES - MAX_KEY_LENGTH]; - signal is_next_pair_at_depth[DATA_BYTES]; - signal is_key_match_for_value[DATA_BYTES + 1]; + component State[DATA_BYTES - MAX_KEY_LENGTH]; + State[0] = StateUpdate(MAX_STACK_HEIGHT); + State[0].byte <== data[0]; + for(var i = 0; i < MAX_STACK_HEIGHT; i++) { + State[0].stack[i] <== [0,0]; + } + State[0].parsing_string <== 0; + State[0].parsing_number <== 0; + + signal parsing_key[DATA_BYTES - MAX_KEY_LENGTH]; + signal parsing_value[DATA_BYTES - MAX_KEY_LENGTH]; + signal parsing_object_value[DATA_BYTES - MAX_KEY_LENGTH]; + signal is_key_match[DATA_BYTES - MAX_KEY_LENGTH]; + signal is_key_match_for_value[DATA_BYTES+1 - MAX_KEY_LENGTH]; is_key_match_for_value[0] <== 0; + signal is_next_pair_at_depth[DATA_BYTES - MAX_KEY_LENGTH]; + signal or[DATA_BYTES - MAX_KEY_LENGTH]; - // Initialize values knowing 0th bit of data will never be a key/value - parsing_key[0] <== 0; - parsing_value[0] <== 0; - is_key_match[0] <== 0; - - component stackSelector[DATA_BYTES]; - stackSelector[0] = ArraySelector(MAX_STACK_HEIGHT + 1, 2); - stackSelector[0].in <== stack[0]; - stackSelector[0].index <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1]; + // initialise first iteration - component nextStackSelector[DATA_BYTES]; - nextStackSelector[0] = ArraySelector(MAX_STACK_HEIGHT + 1, 2); - nextStackSelector[0].in <== stack[0]; - nextStackSelector[0].index <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1] + 1; + // check inside key or value + parsing_key[0] <== InsideKey()(State[0].next_stack[0], State[0].next_parsing_string, State[0].next_parsing_number); + parsing_value[0] <== InsideValueObject()(State[0].next_stack[0], State[0].next_stack[1], State[0].next_parsing_string, State[0].next_parsing_number); - is_next_pair_at_depth[0] <== NextKVPairAtDepth(MAX_STACK_HEIGHT + 1)(stack[0], data[0],step_in[TOTAL_BYTES_ACROSS_NIVC - 1]); + is_key_match[0] <== 0; + is_next_pair_at_depth[0] <== NextKVPairAtDepth(MAX_STACK_HEIGHT)(State[0].next_stack, data[0], 0); is_key_match_for_value[1] <== Mux1()([is_key_match_for_value[0] * (1-is_next_pair_at_depth[0]), is_key_match[0] * (1-is_next_pair_at_depth[0])], is_key_match[0]); - is_value_match[0] <== parsing_value[0] * is_key_match_for_value[1]; - - signal or[DATA_BYTES]; - or[0] <== is_value_match[0]; - step_out[0] <== data[0] * or[0]; - - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - // Grab the stack at the indicated height (from `step_in`) - stackSelector[data_idx] = ArraySelector(MAX_STACK_HEIGHT + 1, 2); - stackSelector[data_idx].in <== stack[data_idx]; - stackSelector[data_idx].index <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1]; - - nextStackSelector[data_idx] = ArraySelector(MAX_STACK_HEIGHT + 1, 2); - nextStackSelector[data_idx].in <== stack[data_idx]; - nextStackSelector[data_idx].index <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1] + 1; - - // Detect if we are parsing - parsing_key[data_idx] <== InsideKey()(stackSelector[data_idx].out, parsingData[data_idx][0], parsingData[data_idx][1]); - parsing_value[data_idx] <== InsideValueObject()(stackSelector[data_idx].out, nextStackSelector[data_idx].out, parsingData[data_idx][0], parsingData[data_idx][1]); + is_value_match[0] <== parsing_value[0] * is_key_match_for_value[1]; + + step_out[0] <== data[0] * is_value_match[0]; + + // TODO (autoparallel): it might be dumb to do this with the max key length but fuck it + for(var data_idx = 1; data_idx < DATA_BYTES - MAX_KEY_LENGTH; data_idx++) { + State[data_idx] = StateUpdate(MAX_STACK_HEIGHT); + State[data_idx].byte <== data[data_idx]; + State[data_idx].stack <== State[data_idx - 1].next_stack; + State[data_idx].parsing_string <== State[data_idx - 1].next_parsing_string; + State[data_idx].parsing_number <== State[data_idx - 1].next_parsing_number; + + // - parsing key + // - parsing value (different for string/numbers and array) + // - key match (key 1, key 2) + // - is next pair + // - is key match for value + // - value_mask + // - mask + + // check if inside key or not + parsing_key[data_idx] <== InsideKey()(State[data_idx].next_stack[0], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number); + // check if inside value + parsing_value[data_idx] <== InsideValueObject()(State[data_idx].next_stack[0], State[data_idx].next_stack[1], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number); // to get correct value, check: // - key matches at current index and depth of key is as specified // - whether next KV pair starts // - whether key matched for a value (propogate key match until new KV pair of lower depth starts) - is_key_match[data_idx] <== KeyMatchAtIndex(paddedDataLen, MAX_KEY_LENGTH, data_idx)(data, key, keyLen, parsing_key[data_idx]); - is_next_pair_at_depth[data_idx] <== NextKVPairAtDepth(MAX_STACK_HEIGHT + 1)(stack[data_idx], data[data_idx], step_in[TOTAL_BYTES_ACROSS_NIVC - 1]); - + is_key_match[data_idx] <== KeyMatchAtIndex(DATA_BYTES, MAX_KEY_LENGTH, data_idx)(data, key, keyLen, parsing_key[data_idx]); + is_next_pair_at_depth[data_idx] <== NextKVPairAtDepth(MAX_STACK_HEIGHT)(State[data_idx].next_stack, data[data_idx], 0); is_key_match_for_value[data_idx+1] <== Mux1()([is_key_match_for_value[data_idx] * (1-is_next_pair_at_depth[data_idx]), is_key_match[data_idx] * (1-is_next_pair_at_depth[data_idx])], is_key_match[data_idx]); - is_value_match[data_idx] <== is_key_match_for_value[data_idx+1] * parsing_value[data_idx]; + is_value_match[data_idx] <== is_key_match_for_value[data_idx+1] * parsing_value[data_idx]; + + or[data_idx] <== OR()(is_value_match[data_idx], is_value_match[data_idx - 1]); - // Set the next NIVC step to only have the masked data - or[data_idx] <== OR()(is_value_match[data_idx], is_value_match[data_idx -1]); + // mask = currently parsing value and all subsequent keys matched step_out[data_idx] <== data[data_idx] * or[data_idx]; } - // Append the parser state back on `step_out` - for (var i = DATA_BYTES ; i < TOTAL_BYTES_ACROSS_NIVC - 1 ; i++) { - step_out[i] <== step_in[i]; + for(var i = DATA_BYTES - MAX_KEY_LENGTH; i < 2 * DATA_BYTES ; i ++) { + step_out[i] <== 0; } - // No need to pad as this is currently when TOTAL_BYTES == TOTAL_BYTES_ACROSS_NIVC - - // Finally, update the current depth we are extracting from - step_out[TOTAL_BYTES_ACROSS_NIVC - 1] <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1] + 1; } template JsonMaskArrayIndexNIVC(DATA_BYTES, MAX_STACK_HEIGHT) { // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - assert(MAX_STACK_HEIGHT >= 2); - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; - // ------------------------------------------------------------------------------------------------------------------ // - + assert(MAX_STACK_HEIGHT >= 2); // TODO (autoparallel): idk if we need this now + var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; // aes ct/pt + ctr // ------------------------------------------------------------------------------------------------------------------ // - // ~ Unravel from previous NIVC step ~ - // Read in from previous NIVC step (JsonParseNIVC) - signal input step_in[TOTAL_BYTES_ACROSS_NIVC]; + signal input step_in[TOTAL_BYTES_ACROSS_NIVC]; signal output step_out[TOTAL_BYTES_ACROSS_NIVC]; - // Grab the raw data bytes from the `step_in` variable + // Declaration of signals. signal data[DATA_BYTES]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - data[i] <== step_in[i]; - } + signal input index; - // Decode the encoded data in `step_in` back into parser variables - signal stack[DATA_BYTES][MAX_STACK_HEIGHT + 1][2]; - signal parsingData[DATA_BYTES][2]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - for (var j = 0 ; j < MAX_STACK_HEIGHT + 1 ; j++) { - if (j < MAX_STACK_HEIGHT) { - stack[i][j][0] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2]; - stack[i][j][1] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2 + 1]; - } else { - // Add one extra stack element without doing this while parsing. - // Stack under/overflow caught in parsing. - stack[i][j][0] <== 0; - stack[i][j][1] <== 0; - } - - } - parsingData[i][0] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2]; - parsingData[i][1] <== step_in[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2 + 1]; + for(var i = 0 ; i < DATA_BYTES ; i++) { + data[i] <== step_in[i]; } - // ------------------------------------------------------------------------------------------------------------------ // - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Array index masking ~ - signal input index; + // value starting index in `data` + signal value_starting_index[DATA_BYTES]; - signal parsing_array[DATA_BYTES]; + component State[DATA_BYTES]; + State[0] = StateUpdate(MAX_STACK_HEIGHT); + State[0].byte <== data[0]; + for(var i = 0; i < MAX_STACK_HEIGHT; i++) { + State[0].stack[i] <== [0,0]; + } + State[0].parsing_string <== 0; + State[0].parsing_number <== 0; - component stackSelector[DATA_BYTES]; - stackSelector[0] = ArraySelector(MAX_STACK_HEIGHT + 1, 2); - stackSelector[0].in <== stack[0]; - stackSelector[0].index <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1]; + signal parsing_array[DATA_BYTES]; + signal or[DATA_BYTES]; - component nextStackSelector[DATA_BYTES]; - nextStackSelector[0] = ArraySelector(MAX_STACK_HEIGHT + 1, 2); - nextStackSelector[0].in <== stack[0]; - nextStackSelector[0].index <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1] + 1; + parsing_array[0] <== InsideArrayIndexObject()(State[0].next_stack[0], State[0].next_stack[1], State[0].next_parsing_string, State[0].next_parsing_number, index); + step_out[0] <== data[0] * parsing_array[0]; // TODO (autoparallel): is this totally correcot or do we need an or, i think it's right - parsing_array[0] <== InsideArrayIndexObject()(stackSelector[0].out, nextStackSelector[0].out, parsingData[0][0], parsingData[0][1], index); - signal or[DATA_BYTES]; - or[0] <== parsing_array[0]; - step_out[0] <== data[0] * or[0]; for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - stackSelector[data_idx] = ArraySelector(MAX_STACK_HEIGHT + 1, 2); - stackSelector[data_idx].in <== stack[data_idx]; - stackSelector[data_idx].index <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1]; + State[data_idx] = StateUpdate(MAX_STACK_HEIGHT); + State[data_idx].byte <== data[data_idx]; + State[data_idx].stack <== State[data_idx - 1].next_stack; + State[data_idx].parsing_string <== State[data_idx - 1].next_parsing_string; + State[data_idx].parsing_number <== State[data_idx - 1].next_parsing_number; - nextStackSelector[data_idx] = ArraySelector(MAX_STACK_HEIGHT + 1, 2); - nextStackSelector[data_idx].in <== stack[data_idx]; - nextStackSelector[data_idx].index <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1] + 1; + parsing_array[data_idx] <== InsideArrayIndexObject()(State[data_idx].next_stack[0], State[data_idx].next_stack[1], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number, index); - parsing_array[data_idx] <== InsideArrayIndexObject()(stackSelector[data_idx].out, nextStackSelector[data_idx].out, parsingData[data_idx][0], parsingData[data_idx][1], index); - - or[data_idx] <== OR()(parsing_array[data_idx], parsing_array[data_idx - 1]); + or[data_idx] <== OR()(parsing_array[data_idx], parsing_array[data_idx - 1]); step_out[data_idx] <== data[data_idx] * or[data_idx]; } - - // Write the `step_out` with masked data - - // Append the parser state back on `step_out` - for (var i = DATA_BYTES ; i < TOTAL_BYTES_ACROSS_NIVC - 1 ; i++) { - step_out[i] <== step_in[i]; + for(var i = DATA_BYTES ; i < 2 * DATA_BYTES ; i++) { + step_out[i] <== 0; } - // No need to pad as this is currently when TOTAL_BYTES == TOTAL_BYTES_USED - step_out[TOTAL_BYTES_ACROSS_NIVC - 1] <== step_in[TOTAL_BYTES_ACROSS_NIVC - 1] + 1; } diff --git a/circuits/json/nivc/parse.circom b/circuits/json/nivc/parse.circom deleted file mode 100644 index 4650dfa..0000000 --- a/circuits/json/nivc/parse.circom +++ /dev/null @@ -1,61 +0,0 @@ -pragma circom 2.1.9; - -include "../parser/parser.circom"; - -template JsonParseNIVC(DATA_BYTES, MAX_STACK_HEIGHT) { - // ------------------------------------------------------------------------------------------------------------------ // - // ~~ Set sizes at compile time ~~ - // Total number of variables in the parser for each byte of data - var PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; - // ------------------------------------------------------------------------------------------------------------------ // - - // Read in from previous NIVC step (AESNIVC) - signal input step_in[TOTAL_BYTES_ACROSS_NIVC]; - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Parse JSON ~ - // Initialize the parser - component State[DATA_BYTES]; - State[0] = StateUpdate(MAX_STACK_HEIGHT); - for(var i = 0; i < MAX_STACK_HEIGHT; i++) { - State[0].stack[i] <== [0,0]; - } - State[0].parsing_string <== 0; - State[0].parsing_number <== 0; - State[0].byte <== step_in[0]; - - // Parse all the data to generate the complete parser state - for(var i = 1; i < DATA_BYTES; i++) { - State[i] = StateUpdate(MAX_STACK_HEIGHT); - State[i].byte <== step_in[i]; - State[i].stack <== State[i - 1].next_stack; - State[i].parsing_string <== State[i - 1].next_parsing_string; - State[i].parsing_number <== State[i - 1].next_parsing_number; - } - // ------------------------------------------------------------------------------------------------------------------ // - - // ------------------------------------------------------------------------------------------------------------------ // - // ~ Write to `step_out` for next NIVC step - // Pass the data bytes back out in the first `step_out` signals - signal output step_out[TOTAL_BYTES_ACROSS_NIVC]; - for (var i = 0 ; i < DATA_BYTES ; i++) { - step_out[i] <== step_in[i]; - } - - // Decode the parser state into the `step_out` remaining signals - for (var i = 0 ; i < DATA_BYTES ; i++) { - for (var j = 0 ; j < MAX_STACK_HEIGHT ; j++) { - step_out[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2] <== State[i].next_stack[j][0]; - step_out[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + j * 2 + 1] <== State[i].next_stack[j][1]; - } - step_out[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2] <== State[i].next_parsing_string; - step_out[DATA_BYTES + i * PER_ITERATION_DATA_LENGTH + MAX_STACK_HEIGHT * 2 + 1] <== State[i].next_parsing_number; - } - // No need to pad as this is currently when TOTAL_BYTES == TOTAL_BYTES_USED - step_out[TOTAL_BYTES_ACROSS_NIVC - 1] <== 0; // Initial depth set to 0 for extraction - // ------------------------------------------------------------------------------------------------------------------ // -} - -// component main { public [step_in] } = JsonParseNIVC(320, 5); - diff --git a/circuits/test/json/nivc/masker_nivc.test.ts b/circuits/test/json/nivc/masker_nivc.test.ts index be849b9..acc41ae 100644 --- a/circuits/test/json/nivc/masker_nivc.test.ts +++ b/circuits/test/json/nivc/masker_nivc.test.ts @@ -31,7 +31,6 @@ let json_input = [123, 13, 10, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 123 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, 10, 32, 32, 32, 125, 13, 10, 125]; describe("NIVC Extract", async () => { - let parse_circuit: WitnessTester<["step_in"], ["step_out"]>; let json_mask_object_circuit: WitnessTester<["step_in", "key", "keyLen"], ["step_out"]>; let json_mask_arr_circuit: WitnessTester<["step_in", "index"], ["step_out"]>; let extract_value_circuit: WitnessTester<["step_in"], ["step_out"]>; @@ -40,17 +39,9 @@ describe("NIVC Extract", async () => { const MAX_STACK_HEIGHT = 5; const MAX_KEY_LENGTH = 8; const MAX_VALUE_LENGTH = 35; - const PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; before(async () => { - parse_circuit = await circomkit.WitnessTester(`JsonParseNIVC`, { - file: "json/nivc/parse", - template: "JsonParseNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], - }); - console.log("#constraints:", await parse_circuit.getConstraintCount()); - json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { file: "json/nivc/masker", template: "JsonMaskArrayIndexNIVC", @@ -87,9 +78,8 @@ describe("NIVC Extract", async () => { let value = toByte("\"Taylor Swift\""); it("parse and mask", async () => { - let json_parse = await parse_circuit.compute({ step_in: extended_json_input }, ["step_out"]); - let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: json_parse.step_out, key: key0, keyLen: key0Len }, ["step_out"]); + let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: extended_json_input, key: key0, keyLen: key0Len }, ["step_out"]); let json_extract_key1 = await json_mask_object_circuit.compute({ step_in: json_extract_key0.step_out, key: key1, keyLen: key1Len }, ["step_out"]); From 812cbf3d46f50a4dfbcdae21bac3b90eb3126595 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Tue, 5 Nov 2024 16:05:06 -0700 Subject: [PATCH 7/9] clean up JSON and fix NIVC test --- .../json_extract_value_1024b.circom | 2 +- .../json_extract_value_512b.circom | 2 +- circuits/json/nivc/extractor.circom | 3 +-- circuits/test/full/full.test.ts | 24 ++++++------------- 4 files changed, 10 insertions(+), 21 deletions(-) diff --git a/builds/target_1024b/json_extract_value_1024b.circom b/builds/target_1024b/json_extract_value_1024b.circom index 7f4d122..fffbc10 100644 --- a/builds/target_1024b/json_extract_value_1024b.circom +++ b/builds/target_1024b/json_extract_value_1024b.circom @@ -2,4 +2,4 @@ pragma circom 2.1.9; include "../../circuits/json/nivc/extractor.circom"; -component main { public [step_in] } = MaskExtractFinal(1024, 10, 50); \ No newline at end of file +component main { public [step_in] } = MaskExtractFinal(1024, 50); \ No newline at end of file diff --git a/builds/target_512b/json_extract_value_512b.circom b/builds/target_512b/json_extract_value_512b.circom index a7fa283..600cc0a 100644 --- a/builds/target_512b/json_extract_value_512b.circom +++ b/builds/target_512b/json_extract_value_512b.circom @@ -2,4 +2,4 @@ pragma circom 2.1.9; include "../../circuits/json/nivc/extractor.circom"; -component main { public [step_in] } = MaskExtractFinal(512, 10, 50); \ No newline at end of file +component main { public [step_in] } = MaskExtractFinal(512, 50); \ No newline at end of file diff --git a/circuits/json/nivc/extractor.circom b/circuits/json/nivc/extractor.circom index 95220ab..32b4b1a 100644 --- a/circuits/json/nivc/extractor.circom +++ b/circuits/json/nivc/extractor.circom @@ -3,9 +3,8 @@ pragma circom 2.1.9; include "circomlib/circuits/gates.circom"; include "@zk-email/circuits/utils/array.circom"; -template MaskExtractFinal(DATA_BYTES, MAX_STACK_HEIGHT, MAX_VALUE_LENGTH) { +template MaskExtractFinal(DATA_BYTES, MAX_VALUE_LENGTH) { // ------------------------------------------------------------------------------------------------------------------ // - assert(MAX_STACK_HEIGHT >= 2); var TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; // aes pt/ct + ctr // ------------------------------------------------------------------------------------------------------------------ // signal input step_in[TOTAL_BYTES_ACROSS_NIVC]; diff --git a/circuits/test/full/full.test.ts b/circuits/test/full/full.test.ts index cca96e1..380d862 100644 --- a/circuits/test/full/full.test.ts +++ b/circuits/test/full/full.test.ts @@ -49,8 +49,7 @@ describe("NIVC_FULL", async () => { const DATA_BYTES = 320; const MAX_STACK_HEIGHT = 5; - const PER_ITERATION_DATA_LENGTH = MAX_STACK_HEIGHT * 2 + 2; - const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * (PER_ITERATION_DATA_LENGTH + 1) + 1; + const TOTAL_BYTES_ACROSS_NIVC = DATA_BYTES * 2 + 4; const MAX_HEADER_NAME_LENGTH = 20; const MAX_HEADER_VALUE_LENGTH = 35; @@ -69,37 +68,30 @@ describe("NIVC_FULL", async () => { aesCircuit = await circomkit.WitnessTester("AESGCTRFOLD", { file: "aes-gcm/nivc/aes-gctr-nivc", template: "AESGCTRFOLD", - params: [DATA_BYTES, MAX_STACK_HEIGHT], + params: [DATA_BYTES], }); console.log("#constraints (AES-GCTR):", await aesCircuit.getConstraintCount()); httpParseAndLockStartLineCircuit = await circomkit.WitnessTester(`ParseAndLockStartLine`, { file: "http/nivc/parse_and_lock_start_line", template: "ParseAndLockStartLine", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], + params: [DATA_BYTES, MAX_BEGINNING_LENGTH, MAX_MIDDLE_LENGTH, MAX_FINAL_LENGTH], }); console.log("#constraints (HTTP-PARSE-AND-LOCK-START-LINE):", await httpParseAndLockStartLineCircuit.getConstraintCount()); lockHeaderCircuit = await circomkit.WitnessTester(`LockHeader`, { file: "http/nivc/lock_header", template: "LockHeader", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH], + params: [DATA_BYTES, MAX_HEADER_NAME_LENGTH, MAX_HEADER_VALUE_LENGTH], }); console.log("#constraints (HTTP-LOCK-HEADER):", await lockHeaderCircuit.getConstraintCount()); bodyMaskCircuit = await circomkit.WitnessTester(`BodyMask`, { file: "http/nivc/body_mask", template: "HTTPMaskBodyNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], + params: [DATA_BYTES], }); console.log("#constraints (HTTP-BODY-MASK):", await bodyMaskCircuit.getConstraintCount()); - parse_circuit = await circomkit.WitnessTester(`JsonParseNIVC`, { - file: "json/nivc/parse", - template: "JsonParseNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], - }); - console.log("#constraints (JSON-PARSE):", await parse_circuit.getConstraintCount()); - json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { file: "json/nivc/masker", template: "JsonMaskArrayIndexNIVC", @@ -117,7 +109,7 @@ describe("NIVC_FULL", async () => { extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { file: "json/nivc/extractor", template: "MaskExtractFinal", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_VALUE_LENGTH], + params: [DATA_BYTES, MAX_VALUE_LENGTH], }); console.log("#constraints (JSON-MASK-EXTRACT-FINAL):", await extract_value_circuit.getConstraintCount()); }); @@ -175,9 +167,7 @@ describe("NIVC_FULL", async () => { let value = toByte("\"Taylor Swift\""); - let json_parse = await parse_circuit.compute({ step_in: bodyMaskOut }, ["step_out"]); - - let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: json_parse.step_out, key: key0, keyLen: key0Len }, ["step_out"]); + let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: bodyMaskOut, key: key0, keyLen: key0Len }, ["step_out"]); let json_num = json_extract_key0.step_out as number[]; console.log("json_extract_key0", json_num); From aa5fdf1dbca82b0618e097e510c365e273e12734 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Tue, 5 Nov 2024 16:06:38 -0700 Subject: [PATCH 8/9] Update masker_nivc.test.ts --- circuits/test/json/nivc/masker_nivc.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/test/json/nivc/masker_nivc.test.ts b/circuits/test/json/nivc/masker_nivc.test.ts index acc41ae..d3ec35b 100644 --- a/circuits/test/json/nivc/masker_nivc.test.ts +++ b/circuits/test/json/nivc/masker_nivc.test.ts @@ -59,7 +59,7 @@ describe("NIVC Extract", async () => { extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { file: "json/nivc/extractor", template: "MaskExtractFinal", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_VALUE_LENGTH], + params: [DATA_BYTES, MAX_VALUE_LENGTH], }); console.log("#constraints:", await extract_value_circuit.getConstraintCount()); }); From f870e53ae240e95dd4d093ab4ed5149300fd9a26 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Tue, 5 Nov 2024 16:27:10 -0700 Subject: [PATCH 9/9] fix witcalc warnings --- circuits/json/nivc/masker.circom | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/circuits/json/nivc/masker.circom b/circuits/json/nivc/masker.circom index 97f1114..b10351f 100644 --- a/circuits/json/nivc/masker.circom +++ b/circuits/json/nivc/masker.circom @@ -19,8 +19,6 @@ template JsonMaskObjectNIVC(DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH) { data[i] <== step_in[i]; } - // Constraints. - signal value_starting_index[DATA_BYTES - MAX_KEY_LENGTH]; // flag determining whether this byte is matched value signal is_value_match[DATA_BYTES - MAX_KEY_LENGTH]; @@ -35,12 +33,11 @@ template JsonMaskObjectNIVC(DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH) { signal parsing_key[DATA_BYTES - MAX_KEY_LENGTH]; signal parsing_value[DATA_BYTES - MAX_KEY_LENGTH]; - signal parsing_object_value[DATA_BYTES - MAX_KEY_LENGTH]; signal is_key_match[DATA_BYTES - MAX_KEY_LENGTH]; signal is_key_match_for_value[DATA_BYTES+1 - MAX_KEY_LENGTH]; is_key_match_for_value[0] <== 0; signal is_next_pair_at_depth[DATA_BYTES - MAX_KEY_LENGTH]; - signal or[DATA_BYTES - MAX_KEY_LENGTH]; + signal or[DATA_BYTES - MAX_KEY_LENGTH - 1]; // initialise first iteration @@ -85,12 +82,12 @@ template JsonMaskObjectNIVC(DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH) { is_key_match_for_value[data_idx+1] <== Mux1()([is_key_match_for_value[data_idx] * (1-is_next_pair_at_depth[data_idx]), is_key_match[data_idx] * (1-is_next_pair_at_depth[data_idx])], is_key_match[data_idx]); is_value_match[data_idx] <== is_key_match_for_value[data_idx+1] * parsing_value[data_idx]; - or[data_idx] <== OR()(is_value_match[data_idx], is_value_match[data_idx - 1]); + or[data_idx - 1] <== OR()(is_value_match[data_idx], is_value_match[data_idx - 1]); // mask = currently parsing value and all subsequent keys matched - step_out[data_idx] <== data[data_idx] * or[data_idx]; + step_out[data_idx] <== data[data_idx] * or[data_idx - 1]; } - for(var i = DATA_BYTES - MAX_KEY_LENGTH; i < 2 * DATA_BYTES ; i ++) { + for(var i = DATA_BYTES - MAX_KEY_LENGTH; i < 2 * DATA_BYTES + 4; i ++) { step_out[i] <== 0; } } @@ -111,9 +108,6 @@ template JsonMaskArrayIndexNIVC(DATA_BYTES, MAX_STACK_HEIGHT) { data[i] <== step_in[i]; } - // value starting index in `data` - signal value_starting_index[DATA_BYTES]; - component State[DATA_BYTES]; State[0] = StateUpdate(MAX_STACK_HEIGHT); State[0].byte <== data[0]; @@ -124,7 +118,7 @@ template JsonMaskArrayIndexNIVC(DATA_BYTES, MAX_STACK_HEIGHT) { State[0].parsing_number <== 0; signal parsing_array[DATA_BYTES]; - signal or[DATA_BYTES]; + signal or[DATA_BYTES - 1]; parsing_array[0] <== InsideArrayIndexObject()(State[0].next_stack[0], State[0].next_stack[1], State[0].next_parsing_string, State[0].next_parsing_number, index); step_out[0] <== data[0] * parsing_array[0]; // TODO (autoparallel): is this totally correcot or do we need an or, i think it's right @@ -139,10 +133,10 @@ template JsonMaskArrayIndexNIVC(DATA_BYTES, MAX_STACK_HEIGHT) { parsing_array[data_idx] <== InsideArrayIndexObject()(State[data_idx].next_stack[0], State[data_idx].next_stack[1], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number, index); - or[data_idx] <== OR()(parsing_array[data_idx], parsing_array[data_idx - 1]); - step_out[data_idx] <== data[data_idx] * or[data_idx]; + or[data_idx - 1] <== OR()(parsing_array[data_idx], parsing_array[data_idx - 1]); + step_out[data_idx] <== data[data_idx] * or[data_idx - 1]; } - for(var i = DATA_BYTES ; i < 2 * DATA_BYTES ; i++) { + for(var i = DATA_BYTES ; i < 2 * DATA_BYTES + 4; i++) { step_out[i] <== 0; } }