From 2af0bcdeb3b6262fb1200fd6c1cede13de397c70 Mon Sep 17 00:00:00 2001 From: Sambhav Date: Thu, 29 Aug 2024 13:42:29 +0530 Subject: [PATCH] remove deleted files (#66) * remove deleted files * use pwd to get working director * update to action/v4 * print tree * try tmate * fix invalid directory --- .github/workflows/test.yml | 8 +- circuits/parser_http_request/language.circom | 49 --- circuits/parser_http_request/machine.circom | 28 -- circuits/parser_http_request/parser.circom | 24 -- circuits/parser_json/language.circom | 41 --- circuits/parser_json/machine.circom | 334 ------------------ circuits/parser_json/parser.circom | 53 --- circuits/test/parser_json/index.ts | 56 --- .../test/parser_json/parsing_types.test.ts | 110 ------ circuits/test/parser_json/stack.test.ts | 235 ------------ circuits/test/parser_json/values.test.ts | 130 ------- examples/json/test/value_array.json | 2 +- examples/json/test/value_array_object.json | 2 +- examples/json/test/value_object.json | 2 +- src/bin/codegen.rs | 6 +- src/{main.rs => bin/witness.rs} | 0 16 files changed, 12 insertions(+), 1068 deletions(-) delete mode 100644 circuits/parser_http_request/language.circom delete mode 100644 circuits/parser_http_request/machine.circom delete mode 100644 circuits/parser_http_request/parser.circom delete mode 100644 circuits/parser_json/language.circom delete mode 100644 circuits/parser_json/machine.circom delete mode 100644 circuits/parser_json/parser.circom delete mode 100644 circuits/test/parser_json/index.ts delete mode 100644 circuits/test/parser_json/parsing_types.test.ts delete mode 100644 circuits/test/parser_json/stack.test.ts delete mode 100644 circuits/test/parser_json/values.test.ts rename src/{main.rs => bin/witness.rs} (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3943f72..41e2171 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,12 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: '16' + node-version: '20' - name: Install dependencies run: | @@ -32,4 +32,4 @@ jobs: circom --version - name: Run tests - run: npm run par-test + run: npm run test diff --git a/circuits/parser_http_request/language.circom b/circuits/parser_http_request/language.circom deleted file mode 100644 index a001d86..0000000 --- a/circuits/parser_http_request/language.circom +++ /dev/null @@ -1,49 +0,0 @@ -pragma circom 2.1.9; - -// All the possible request methods: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods - -template Syntax() { - //-Delimeters---------------------------------------------------------------------------------// - // - ASCII char `:` - signal output COLON <== 58; - // - ASCII char `;` - signal output SEMICOLON <== 59; - // - ASCII char `,` - signal output COMMA <== 44; - // - ASCII char `"` - signal output QUOTE <== 34; - //-White_space--------------------------------------------------------------------------------// - // - ASCII pair: `\r\n` - signal output CLRF <== [13, 10]; // https://www.rfc-editor.org/rfc/rfc2616#section-2.2 - // https://www.rfc-editor.org/rfc/rfc7230#section-3.5 - // - ASCII char: ` ` - signal output SPACE <== 32; - //-Escape-------------------------------------------------------------------------------------// - // - ASCII char: `\` - signal output ESCAPE <== 92; -} - -template RequestMethod() { - signal output GET[3] <== [71, 69, 84]; - // signal output HEAD[4] <== [72, 69, 65, 68]; - signal output POST[4] <== [80, 79, 83, 84]; - // signal output PUT <== 3; - // signal output DELETE <== 4; - // signal output CONNECT <== 5; - // signal output OPTIONS <== 6; - // signal output TRACE <== 7; - // signal output PATCH <== 8; -} - -// NOTE: Starting at 1 to avoid a false positive with a 0. -template RequestMethodTag() { - signal output GET <== 1; - // signal output HEAD <== 2; - signal output POST <== 3; - // signal output PUT <== 4; - // signal output DELETE <== 5; - // signal output CONNECT <== 6; - // signal output OPTIONS <== 7; - // signal output TRACE <== 8; - // signal output PATCH <== 9; -} \ No newline at end of file diff --git a/circuits/parser_http_request/machine.circom b/circuits/parser_http_request/machine.circom deleted file mode 100644 index ee0cff1..0000000 --- a/circuits/parser_http_request/machine.circom +++ /dev/null @@ -1,28 +0,0 @@ -pragma circom 2.1.9; - -include "language.circom"; -include "../utils/array.circom"; - -template ParseMethod() { - signal input bytes[7]; - signal output MethodTag; - - component RequestMethod = RequestMethod(); - component RequestMethodTag = RequestMethodTag(); - - component IsGet = IsEqualArray(3); - for(var byte_idx = 0; byte_idx < 3; byte_idx++) { - IsGet.in[0][byte_idx] <== bytes[byte_idx]; - IsGet.in[1][byte_idx] <== RequestMethod.GET[byte_idx]; - } - signal TagGet <== IsGet.out * RequestMethodTag.GET; - - component IsPost = IsEqualArray(4); - for(var byte_idx = 0; byte_idx < 4; byte_idx++) { - IsPost.in[0][byte_idx] <== bytes[byte_idx]; - IsPost.in[1][byte_idx] <== RequestMethod.POST[byte_idx]; - } - signal TagPost <== IsPost.out * RequestMethodTag.POST; - - MethodTag <== TagGet + TagPost; -} \ No newline at end of file diff --git a/circuits/parser_http_request/parser.circom b/circuits/parser_http_request/parser.circom deleted file mode 100644 index 9fd9524..0000000 --- a/circuits/parser_http_request/parser.circom +++ /dev/null @@ -1,24 +0,0 @@ -pragma circom 2.1.9; - -include "../utils/bytes.circom"; -include "machine.circom"; - - -template Parser(DATA_BYTES) { - signal input data[DATA_BYTES]; - - signal output Method; - - //--------------------------------------------------------------------------------------------// - //-CONSTRAINTS--------------------------------------------------------------------------------// - //--------------------------------------------------------------------------------------------// - component dataASCII = ASCII(DATA_BYTES); - dataASCII.in <== data; - //--------------------------------------------------------------------------------------------// - - component ParseMethod = ParseMethod(); - for(var byte_idx = 0; byte_idx < 7; byte_idx++) { - ParseMethod.bytes[byte_idx] <== data[byte_idx]; - } - log("MethodTag: ", ParseMethod.MethodTag); -} \ No newline at end of file diff --git a/circuits/parser_json/language.circom b/circuits/parser_json/language.circom deleted file mode 100644 index 2a30a8e..0000000 --- a/circuits/parser_json/language.circom +++ /dev/null @@ -1,41 +0,0 @@ -pragma circom 2.1.9; - -template Syntax() { - //-Delimeters---------------------------------------------------------------------------------// - // - ASCII char: `{` - signal output START_BRACE <== 123; - // - ASCII char: `}` - signal output END_BRACE <== 125; - // - ASCII char `[` - signal output START_BRACKET <== 91; - // - ASCII char `]` - signal output END_BRACKET <== 93; - // - ASCII char `"` - signal output QUOTE <== 34; - // - ASCII char `:` - signal output COLON <== 58; - // - ASCII char `,` - signal output COMMA <== 44; - //-White_space--------------------------------------------------------------------------------// - // - ASCII char: `\n` - signal output NEWLINE <== 10; - // - ASCII char: ` ` - signal output SPACE <== 32; - //-Escape-------------------------------------------------------------------------------------// - // - ASCII char: `\` - signal output ESCAPE <== 92; - //-Number_Remapping---------------------------------------------------------------------------// - signal output NUMBER <== 256; // past a u8 -- reserved for ANY numerical ASCII (48 - 57) -} - -template Command() { - // STATE = [read_write_value, parsing_string, parsing_number] - 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 `[` - signal output END_BRACKET[3] <== [-2, 0, -1 ]; // Command returned by switch if we hit a start bracket `]` - signal output QUOTE[3] <== [0, 1, 0 ]; // Command returned by switch if we hit a quote `"` - signal output COLON[3] <== [3, 0, 0 ]; // Command returned by switch if we hit a colon `:` - signal output COMMA[3] <== [4, 0, -1 ]; // Command returned by switch if we hit a comma `,` - signal output NUMBER[3] <== [256, 0, 1 ]; // Command returned by switch if we hit some decimal number (e.g., ASCII 48-57) -} \ No newline at end of file diff --git a/circuits/parser_json/machine.circom b/circuits/parser_json/machine.circom deleted file mode 100644 index 9fda500..0000000 --- a/circuits/parser_json/machine.circom +++ /dev/null @@ -1,334 +0,0 @@ -/* -# `machine` -This module consists of the core parsing components for generating proofs of selective disclosure in JSON. - -## Layout -The key ingredients of `parser` are: - - `StateUpdate`: has as input a current state of a stack-machine parser. - Also takes in a `byte` as input which combines with the current state - to produce the `next_*` states. - - `StateToMask`: Reads the current state to decide whether accept instruction tokens - or ignore them for the current task (e.g., ignore `[` if `parsing_string == 1`). - - `GetTopOfStack`: Helper function that yields the topmost allocated stack value - and a pointer (index) to that value. - - `RewriteStack`: Combines all the above data and produces the `next_stack`. - -`parser` brings in many functions from the `utils` module and `language`. -The inclusion of `langauge` allows for this file to (eventually) be generic over -a grammar for different applications (e.g., HTTP, YAML, TOML, etc.). - -## Testing -Tests for this module are located in the files: `circuits/test/parser/*.test.ts -*/ - -pragma circom 2.1.9; - -include "../utils/array.circom"; -include "../utils/bytes.circom"; -include "../utils/operators.circom"; -include "language.circom"; - -/* -This template is for updating the state of the parser from a current state to a next state. - -# Params: - - `MAX_STACK_HEIGHT`: the maximum stack height that can be used before triggering overflow. - -# Inputs: - - `byte` : the byte value of ASCII that was read by the parser. - - `stack[MAX_STACK_HEIGHT][2]`: the stack machine's current stack. - - `parsing_number` : a bool flag that indicates whether the parser is currently parsing a string or not. - - `parsing_number` : a bool flag that indicates whether the parser is currently parsing a number or not. - -# Outputs: - - `next_stack[MAX_STACK_HEIGHT][2]`: the stack machine's stack after reading `byte`. - - `next_parsing_number` : a bool flag that indicates whether the parser is currently parsing a string or not after reading `byte`. - - `next_parsing_number` : a bool flag that indicates whether the parser is currently parsing a number or not after reading `byte`. -*/ -template StateUpdate(MAX_STACK_HEIGHT) { - signal input byte; // TODO: Does this need to be constrained within here? - - signal input stack[MAX_STACK_HEIGHT][2]; - signal input parsing_string; - signal input parsing_number; - - signal output next_stack[MAX_STACK_HEIGHT][2]; - signal output next_parsing_string; - signal output next_parsing_number; - - component Syntax = Syntax(); - component Command = Command(); - - //--------------------------------------------------------------------------------------------// - // Break down what was read - // * read in a start brace `{` * - component readStartBrace = IsEqual(); - readStartBrace.in <== [byte, Syntax.START_BRACE]; - // * read in an end brace `}` * - component readEndBrace = IsEqual(); - readEndBrace.in <== [byte, Syntax.END_BRACE]; - // * read in a start bracket `[` * - component readStartBracket = IsEqual(); - readStartBracket.in <== [byte, Syntax.START_BRACKET]; - // * read in an end bracket `]` * - component readEndBracket = IsEqual(); - readEndBracket.in <== [byte, Syntax.END_BRACKET]; - // * read in a colon `:` * - component readColon = IsEqual(); - readColon.in <== [byte, Syntax.COLON]; - // * read in a comma `,` * - component readComma = IsEqual(); - readComma.in <== [byte, Syntax.COMMA]; - // * read in some delimeter * - signal readDelimeter <== readStartBrace.out + readEndBrace.out + readStartBracket.out + readEndBracket.out - + readColon.out + readComma.out; - // * read in some number * - component readNumber = InRange(8); - readNumber.in <== byte; - readNumber.range <== [48, 57]; // This is the range where ASCII digits are - // * read in a quote `"` * - component readQuote = IsEqual(); - readQuote.in <== [byte, Syntax.QUOTE]; - component readOther = IsZero(); - readOther.in <== readDelimeter + readNumber.out + readQuote.out; - //--------------------------------------------------------------------------------------------// - // Yield instruction based on what byte we read * - component readStartBraceInstruction = ScalarArrayMul(3); - readStartBraceInstruction.scalar <== readStartBrace.out; - readStartBraceInstruction.array <== Command.START_BRACE; - component readEndBraceInstruction = ScalarArrayMul(3); - readEndBraceInstruction.scalar <== readEndBrace.out; - readEndBraceInstruction.array <== Command.END_BRACE; - component readStartBracketInstruction = ScalarArrayMul(3); - readStartBracketInstruction.scalar <== readStartBracket.out; - readStartBracketInstruction.array <== Command.START_BRACKET; - component readEndBracketInstruction = ScalarArrayMul(3); - readEndBracketInstruction.scalar <== readEndBracket.out; - readEndBracketInstruction.array <== Command.END_BRACKET; - component readColonInstruction = ScalarArrayMul(3); - readColonInstruction.scalar <== readColon.out; - readColonInstruction.array <== Command.COLON; - component readCommaInstruction = ScalarArrayMul(3); - readCommaInstruction.scalar <== readComma.out; - readCommaInstruction.array <== Command.COMMA; - component readNumberInstruction = ScalarArrayMul(3); - readNumberInstruction.scalar <== readNumber.out; - readNumberInstruction.array <== Command.NUMBER; - component readQuoteInstruction = ScalarArrayMul(3); - readQuoteInstruction.scalar <== readQuote.out; - readQuoteInstruction.array <== Command.QUOTE; - - component Instruction = GenericArrayAdd(3,8); - Instruction.arrays <== [readStartBraceInstruction.out, readEndBraceInstruction.out, - readStartBracketInstruction.out, readEndBracketInstruction.out, - readColonInstruction.out, readCommaInstruction.out, - readNumberInstruction.out, readQuoteInstruction.out]; - //--------------------------------------------------------------------------------------------// - // Apply state changing data - // * get the instruction mask based on current state * - component mask = StateToMask(MAX_STACK_HEIGHT); - mask.readDelimeter <== readDelimeter; - mask.readNumber <== readNumber.out; - mask.parsing_string <== parsing_string; - mask.parsing_number <== parsing_number; - // * multiply the mask array elementwise with the instruction array * - component mulMaskAndOut = ArrayMul(3); - mulMaskAndOut.lhs <== mask.out; - mulMaskAndOut.rhs <== [Instruction.out[0], Instruction.out[1], Instruction.out[2] - readOther.out]; - // * compute the new stack * - component newStack = RewriteStack(MAX_STACK_HEIGHT); - newStack.stack <== stack; - newStack.read_write_value <== mulMaskAndOut.out[0]; - newStack.readStartBrace <== readStartBrace.out; - newStack.readStartBracket <== readStartBracket.out; - newStack.readEndBrace <== readEndBrace.out; - newStack.readEndBracket <== readEndBracket.out; - 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]; - //--------------------------------------------------------------------------------------------// -} - -/* -This template is for updating the state of the parser from a current state to a next state. - -# Params: - - `n`: tunable parameter for the number of `parsing_states` needed (TODO: could be removed). - -# Inputs: - - `readDelimeter` : a bool flag that indicates whether the byte value read was a delimeter. - - `readNumber` : a bool flag that indicates whether the byte value read was a number. - - `parsing_number`: a bool flag that indicates whether the parser is currently parsing a string or not. - - `parsing_number`: a bool flag that indicates whether the parser is currently parsing a number or not. - -# Outputs: - - `out[3]`: an array of values fed to update the stack and the parsing state flags. - - 0: mask for `read_write_value` - - 1: mask for `parsing_string` - - 2: mask for `parsing_number` -*/ -template StateToMask(n) { - // TODO: Probably need to assert things are bits where necessary. - signal input readDelimeter; - signal input readNumber; - signal input parsing_string; - signal input parsing_number; - signal output out[3]; - - - // `read_write_value`can change: IF NOT `parsing_string` - out[0] <== (1 - parsing_string); - - // `parsing_string` can change: - out[1] <== 1 - 2 * parsing_string; - - - //--------------------------------------------------------------------------------------------// - // `parsing_number` is more complicated to deal with - /* We have the possible relevant states below: - [isParsingString, isParsingNumber, readNumber, readDelimeter]; - 1 2 4 8 - Above is the binary value for each if is individually enabled - This is a total of 2^4 states - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - [0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]; - and the above is what we want to set `next_parsing_number` to given those - possible. - Below is an optimized version that could instead be done with a `Switch` - */ - signal parsingNumberReadDelimeter <== parsing_number * (readDelimeter); - signal readNumberNotParsingNumber <== (1 - parsing_number) * readNumber; - signal notParsingStringAndParsingNumberReadDelimeterOrReadNumberNotParsingNumber <== (1 - parsing_string) * (parsingNumberReadDelimeter + readNumberNotParsingNumber); - // 10 above ^^^^^^^^^^^^^^^^^ 4 above ^^^^^^^^^^^^^^^^^^ - signal parsingNumberNotReadNumber <== parsing_number * (1 - readNumber) ; - signal parsingNumberNotReadNumberNotReadDelimeter <== parsingNumberNotReadNumber * (1-readDelimeter); - out[2] <== notParsingStringAndParsingNumberReadDelimeterOrReadNumberNotParsingNumber + parsingNumberNotReadNumberNotReadDelimeter; - // Sorry about the long names, but they hopefully read clearly! -} - -// TODO: Check if underconstrained -/* -This template is for getting the values at the top of the stack as well as the pointer to the top. - -# Params: - - `n`: tunable parameter for the stack height. - -# Inputs: - - `stack[n][2]` : the stack to get the values and pointer of. - -# Outputs: - - `value[2]`: the value at the top of the stack - - `pointer` : the pointer for the top of stack index -*/ -template GetTopOfStack(n) { - signal input stack[n][2]; - signal output value[2]; - signal output pointer; - - component isUnallocated[n]; - component atTop = SwitchArray(n,2); - var selector = 0; - for(var i = 0; i < n; i++) { - isUnallocated[i] = IsEqualArray(2); - isUnallocated[i].in[0] <== [0,0]; - isUnallocated[i].in[1] <== stack[i]; - selector += (1 - isUnallocated[i].out); - atTop.branches[i] <== i + 1; - atTop.vals[i] <== stack[i]; - } - atTop.case <== selector; - value <== atTop.out; - pointer <== selector; -} - -// TODO: IMPORTANT NOTE, THE STACK IS CONSTRAINED TO 2**8 so the InRange work (could be changed) -/* -This template is for updating the stack given the current stack and the byte we read in `StateUpdate`. - -# Params: - - `n`: tunable parameter for the number of bits needed to represent the `MAX_STACK_HEIGHT`. - -# Inputs: - - `read_write_value` : what value should be pushed to or popped from the stack. - - `readStartBrace` : a bool flag that indicates whether the byte value read was a start brace `{`. - - `readEndBrace` : a bool flag that indicates whether the byte value read was a end brace `}`. - - `readStartBracket` : a bool flag that indicates whether the byte value read was a start bracket `[`. - - `readEndBracket` : a bool flag that indicates whether the byte value read was a end bracket `]`. - - `readColon` : a bool flag that indicates whether the byte value read was a colon `:`. - - `readComma` : a bool flag that indicates whether the byte value read was a comma `,`. - -# Outputs: - - `next_stack[n][2]`: the next stack of the parser. -*/ -template RewriteStack(n) { - assert(n < 2**8); - signal input stack[n][2]; - signal input read_write_value; - signal input readStartBrace; - signal input readStartBracket; - signal input readEndBrace; - signal input readEndBracket; - signal input readColon; - signal input readComma; - - signal output next_stack[n][2]; - - //--------------------------------------------------------------------------------------------// - // * scan value on top of stack * - component topOfStack = GetTopOfStack(n); - topOfStack.stack <== stack; - signal pointer <== topOfStack.pointer; - signal current_value[2] <== topOfStack.value; - // * check if we are currently in a value of an object * - component inObjectValue = IsEqualArray(2); - inObjectValue.in[0] <== current_value; - inObjectValue.in[1] <== [1,1]; - // * check if value indicates currently in an array * - component inArray = IsEqual(); - inArray.in[0] <== current_value[0]; - inArray.in[1] <== 2; - //--------------------------------------------------------------------------------------------// - - //--------------------------------------------------------------------------------------------// - // * composite signals * - signal readCommaInArray <== readComma * inArray.out; - signal readCommaNotInArray <== readComma * (1 - inArray.out); - //--------------------------------------------------------------------------------------------// - - //--------------------------------------------------------------------------------------------// - // * determine whether we are pushing or popping from the stack * - component isPush = IsEqual(); - isPush.in <== [readStartBrace + readStartBracket, 1]; - component isPop = IsEqual(); - isPop.in <== [readEndBrace + readEndBracket, 1]; - // * set an indicator array for where we are pushing to or popping from* - component indicator[n]; - for(var i = 0; i < n; i++) { - // Points - indicator[i] = IsZero(); - indicator[i].in <== pointer - isPop.out - readColon - readComma - i; // Note, pointer points to unallocated region! - } - //--------------------------------------------------------------------------------------------// - - //--------------------------------------------------------------------------------------------// - // * loop to modify the stack by rebuilding it * - signal stack_change_value[2] <== [(isPush.out + isPop.out) * read_write_value, readColon + readCommaInArray - readCommaNotInArray]; - signal second_index_clear[n]; - for(var i = 0; i < n; i++) { - next_stack[i][0] <== stack[i][0] + indicator[i].out * stack_change_value[0]; - second_index_clear[i] <== stack[i][1] * (readEndBrace + readEndBracket); // Checking if we read some end char - next_stack[i][1] <== stack[i][1] + indicator[i].out * (stack_change_value[1] - second_index_clear[i]); - } - //--------------------------------------------------------------------------------------------// - - //--------------------------------------------------------------------------------------------// - // * check for under or overflow - component isUnderflowOrOverflow = InRange(8); - isUnderflowOrOverflow.in <== pointer - isPop.out + isPush.out; - isUnderflowOrOverflow.range <== [0,n]; - isUnderflowOrOverflow.out === 1; - //--------------------------------------------------------------------------------------------// -} \ No newline at end of file diff --git a/circuits/parser_json/parser.circom b/circuits/parser_json/parser.circom deleted file mode 100644 index f3e4b51..0000000 --- a/circuits/parser_json/parser.circom +++ /dev/null @@ -1,53 +0,0 @@ -pragma circom 2.1.9; - -include "../utils/bytes.circom"; -include "machine.circom"; - -template Parser(DATA_BYTES, MAX_STACK_HEIGHT) { - signal input data[DATA_BYTES]; - - // TODO: Add assertions on the inputs here! - - //--------------------------------------------------------------------------------------------// - //-CONSTRAINTS--------------------------------------------------------------------------------// - //--------------------------------------------------------------------------------------------// - component dataASCII = ASCII(DATA_BYTES); - dataASCII.in <== data; - //--------------------------------------------------------------------------------------------// - // Initialze the parser - 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; - - for(var data_idx = 1; data_idx < DATA_BYTES; 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; - - // // Debugging - // for(var i = 0; i { - let circuit: WitnessTester< - ["byte", "stack", "parsing_string", "parsing_number"], - ["next_stack", "next_parsing_string", "next_parsing_number"] - >; - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description}\n${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - before(async () => { - circuit = await circomkit.WitnessTester(`StateUpdate`, { - file: "circuits/parser_json/machine", - template: "StateUpdate", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - }); - - //-TEST_1----------------------------------------------------------// - // init: ZEROS then read `do_nothing` byte - // expect: ZEROS - generatePassCase(INITIAL_IN, INITIAL_OUT, ">>>> `NUL` read"); - - - //-TEST_2----------------------------------------------------------// - // state: stack == [[1, 0], [0, 0], [0, 0], [0, 0]] - // read: `"` - // expect: parsing_string --> 1 - let in_object_find_key = { ...INITIAL_IN }; - in_object_find_key.stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - in_object_find_key.byte = Delimiters.QUOTE; - let in_object_find_key_out = { ...INITIAL_OUT }; - in_object_find_key_out.next_stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - in_object_find_key_out.next_parsing_string = 1; - generatePassCase(in_object_find_key, - in_object_find_key_out, - ">>>> `\"` read" - ); - - //-TEST_3----------------------------------------------------------// - // state: stack = [[1, 0], [0, 0], [0, 0], [0, 0]], parsing_string == 1 - // read: ` ` - // expect: NIL - let in_key = { ...INITIAL_IN }; - in_key.stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - in_key.parsing_string = 1; - in_key.byte = WhiteSpace.SPACE; - let in_key_out = { ...INITIAL_OUT }; - in_key_out.next_stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - in_key_out.next_parsing_string = 1; - generatePassCase(in_key, in_key_out, ">>>> ` ` read"); - - //-TEST_4----------------------------------------------------------// - // init: stack == [[1, 0], [0, 0], [0, 0], [0, 0]] - // read: `"` - // expect: parsing_string --> 0 - // - let in_key_to_exit = { ...INITIAL_IN }; - in_key_to_exit.stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - in_key_to_exit.parsing_string = 1 - in_key_to_exit.byte = Delimiters.QUOTE; - let in_key_to_exit_out = { ...INITIAL_OUT }; - in_key_to_exit_out.next_stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - generatePassCase(in_key_to_exit, in_key_to_exit_out, "`\"` read"); - - //-TEST_5----------------------------------------------------------// - // state: stack == [[1, 1], [0, 0], [0, 0], [0, 0]] - // read: `"` - // expect: parsing_string --> 1 - let in_tree_find_value = { ...INITIAL_IN }; - in_tree_find_value.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - in_tree_find_value.byte = Delimiters.QUOTE; - let in_tree_find_value_out = { ...INITIAL_OUT }; - in_tree_find_value_out.next_stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - in_tree_find_value_out.next_parsing_string = 1; - generatePassCase(in_tree_find_value, - in_tree_find_value_out, - ">>>> `\"` read" - ); - - //-TEST_6----------------------------------------------------------// - // state: stack == [[1, 1], [0, 0], [0, 0], [0, 0]];, parsing_string == 1 - // read: `"` - // expect: parsing_string == 0, - let in_value_to_exit = { ...INITIAL_IN }; - in_value_to_exit.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - in_value_to_exit.parsing_string = 1; - in_value_to_exit.byte = Delimiters.QUOTE; - let in_value_to_exit_out = { ...INITIAL_OUT }; - in_value_to_exit_out.next_stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - generatePassCase(in_value_to_exit, - in_value_to_exit_out, - ">>>> `\"` is read" - ); - -}); - - - diff --git a/circuits/test/parser_json/stack.test.ts b/circuits/test/parser_json/stack.test.ts deleted file mode 100644 index ff5e97a..0000000 --- a/circuits/test/parser_json/stack.test.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { circomkit, WitnessTester, generateDescription } from "../common"; -import { Delimiters, WhiteSpace, Numbers, Escape, INITIAL_IN, INITIAL_OUT } from '.'; - -describe("GetTopOfStack", () => { - let circuit: WitnessTester<["stack"], ["value", "pointer"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`GetTopOfStack`, { - file: "circuits/parser_json/machine", - template: "GetTopOfStack", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any) { - const description = generateDescription(input); - - it(`(valid) witness: ${description}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - let input = { stack: [[1, 0], [2, 0], [3, 1], [4, 2]] }; - let output = { value: [4, 2], pointer: 3 }; - generatePassCase(input, output); - - input.stack[2] = [0, 0]; - input.stack[3] = [0, 0]; - output.value = [2, 0] - output.pointer = 1; - generatePassCase(input, output); - - input.stack[0] = [0, 0]; - input.stack[1] = [0, 0]; - output.value = [0, 0] - output.pointer = 0; - generatePassCase(input, output); -}); - -describe("StateUpdate :: RewriteStack", () => { - let circuit: WitnessTester< - ["byte", "stack", "parsing_string", "parsing_number"], - ["next_stack", "next_parsing_string", "next_parsing_number"] - >; - before(async () => { - circuit = await circomkit.WitnessTester(`GetTopOfStack`, { - file: "circuits/parser_json/machine", - template: "StateUpdate", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description}\n${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - function generateFailCase(input: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description}\n${desc}`, async () => { - await circuit.expectFail(input); - }); - } - - //-TEST_1----------------------------------------------------------// - // init: stack == [[0, 0], [0, 0], [0, 0], [0, 0]] - // read: `{` - // expect: stack --> [[1, 0], [0, 0], [0, 0], [0, 0]] - let read_start_brace = { ...INITIAL_IN }; - read_start_brace.byte = Delimiters.START_BRACE; - let read_start_brace_out = { ...INITIAL_OUT }; - read_start_brace_out.next_stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - generatePassCase(read_start_brace, - read_start_brace_out, - ">>>> `{` read" - ); - - //-TEST_2----------------------------------------------------------// - // state: stack == [[1, 0], [0, 0], [0, 0], [0, 0]] - // read: `{` - // expect: stack --> [[1, 0], [1, 0], [0, 0], [0, 0]] - let in_object = { ...INITIAL_IN }; - in_object.stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - in_object.byte = Delimiters.START_BRACE; - let in_object_out = { ...INITIAL_OUT }; - in_object_out.next_stack = [[1, 0], [1, 0], [0, 0], [0, 0]]; - generatePassCase(in_object, in_object_out, ">>>> `{` read"); - - //-TEST_3----------------------------------------------------------// - // state: stack == [[1, 0], [0, 0], [0, 0], [0, 0]] - // read: `}` - // expect: stack --> [[0, 0], [0, 0], [0, 0], [0, 0]] - let in_object_to_leave = { ...INITIAL_IN }; - in_object_to_leave.stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - in_object_to_leave.byte = Delimiters.END_BRACE; - let in_object_to_leave_out = { ...INITIAL_OUT }; - generatePassCase(in_object_to_leave, - in_object_to_leave_out, - ">>>> `}` read" - ); - - //-TEST_4----------------------------------------------------------// - // init: stack == [[1, 0], [0, 0], [0, 0], [0, 0]] - // read: `[` - // expect: stack --> [[1, 0], [2, 0], [0, 0], [0, 0]] - let in_object_to_read_start_bracket = { ...INITIAL_IN }; - in_object_to_read_start_bracket.byte = Delimiters.START_BRACKET; - in_object_to_read_start_bracket.stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - let in_object_to_read_start_bracket_out = { ...INITIAL_OUT }; - in_object_to_read_start_bracket_out.next_stack = [[1, 0], [2, 0], [0, 0], [0, 0]]; - generatePassCase(in_object_to_read_start_bracket, - in_object_to_read_start_bracket_out, - ">>>> `[` read" - ); - - //-TEST_5----------------------------------------------------------// - // init: stack == [[1, 0], [2, 0], [0, 0], [0, 0]] - // read: `]` - // expect: stack --> [[1, 0], [0, 0], [0, 0], [0, 0]] - let in_object_and_array = { ...INITIAL_IN }; - in_object_and_array.byte = Delimiters.END_BRACKET; - in_object_and_array.stack = [[1, 0], [2, 0], [0, 0], [0, 0]]; - let in_object_and_array_out = { ...INITIAL_OUT }; - in_object_and_array_out.next_stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - generatePassCase(in_object_and_array, - in_object_and_array_out, - ">>>> `]` read" - ); - - //-TEST_6-----------------------------------------------------------// - // state: stack == [[1, 0], [0, 0], [0, 0], [0, 0]] - // read: `:` - // expect: stack --> [[1, 1], [0, 0], [0, 0], [0, 0]] - let parsed_key_wait_to_parse_value = { ...INITIAL_IN }; - parsed_key_wait_to_parse_value.stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - parsed_key_wait_to_parse_value.byte = Delimiters.COLON; - let parsed_key_wait_to_parse_value_out = { ...INITIAL_OUT }; - parsed_key_wait_to_parse_value_out.next_stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - generatePassCase(parsed_key_wait_to_parse_value, - parsed_key_wait_to_parse_value_out, - ">>>> `:` read" - ); - - //-TEST_7----------------------------------------------------------// - // init: stack == [[1, 0], [0, 0], [0, 0], [0, 0]] - // expect: stack --> [[1, 0], [0, 0], [0, 0], [0, 0]] - let in_object_and_value = { ...INITIAL_IN }; - in_object_and_value.byte = Delimiters.COMMA; - in_object_and_value.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - let in_object_and_value_out = { ...INITIAL_OUT }; - in_object_and_value_out.next_stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - generatePassCase(in_object_and_value, - in_object_and_value_out, - ">>>> `,` read" - ); - - //-TEST_8----------------------------------------------------------// - // init: stack == [[1, 1], [0, 0], [0, 0], [0, 0]] - // read: `}` - // expect: stack --> [[0, 0], [0, 0], [0, 0], [0, 0]] - let in_object_and_value_to_leave_object = { ...INITIAL_IN }; - in_object_and_value_to_leave_object.byte = Delimiters.END_BRACE; - in_object_and_value_to_leave_object.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - let in_object_and_value_to_leave_object_out = { ...INITIAL_OUT }; - in_object_and_value_to_leave_object_out.next_stack = [[0, 0], [0, 0], [0, 0], [0, 0]]; - generatePassCase(in_object_and_value_to_leave_object, - in_object_and_value_to_leave_object_out, - ">>>> `}` read" - ); - - //-TEST_9----------------------------------------------------------// - // idea: Inside a number value after a key in an object. - // state: stack == [[1, 1], [0, 0], [0, 0], [0, 0]], parsing_number == 1 - // read: `,` - // expect: pointer --> 2 - // stack --> [[1, 0], [0, 0], [0, 0], [0, 0]] - // parsing_number --> 0 - let inside_number = { ...INITIAL_IN }; - inside_number.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - inside_number.parsing_number = 1; - inside_number.byte = Delimiters.COMMA; - let inside_number_out = { ...INITIAL_OUT }; - inside_number_out.next_stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - generatePassCase(inside_number, inside_number_out, ">>>> `,` read"); - - - // TODO: FAIL CASES, ADD STACK UNDERFLOW CASES TOO and RENUMBER - //-TEST_3----------------------------------------------------------// - // state: INIT - // read: `}` - // expect: FAIL (stack underflow) - let read_end_brace = { ...INITIAL_IN }; - read_end_brace.byte = Delimiters.END_BRACE; - generateFailCase(read_end_brace, - ">>>> `}` read --> (stack underflow)" - ); - - //-TEST_9----------------------------------------------------------// - // init: stack == [[1, 0], [1, 0], [1, 0], [1, 0]] - // expect: FAIL, STACK OVERFLOW - let in_max_stack = { ...INITIAL_IN }; - in_max_stack.byte = Delimiters.START_BRACE; - in_max_stack.stack = [[1, 0], [1, 0], [1, 0], [1, 0]]; - generateFailCase(in_max_stack, ">>>> `{` read --> (stack overflow)"); - - //-TEST_10----------------------------------------------------------// - // init: stack == [[1, 0], [1, 0], [1, 0], [1, 0]] - // expect: FAIL, STACK OVERFLOW - let in_max_stack_2 = { ...INITIAL_IN }; - in_max_stack_2.byte = Delimiters.START_BRACKET; - in_max_stack_2.stack = [[1, 0], [1, 0], [1, 0], [1, 0]]; - generateFailCase(in_max_stack, ">>>> `[` read --> (stack overflow)"); - - // TODO: This requires a more careful check of the stack that popping clears the current value. Use an IsZero - // //-TEST_3----------------------------------------------------------// - // // init: stack == [1,0,0,0] - // // read: `]` - // // expect: FAIL, INVALID CHAR - // let in_object_to_read_start_bracket = { ...INITIAL_IN }; - // in_object_to_read_start_bracket.byte = Delimiters.START_BRACKET; - // in_object_to_read_start_bracket.pointer = 1; - // in_object_to_read_start_bracket.stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - // let in_object_to_read_start_bracket_out = { ...INITIAL_OUT }; - // in_object_to_read_start_bracket_out.next_pointer = 2; - // in_object_to_read_start_bracket_out.next_stack = [[1, 0], [2, 0], [0, 0], [0, 0]]; - // generatePassCase(in_object_to_read_start_bracket, - // in_object_to_read_start_bracket_out, - // ">>>> `[` read" - // ); -}); \ No newline at end of file diff --git a/circuits/test/parser_json/values.test.ts b/circuits/test/parser_json/values.test.ts deleted file mode 100644 index d96e757..0000000 --- a/circuits/test/parser_json/values.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { circomkit, WitnessTester, generateDescription } from "../common"; -import { Delimiters, WhiteSpace, Numbers, Escape, INITIAL_IN, INITIAL_OUT } from '.'; - -describe("StateUpdate :: Values", () => { - let circuit: WitnessTester< - ["byte", "pointer", "stack", "parsing_string", "parsing_number"], - ["next_pointer", "next_stack", "next_parsing_string", "next_parsing_number"] - >; - before(async () => { - circuit = await circomkit.WitnessTester(`GetTopOfStack`, { - file: "circuits/parser_json/machine", - template: "StateUpdate", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description}\n${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - describe("StateUpdate :: Values :: Number", () => { - //-TEST_1----------------------------------------------------------// - // idea: Read a number value after a key in an object. - // state: stack == [[1, 1], [0, 0], [0, 0], [0, 0]] - // read: `0` - // expect: stack --> [[1, 1], [0, 0], [0, 0], [0, 0]] - // parsing_number --> 1 - let read_number = { ...INITIAL_IN }; - read_number.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - read_number.byte = Numbers.ZERO; - let read_number_out = { ...INITIAL_OUT }; - read_number_out.next_stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - read_number_out.next_parsing_number = 1; - generatePassCase(read_number, read_number_out, ">>>> `0` read"); - - // // TODO: Note that reading a space while reading a number will not throw an error! - - //-TEST_2----------------------------------------------------------// - // idea: Inside a number value after a key in an object. - // state: stack == [[1, 1], [0, 0], [0, 0], [0, 0]], parsing_number == 1 - // read: `1` - // expect: stack --> [[1, 1], [0, 0], [0, 0], [0, 0]] - // parsing_number --> 0 - let inside_number_continue = { ...INITIAL_IN }; - inside_number_continue.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - inside_number_continue.parsing_number = 1; - inside_number_continue.byte = Numbers.ONE; - let inside_number_continue_out = { ...INITIAL_OUT }; - inside_number_continue_out.next_stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - inside_number_continue_out.next_parsing_number = 1; - generatePassCase(inside_number_continue, inside_number_continue_out, ">>>> `1` read"); - - //-TEST_2----------------------------------------------------------// - // idea: Inside a number value after a key in an object. - // state: stack == [[1, 1], [0, 0], [0, 0], [0, 0]], parsing_number == 1 - // read: `1` - // expect: stack --> [[1, 1], [0, 0], [0, 0], [0, 0]] - // parsing_number --> 0 - let inside_number_exit = { ...INITIAL_IN }; - inside_number_exit.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - inside_number_exit.parsing_number = 1; - inside_number_exit.byte = WhiteSpace.SPACE; - let inside_number_exit_out = { ...INITIAL_OUT }; - inside_number_exit_out.next_stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - inside_number_exit_out.next_parsing_number = 0; - generatePassCase(inside_number_exit, inside_number_exit_out, ">>>> ` ` read"); - - //-TEST_3----------------------------------------------------------// - // idea: Inside a number value after a key in an object. - // state: stack == [[1, 1], [0, 0], [0, 0], [0, 0]], parsing_number == 1 - // read: `$` - // expect: stack --> [[1, 1], [0, 0], [0, 0], [0, 0]] - // parsing_number --> 0 - let inside_number_exit2 = { ...INITIAL_IN }; - inside_number_exit2.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - inside_number_exit2.parsing_number = 1; - inside_number_exit2.byte = 36; // Dollar sign `$` - let inside_number_exit2_out = { ...INITIAL_OUT }; - inside_number_exit2_out.next_stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - inside_number_exit2_out.next_parsing_number = 0; - generatePassCase(inside_number_exit2, inside_number_exit2_out, ">>>> `$` read"); - }); - - describe("StateUpdate :: Values :: String", () => { - //-TEST_4----------------------------------------------------------// - // idea: Inside a string key inside an object - // state: stack == [[1, 0], [0, 0], [0, 0], [0, 0]], parsing_string == 1 - // read: `,` - // expect: stack --> [[1, 0], [0, 0], [0, 0], [0, 0]] - // parsing_string --> 0 - let inside_number = { ...INITIAL_IN }; - inside_number.stack = [[1, 1], [0, 0], [0, 0], [0, 0]]; - inside_number.parsing_string = 1; - inside_number.byte = Delimiters.COMMA; - let inside_number_out = { ...INITIAL_OUT }; - inside_number_out.next_stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - inside_number_out.next_parsing_string = 1; - generatePassCase(inside_number, inside_number_out, ">>>> `,` read"); - }); - - describe("StateUpdate :: Values :: Array", () => { - // Internal array parsing -----------------------------------------// - - //-TEST_10----------------------------------------------------------// - // init: stack == [[1, 0], [2, 0], [0, 0], [0, 0]] - // read: `,` - // expext: stack --> [[1, 0], [2, 1], [0, 0], [0, 0]] - let in_arr = { ...INITIAL_IN }; - in_arr.stack = [[1, 0], [2, 0], [0, 0], [0, 0]]; - in_arr.byte = Delimiters.COMMA; - let in_arr_out = { ...INITIAL_OUT }; - in_arr_out.next_stack = [[1, 0], [2, 1], [0, 0], [0, 0]]; - generatePassCase(in_arr, in_arr_out, ">>>> `,` read"); - - //-TEST_10----------------------------------------------------------// - // init: stack == [[1, 0], [2, 1], [0, 0], [0, 0]] - // read: `]` - // expect: stack --> [[1, 0], [0, 0], [0, 0], [0, 0]] - let in_arr_idx_to_leave = { ...INITIAL_IN }; - in_arr_idx_to_leave.stack = [[1, 0], [2, 1], [0, 0], [0, 0]]; - in_arr_idx_to_leave.byte = Delimiters.END_BRACKET; - let in_arr_idx_to_leave_out = { ...INITIAL_OUT }; - in_arr_idx_to_leave_out.next_stack = [[1, 0], [0, 0], [0, 0], [0, 0]]; - generatePassCase(in_arr_idx_to_leave, in_arr_idx_to_leave_out, ">>>> `]` read"); - }); -}); \ No newline at end of file diff --git a/examples/json/test/value_array.json b/examples/json/test/value_array.json index 865f425..e0dc999 100644 --- a/examples/json/test/value_array.json +++ b/examples/json/test/value_array.json @@ -1 +1 @@ -{ "k" : [420,69] } \ No newline at end of file +{ "k" : [ 420 , 69 , 4200 , 600 ], "b": [ "ab" , "ba", "ccc", "d" ] } \ No newline at end of file diff --git a/examples/json/test/value_array_object.json b/examples/json/test/value_array_object.json index 2bbaec9..3a0a544 100644 --- a/examples/json/test/value_array_object.json +++ b/examples/json/test/value_array_object.json @@ -1 +1 @@ -{"a":[{"b":5},{"c":"b"}]} \ No newline at end of file +{"a":[{"b":[1,4]},{"c":"b"}]} \ No newline at end of file diff --git a/examples/json/test/value_object.json b/examples/json/test/value_object.json index dfaaba1..fdb08e1 100644 --- a/examples/json/test/value_object.json +++ b/examples/json/test/value_object.json @@ -1 +1 @@ -{ "a": { "b": "c" } } \ No newline at end of file +{ "a": { "d" : "e", "e": "c" }, "e": { "f": "a", "e": "2" }, "g": { "h": { "a": "c" }} } \ No newline at end of file diff --git a/src/bin/codegen.rs b/src/bin/codegen.rs index fc4b8fa..d9ab4d2 100644 --- a/src/bin/codegen.rs +++ b/src/bin/codegen.rs @@ -1,6 +1,6 @@ use clap::Parser; use serde::{Deserialize, Serialize}; -use std::fs; +use std::fs::{self, create_dir_all}; use std::path::PathBuf; use std::str::FromStr; @@ -487,6 +487,10 @@ fn parse_json_request( let mut file_path = std::env::current_dir()?; file_path.push("circuits"); file_path.push("main"); + + // create dir if doesn't exist + create_dir_all(&file_path)?; + file_path.push(format!("{}.circom", output_filename)); fs::write(&file_path, circuit_buffer)?; diff --git a/src/main.rs b/src/bin/witness.rs similarity index 100% rename from src/main.rs rename to src/bin/witness.rs