Skip to content

Instantly share code, notes, and snippets.

@enricobottazzi
Created July 28, 2023 07:10
Show Gist options
  • Save enricobottazzi/1687b3393262984ed9c46f8146e5ae90 to your computer and use it in GitHub Desktop.
Save enricobottazzi/1687b3393262984ed9c46f8146e5ae90 to your computer and use it in GitHub Desktop.

Open this in zkREPL →

This file can be included into other zkREPLs with include "gist:1687b3393262984ed9c46f8146e5ae90";

pragma circom 2.1.4;
include "circomlib/comparators.circom";
/*
Inputs:
---------
- in: Array of tuples
- match: Arbitrary value that defines a match condition
Outputs:
---------
- num_match: Number of elements of `in` whose first entry matches `match`
- out: Array of tuples in which the first `num_match` entries are the tuples in `in` for which the `match` condition is satisfied
The remaining entries are 0-padded
Functionality:
--------------
1. Find the indexes of `in` that satisfies the `match` condition
2. Start a loop for each element of `in`
3. For each loop round find the next available matching tuple and sequentially add it to `out`. When there are no longer matching tuples pad `out` with 0.
4. At the end of each loop round increase `num_match_added_to_out` if and only if a matching tuple was added to `out`
5. After the loop has ended, assign the value of the variable `num_match_added_to_out` to `num_match`
Number of non-linear constraints (per instantiation):
--------------
40200
*/
template Filter () {
signal input in[100][2];
signal input match;
signal output num_match;
signal output out[100][2];
signal matching_indexes[100];
component find_matching_indexes = FindMatchingIndexes();
for(var i=0; i<100; i++) {
find_matching_indexes.in[i] <== in[i][0];
}
find_matching_indexes.match <== match;
matching_indexes <== find_matching_indexes.out;
var num_match_added_to_out;
component perform_assignment_cycle[100];
for(var i=0; i<100; i++) {
perform_assignment_cycle[i] = PerformAssignmentCycle();
perform_assignment_cycle[i].num_match_added_to_out <== num_match_added_to_out;
for(var z=0; z<100; z++) {
perform_assignment_cycle[i].in[z][0] <== in[z][0];
perform_assignment_cycle[i].in[z][1] <== in[z][1];
}
perform_assignment_cycle[i].matching_indexes <== matching_indexes;
out[i][0] <== perform_assignment_cycle[i].tuple_to_assign[0];
out[i][1] <== perform_assignment_cycle[i].tuple_to_assign[1];
num_match_added_to_out += perform_assignment_cycle[i].new_match_added;
}
num_match <== num_match_added_to_out;
}
/*
Inputs:
---------
- in: Array of values
- match: Arbitrary value that defines a match condition
Outputs:
---------
- out: Array of binary values.
A `0` value at index `i` of the array indicates that the matching condition is not satisfied at index `i`
A `1` value at index `z` of the array indicates that the matching condition is satisfied at index `z`
Functionality:
--------------
1. Start a loop for each element of `in`
2. For each loop check that `in[i]` is equal to `match`
3. Assign the binary output to `out[i]`
Number of non-linear constraints (per instantiation):
--------------
200
*/
template FindMatchingIndexes() {
signal input in[100];
signal input match;
signal output out[100];
component is_equal[100];
for(var i=0; i<100; i++) {
is_equal[i] = IsEqual ();
is_equal[i].in[0] <== in[i];
is_equal[i].in[1] <== match;
out[i] <== is_equal[i].out;
}
}
/*
Inputs:
---------
- num_match_added_to_out: Indicates the number of matching tuples added to `out` up to this point
- in: Array of tuples
- matching_indexes: Array of binary values
Outputs:
---------
- tuple_to_assign: Tuple to be assigned to `out. If no matching condition was found, it is a 0-padded tuple
- new_match_added: Binary value that indicates if a new matching condition was found or not in the cycle
Functionality:
--------------
1. Start a loop for each element of `in`
2. For each loop round increase the variable `num_match_spotted_in_cycle` by 1 if and only if the corresponding index is a match
3. For each loop round verify that a matching condition was found and, if, verify that the corresponding tuple hasn't been added to `out` yet
4. If a new matching condition was found, add the corresponding tuple to the running sum. If no matching condition was found, add a 0-padded tuple to the running sum
5. Increase the `new_match` variable by 1 if and only if a new matching condition was found.
6. Increase the `num_match_spotted_in_cycle` by 1 if and only if a new matching condition was found. This is a trick added to avoid that the `is_new_match`
condition would be satisfied for two consecutive loop rounds in the case in which a matching tuple is followed by a non-matching tuples.
In particular, `is_new_match` would return true in that case. Consider that we only want to find 1 new matching condition per assignment cycle, increasing
`num_match_spotted_in_cycle` by 1 after the first matching condition was found, would guarantee that `is_new_match` would never return true again for that cycle.
Number of non-linear constraints (per instantiation):
--------------
400
*/
template PerformAssignmentCycle() {
signal input num_match_added_to_out;
signal input in[100][2];
signal input matching_indexes[100];
signal output tuple_to_assign[2];
signal output new_match_added;
component is_new_match[100];
var num_match_spotted_in_cycle;
var new_match;
component running_sum = RunningSum();
for(var z=0; z<100; z++) {
num_match_spotted_in_cycle += matching_indexes[z];
is_new_match[z] = IsNewMatch();
is_new_match[z].num_match_spotted_in_cycle <== num_match_spotted_in_cycle;
is_new_match[z].num_match_added_to_out <== num_match_added_to_out;
running_sum.in[z][0] <== in[z][0] * is_new_match[z].out;
running_sum.in[z][1] <== in[z][1] * is_new_match[z].out;
new_match += is_new_match[z].out;
num_match_spotted_in_cycle += is_new_match[z].out;
}
tuple_to_assign[0] <== running_sum.out[0];
tuple_to_assign[1] <== running_sum.out[1];
new_match_added <== new_match;
}
/*
Inputs:
---------
- in: Array of tuples
Outputs:
---------
- out: Tuple
Functionality:
--------------
1. Initialize an intermediate signal `partial_sum` to the value of the first tuple of `in`
2. Start a loop for each element of `in` starting from 1
3. For each loop round add the current tuple of `in` to `partial_sum`. In particular the running sum:
- adds the first element of the tuple to the previous first element of `partial_sum`
- adds the second element of the tuple to the previous second element of `partial_sum`
4. Assign the accumulated `partial_sum` after the last loop round to `out` tuple
Number of non-linear constraints (per instantiation):
--------------
2
*/
template RunningSum() {
signal input in[100][2];
signal output out[2];
signal partial_sum[100][2];
partial_sum[0][0] <== in[0][0];
partial_sum[0][1] <== in[0][1];
for (var i=1; i < 100; i++) {
partial_sum[i][0] <== partial_sum[i - 1][0] + in[i][0];
partial_sum[i][1] <== partial_sum[i - 1][1] + in[i][1];
}
out[0] <== partial_sum[100 - 1][0];
out[1] <== partial_sum[100 - 1][1];
}
/*
Inputs:
---------
- num_match_spotted_in_cycle: Value that indicates the number of matching conditions spotted in the cycle
- num_match_added_to_out: Value that indicates the number of matching tuples added to `out`
Outputs:
---------
- out: A binary value that indicates if a tuple that hasn't been added to `out` yet was found
Functionality:
--------------
1. Evaluate if the expression `num_match_spotted_in_cycle - num_match_added_to_out` is equal to 1.
If this expression equals to 1, it means that the next available matching tuple was spotted.
2. Assign the binary result of the evaluation to `out`
Number of non-linear constraints (per instantiation):
--------------
2
*/
template IsNewMatch () {
signal input num_match_spotted_in_cycle;
signal input num_match_added_to_out;
signal output out;
component is_equal = IsEqual();
is_equal.in[0] <== num_match_spotted_in_cycle - num_match_added_to_out;
is_equal.in[1] <== 1;
out <== is_equal.out;
}
component main = Filter();
/* INPUT = {
"in": [
[
6,
8
],
[
7,
6
],
[
10,
7
],
[
7,
5
],
[
2,
9
],
[
8,
6
],
[
9,
4
],
[
2,
7
],
[
7,
6
],
[
8,
1
],
[
5,
5
],
[
3,
9
],
[
4,
9
],
[
3,
4
],
[
10,
5
],
[
1,
10
],
[
2,
10
],
[
7,
3
],
[
10,
4
],
[
9,
5
],
[
6,
9
],
[
7,
8
],
[
10,
5
],
[
1,
7
],
[
9,
7
],
[
9,
8
],
[
5,
4
],
[
9,
8
],
[
2,
2
],
[
5,
3
],
[
1,
5
],
[
1,
9
],
[
1,
3
],
[
6,
6
],
[
10,
1
],
[
1,
7
],
[
6,
9
],
[
4,
3
],
[
9,
8
],
[
7,
9
],
[
2,
10
],
[
3,
6
],
[
5,
6
],
[
8,
5
],
[
9,
2
],
[
3,
1
],
[
5,
4
],
[
2,
4
],
[
5,
7
],
[
2,
4
],
[
7,
7
],
[
4,
10
],
[
7,
9
],
[
8,
10
],
[
2,
2
],
[
6,
8
],
[
10,
10
],
[
5,
2
],
[
4,
4
],
[
3,
3
],
[
4,
4
],
[
3,
7
],
[
1,
5
],
[
10,
1
],
[
7,
10
],
[
8,
9
],
[
8,
3
],
[
9,
1
],
[
7,
4
],
[
2,
4
],
[
8,
7
],
[
2,
5
],
[
1,
8
],
[
5,
6
],
[
2,
3
],
[
3,
8
],
[
10,
5
],
[
8,
9
],
[
8,
1
],
[
3,
8
],
[
5,
10
],
[
7,
4
],
[
7,
1
],
[
4,
9
],
[
6,
1
],
[
7,
6
],
[
6,
2
],
[
7,
10
],
[
3,
7
],
[
4,
3
],
[
4,
6
],
[
4,
1
],
[
3,
7
],
[
7,
8
],
[
3,
10
],
[
2,
8
],
[
4,
9
],
[
2,
10
],
[
7,
5
],
[
9,
1
]
],
"match": "5"
} */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment