diff --git a/circuits/json/interpreter.circom b/circuits/json/interpreter.circom deleted file mode 100644 index 9b73a35..0000000 --- a/circuits/json/interpreter.circom +++ /dev/null @@ -1,474 +0,0 @@ -pragma circom 2.1.9; - -include "./parser/parser.circom"; -include "./parser/language.circom"; -include "../utils/search.circom"; -include "../utils/array.circom"; -include "circomlib/circuits/mux1.circom"; -include "circomlib/circuits/gates.circom"; -include "@zk-email/circuits/utils/functions.circom"; -include "@zk-email/circuits/utils/array.circom"; - -/// Checks if current byte is inside a JSON key or not -/// -/// # Arguments -/// - `n`: maximum stack depth -/// -/// # Inputs -/// - `stack`: current stack state -/// - `parsing_string`: whether current byte is inside a string or not -/// - `parsing_number`: wheter current byte is inside a number or not -/// -/// # Output -/// - `out`: Returns `1` if current byte is inside a key -template InsideKeyAtTop(n) { - signal input stack[n][2]; - signal input parsing_string; - signal input parsing_number; - - signal output out; - - component topOfStack = GetTopOfStack(n); - topOfStack.stack <== stack; - _ <== topOfStack.pointer; - signal currentVal[2] <== topOfStack.value; - - signal parsingStringAndNotNumber <== parsing_string * (1 - parsing_number); - signal ifParsingKey <== currentVal[0] * (1-currentVal[1]); - - out <== ifParsingKey * parsingStringAndNotNumber; -} - -/// Checks if current byte is inside a JSON key or not -/// -/// # Inputs -/// - `stack`: current stack state -/// - `parsing_string`: whether current byte is inside a string or not -/// - `parsing_number`: wheter current byte is inside a number or not -/// -/// # Output -/// - `out`: Returns `1` if current byte is inside a key -template InsideKey() { - signal input stack[2]; - signal input parsing_string; - signal input parsing_number; - - signal output out; - - signal parsingStringAndNotNumber <== parsing_string * (1 - parsing_number); - signal ifParsingKey <== stack[0] * (1-stack[1]); - - out <== ifParsingKey * parsingStringAndNotNumber; -} - -/// Checks if current byte is inside a JSON value or not -/// -/// # Arguments -/// - `n`: maximum stack depth -/// -/// # Inputs -/// - `stack`: current stack state -/// - `parsing_string`: whether current byte is inside a string or not -/// - `parsing_number`: wheter current byte is inside a number or not -/// -/// # Output -/// - `out`: Returns `1` if current byte is inside a value -template InsideValueAtTop(n) { - signal input stack[n][2]; - signal input parsing_string; - signal input parsing_number; - - signal output out; - - component topOfStack = GetTopOfStack(n); - topOfStack.stack <== stack; - signal currentVal[2] <== topOfStack.value; - - signal parsingStringXORNumber <== XOR()(parsing_string, parsing_number); - - signal ifParsingValue <== currentVal[0] * currentVal[1]; - - out <== ifParsingValue * parsingStringXORNumber; -} - -/// Checks if current byte is inside a JSON value at specified depth -/// -/// # Inputs -/// - `stack`: current stack state -/// - `parsing_string`: whether current byte is inside a string or not -/// - `parsing_number`: wheter current byte is inside a number or not -/// -/// # Output -/// - `out`: Returns `1` if current byte is inside a value -template InsideValue() { - signal input stack[2]; - signal input parsing_string; - signal input parsing_number; - - signal output out; - - signal ifParsingValue <== stack[0] * stack[1]; - signal parsingStringXORNumber <== XOR()(parsing_string, parsing_number); - - out <== ifParsingValue * parsingStringXORNumber; -} - -/// Checks if current byte is inside a JSON value at specified depth -/// -/// # Inputs -/// - `stack`: current stack state -/// - `parsing_string`: whether current byte is inside a string or not -/// - `parsing_number`: wheter current byte is inside a number or not -/// -/// # Output -/// - `out`: Returns `1` if current byte is inside a value -template InsideValueObject() { - signal input prev_stack[2]; - signal input curr_stack[2]; - signal input parsing_string; - signal input parsing_number; - - signal output out; - - signal insideObject <== IsEqual()([curr_stack[0], 1]); - signal insideArrayArray <== IsEqual()([curr_stack[0], 2]); - - signal ifParsingValue <== prev_stack[0] * prev_stack[1]; - signal parsingStringXORNumber <== XOR()(parsing_string, parsing_number); - signal insideObjectXORArray <== XOR()(insideObject, insideArrayArray); - signal isInsideObjectOrStringValue <== Mux1()([parsingStringXORNumber, insideObjectXORArray], insideObjectXORArray); - - out <== ifParsingValue * isInsideObjectOrStringValue; -} - -/// Checks if current byte is inside an array at specified index -/// -/// # Arguments -/// - `n`: maximum stack depth -/// - `index`: index of array element -/// -/// # Inputs -/// - `stack`: current stack state -/// - `parsing_string`: whether current byte is inside a string or not -/// - `parsing_number`: wheter current byte is inside a number or not -/// -/// # Output -/// - `out`: Returns `1` if current byte represents an array element at `index` -template InsideArrayIndexAtTop(n, index) { - signal input stack[n][2]; - signal input parsing_string; - signal input parsing_number; - - signal output out; - - component topOfStack = GetTopOfStack(n); - topOfStack.stack <== stack; - signal currentVal[2] <== topOfStack.value; - - signal insideArray <== IsEqual()([currentVal[0], 2]); - signal insideIndex <== IsEqual()([currentVal[1], index]); - signal insideArrayIndex <== insideArray * insideIndex; - signal parsingStringXORNumber <== XOR()(parsing_string, parsing_number); - - out <== insideArrayIndex * parsingStringXORNumber; -} - -/// Checks if current byte is inside an array index at specified depth -/// -/// # Arguments -/// - `index`: array element index -/// -/// # Inputs -/// - `stack`: current stack state -/// - `parsing_string`: whether current byte is inside a string or not -/// - `parsing_number`: wheter current byte is inside a number or not -/// -/// # Output -/// - `out`: Returns `1` if current byte is inside an array index -template InsideArrayIndex(index) { - signal input stack[2]; - signal input parsing_string; - signal input parsing_number; - - signal output out; - - signal insideArray <== IsEqual()([stack[0], 2]); - signal insideIndex <== IsEqual()([stack[1], index]); - signal insideArrayIndex <== insideArray * insideIndex; - out <== insideArrayIndex * (parsing_string + parsing_number); -} - -/// Checks if current byte is inside an array index at specified depth -/// -/// # Arguments -/// - `index`: array element index -/// -/// # Inputs -/// - `stack`: current stack state -/// - `parsing_string`: whether current byte is inside a string or not -/// - `parsing_number`: wheter current byte is inside a number or not -/// -/// # Output -/// - `out`: Returns `1` if current byte is inside an array index -template InsideArrayIndexObject() { - signal input prev_stack[2]; - signal input curr_stack[2]; - signal input parsing_string; - signal input parsing_number; - signal input index; - - signal output out; - - signal insideArray <== IsEqual()([prev_stack[0], 2]); - signal insideIndex <== IsEqual()([prev_stack[1], index]); - signal insideObject <== IsEqual()([curr_stack[0], 1]); - signal insideArrayArray <== IsEqual()([curr_stack[0], 2]); - - signal parsingStringXORNumber <== XOR()(parsing_string, parsing_number); - signal insideObjectXORArray <== XOR()(insideObject, insideArrayArray); - signal isInsideObjectOrStringValue <== Mux1()([parsingStringXORNumber, insideObjectXORArray], insideObjectXORArray); - signal insideArrayIndex <== insideArray * insideIndex; - out <== insideArrayIndex * isInsideObjectOrStringValue; -} - -/// Returns whether next key-value pair starts. -/// -/// # Arguments -/// - `n`: maximum stack depth -/// -/// # Inputs -/// - `stack`: current stack state -/// - `curr_byte`: current parsed byte -/// -/// # Output -/// - `out`: Returns `1` for next key-value pair. -template NextKVPair(n) { - signal input stack[n][2]; - signal input currByte; - signal output out; - - component topOfStack = GetTopOfStack(n); - topOfStack.stack <== stack; - signal currentVal[2] <== topOfStack.value; - - signal isNextPair <== IsEqualArray(2)([currentVal, [1, 0]]); - - component syntax = Syntax(); - signal isComma <== IsEqual()([currByte, syntax.COMMA]); // `, -> 44` - - out <== isNextPair*isComma ; -} - -/// Returns whether next key-value pair starts. -/// Applies following checks: -/// - get top of stack value and check whether parsing key: `[1, 0]` -/// - current byte = `,` -/// - current stack height is less than the key to be matched (it means that new key has started) -/// -/// # Arguments -/// - `n`: maximum stack depth -/// - `depth`: depth of matched key-value pair -/// -/// # Inputs -/// - `stack`: current stack state -/// - `curr_byte`: current parsed byte -/// -/// # Output -/// - `out`: Returns `1` for next key-value pair at specified depth. -template NextKVPairAtDepth(n) { - signal input stack[n][2]; - signal input currByte; - signal input depth; - signal output out; - - var logMaxDepth = log2Ceil(n+1); - - component topOfStack = GetTopOfStack(n); - topOfStack.stack <== stack; - signal currentVal[2] <== topOfStack.value; - signal pointer <== topOfStack.pointer; - - signal isNextPair <== IsEqualArray(2)([currentVal, [1, 0]]); - - // `,` -> 44 - signal isComma <== IsEqual()([currByte, 44]); - // pointer <= depth - // TODO: `LessThan` circuit warning - signal atLessDepth <== LessEqThan(logMaxDepth)([pointer-1, depth]); - // current depth is less than key depth - signal isCommaAtDepthLessThanCurrent <== isComma * atLessDepth; - - out <== isNextPair * isCommaAtDepthLessThanCurrent; -} - -/// Matches a JSON key at an `index` using Substring Matching -/// -/// # Arguments -/// - `dataLen`: parsed data length -/// - `keyLen`: key length -/// -/// # Inputs -/// - `data`: data bytes -/// - `key`: key bytes -/// - `r`: random number for substring matching. **Need to be chosen carefully.** -/// - `index`: data index to match from -/// - `parsing_key`: if current byte is inside a key -/// -/// # Output -/// - `out`: Returns `1` if `key` matches `data` at `index` -template KeyMatch(dataLen, keyLen) { - signal input data[dataLen]; - signal input key[keyLen]; - signal input index; - signal input parsing_key; - - // `"` -> 34 - signal end_of_key <== IndexSelector(dataLen)(data, index + keyLen); - signal is_end_of_key_equal_to_quote <== IsEqual()([end_of_key, 34]); - - signal start_of_key <== IndexSelector(dataLen)(data, index - 1); - signal is_start_of_key_equal_to_quote <== IsEqual()([start_of_key, 34]); - - signal substring_match <== SubstringMatchWithIndex(dataLen, keyLen)(data, key, index); - - signal is_key_between_quotes <== is_start_of_key_equal_to_quote * is_end_of_key_equal_to_quote; - signal is_parsing_correct_key <== is_key_between_quotes * parsing_key; - - signal output out <== substring_match * is_parsing_correct_key; -} - -/// Matches a JSON key at an `index` using Substring Matching at specified depth -/// -/// # Arguments -/// - `dataLen`: parsed data length -/// - `n`: maximum stack height -/// - `keyLen`: key length -/// - `depth`: depth of key to be matched -/// -/// # Inputs -/// - `data`: data bytes -/// - `key`: key bytes -/// - `r`: random number for substring matching. **Need to be chosen carefully.** -/// - `index`: data index to match from -/// - `parsing_key`: if current byte is inside a key -/// - `stack`: parser stack output -/// -/// # Output -/// - `out`: Returns `1` if `key` matches `data` at `index` -template KeyMatchAtDepth(dataLen, n, keyLen, depth) { - signal input data[dataLen]; - signal input key[keyLen]; - signal input index; - signal input parsing_key; - signal input stack[n][2]; - - component topOfStack = GetTopOfStack(n); - topOfStack.stack <== stack; - signal pointer <== topOfStack.pointer; - _ <== topOfStack.value; - - // `"` -> 34 - - // end of key equals `"` - signal end_of_key <== IndexSelector(dataLen)(data, index + keyLen); - signal is_end_of_key_equal_to_quote <== IsEqual()([end_of_key, 34]); - - // start of key equals `"` - signal start_of_key <== IndexSelector(dataLen)(data, index - 1); - signal is_start_of_key_equal_to_quote <== IsEqual()([start_of_key, 34]); - - // key matches - signal substring_match <== SubstringMatchWithIndex(dataLen, keyLen)(data, key, index); - - // key should be a string - signal is_key_between_quotes <== is_start_of_key_equal_to_quote * is_end_of_key_equal_to_quote; - - // is the index given correct? - signal is_parsing_correct_key <== is_key_between_quotes * parsing_key; - // is the key given by index at correct depth? - signal is_key_at_depth <== IsEqual()([pointer-1, depth]); - - signal is_parsing_correct_key_at_depth <== is_parsing_correct_key * is_key_at_depth; - - signal output out <== substring_match * is_parsing_correct_key_at_depth; -} - -template MatchPaddedKey(n) { - signal input in[2][n]; - signal input keyLen; - signal output out; - - var accum = 0; - component equalComponent[n]; - component isPaddedElement[n]; - - signal isEndOfKey[n]; - signal isQuote[n]; - signal endOfKeyAccum[n+1]; - endOfKeyAccum[0] <== 0; - - for(var i = 0; i < n; i++) { - isEndOfKey[i] <== IsEqual()([i, keyLen]); - isQuote[i] <== IsEqual()([in[1][i], 34]); - endOfKeyAccum[i+1] <== endOfKeyAccum[i] + isEndOfKey[i] * isQuote[i]; - - // TODO: might not be right to check for zero, instead check for -1? - isPaddedElement[i] = IsZero(); - isPaddedElement[i].in <== in[0][i]; - - equalComponent[i] = IsEqual(); - equalComponent[i].in[0] <== in[0][i]; - equalComponent[i].in[1] <== in[1][i] * (1-isPaddedElement[i].out); - accum += equalComponent[i].out; - } - - signal isEndOfKeyEqualToQuote <== IsEqual()([endOfKeyAccum[n], 1]); - - component totalEqual = IsEqual(); - totalEqual.in[0] <== n; - totalEqual.in[1] <== accum; - out <== totalEqual.out * isEndOfKeyEqualToQuote; -} - -/// Matches a JSON key at an `index` using Substring Matching at specified depth -/// -/// # Arguments -/// - `dataLen`: parsed data length -/// - `maxKeyLen`: maximum possible key length -/// - `index`: index of key in `data` -/// -/// # Inputs -/// - `data`: data bytes -/// - `key`: key bytes -/// - `parsing_key`: if current byte is inside a key -/// -/// # Output -/// - `out`: Returns `1` if `key` matches `data` at `index` -template KeyMatchAtIndex(dataLen, maxKeyLen, index) { - signal input data[dataLen]; - signal input key[maxKeyLen]; - signal input keyLen; - signal input parsing_key; - - signal paddedKey[maxKeyLen + 1]; - for (var i = 0 ; i < maxKeyLen ; i++) { - paddedKey[i] <== key[i]; - } - paddedKey[maxKeyLen] <== 0; - // `"` -> 34 - - // start of key equal to quote - signal startOfKeyEqualToQuote <== IsEqual()([data[index - 1], 34]); - signal isParsingCorrectKey <== parsing_key * startOfKeyEqualToQuote; - - // key matches - component isSubstringMatch = MatchPaddedKey(maxKeyLen+1); - isSubstringMatch.in[0] <== paddedKey; - isSubstringMatch.keyLen <== keyLen; - for(var matcher_idx = 0; matcher_idx <= maxKeyLen; matcher_idx++) { - isSubstringMatch.in[1][matcher_idx] <== data[index + matcher_idx]; - } - _ <== data; - - signal output out <== isSubstringMatch.out * isParsingCorrectKey; -} \ No newline at end of file diff --git a/circuits/json/nivc/extractor.circom b/circuits/json/nivc/extractor.circom deleted file mode 100644 index f2de60f..0000000 --- a/circuits/json/nivc/extractor.circom +++ /dev/null @@ -1,32 +0,0 @@ -pragma circom 2.1.9; - -include "circomlib/circuits/gates.circom"; -include "@zk-email/circuits/utils/array.circom"; -include "../../utils/hash.circom"; - -template MaskExtractFinal(DATA_BYTES, MAX_VALUE_LENGTH) { - signal input step_in[1]; - signal input data[DATA_BYTES]; - - signal output step_out[1]; - - signal is_zero_mask[DATA_BYTES]; - signal is_prev_starting_index[DATA_BYTES]; - signal value_starting_index[DATA_BYTES]; - - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; - - value_starting_index[0] <== 0; - is_prev_starting_index[0] <== 0; - is_zero_mask[0] <== IsZero()(data[0]); - for (var i=1 ; i < DATA_BYTES ; i++) { - is_zero_mask[i] <== IsZero()(data[i]); - is_prev_starting_index[i] <== IsZero()(value_starting_index[i-1]); - value_starting_index[i] <== value_starting_index[i-1] + i * (1-is_zero_mask[i]) * is_prev_starting_index[i]; - } - - signal value[MAX_VALUE_LENGTH] <== SelectSubArray(DATA_BYTES, MAX_VALUE_LENGTH)(data, value_starting_index[DATA_BYTES-1], MAX_VALUE_LENGTH); - - step_out[0] <== DataHasher(MAX_VALUE_LENGTH)(value); -} \ No newline at end of file diff --git a/circuits/json/nivc/masker.circom b/circuits/json/nivc/masker.circom deleted file mode 100644 index 97fcf8d..0000000 --- a/circuits/json/nivc/masker.circom +++ /dev/null @@ -1,136 +0,0 @@ -pragma circom 2.1.9; - -include "../interpreter.circom"; -include "../../utils/hash.circom"; - -template JsonMaskObjectNIVC(DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH) { - signal input step_in[1]; - signal input key[MAX_KEY_LENGTH]; - signal input keyLen; - - signal output step_out[1]; - - // Authenticate the (potentially further masked) plaintext we are passing in - signal input data[DATA_BYTES]; - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; - - // flag determining whether this byte is matched value - signal is_value_match[DATA_BYTES - MAX_KEY_LENGTH]; - - 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 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 - 1]; - - // initialise first iteration - - // 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_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 masked[DATA_BYTES]; - masked[0] <== data[0] * is_value_match[0]; - - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - if(data_idx < DATA_BYTES - MAX_KEY_LENGTH) { - 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) - - // TODO (autoparallel): this can be optimized i'm sure of it, running without it saves 110k constraints on 1024b (553k with it) - is_key_match[data_idx] <== KeyMatchAtIndex(DATA_BYTES, MAX_KEY_LENGTH, data_idx)(data, key, keyLen, parsing_key[data_idx]); - - // TODO (autoparallel): this could also likely be optimized, costs like 140k constraints itself - 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]; - - 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 - masked[data_idx] <== data[data_idx] * or[data_idx - 1]; // TODO here - } else { - masked[data_idx] <== 0; - } - } - step_out[0] <== DataHasher(DATA_BYTES)(masked); -} - -template JsonMaskArrayIndexNIVC(DATA_BYTES, MAX_STACK_HEIGHT) { - signal input step_in[1]; - signal input index; - - signal output step_out[1]; - - // Authenticate the (potentially further masked) plaintext we are passing in - signal input data[DATA_BYTES]; - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; - - 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; - - signal parsing_array[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); - signal masked[DATA_BYTES]; - masked[0] <== data[0] * parsing_array[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; - - 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 - 1] <== OR()(parsing_array[data_idx], parsing_array[data_idx - 1]); - masked[data_idx] <== data[data_idx] * or[data_idx - 1]; - } - step_out[0] <== DataHasher(DATA_BYTES)(masked); -} diff --git a/circuits/test/full/full.test.ts b/circuits/test/full/full.test.ts index acfc1e9..361dbcc 100644 --- a/circuits/test/full/full.test.ts +++ b/circuits/test/full/full.test.ts @@ -128,9 +128,6 @@ const json_key3_mask_hash = DataHasher(json_key3_mask); describe("Example NIVC Proof", async () => { let PlaintextAuthentication: WitnessTester<["key", "nonce", "counter", "plainText", "step_in"], ["step_out"]>; let HTTPVerification: WitnessTester<["step_in", "data", "main_digests"], ["step_out"]>; - let json_mask_object_circuit: WitnessTester<["step_in", "data", "key", "keyLen"], ["step_out"]>; - let json_mask_arr_circuit: WitnessTester<["step_in", "data", "index"], ["step_out"]>; - let extract_value_circuit: WitnessTester<["step_in", "data"], ["step_out"]>; const MAX_NUMBER_OF_HEADERS = 2; const DATA_BYTES = 320; @@ -153,26 +150,6 @@ describe("Example NIVC Proof", async () => { }); console.log("#constraints (HTTPVerification):", await HTTPVerification.getConstraintCount()); - json_mask_object_circuit = await circomkit.WitnessTester(`JsonMaskObjectNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskObjectNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH], - }); - console.log("#constraints (JSON-MASK-OBJECT):", await json_mask_object_circuit.getConstraintCount()); - - json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskArrayIndexNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], - }); - console.log("#constraints (JSON-MASK-ARRAY-INDEX):", await json_mask_arr_circuit.getConstraintCount()); - - extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { - file: "json/nivc/extractor", - template: "MaskExtractFinal", - params: [DATA_BYTES, MAX_VALUE_LENGTH], - }); - console.log("#constraints (JSON-MASK-EXTRACT-FINAL):", await extract_value_circuit.getConstraintCount()); }); it("Spotify Example", async () => { diff --git a/circuits/test/json/extractor/interpreter.test.ts b/circuits/test/json/extractor/interpreter.test.ts deleted file mode 100644 index eed2ab2..0000000 --- a/circuits/test/json/extractor/interpreter.test.ts +++ /dev/null @@ -1,445 +0,0 @@ -import { circomkit, WitnessTester, generateDescription, readJSONInputFile } from "../../common"; - -describe("Interpreter", async () => { - describe("InsideKeyAtTop", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`InsideKeyAtTop`, { - file: "json/interpreter", - template: "InsideKeyAtTop", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, ""); - - let input2 = { stack: [[1, 0], [2, 0], [1, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, ""); - - let input3 = { stack: [[1, 0], [0, 0], [0, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, "parsing number as a key"); - }); - - describe("InsideKey", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`InsideKey`, { - file: "json/interpreter", - template: "InsideKey", - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [1, 0], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, ""); - - // fail cases - - let input2 = { stack: [1, 1], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, { out: 0 }, "invalid stack"); - - let input3 = { stack: [1, 0], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input3, { out: 0 }, "parsing number as a key"); - }); - - describe("InsideValueAtTop", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`InsideValueAtTop`, { - file: "json/interpreter", - template: "InsideValueAtTop", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, ""); - - let input2 = { stack: [[1, 0], [2, 0], [1, 1], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, ""); - - let input3 = { stack: [[1, 1], [0, 0], [0, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, "parsing number and key both"); - }); - - describe("InsideValue", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - function generatePassCase(input: any, expected: any, depth: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`InsideValue`, { - file: "json/interpreter", - template: "InsideValue", - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - input.stack = input.stack[depth]; - - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, 3, ""); - - let input2 = { stack: [[1, 0], [2, 0], [1, 1], [1, 1]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, 2, ""); - - let input3 = { stack: [[1, 1], [0, 0], [0, 0], [1, 1]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, 0, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, 0, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, 3, "parsing number and key both"); - }); - - describe("InsideArrayIndexAtTop", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - function generatePassCase(input: any, expected: any, index: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`InsideArrayIndexAtTop`, { - file: "json/interpreter", - template: "InsideArrayIndexAtTop", - params: [4, index], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [2, 1]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, 1, ""); - - let input2 = { stack: [[1, 0], [2, 0], [2, 3], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, 3, ""); - - let input3 = { stack: [[2, 10], [0, 0], [0, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, 10, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, 4, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, 4, "parsing number and key both"); - - let input6 = { stack: [[1, 0], [2, 0], [3, 1], [2, 4]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input6, { out: 0 }, 3, "incorrect index"); - }); - - describe("InsideArrayIndex", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - function generatePassCase(input: any, expected: any, index: number, depth: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`InsideArrayIndex`, { - file: "json/interpreter", - template: "InsideArrayIndex", - params: [index], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - input.stack = input.stack[depth] - - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [2, 1]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, 1, 3, ""); - - let input2 = { stack: [[1, 0], [2, 0], [2, 3], [2, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, 3, 2, ""); - - let input3 = { stack: [[2, 10], [0, 0], [1, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, 10, 0, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, 4, 2, "invalid stack depth"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, 4, 1, "parsing number and key both"); - }); - - describe("NextKVPair", async () => { - let circuit: WitnessTester<["stack", "currByte"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`NextKVPair`, { - file: "json/interpreter", - template: "NextKVPair", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], currByte: 44 }; - let output = { out: 1 }; - generatePassCase(input1, output, ""); - - let input2 = { stack: [[1, 0], [2, 0], [1, 0], [0, 0]], currByte: 44 }; - generatePassCase(input2, output, ""); - - let input3 = { stack: [[1, 0], [0, 0], [0, 0], [0, 0]], currByte: 44 }; - generatePassCase(input3, output, ""); - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], currByte: 44 }; - generatePassCase(input4, { out: 0 }, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], currByte: 34 }; - generatePassCase(input5, { out: 0 }, "incorrect currByte"); - }); - - describe("NextKVPairAtDepth", async () => { - let circuit: WitnessTester<["stack", "currByte", "depth"], ["out"]>; - - 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], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - 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, ""); - - // 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, depth: 2 }; - generatePassCase(input2, { out: 0 }, ""); - - 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, depth: 2 }; - generatePassCase(input4, { out: 0 }, "incorrect currByte"); - }); - - describe("KeyMatch", async () => { - let circuit: WitnessTester<["data", "key", "index", "parsing_key"], ["out"]>; - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`KeyMatch`, { - file: "json/interpreter", - template: "KeyMatch", - params: [input.data.length, input.key.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - let input = readJSONInputFile("value_array_object.json", ["a"]); - - let output = { out: 1 }; - let input1 = { data: input[0], key: input[1][0], index: 2, parsing_key: 1 }; - generatePassCase(input1, output, ""); - - let input2 = { data: input[0], key: [99], index: 20, parsing_key: 1 }; - generatePassCase(input2, output, ""); - - // fail cases - - let input3 = { data: input[0], key: input[1][0], index: 3, parsing_key: 1 }; - generatePassCase(input3, { out: 0 }, "wrong index"); - - let input4 = { data: input[0], key: [98], index: 2, parsing_key: 1 }; - generatePassCase(input4, { out: 0 }, "wrong key"); - - let input5 = { data: input[0], key: [97], index: 2, parsing_key: 0 }; - generatePassCase(input5, { out: 0 }, "not parsing key"); - }); - - describe("KeyMatchAtDepth", async () => { - let circuit: WitnessTester<["data", "key", "index", "parsing_key", "stack"], ["out"]>; - - function generatePassCase(input: any, expected: any, depth: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`KeyMatchAtDepth`, { - file: "json/interpreter", - template: "KeyMatchAtDepth", - params: [input.data.length, 4, input.key.length, depth], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - let input = readJSONInputFile("value_array_object.json", ["a", 0, "b", 0]); - - let output = { out: 1 }; - - let input1 = { data: input[0], key: input[1][0], index: 2, parsing_key: 1, stack: [[1, 0], [0, 0], [0, 0], [0, 0]] }; - generatePassCase(input1, output, 0, ""); - - let input2 = { data: input[0], key: input[1][2], index: 8, parsing_key: 1, stack: [[1, 1], [2, 0], [1, 0], [0, 0]] }; - generatePassCase(input2, output, 2, ""); - - let input3 = { data: input[0], key: [99], index: 20, parsing_key: 1, stack: [[1, 1], [2, 1], [1, 1], [0, 0]] }; - generatePassCase(input3, output, 2, "wrong stack"); - - // fail cases - - let input4 = { data: input[0], key: input[1][1], index: 3, parsing_key: 1, stack: [[1, 0], [2, 0], [1, 0], [0, 0]] }; - generatePassCase(input4, { out: 0 }, 2, "wrong key"); - - let input5 = { data: input[0], key: [97], index: 12, parsing_key: 0, stack: [[1, 1], [2, 0], [1, 1], [0, 0]] }; - generatePassCase(input5, { out: 0 }, 3, "not parsing key"); - - let input6Data = input[0].slice(0); - input6Data.splice(1, 1, 35); - let input6 = { data: input6Data, key: input[1][0], index: 2, parsing_key: 1, stack: [[1, 0], [0, 0], [0, 0], [0, 0]] }; - generatePassCase(input6, { out: 0 }, 0, "invalid key (not surrounded by quotes)"); - - let input7 = { data: input[0], key: input[1][0], index: 2, parsing_key: 1, stack: [[1, 0], [0, 0], [0, 0], [0, 0]] }; - generatePassCase(input6, { out: 0 }, 1, "wrong depth"); - }); - - describe("KeyMatchAtIndex", async () => { - let circuit: WitnessTester<["data", "key", "keyLen", "parsing_key"], ["out"]>; - let maxKeyLen = 3; - - function generatePassCase(input: any, expected: any, index: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - // pad key with 0's - let padded_key = input.key.concat(Array(maxKeyLen - input.key.length).fill(0)); - input.key = padded_key; - - circuit = await circomkit.WitnessTester(`KeyMatchAtIndex`, { - file: "json/interpreter", - template: "KeyMatchAtIndex", - params: [input.data.length, maxKeyLen, index], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - let input = readJSONInputFile("value_array_object.json", ["a", 0, "b", 0]); - - let output = { out: 1 }; - - let key1 = input[1][0]; - let input1 = { data: input[0], key: key1, keyLen: key1.length, parsing_key: 1 }; - generatePassCase(input1, output, 2, ""); - - let key2 = input[1][2]; - let input2 = { data: input[0], key: key2, keyLen: key2.length, parsing_key: 1 }; - generatePassCase(input2, output, 8, ""); - - let input3 = { data: input[0], key: [99], keyLen: 1, parsing_key: 1 }; - generatePassCase(input3, output, 20, "wrong stack"); - - // fail cases - - let failOutput = { out: 0 }; - let key4 = input[1][1]; - let input4 = { data: input[0], key: key4, keyLen: key4.length, parsing_key: 1 }; - generatePassCase(input4, failOutput, 3, "wrong key"); - - let input5 = { data: input[0], key: [97], keyLen: 1, parsing_key: 0 }; - generatePassCase(input5, failOutput, 12, "not parsing key"); - - let input6Data = input[0].slice(0); - input6Data.splice(1, 1, 35); - let input6 = { data: input6Data, key: input[1][0], keyLen: input[1][0].length, parsing_key: 1 }; - generatePassCase(input6, failOutput, 2, "invalid key (not surrounded by quotes)"); - - let input7 = { data: input[0], key: input[1][0], keyLen: input[1][0].length, parsing_key: 1 }; - generatePassCase(input6, failOutput, 2, "wrong depth"); - }); -}); \ No newline at end of file diff --git a/circuits/test/json/parser/hash_parser.test.ts b/circuits/test/json/hash_parser.test.ts similarity index 98% rename from circuits/test/json/parser/hash_parser.test.ts rename to circuits/test/json/hash_parser.test.ts index 71e899c..db52945 100644 --- a/circuits/test/json/parser/hash_parser.test.ts +++ b/circuits/test/json/hash_parser.test.ts @@ -1,5 +1,5 @@ import { poseidon2 } from "poseidon-lite"; -import { circomkit, WitnessTester, readJSONInputFile, strToBytes, JsonMaskType, jsonTreeHasher, compressTreeHash } from "../../common"; +import { circomkit, WitnessTester, readJSONInputFile, strToBytes, JsonMaskType, jsonTreeHasher, compressTreeHash } from "../common"; describe("Hash Parser", () => { let hash_parser: WitnessTester<["data", "polynomial_input", "sequence_digest"]>; diff --git a/circuits/test/json/parser/index.ts b/circuits/test/json/index.ts similarity index 100% rename from circuits/test/json/parser/index.ts rename to circuits/test/json/index.ts diff --git a/circuits/test/json/nivc/masker_nivc.test.ts b/circuits/test/json/nivc/masker_nivc.test.ts deleted file mode 100644 index 0d9a265..0000000 --- a/circuits/test/json/nivc/masker_nivc.test.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { circomkit, WitnessTester, generateDescription, readJsonFile, toByte } from "../../common"; -import { DataHasher } from "../../common/poseidon"; -import { assert } from "chai"; - -// HTTP/1.1 200 OK -// content-type: application/json; charset=utf-8 -// content-encoding: gzip -// Transfer-Encoding: chunked -// -// { -// "data": { -// "items": [ -// { -// "data": "Artist", -// "profile": { -// "name": "Taylor Swift" -// } -// } -// ] -// } -// } - -// 202 bytes in the JSON -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, 34, 105, 116, 101, 109, 115, 34, 58, 32, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, - 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, - 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, - 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, 10, 32, 32, 32, 125, 13, 10, 125]; - -const json_key0_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, - 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, - 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, - 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, 10, 32, 32, 32, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -const json_key0_mask_hash = DataHasher(json_key0_mask); - -const json_key1_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, - 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, - 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, - 32, 32, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -const json_key1_mask_hash = DataHasher(json_key1_mask); - -const json_arr_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, - 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 102, 105, - 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, - 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; -const json_arr_mask_hash = DataHasher(json_arr_mask); - -const json_key2_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, - 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; - -const json_key2_mask_hash = DataHasher(json_key2_mask); - -const json_key3_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; -const json_key3_mask_hash = DataHasher(json_key3_mask); - -describe("NIVC Extract", async () => { - let json_mask_object_circuit: WitnessTester<["step_in", "data", "key", "keyLen"], ["step_out"]>; - let json_mask_arr_circuit: WitnessTester<["step_in", "data", "index"], ["step_out"]>; - let extract_value_circuit: WitnessTester<["step_in", "data"], ["step_out"]>; - - const DATA_BYTES = 208; - const MAX_STACK_HEIGHT = 5; - const MAX_KEY_LENGTH = 8; - const MAX_VALUE_LENGTH = 32; - - before(async () => { - json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskArrayIndexNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], - }); - console.log("#constraints:", await json_mask_arr_circuit.getConstraintCount()); - - json_mask_object_circuit = await circomkit.WitnessTester(`JsonMaskObjectNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskObjectNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH], - }); - console.log("#constraints:", await json_mask_object_circuit.getConstraintCount()); - - extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { - file: "json/nivc/extractor", - template: "MaskExtractFinal", - params: [DATA_BYTES, MAX_VALUE_LENGTH], - }); - console.log("#constraints:", await extract_value_circuit.getConstraintCount()); - }); - - - let key0 = [100, 97, 116, 97, 0, 0, 0, 0]; // "data" - let key0Len = 4; - let key1 = [105, 116, 101, 109, 115, 0, 0, 0]; // "items" - let key1Len = 5; - let key2 = [112, 114, 111, 102, 105, 108, 101, 0]; // "profile" - let key2Len = 7; - let key3 = [110, 97, 109, 101, 0, 0, 0, 0]; // "name" - let key3Len = 4; - - let value = toByte("\"Taylor Swift\""); - - it("parse and mask", async () => { - - console.log(json_input.length); - let extended_json_input = json_input.concat(Array(Math.max(0, DATA_BYTES - json_input.length)).fill(0)); - - let jsonInputHash = DataHasher(extended_json_input); - let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: jsonInputHash, data: extended_json_input, key: key0, keyLen: key0Len }, ["step_out"]); - console.log("JSON Extract key0 `step_out`:", json_extract_key0.step_out); - assert.deepEqual(json_extract_key0.step_out, json_key0_mask_hash); - - let json_extract_key1 = await json_mask_object_circuit.compute({ step_in: json_extract_key0.step_out, data: json_key0_mask, key: key1, keyLen: key1Len }, ["step_out"]); - assert.deepEqual(json_extract_key1.step_out, json_key1_mask_hash); - console.log("JSON Extract key1 `step_out`:", json_extract_key1.step_out); - - let json_extract_arr = await json_mask_arr_circuit.compute({ step_in: json_extract_key1.step_out, index: 0, data: json_key1_mask }, ["step_out"]); - assert.deepEqual(json_extract_arr.step_out, json_arr_mask_hash); - console.log("JSON Extract arr `step_out`:", json_extract_arr.step_out); - - let json_extract_key2 = await json_mask_object_circuit.compute({ step_in: json_extract_arr.step_out, data: json_arr_mask, key: key2, keyLen: key2Len }, ["step_out"]); - assert.deepEqual(json_extract_key2.step_out, json_key2_mask_hash); - console.log("JSON Extract key2 `step_out`:", json_extract_key2.step_out); - - let json_extract_key3 = await json_mask_object_circuit.compute({ step_in: json_extract_key2.step_out, data: json_key2_mask, key: key3, keyLen: key3Len }, ["step_out"]); - assert.deepEqual(json_extract_key3.step_out, json_key3_mask_hash); - console.log("JSON Extract key3 `step_out`:", json_extract_key3.step_out); - - value = value.concat(Array(MAX_VALUE_LENGTH - value.length).fill(0)); - let final_value_hash = DataHasher(value); - let extractValue = await extract_value_circuit.compute({ step_in: json_extract_key3.step_out, data: json_key3_mask }, ["step_out"]); - console.log("JSON Extract finalValue `step_out`:", extractValue.step_out); - assert.deepEqual(extractValue.step_out, final_value_hash); - }); -}); \ No newline at end of file diff --git a/circuits/test/json/parser/parser.test.ts b/circuits/test/json/parser.test.ts similarity index 97% rename from circuits/test/json/parser/parser.test.ts rename to circuits/test/json/parser.test.ts index eccbc99..557548f 100644 --- a/circuits/test/json/parser/parser.test.ts +++ b/circuits/test/json/parser.test.ts @@ -1,4 +1,4 @@ -import { circomkit, WitnessTester, generateDescription, readJSONInputFile } from "../../common"; +import { circomkit, WitnessTester, generateDescription, readJSONInputFile } from "../common"; describe("json-parser", () => { let circuit: WitnessTester<["data"]>; diff --git a/circuits/test/json/parser/parsing_types.test.ts b/circuits/test/json/parsing_types.test.ts similarity index 99% rename from circuits/test/json/parser/parsing_types.test.ts rename to circuits/test/json/parsing_types.test.ts index 88d892e..4dfb9d3 100644 --- a/circuits/test/json/parser/parsing_types.test.ts +++ b/circuits/test/json/parsing_types.test.ts @@ -1,4 +1,4 @@ -import { circomkit, WitnessTester, generateDescription } from "../../common"; +import { circomkit, WitnessTester, generateDescription } from "../common"; import { Delimiters, WhiteSpace, Numbers, Escape, INITIAL_IN, INITIAL_OUT } from '.'; diff --git a/circuits/test/json/parser/stack.test.ts b/circuits/test/json/stack.test.ts similarity index 99% rename from circuits/test/json/parser/stack.test.ts rename to circuits/test/json/stack.test.ts index 860737e..95a738b 100644 --- a/circuits/test/json/parser/stack.test.ts +++ b/circuits/test/json/stack.test.ts @@ -1,4 +1,4 @@ -import { circomkit, WitnessTester, generateDescription } from "../../common"; +import { circomkit, WitnessTester, generateDescription } from "../common"; import { Delimiters, WhiteSpace, Numbers, Escape, INITIAL_IN, INITIAL_OUT } from '.'; describe("GetTopOfStack", () => { diff --git a/circuits/test/json/parser/values.test.ts b/circuits/test/json/values.test.ts similarity index 99% rename from circuits/test/json/parser/values.test.ts rename to circuits/test/json/values.test.ts index 069525b..ac18ac3 100644 --- a/circuits/test/json/parser/values.test.ts +++ b/circuits/test/json/values.test.ts @@ -1,4 +1,4 @@ -import { circomkit, WitnessTester, generateDescription } from "../../common"; +import { circomkit, WitnessTester, generateDescription } from "../common"; import { Delimiters, WhiteSpace, Numbers, Escape, INITIAL_IN, INITIAL_OUT } from '.'; describe("StateUpdate :: Values", () => { diff --git a/examples/json/array_only.json b/examples/json/array_only.json index a23b6b6..4d16559 100644 --- a/examples/json/array_only.json +++ b/examples/json/array_only.json @@ -1 +1 @@ -[42,{"a":"b"},[0,1],"foobar"] \ No newline at end of file +[ 42, { "a" : "b" } , [ 0 , 1 ] , "foobar"] \ No newline at end of file diff --git a/examples/json/spotify.json b/examples/json/spotify.json index 876df5e..e77f520 100644 --- a/examples/json/spotify.json +++ b/examples/json/spotify.json @@ -1 +1 @@ -{"data":{"items":[{"data":"Artist","profile":{"name":"Taylor Swift"}}]}} \ No newline at end of file +{ "data" : { "items" : [ { "data" : "Artist" , "profile" : { "name" : "Taylor Swift" } } ] } } \ No newline at end of file diff --git a/examples/json/value_array.json b/examples/json/value_array.json index 7713359..ca7dfcb 100644 --- a/examples/json/value_array.json +++ b/examples/json/value_array.json @@ -1 +1 @@ -{"k":[420,69,4200,600],"b":["ab","ba","ccc","d"]} \ 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/value_array_object.json b/examples/json/value_array_object.json index 3a0a544..5768e48 100644 --- a/examples/json/value_array_object.json +++ b/examples/json/value_array_object.json @@ -1 +1 @@ -{"a":[{"b":[1,4]},{"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/value_object.json b/examples/json/value_object.json index 10c330d..a3b29be 100644 --- a/examples/json/value_object.json +++ b/examples/json/value_object.json @@ -1 +1 @@ -{"a":{"d":"e","e":"c"},"e":{"f":"a","e":"2"},"g":{"h":{"a":"c"}},"ab":"foobar","bc":42,"dc":[0,1,"a"]} \ No newline at end of file +{ "a" : { "d" : "e" , "e" : "c" } , "e" : { "f" : "a" , "e" : "2" } , "g" : { "h" : { "a" : "c" } } , "ab" : "foobar" , "bc" : 42 , "dc" : [ 0 , 1 , "a" ] } \ No newline at end of file