Skip to content

Commit

Permalink
add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Autoparallel committed Aug 22, 2024
1 parent 91c3564 commit 167da25
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 50 deletions.
14 changes: 10 additions & 4 deletions circuits/parser.circom
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ The key ingredients of `parser` are:
`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;
Expand Down Expand Up @@ -64,6 +67,7 @@ template StateUpdate(MAX_STACK_HEIGHT) {
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];
//--------------------------------------------------------------------------------------------//
Expand Down Expand Up @@ -164,8 +168,8 @@ template StateToMask(n) {
signal readNumberNotParsingNumber <== (1 - parsing_number) * readNumber;
signal notParsingStringAndParsingNumberReadDelimeterOrReadNumberNotParsingNumber <== (1 - parsing_string) * (parsingNumberReadDelimeter + readNumberNotParsingNumber);
// 10 above ^^^^^^^^^^^^^^^^^ 4 above ^^^^^^^^^^^^^^^^^^
signal temp <== parsing_number * (1 - readNumber) ;
signal parsingNumberNotReadNumberNotReadDelimeter <== temp * (1-readDelimeter);
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!
}
Expand Down Expand Up @@ -193,6 +197,9 @@ template GetTopOfStack(n) {
}

// TODO: IMPORTANT NOTE, THE STACK IS CONSTRAINED TO 2**8 so the InRange work (could be changed)
/*
*/
template RewriteStack(n) {
assert(n < 2**8);
signal input stack[n][2];
Expand Down Expand Up @@ -224,7 +231,6 @@ template RewriteStack(n) {

//--------------------------------------------------------------------------------------------//
// * composite signals *
signal readEndChar <== readEndBrace + readEndBracket;
signal readCommaInArray <== readComma * inArray.out;
signal readCommaNotInArray <== readComma * (1 - inArray.out);
//--------------------------------------------------------------------------------------------//
Expand All @@ -250,7 +256,7 @@ template RewriteStack(n) {
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] * readEndChar;
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]);
}
//--------------------------------------------------------------------------------------------//
Expand Down
214 changes: 168 additions & 46 deletions circuits/utils.circom
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
/*
# `utils`
This module consists of helper templates for convencience.
It mostly extends the `bitify` and `comparators` modules from Circomlib.
## Layout
The key ingredients of `utils` are:
- `ASCII`: Verify if a an input array contains valid ASCII values (e.g., u8 vals).
- `IsEqualArray`: Check if two arrays are equal component by component.
- `Contains`: Check if an element is contained in a given array.
- `ArrayAdd`: Add two arrays together component by component.
- `ArrayMul`: Multiply two arrays together component by component.
- `GenericArrayAdd`: Add together an arbitrary amount of arrays.
- `ScalarArrayMul`: Multiply each array element by a scalar value.
- `InRange`: Check if a given number is in a given range.
- `Switch`: Return a scalar value given a specific case.
- `SwitchArray`: Return an array given a specific case.
## Testing
Tests for this module are located in the file: `./test/utils/utils.test.ts`
*/

pragma circom 2.1.9;

include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/comparators.circom";



/*
All tests for this file are located in: `./test/utils/utils.test.ts`
*/
This template passes if a given array contains only valid ASCII values (e.g., u8 vals).
# Params:
- `n`: the length of the array
# Inputs:
- `in[n]`: array to check
*/
template ASCII(n) {
signal input in[n];

Expand All @@ -18,12 +48,16 @@ template ASCII(n) {
}

/*
This function is an indicator for two equal array inputs.
This template is an indicator for two equal array inputs.
# Params:
- `n`: the length of arrays to compare
# Inputs:
- `n`: the length of arrays to compare
- `in[2][n]`: two arrays of `n` numbers
- `out`: either `0` or `1`
- `in[2][n]`: two arrays of `n` numbers
# Outputs:
- `out`: either `0` or `1`
- `1` if `in[0]` is equal to `in[1]` as arrays (i.e., component by component)
- `0` otherwise
*/
Expand All @@ -50,20 +84,24 @@ template IsEqualArray(n) {

// TODO: There should be a way to have the below assertion come from the field itself.
/*
This function is an indicator for if an array contains an element.
This template is an indicator for if an array contains an element.
# Params:
- `n`: the size of the array to search through
# Inputs:
- `n`: the size of the array to search through
- `in`: a number
- `array[n]`: the array we want to search through
- `out`: either `0` or `1`
- `in`: a number
- `array[n]`: the array we want to search through
# Outputs:
- `out`: either `0` or `1`
- `1` if `in` is found inside `array`
- `0` otherwise
*/
template Contains(n) {
assert(n > 0);
/*
If `n = p` for this large `p`, then it could be that this function
If `n = p` for this large `p`, then it could be that this template
returns the wrong value if every element in `array` was equal to `in`.
This is EXTREMELY unlikely and iterating this high is impossible anyway.
But it is better to check than miss something, so we bound it by `2**254` for now.
Expand All @@ -89,6 +127,18 @@ template Contains(n) {
out <== 1 - someEqual.out;
}

/*
This template adds two arrays component by component.
# Params:
- `n`: the length of arrays to compare
# Inputs:
- `in[2][n]`: two arrays of `n` numbers
# Outputs:
- `out[n]`: the array sum value
*/
template ArrayAdd(n) {
signal input lhs[n];
signal input rhs[n];
Expand All @@ -99,6 +149,18 @@ template ArrayAdd(n) {
}
}

/*
This template multiplies two arrays component by component.
# Params:
- `n`: the length of arrays to compare
# Inputs:
- `in[2][n]`: two arrays of `n` numbers
# Outputs:
- `out[n]`: the array multiplication value
*/
template ArrayMul(n) {
signal input lhs[n];
signal input rhs[n];
Expand All @@ -109,6 +171,19 @@ template ArrayMul(n) {
}
}

/*
This template multiplies two arrays component by component.
# Params:
- `m`: the length of the arrays to add
- `n`: the number of arrays to add
# Inputs:
- `arrays[m][n]`: `n` arrays of `m` numbers
# Outputs:
- `out[m]`: the sum of all the arrays
*/
template GenericArrayAdd(m,n) {
signal input arrays[n][m];
signal output out[m];
Expand All @@ -122,6 +197,18 @@ template GenericArrayAdd(m,n) {
out <== accum;
}

/*
This template multiplies each component of an array by a scalar value.
# Params:
- `n`: the length of the array
# Inputs:
- `array[n]`: an array of `n` numbers
# Outputs:
- `out[n]`: the scalar multiplied array
*/
template ScalarArrayMul(n) {
signal input array[n];
signal input scalar;
Expand All @@ -132,6 +219,20 @@ template ScalarArrayMul(n) {
}
}

/*
This template checks if a given `n`-bit value is contained in a range of `n`-bit values
# Params:
- `n`: the number of bits to use
# Inputs:
- `range[2]`: the lower and upper bound of the array, respectively
# Outputs:
- `out`: either `0` or `1`
- `1` if `in` is within the range
- `0` otherwise
*/
template InRange(n) {
signal input in;
signal input range[2];
Expand All @@ -147,74 +248,95 @@ template InRange(n) {
}

/*
This function is creates an exhaustive switch statement from `0` up to `n`.
This template is creates an exhaustive switch statement from a list of branch values.
# Params:
- `n`: the number of switch cases
# Inputs:
- `m`: the number of switch cases
- `n`: the output array length
- `case`: which case of the switch to select
- `branches[m]`: the values that enable taking different branches in the switch
- `case`: which case of the switch to select
- `branches[n]`: the values that enable taking different branches in the switch
(e.g., if `branch[i] == 10` then if `case == 10` we set `out == `vals[i]`)
- `vals[m][n]`: the value that is emitted for a given switch case
- `vals[n]`: the value that is emitted for a given switch case
(e.g., `val[i]` array is emitted on `case == `branch[i]`)
# Outputs
- `match`: is set to `0` if `case` does not match on any of `branches`
- `out[n]`: the selected output value if one of `branches` is selected (will be `[0,0,...]` otherwise)
- `match`: is set to `0` if `case` does not match on any of `branches`
- `out[n]`: the selected output value if one of `branches` is selected (will be `0` otherwise)
^^^^^^ BEWARE OF THIS FACT ABOVE!
*/
template SwitchArray(m, n) {
assert(m > 0);
template Switch(n) {
assert(n > 0);
signal input case;
signal input branches[m];
signal input vals[m][n];
signal input branches[n];
signal input vals[n];
signal output match;
signal output out[n];
signal output out;


// Verify that the `case` is in the possible set of branches
component indicator[m];
component matchChecker = Contains(m);
signal component_out[m][n];
var sum[n];
for(var i = 0; i < m; i++) {
component indicator[n];
component matchChecker = Contains(n);
signal temp_val[n];
var sum;
for(var i = 0; i < n; i++) {
indicator[i] = IsZero();
indicator[i].in <== case - branches[i];
matchChecker.array[i] <== 1 - indicator[i].out;
for(var j = 0; j < n; j++) {
component_out[i][j] <== indicator[i].out * vals[i][j];
sum[j] += component_out[i][j];
}
temp_val[i] <== indicator[i].out * vals[i];
sum += temp_val[i];
}
matchChecker.in <== 0;
match <== matchChecker.out;

out <== sum;
}

template Switch(n) {
/*
This template is creates an exhaustive switch statement from a list of branch values.
# Params:
- `m`: the number of switch cases
- `n`: the output array length
# Inputs:
- `case`: which case of the switch to select
- `branches[m]`: the values that enable taking different branches in the switch
(e.g., if `branch[i] == 10` then if `case == 10` we set `out == `vals[i]`)
- `vals[m][n]`: the value that is emitted for a given switch case
(e.g., `val[i]` array is emitted on `case == `branch[i]`)
# Outputs
- `match`: is set to `0` if `case` does not match on any of `branches`
- `out[n]`: the selected output value if one of `branches` is selected (will be `[0,0,...]` otherwise)
^^^^^^ BEWARE OF THIS FACT ABOVE!
*/
template SwitchArray(m, n) {
assert(m > 0);
assert(n > 0);
signal input case;
signal input branches[n];
signal input vals[n];
signal input branches[m];
signal input vals[m][n];
signal output match;
signal output out;
signal output out[n];


// Verify that the `case` is in the possible set of branches
component indicator[n];
component matchChecker = Contains(n);
signal temp_val[n];
var sum;
for(var i = 0; i < n; i++) {
component indicator[m];
component matchChecker = Contains(m);
signal component_out[m][n];
var sum[n];
for(var i = 0; i < m; i++) {
indicator[i] = IsZero();
indicator[i].in <== case - branches[i];
matchChecker.array[i] <== 1 - indicator[i].out;
temp_val[i] <== indicator[i].out * vals[i];
sum += temp_val[i];
for(var j = 0; j < n; j++) {
component_out[i][j] <== indicator[i].out * vals[i][j];
sum[j] += component_out[i][j];
}
}
matchChecker.in <== 0;
match <== matchChecker.out;

out <== sum;
}
}

0 comments on commit 167da25

Please sign in to comment.