Skip to content

Commit

Permalink
add valueArraySize input to v3 circuits
Browse files Browse the repository at this point in the history
  • Loading branch information
volodymyr-basiuk committed Feb 15, 2024
1 parent 1a1f212 commit 0b2e988
Show file tree
Hide file tree
Showing 63 changed files with 286 additions and 75 deletions.
1 change: 1 addition & 0 deletions circuits/credentialAtomicQueryV3.circom
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ component main{public [requestID,
claimPathNotExists,
operator,
value,
valueArraySize,
timestamp,
isRevocationChecked,
proofType,
Expand Down
20 changes: 17 additions & 3 deletions circuits/lib/query/processQueryWithModifiers.circom
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ include "../../../node_modules/circomlib/circuits/comparators.circom";
include "query.circom";
include "modifiers.circom";
include "../utils/claimUtils.circom";
include "../utils/arraySizeValidator.circom";

template ProcessQueryWithModifiers(claimLevels, valueArraySize){
template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){
signal input enabled;
signal input claimPathNotExists; // 0 for inclusion, 1 for non-inclusion
signal input claimPathMtp[claimLevels];
Expand All @@ -16,7 +17,8 @@ template ProcessQueryWithModifiers(claimLevels, valueArraySize){
signal input claimPathValue; // value in this path in merklized json-ld document
signal input slotIndex;
signal input operator;
signal input value[valueArraySize];
signal input value[maxValueArraySize];
signal input valueArraySize;

signal input issuerClaim[8];
signal input merklized;
Expand Down Expand Up @@ -55,9 +57,21 @@ template ProcessQueryWithModifiers(claimLevels, valueArraySize){
// Query Operator Processing
/////////////////////////////////////////////////////////////////

// verify value array length
// 801 constraints (ArraySizeValidator+ForceEqualIfEnabled)
signal arrSizeSatisfied <== ArraySizeValidator(maxValueArraySize)(
valueArraySize <== valueArraySize,
operator <== operator
);

ForceEqualIfEnabled()(
enabled,
[arrSizeSatisfied, 1]
);

// verify query
// 1756 constraints (Query+LessThan+ForceEqualIfEnabled)
signal querySatisfied <== Query(valueArraySize)(
signal querySatisfied <== Query(maxValueArraySize)(
in <== fieldValue,
value <== value,
operator <== operator
Expand Down
6 changes: 3 additions & 3 deletions circuits/lib/query/query.circom
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ include "comparators.circom";
*/

// Query template works only with Query operators (0-15), for the rest returns 0
template Query (valueArraySize) {
template Query (maxValueArraySize) {
// signals
signal input in;
signal input value[valueArraySize];
signal input value[maxValueArraySize];
signal input operator;
signal output out;

Expand All @@ -47,7 +47,7 @@ template Query (valueArraySize) {
signal gte <== NOT()(lt); // gte === !lt

// in
signal inComp <== IN(valueArraySize)(in, value);
signal inComp <== IN(maxValueArraySize)(in, value);

// between (value[0] <= in <= value[1])
signal gt2 <== GreaterThan254()([in, value[1]]);
Expand Down
73 changes: 73 additions & 0 deletions circuits/lib/utils/arraySizeValidator.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
pragma circom 2.1.1;
include "../../../node_modules/circomlib/circuits/mux1.circom";
include "../../../node_modules/circomlib/circuits/mux4.circom";
include "../../../node_modules/circomlib/circuits/bitify.circom";
include "../../../node_modules/circomlib/circuits/comparators.circom";
include "../../../node_modules/circomlib/circuits/gates.circom";
include "../query/comparators.circom";
/*
Operators:
Query operators - valueArraySize
0 - noop - 0 elements
1 - equals - 1 element
2 - less than - 1 element
3 - greater than - 1 element
4 - in - less or eq than maxValueArraySize
5 - not in - less or eq than maxValueArraySize
6 - not equals - 1 element
7 - less than or equal - 1 element
8 - greater than or equal - 1 element
9 - between - 2 elements
Modifier/computation operators:
16 - selective disclosure (16 = 10000 binary) - 0 elements
17-31 - 0 elements
*/

// ArraySizeValidator template check valueArraySize for query operators
template ArraySizeValidator (maxValueArraySize) {
// signals
signal input valueArraySize;
signal input operator;
signal output out;

signal sizeEqZero <== IsEqual()([valueArraySize, 0]);
signal sizeEqOne <== IsEqual()([valueArraySize, 1]);
signal sizeEqTwo <== IsEqual()([valueArraySize, 2]);
signal sizeLessOrEqMax <== LessThan254()([valueArraySize, maxValueArraySize + 1]);

signal opBits[5] <== Num2Bits(5)(operator); // values 0-15 are query operators, 16-31 - modifiers/computations

// query operator mux
component mux = Mux4();
mux.s <== [opBits[0], opBits[1], opBits[2], opBits[3]];

// We don't use 5th bit (opBits[4]) here; which specifies whether operator is query or
// modifier/computation operator. It's used in the final mux.
_ <== opBits[4];

mux.c[0] <== sizeEqZero; // noop; skip execution
mux.c[1] <== sizeEqOne; // equals
mux.c[2] <== sizeEqOne; // lt
mux.c[3] <== sizeEqOne; // gt
mux.c[4] <== sizeLessOrEqMax; // in
mux.c[5] <== sizeLessOrEqMax; // nin
mux.c[6] <== sizeEqOne; // neq
mux.c[7] <== sizeEqOne; // lte
mux.c[8] <== sizeEqOne; // gte
mux.c[9] <== sizeEqTwo; // between
mux.c[10] <== sizeEqZero; // not used
mux.c[11] <== sizeEqZero; // not used
mux.c[12] <== sizeEqZero; // not used
mux.c[13] <== sizeEqZero; // not used
mux.c[14] <== sizeEqZero; // not used
mux.c[15] <== sizeEqZero; // not used

// final output mux
out <== Mux1()(
s <== opBits[4], // specifies whether operator is query or modifier/computation operator
c <== [mux.out, sizeEqZero]
);

}


9 changes: 5 additions & 4 deletions circuits/offchain/credentialAtomicQueryV3OffChain.circom
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ include "../lib/utils/nullify.circom";
include "../lib/utils/idUtils.circom";
include "../lib/utils/safeOne.circom";

template credentialAtomicQueryV3OffChain(issuerLevels, claimLevels, valueArraySize) {
template credentialAtomicQueryV3OffChain(issuerLevels, claimLevels, maxValueArraySize) {
// common outputs for Sig and MTP
signal output merklized;
signal output userID;
Expand Down Expand Up @@ -50,8 +50,8 @@ template credentialAtomicQueryV3OffChain(issuerLevels, claimLevels, valueArraySi
signal input claimPathValue; // value in this path in merklized json-ld document
signal input slotIndex;
signal input operator;
signal input value[valueArraySize];

signal input value[maxValueArraySize];
signal input valueArraySize;
signal input issuerClaim[8];

// MTP specific
Expand Down Expand Up @@ -237,7 +237,7 @@ template credentialAtomicQueryV3OffChain(issuerLevels, claimLevels, valueArraySi
// Process Query with Modifiers
/////////////////////////////////////////////////////////////////
// output value only if modifier operation was selected
operatorOutput <== ProcessQueryWithModifiers(claimLevels, valueArraySize)(
operatorOutput <== ProcessQueryWithModifiers(claimLevels, maxValueArraySize)(
one,
claimPathNotExists,
claimPathMtp,
Expand All @@ -249,6 +249,7 @@ template credentialAtomicQueryV3OffChain(issuerLevels, claimLevels, valueArraySi
slotIndex,
operator,
value,
valueArraySize,
issuerClaim,
merklized,
merklize.out
Expand Down
12 changes: 7 additions & 5 deletions circuits/onchain/credentialAtomicQueryV3OnChain.circom
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ checks:
idOwnershipLevels - Merkle tree depth level for personal claims
issuerLevels - Merkle tree depth level for claims issued by the issuer
claimLevels - Merkle tree depth level for claim JSON-LD document
valueArraySize - Number of elements in comparison array for in/notin operation if level = 3 number of values for
maxValueArraySize - Number of elements in comparison array for in/notin operation if level = 3 number of values for
comparison ["1", "2", "3"]
idOwnershipLevels - Merkle tree depth level for personal claims
onChainLevels - Merkle tree depth level for Auth claim on-chain
*/
template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, valueArraySize, idOwnershipLevels, onChainLevels) {
template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, maxValueArraySize, idOwnershipLevels, onChainLevels) {
// flag indicates if merklized flag set in issuer claim (if set MTP is used to verify that
// claimPathValue and claimPathKey are stored in the merkle tree) and verification is performed
// on root stored in the index or value slot
Expand Down Expand Up @@ -123,7 +123,8 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, valueArraySiz

signal input slotIndex;
signal input operator;
signal input value[valueArraySize];
signal input value[maxValueArraySize];
signal input valueArraySize;

// MTP specific
signal input issuerClaimMtp[issuerLevels];
Expand Down Expand Up @@ -203,7 +204,7 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, valueArraySiz
// Claim checks
/////////////////////////////////////////////////////////////////

(merklized, userID, issuerState, linkID, nullifier, operatorOutput) <== credentialAtomicQueryV3OffChain(issuerLevels, claimLevels, valueArraySize)(
(merklized, userID, issuerState, linkID, nullifier, operatorOutput) <== credentialAtomicQueryV3OffChain(issuerLevels, claimLevels, maxValueArraySize)(
proofType <== proofType,
requestID <== requestID,
userGenesisID <== userGenesisID,
Expand Down Expand Up @@ -231,6 +232,7 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, valueArraySiz
slotIndex <== slotIndex,
operator <== operator,
value <== value,
valueArraySize <== valueArraySize,
issuerClaim <== issuerClaim,
issuerClaimMtp <== issuerClaimMtp,
issuerClaimClaimsTreeRoot <== issuerClaimClaimsTreeRoot,
Expand Down Expand Up @@ -258,7 +260,7 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, valueArraySiz
/////////////////////////////////////////////////////////////////
// Verify query hash matches
/////////////////////////////////////////////////////////////////
signal valueHash <== SpongeHash(valueArraySize, 6)(value); // 6 - max size of poseidon hash available on-chain
signal valueHash <== SpongeHash(maxValueArraySize, 6)(value); // 6 - max size of poseidon hash available on-chain

circuitQueryHash <== Poseidon(6)([
claimSchema,
Expand Down
5 changes: 5 additions & 0 deletions test/circuits/utils/utils_arraySizeValidatorTest.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma circom 2.1.1;

include "../../../circuits/lib/utils/arraySizeValidator.circom";

component main = ArraySizeValidator(64);
79 changes: 79 additions & 0 deletions test/utils/arraySizeValidator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {describe} from "mocha";

const path = require("path");
const wasm_tester = require("circom_tester").wasm;

describe("Test ArraySizeValidator template:", async function () {
const tests = [
{
desc: "eq require 1 value array size input",
input: {
valueArraySize: "1",
operator: "1",
},
expOut: { out: "1" }
},
{
desc: "between require 2 value array size input",
input: {
valueArraySize: "2",
operator: "9",
},
expOut: { out: "1" }
},
{
desc: "in require less than 64 size input",
input: {
valueArraySize: "64",
operator: "4",
},
expOut: { out: "1" }
},
{
desc: "nin more than 64 size input",
input: {
valueArraySize: "65",
operator: "5",
},
expOut: { out: "0" }
},
{
desc: "sd with 1 value arr size",
input: {
valueArraySize: "1",
operator: "16",
},
expOut: { out: "0" }
},
{
desc: "sd with 0 value arr size",
input: {
valueArraySize: "0",
operator: "16",
},
expOut: { out: "1" }
},
{
desc: "gte with 2 value arr size",
input: {
valueArraySize: "2",
operator: "8",
},
expOut: { out: "0" }
},
];

let circuit;

before(async function () {
circuit = await wasm_tester(path.join(__dirname, "../circuits/utils/", "utils_arraySizeValidatorTest.circom"));
});

tests.forEach(({ desc, input, expOut }) => {
it(`${desc}`, async function () {
const w = await circuit.calculateWitness(input, true);
await circuit.assertOut(w, expOut);
await circuit.checkConstraints(w);
});
});
});
Loading

0 comments on commit 0b2e988

Please sign in to comment.