diff --git a/circuits.json b/circuits.json index 699d488..3ae4177 100644 --- a/circuits.json +++ b/circuits.json @@ -1,37 +1,51 @@ { - "two_keys_test": { - "file": "main/json_two_keys_test", - "template": "ExtractStringValue", + "value_number_test": { + "file": "main/json_value_number_test", + "template": "ExtractNumValue", "params": [ - 40, + 12, + 1, 1, - 4, 0, - 3 + 2 ] }, - "value_array_number_test": { - "file": "main/json_value_array_number_test", - "template": "ExtractNumValue", + "json-parser": { + "file": "json/parser/parser", + "template": "Parser", "params": [ - 73, - 2, - 1, - 0, - 2, - 1, - 4 + 157, + 13 ] }, - "value_number_test": { - "file": "main/json_value_number_test", - "template": "ExtractNumValue", + "value_string_test": { + "file": "main/json_value_string_test", + "template": "ExtractStringValue", "params": [ 12, 1, 1, 0, - 2 + 1 + ] + }, + "spotify_test": { + "file": "main/json_spotify_test", + "template": "ExtractStringValue", + "params": [ + 85, + 5, + 4, + 0, + 5, + 1, + 0, + 2, + 7, + 3, + 4, + 4, + 12 ] }, "http-parser": { @@ -41,31 +55,30 @@ 60 ] }, - "get_request_test": { - "file": "main/http_get_request_test", - "template": "LockHTTPRequest", + "spotify_top_artists_test": { + "file": "main/http_spotify_top_artists_test", + "template": "LockHTTPResponse", "params": [ - 60, - 3, - 4, + 203, + 85, 8, - 6, - 16, - 4, - 9 + 3, + 2, + 12, + 31 ] }, - "value_array_string_test": { - "file": "main/json_value_array_string_test", - "template": "ExtractStringValue", + "value_array_number_test": { + "file": "main/json_value_array_number_test", + "template": "ExtractNumValue", "params": [ 73, 2, 1, 0, + 2, 1, - 1, - 2 + 4 ] }, "value_array_object_test": { @@ -85,60 +98,40 @@ 1 ] }, - "spotify_top_artists_test": { - "file": "main/http_spotify_top_artists_test", - "template": "LockHTTPResponse", - "params": [ - 203, - 85, - 8, - 3, - 2, - 12, - 31 - ] - }, - "spotify_test": { - "file": "main/json_spotify_test", + "value_string": { + "file": "main/json_value_string", "template": "ExtractStringValue", "params": [ - 85, - 5, - 4, - 0, - 5, + 12, + 1, 1, 0, - 2, - 7, - 3, - 4, - 4, - 12 + 1 ] }, - "value_string": { - "file": "main/json_value_string", + "two_keys_test": { + "file": "main/json_two_keys_test", "template": "ExtractStringValue", "params": [ - 12, - 1, + 40, 1, + 4, 0, - 1 + 3 ] }, - "get_response_test": { - "file": "main/http_get_response_test", - "template": "LockHTTPResponse", + "get_request_test": { + "file": "main/http_get_request_test", + "template": "LockHTTPRequest", "params": [ - 89, - 18, - 8, + 60, 3, - 2, - 12, - 16 + 4, + 8, + 6, + 16, + 4, + 9 ] }, "value_array_nested_test": { @@ -156,17 +149,6 @@ 1 ] }, - "value_string_test": { - "file": "main/json_value_string_test", - "template": "ExtractStringValue", - "params": [ - 12, - 1, - 1, - 0, - 1 - ] - }, "spotify_top_artists": { "file": "main/extended_spotify_top_artists", "template": "HttpJson", @@ -192,19 +174,11 @@ 12 ] }, - "json-parser": { - "file": "json/parser/parser", - "template": "Parser", - "params": [ - 157, - 13 - ] - }, "value_object_test": { "file": "main/json_value_object_test", "template": "ExtractStringValue", "params": [ - 88, + 134, 3, 1, 0, @@ -212,5 +186,31 @@ 1, 1 ] + }, + "value_array_string_test": { + "file": "main/json_value_array_string_test", + "template": "ExtractStringValue", + "params": [ + 73, + 2, + 1, + 0, + 1, + 1, + 2 + ] + }, + "get_response_test": { + "file": "main/http_get_response_test", + "template": "LockHTTPResponse", + "params": [ + 89, + 18, + 8, + 3, + 2, + 12, + 16 + ] } } \ No newline at end of file diff --git a/circuits/json/extractor.circom b/circuits/json/extractor.circom index 0b75ab1..b58da5c 100644 --- a/circuits/json/extractor.circom +++ b/circuits/json/extractor.circom @@ -44,7 +44,7 @@ template ObjectExtractor(DATA_BYTES, MAX_STACK_HEIGHT, maxKeyLen, maxValueLen) { 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_key_match[0] <== 0; - is_next_pair_at_depth[0] <== NextKVPairAtDepth(MAX_STACK_HEIGHT, 0)(State[0].next_stack, data[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]; @@ -75,7 +75,7 @@ template ObjectExtractor(DATA_BYTES, MAX_STACK_HEIGHT, maxKeyLen, maxValueLen) { // - 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(DATA_BYTES, maxKeyLen, data_idx)(data, key, keyLen, parsing_key[data_idx]); - is_next_pair_at_depth[data_idx] <== NextKVPairAtDepth(MAX_STACK_HEIGHT, 0)(State[data_idx].next_stack, data[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]; diff --git a/circuits/test/json/extractor/interpreter.test.ts b/circuits/test/json/extractor/interpreter.test.ts index 219beac..82c3a21 100644 --- a/circuits/test/json/extractor/interpreter.test.ts +++ b/circuits/test/json/extractor/interpreter.test.ts @@ -267,16 +267,16 @@ describe("Interpreter", async () => { }); describe("NextKVPairAtDepth", async () => { - let circuit: WitnessTester<["stack", "currByte"], ["out"]>; + let circuit: WitnessTester<["stack", "currByte", "depth"], ["out"]>; - function generatePassCase(input: any, expected: any, depth: number, desc: string) { + function generatePassCase(input: any, expected: any, desc: string) { const description = generateDescription(input); it(`(valid) witness: ${description} ${desc}`, async () => { circuit = await circomkit.WitnessTester(`NextKVPairAtDepth`, { file: "json/interpreter", template: "NextKVPairAtDepth", - params: [4, depth], + params: [4], }); console.log("#constraints:", await circuit.getConstraintCount()); @@ -284,20 +284,20 @@ describe("Interpreter", async () => { }); } - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], currByte: 44 }; + let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], currByte: 44, depth: 3 }; // output = 1 represents correct execution let output = { out: 1 }; - generatePassCase(input1, output, 3, ""); + generatePassCase(input1, output, ""); // key depth is 2, and even if new-kv pair starts at depth greater than 2, it returns 0. - let input2 = { stack: [[1, 0], [2, 0], [1, 1], [1, 0]], currByte: 44 }; - generatePassCase(input2, { out: 0 }, 2, ""); + let input2 = { stack: [[1, 0], [2, 0], [1, 1], [1, 0]], currByte: 44, depth: 2 }; + generatePassCase(input2, { out: 0 }, ""); - let input3 = { stack: [[1, 0], [1, 0], [0, 0], [0, 0]], currByte: 44 }; - generatePassCase(input3, output, 3, "stack height less than specified"); + let input3 = { stack: [[1, 0], [1, 0], [0, 0], [0, 0]], currByte: 44, depth: 3 }; + generatePassCase(input3, output, "stack height less than specified"); - let input4 = { stack: [[1, 0], [2, 0], [1, 0], [0, 0]], currByte: 34 }; - generatePassCase(input4, { out: 0 }, 2, "incorrect currByte"); + let input4 = { stack: [[1, 0], [2, 0], [1, 0], [0, 0]], currByte: 34, depth: 2 }; + generatePassCase(input4, { out: 0 }, "incorrect currByte"); }); describe("KeyMatch", async () => { diff --git a/src/codegen/json.rs b/src/codegen/json.rs index 4fc726f..3e9df17 100644 --- a/src/codegen/json.rs +++ b/src/codegen/json.rs @@ -422,7 +422,7 @@ fn build_json_circuit( Key::String(_) => { num_objects += 1; circuit_buffer += &format!(" is_key{}_match[0] <== KeyMatchAtDepth(DATA_BYTES, MAX_STACK_HEIGHT, keyLen{}, depth{})(data, key{}, 0, parsing_key[0], State[0].next_stack);\n", i+1, i+1, i+1, i+1); - circuit_buffer += &format!(" is_next_pair_at_depth{}[0] <== NextKVPairAtDepth(MAX_STACK_HEIGHT, depth{})(State[0].next_stack, data[0]);\n", i+1, i+1); + circuit_buffer += &format!(" is_next_pair_at_depth{}[0] <== NextKVPairAtDepth(MAX_STACK_HEIGHT)(State[0].next_stack, data[0], depth{});\n", i+1, i+1); circuit_buffer += &format!(" 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]);\n", i+1, i+1, i+1, i+1, i+1, i+1); if debug { circuit_buffer += &format!(" // log(\"is_key{}_match_for_value\", is_key{}_match_for_value[1]);\n\n", i + 1, i + 1); @@ -572,7 +572,7 @@ fn build_json_circuit( Key::String(_) => { num_objects += 1; circuit_buffer += &format!(" is_key{}_match[data_idx] <== KeyMatchAtDepth(DATA_BYTES, MAX_STACK_HEIGHT, keyLen{}, depth{})(data, key{}, data_idx, parsing_key[data_idx], State[data_idx].next_stack);\n", i+1, i+1, i+1, i+1); - circuit_buffer += &format!(" is_next_pair_at_depth{}[data_idx] <== NextKVPairAtDepth(MAX_STACK_HEIGHT, depth{})(State[data_idx].next_stack, data[data_idx]);\n", i+1, i+1); + circuit_buffer += &format!(" is_next_pair_at_depth{}[data_idx] <== NextKVPairAtDepth(MAX_STACK_HEIGHT)(State[data_idx].next_stack, data[data_idx], depth{});\n", i+1, i+1); circuit_buffer += &format!(" 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]);\n", i+1, i+1, i+1, i+1, i+1, i+1); if debug { circuit_buffer += &format!(" // log(\"is_key{}_match_for_value\", is_key{}_match_for_value[data_idx+1]);\n\n", i + 1, i + 1);