From 73a5031d2eaeb7198e6e4efe3c348c2a762b45ef Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Thu, 19 Dec 2024 15:41:03 -0700 Subject: [PATCH] feat: basic parser with escape --- circuits/json/language.circom | 4 ++-- circuits/json/machine.circom | 18 +++++++++++++++--- circuits/json/parser.circom | 22 ++++++++++++++++++++++ circuits/test/json/parser.test.ts | 19 +++++++++++++++++-- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/circuits/json/language.circom b/circuits/json/language.circom index 0566d74..4937b3c 100644 --- a/circuits/json/language.circom +++ b/circuits/json/language.circom @@ -23,7 +23,7 @@ template Syntax() { // signal output SPACE <== 32; //-Escape-------------------------------------------------------------------------------------// // - ASCII char: `\` - // signal output ESCAPE <== 92; + signal output ESCAPE <== 92; //-Number_Remapping---------------------------------------------------------------------------// signal output NUMBER_START <== 48; signal output NUMBER_END <== 57; @@ -31,7 +31,7 @@ template Syntax() { } template Command() { - // STATE = [read_write_value, parsing_string, parsing_number] + // STATE = [read_write_value, parsing_string, parsing_number, escape] signal output START_BRACE[3] <== [1, 0, 0 ]; // Command returned by switch if we hit a start brace `{` signal output END_BRACE[3] <== [-1, 0, -1 ]; // Command returned by switch if we hit a end brace `}` signal output START_BRACKET[3] <== [2, 0, 0 ]; // Command returned by switch if we hit a start bracket `[` diff --git a/circuits/json/machine.circom b/circuits/json/machine.circom index 5fa147a..8785ec8 100644 --- a/circuits/json/machine.circom +++ b/circuits/json/machine.circom @@ -50,10 +50,12 @@ template StateUpdate(MAX_STACK_HEIGHT) { signal input stack[MAX_STACK_HEIGHT][2]; signal input parsing_string; signal input parsing_number; + signal input escaped; signal output next_stack[MAX_STACK_HEIGHT][2]; signal output next_parsing_string; signal output next_parsing_number; + signal output next_escaped; component Command = Command(); component Syntax = Syntax(); @@ -88,6 +90,10 @@ template StateUpdate(MAX_STACK_HEIGHT) { // * read in a quote `"` * component readQuote = IsEqual(); readQuote.in <== [byte, Syntax.QUOTE]; + // * read in a escape `\` * + component readEscape = IsEqual(); + readEscape.in <== [byte, Syntax.ESCAPE]; + component readOther = IsZero(); readOther.in <== readDelimeter + readNumber.out + readQuote.out; //--------------------------------------------------------------------------------------------// @@ -145,9 +151,15 @@ template StateUpdate(MAX_STACK_HEIGHT) { newStack.readColon <== readColon.out; newStack.readComma <== readComma.out; // * set all the next state of the parser * - next_stack <== newStack.next_stack; - next_parsing_string <== parsing_string + mulMaskAndOut.out[1]; - next_parsing_number <== parsing_number + mulMaskAndOut.out[2]; + // b * (y - x) + x --> Simple way of doing a switch with boolean b + for(var i = 0 ; i < MAX_STACK_HEIGHT ; i++) { + next_stack[i][0] <== escaped * (stack[i][0] - newStack.next_stack[i][0]) + newStack.next_stack[i][0]; + next_stack[i][1] <== escaped * (stack[i][1] - newStack.next_stack[i][1]) + newStack.next_stack[i][1]; + } + next_parsing_string <== escaped * (parsing_string - (parsing_string + mulMaskAndOut.out[1])) + (parsing_string + mulMaskAndOut.out[1]); + next_parsing_number <== escaped * (parsing_number - (parsing_number + mulMaskAndOut.out[2])) + (parsing_number + mulMaskAndOut.out[2]); + // Toggle escaped if read + next_escaped <== readEscape.out * (1 - escaped); //--------------------------------------------------------------------------------------------// } diff --git a/circuits/json/parser.circom b/circuits/json/parser.circom index f8f153a..d3d51df 100644 --- a/circuits/json/parser.circom +++ b/circuits/json/parser.circom @@ -15,6 +15,16 @@ template Parser(DATA_BYTES, MAX_STACK_HEIGHT) { } State[0].parsing_string <== 0; State[0].parsing_number <== 0; + State[0].escaped <== 0; + + // Debugging + for(var i = 0; i { it(`array only input`, async () => { let filename = "array_only"; - let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, [0]); + let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, []); circuit = await circomkit.WitnessTester(`Parser`, { file: "json/parser", @@ -20,7 +20,22 @@ describe("JSON Parser", () => { it(`object input`, async () => { let filename = "value_object"; - let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, ["a"]); + let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, []); + + circuit = await circomkit.WitnessTester(`Parser`, { + file: "json/parser", + template: "Parser", + params: [input.length, 3], + }); + + await circuit.expectPass({ + data: input + }); + }); + + it(`string_escape input`, async () => { + let filename = "string_escape"; + let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, []); circuit = await circomkit.WitnessTester(`Parser`, { file: "json/parser",