Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add valueArraySize to multiQuery circuit #124

Merged
merged 6 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion circuits/credentialAtomicQueryV3.circom
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ component main{public [requestID,
claimSchema,
slotIndex,
claimPathKey,
claimPathNotExists,
operator,
value,
valueArraySize,
Expand Down
5 changes: 1 addition & 4 deletions circuits/credentialAtomicQueryV3OnChain.circom
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ component main{public [requestID,
issuerID,
issuerClaimNonRevState,
timestamp,
isRevocationChecked,
challenge,
gistRoot,
proofType,
verifierID,
nullifierSessionID,
authEnabled
isBJJAuthEnabled
]} = credentialAtomicQueryV3OnChain(40, 32, 64, 40, 64);
15 changes: 12 additions & 3 deletions circuits/lib/query/processQueryWithModifiers.circom
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ include "../utils/arraySizeValidator.circom";

template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){
signal input enabled;
signal input claimPathNotExists; // 0 for inclusion, 1 for non-inclusion
signal input claimPathMtp[claimLevels];
signal input claimPathMtpNoAux; // 1 if aux node is empty, 0 if non-empty or for inclusion proofs
signal input claimPathMtpAuxHi; // 0 for inclusion proof
Expand All @@ -27,11 +26,14 @@ template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){
// Modifier/Computation Operator output ($sd)
signal output operatorOutput;

signal smtEnabled <== AND()(enabled, merklized);
signal operatorNotNoop <== NOT()(IsZero()(operator));
signal merklizedAndEnabled <== AND()(enabled, merklized);

signal claimPathNotExists <== AND()(IsZero()(value[0]), IsEqual()([operator, 11])); // for exist and value 0 operator 1, else 0

// check path/in node exists in merkletree specified by jsonldRoot
SMTVerifier(claimLevels)(
enabled <== smtEnabled, // if merklize flag 0 or enabled 0 skip MTP verification
enabled <== AND()(merklizedAndEnabled, operatorNotNoop), // if merklize flag 0 or enabled 0 or NOOP operation skip MTP verification
fnc <== claimPathNotExists, // inclusion
root <== merklizedRoot,
siblings <== claimPathMtp,
Expand All @@ -53,6 +55,13 @@ template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){
merklized
);

// For non-merklized credentials exists / non-exist operators don't work
signal operatorNotExists <== NOT()(IsEqual()([operator, 11]));
ForceEqualIfEnabled()(
AND()(enabled, NOT()(merklized)),
[1, operatorNotExists]
);

/////////////////////////////////////////////////////////////////
// Query Operator Processing
/////////////////////////////////////////////////////////////////
Expand Down
3 changes: 2 additions & 1 deletion circuits/lib/query/query.circom
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ include "comparators.circom";
8 - greater than or equal
9 - between
10 - not between
11 - exist
Modifier/computation operators:
16 - selective disclosure (16 = 10000 binary)
*/
Expand Down Expand Up @@ -76,7 +77,7 @@ template Query (maxValueArraySize) {
queryOpSatisfied.c[8] <== gte; // gte === !lt
queryOpSatisfied.c[9] <== between; // between
queryOpSatisfied.c[10] <== NOT()(between); // not between
queryOpSatisfied.c[11] <== 0; // not used
queryOpSatisfied.c[11] <== 1; // exists;
queryOpSatisfied.c[12] <== 0; // not used
queryOpSatisfied.c[13] <== 0; // not used
queryOpSatisfied.c[14] <== 0; // not used
Expand Down
3 changes: 2 additions & 1 deletion circuits/lib/utils/arraySizeValidator.circom
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ include "../query/comparators.circom";
8 - greater than or equal - 1 element
9 - between - 2 elements
10 - not between - 2 elements
11 - exists - 1 elements (true/false)
Modifier/computation operators:
16 - selective disclosure (16 = 10000 binary) - 0 elements
17-31 - 0 elements
Expand Down Expand Up @@ -62,7 +63,7 @@ template ArraySizeValidator (maxValueArraySize) {
mux.c[8] <== sizeEqOne; // gte
mux.c[9] <== sizeEqTwo; // between
mux.c[10] <== sizeEqTwo; // not between
mux.c[11] <== sizeEqZero; // not used
mux.c[11] <== sizeEqOne; // exist
mux.c[12] <== sizeEqZero; // not used
mux.c[13] <== sizeEqZero; // not used
mux.c[14] <== sizeEqZero; // not used
Expand Down
42 changes: 42 additions & 0 deletions circuits/lib/utils/queryHash.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
pragma circom 2.1.1;
include "./spongeHash.circom";

template QueryHash(maxValueArraySize) {
signal input value[maxValueArraySize];
signal input claimSchema;
signal input slotIndex;
signal input operator;
signal input claimPathKey;
signal input valueArraySize;
signal input merklized;
signal input isRevocationChecked;
signal input verifierID;
signal input nullifierSessionID;

signal output out;

signal claimPathNotExists <== AND()(IsZero()(value[0]), IsEqual()([operator, 11]));

/////////////////////////////////////////////////////////////////
// Calculate query hash
/////////////////////////////////////////////////////////////////
// 4950 constraints (SpongeHash+Poseidon)
signal valueHash <== SpongeHash(maxValueArraySize, 6)(value); // 6 - max size of poseidon hash available on-chain
signal firstPartQueryHash <== Poseidon(6)([
claimSchema,
slotIndex,
operator,
claimPathKey,
claimPathNotExists,
valueHash
]);

out <== Poseidon(6)([
firstPartQueryHash,
valueArraySize,
merklized,
isRevocationChecked,
vmidyllic marked this conversation as resolved.
Show resolved Hide resolved
verifierID,
nullifierSessionID
]);
}
39 changes: 20 additions & 19 deletions circuits/linked/multiQuery.circom
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,17 @@ include "../lib/query/processQueryWithModifiers.circom";
include "../lib/linked/linkId.circom";
include "../lib/utils/claimUtils.circom";
include "../lib/utils/safeOne.circom";
include "../lib/utils/spongeHash.circom";
include "../lib/utils/queryHash.circom";

// This circuit processes multiple query requests at once for a given claim using linked proof
template LinkedMultiQuery(N, claimLevels, valueArraySize) {
template LinkedMultiQuery(N, claimLevels, maxValueArraySize) {

// linked proof signals
signal input linkNonce;
signal input issuerClaim[8];

// query signals
signal input enabled[N]; // 1 if query non-empty, 0 to skip query check
signal input claimSchema;
signal input claimPathNotExists[N]; // 0 for inclusion, 1 for non-inclusion
signal input claimPathMtp[N][claimLevels];
signal input claimPathMtpNoAux[N]; // 1 if aux node is empty, 0 if non-empty or for inclusion proofs
signal input claimPathMtpAuxHi[N]; // 0 for inclusion proof
Expand All @@ -26,7 +24,8 @@ template LinkedMultiQuery(N, claimLevels, valueArraySize) {
signal input claimPathValue[N]; // value in this path in merklized json-ld document
signal input slotIndex[N];
signal input operator[N];
signal input value[N][valueArraySize];
signal input value[N][maxValueArraySize];
signal input valueArraySize[N];

// Outputs
signal output linkID;
Expand Down Expand Up @@ -55,25 +54,24 @@ template LinkedMultiQuery(N, claimLevels, valueArraySize) {
// Verify issuerClaim schema
verifyCredentialSchema()(one, issuerClaimHeader.schema, claimSchema); // 3 constraints

signal valueHash[N];
signal queryHash[N];

signal issuerClaimHash, issuerClaimHi, issuerClaimHv;
(issuerClaimHash, issuerClaimHi, issuerClaimHv) <== getClaimHash()(issuerClaim); // 834 constraints
////////////////////////////////////////////////////////////////////////
// calculate linkID
////////////////////////////////////////////////////////////////////////
linkID <== LinkID()(issuerClaimHash, linkNonce); // 243 constraints


signal operatorNotNoop[N];
/////////////////////////////////////////////////////////////////
// Query Processing Loop
/////////////////////////////////////////////////////////////////
for (var i=0; i<N; i++) {

operatorNotNoop[i] <== NOT()(IsZero()(operator[i]));

// output value only if modifier operation was selected
operatorOutput[i] <== ProcessQueryWithModifiers(claimLevels, valueArraySize)(
enabled[i],
claimPathNotExists[i],
operatorOutput[i] <== ProcessQueryWithModifiers(claimLevels, maxValueArraySize)(
operatorNotNoop[i], // enabled
claimPathMtp[i],
claimPathMtpNoAux[i],
claimPathMtpAuxHi[i],
Expand All @@ -83,6 +81,7 @@ template LinkedMultiQuery(N, claimLevels, valueArraySize) {
slotIndex[i],
operator[i],
value[i],
valueArraySize[i],
issuerClaim,
merklized,
merklize.out
Expand All @@ -92,16 +91,18 @@ template LinkedMultiQuery(N, claimLevels, valueArraySize) {
// Calculate query hash
/////////////////////////////////////////////////////////////////
// 4950 constraints (SpongeHash+Poseidon)
valueHash[i] <== SpongeHash(valueArraySize, 6)(value[i]); // 6 - max size of poseidon hash available on-chain
queryHash[i] <== Poseidon(6)([
circuitQueryHash[i] <== QueryHash(maxValueArraySize)(
value[i],
claimSchema,
slotIndex[i],
operator[i],
claimPathKey[i],
claimPathNotExists[i],
valueHash[i]
]);

circuitQueryHash[i] <== Mux1()([0, queryHash[i]], enabled[i]);
valueArraySize[i],
merklized,
0,
0,
0
);
}

}
2 changes: 1 addition & 1 deletion circuits/linkedMultiQuery10.circom
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ pragma circom 2.1.1;

include "linked/multiQuery.circom";

component main {public [enabled]} = LinkedMultiQuery(10, 32, 64); // 164791 constraints
component main {public [valueArraySize]} = LinkedMultiQuery(10, 32, 64); // 175331 constraints
27 changes: 0 additions & 27 deletions circuits/offchain/credentialAtomicQueryV3OffChain.circom
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ template credentialAtomicQueryV3OffChain(issuerLevels, claimLevels, maxValueArra
/** Query */
signal input claimSchema;

signal input claimPathNotExists; // 0 for inclusion, 1 for non-inclusion
signal input claimPathMtp[claimLevels];
signal input claimPathMtpNoAux; // 1 if aux node is empty, 0 if non-empty or for inclusion proofs
signal input claimPathMtpAuxHi; // 0 for inclusion proof
Expand Down Expand Up @@ -209,38 +208,12 @@ template credentialAtomicQueryV3OffChain(issuerLevels, claimLevels, maxValueArra

merklized <== merklize.flag;

// check path/in node exists in merkletree specified by jsonldRoot
signal operatorNotNoop <== NOT()(IsZero()(operator));
SMTVerifier(claimLevels)(
enabled <== AND()(merklize.flag, operatorNotNoop), // if merklize flag 0 or NOOP operator skip MTP verification
fnc <== claimPathNotExists, // inclusion
root <== merklize.out,
siblings <== claimPathMtp,
oldKey <== claimPathMtpAuxHi,
oldValue <== claimPathMtpAuxHv,
isOld0 <== claimPathMtpNoAux,
key <== claimPathKey,
value <== claimPathValue
); // 9585 constraints

// select value from claim by slot index (0-7)
signal slotValue <== getValueByIndex()(issuerClaim, slotIndex);

// select value for query verification,
// if claim is merklized merklizeFlag = `1|2`, take claimPathValue
// if not merklized merklizeFlag = `0`, take value from selected slot
signal fieldValue <== Mux1()(
[slotValue, claimPathValue],
merklize.flag
);

/////////////////////////////////////////////////////////////////
// Process Query with Modifiers
/////////////////////////////////////////////////////////////////
// output value only if modifier operation was selected
operatorOutput <== ProcessQueryWithModifiers(claimLevels, maxValueArraySize)(
one,
claimPathNotExists,
claimPathMtp,
claimPathMtpNoAux,
claimPathMtpAuxHi,
Expand Down
38 changes: 20 additions & 18 deletions circuits/onchain/credentialAtomicQueryV3OnChain.circom
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ include "../lib/query/query.circom";
include "../lib/utils/idUtils.circom";
include "../lib/utils/spongeHash.circom";
include "../offchain/credentialAtomicQueryV3OffChain.circom";
include "../lib/utils/queryHash.circom";

/**
credentialAtomicQueryV3OnChain.circom - query claim value and verify claim issuer signature or mtp:
Expand All @@ -31,13 +32,6 @@ idOwnershipLevels - Merkle tree depth level for personal claims
onChainLevels - Merkle tree depth level for Auth claim on-chain
*/
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
// if it is not set verification is performed on according to the slotIndex. Value selected from the
// provided slot. For example if slotIndex is `1` value gets from `i_1` slot. If `4` from `v_1`.
signal output merklized;

// userID output signal will be assigned with ProfileID SelectProfile(UserGenesisID, nonce)
// unless nonce == 0, in which case userID will be assigned with userGenesisID
signal output userID;
Expand Down Expand Up @@ -113,7 +107,6 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, maxValueArray
/** Query */
signal input claimSchema;

signal input claimPathNotExists; // 0 for inclusion, 1 for non-inclusion
signal input claimPathMtp[claimLevels];
signal input claimPathMtpNoAux; // 1 if aux node is empty, 0 if non-empty or for inclusion proofs
signal input claimPathMtpAuxHi; // 0 for inclusion proof
Expand Down Expand Up @@ -168,16 +161,23 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, maxValueArray
signal output operatorOutput;

// Enabled/disable checkAuthV2 verification
signal input authEnabled;
signal input isBJJAuthEnabled;

// 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
// if it is not set verification is performed on according to the slotIndex. Value selected from the
// provided slot. For example if slotIndex is `1` value gets from `i_1` slot. If `4` from `v_1`.
signal merklized;

/////////////////////////////////////////////////////////////////
// Auth check
/////////////////////////////////////////////////////////////////

ForceEqualIfEnabled()(NOT()(authEnabled), [profileNonce, 0]);
ForceEqualIfEnabled()(NOT()(isBJJAuthEnabled), [profileNonce, 0]);

checkAuthV2(idOwnershipLevels, onChainLevels)(
authEnabled, // enabled
isBJJAuthEnabled, // enabled
userGenesisID,
userState, // user state
userClaimsTreeRoot,
Expand Down Expand Up @@ -222,7 +222,6 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, maxValueArray
issuerClaimNonRevState <== issuerClaimNonRevState,
timestamp <== timestamp,
claimSchema <== claimSchema,
claimPathNotExists <== claimPathNotExists,
claimPathMtp <== claimPathMtp,
claimPathMtpNoAux <== claimPathMtpNoAux,
claimPathMtpAuxHi <== claimPathMtpAuxHi,
Expand Down Expand Up @@ -260,15 +259,18 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, maxValueArray
/////////////////////////////////////////////////////////////////
// Verify query hash matches
/////////////////////////////////////////////////////////////////
signal valueHash <== SpongeHash(maxValueArraySize, 6)(value); // 6 - max size of poseidon hash available on-chain

circuitQueryHash <== Poseidon(7)([
circuitQueryHash <== QueryHash(maxValueArraySize)(
value,
claimSchema,
slotIndex,
operator,
claimPathKey,
claimPathNotExists,
valueHash,
valueArraySize
]);
valueArraySize,
merklized,
isRevocationChecked,
verifierID,
nullifierSessionID
);

}
2 changes: 1 addition & 1 deletion test/query/query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1250,7 +1250,7 @@ describe("Test query", function () {
});

describe("#Invalid Query Ops", function () {
for (let op = 10; op < 32; op++) {
for (let op = 12; op < 32; op++) {
it("#Invalid Query Op " + op + " (false)", async () => {
const w = await circuit.calculateWitness({
in: "0",
Expand Down
Loading
Loading