From 7acf9f7f790d8e09acbb95b881844d215abbd436 Mon Sep 17 00:00:00 2001 From: vbasiuk Date: Fri, 23 Feb 2024 10:22:58 +0200 Subject: [PATCH 1/6] add valueArraySize public input to linkedMultiQuery --- circuits/linked/multiQuery.circom | 11 +++++++---- circuits/linkedMultiQuery10.circom | 2 +- .../onchain/credentialAtomicQueryV3OnChain.circom | 5 ++--- testvectorgen/credentials/onchain/v3/v3_test.go | 2 -- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/circuits/linked/multiQuery.circom b/circuits/linked/multiQuery.circom index 49d3f553..ba5d4e99 100644 --- a/circuits/linked/multiQuery.circom +++ b/circuits/linked/multiQuery.circom @@ -8,7 +8,7 @@ include "../lib/utils/safeOne.circom"; include "../lib/utils/spongeHash.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; @@ -26,7 +26,9 @@ 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; @@ -71,7 +73,7 @@ template LinkedMultiQuery(N, claimLevels, valueArraySize) { for (var i=0; i Date: Fri, 23 Feb 2024 17:29:15 +0200 Subject: [PATCH 2/6] changes --- circuits/credentialAtomicQueryV3.circom | 1 - .../credentialAtomicQueryV3OnChain.circom | 5 +-- .../query/processQueryWithModifiers.circom | 15 +++++-- circuits/lib/query/query.circom | 6 ++- circuits/lib/utils/arraySizeValidator.circom | 6 ++- circuits/lib/utils/queryHash.circom | 41 +++++++++++++++++++ circuits/linked/multiQuery.circom | 33 +++++++-------- circuits/linkedMultiQuery10.circom | 2 +- .../credentialAtomicQueryV3OffChain.circom | 27 ------------ .../credentialAtomicQueryV3OnChain.circom | 37 +++++++++-------- 10 files changed, 101 insertions(+), 72 deletions(-) create mode 100644 circuits/lib/utils/queryHash.circom diff --git a/circuits/credentialAtomicQueryV3.circom b/circuits/credentialAtomicQueryV3.circom index 8b51909d..4436e315 100644 --- a/circuits/credentialAtomicQueryV3.circom +++ b/circuits/credentialAtomicQueryV3.circom @@ -16,7 +16,6 @@ component main{public [requestID, claimSchema, slotIndex, claimPathKey, - claimPathNotExists, operator, value, valueArraySize, diff --git a/circuits/credentialAtomicQueryV3OnChain.circom b/circuits/credentialAtomicQueryV3OnChain.circom index da74bf17..9e56936d 100644 --- a/circuits/credentialAtomicQueryV3OnChain.circom +++ b/circuits/credentialAtomicQueryV3OnChain.circom @@ -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); diff --git a/circuits/lib/query/processQueryWithModifiers.circom b/circuits/lib/query/processQueryWithModifiers.circom index 2c8ac4b9..56992917 100644 --- a/circuits/lib/query/processQueryWithModifiers.circom +++ b/circuits/lib/query/processQueryWithModifiers.circom @@ -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 @@ -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 <== IsEqual()([operator, 12]); // for non-exist 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, @@ -53,6 +55,13 @@ template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){ merklized ); + // For non-merklized credentials exists / non-exist operators don't work + signal operatorNotEqExistOrNotExist <== NOT()(OR()(IsEqual()([operator, 11]), IsEqual()([operator, 12]))); + ForceEqualIfEnabled()( + AND()(enabled, NOT()(merklized)), + [1, operatorNotEqExistOrNotExist] + ); + ///////////////////////////////////////////////////////////////// // Query Operator Processing ///////////////////////////////////////////////////////////////// diff --git a/circuits/lib/query/query.circom b/circuits/lib/query/query.circom index 513a6282..cb27338d 100644 --- a/circuits/lib/query/query.circom +++ b/circuits/lib/query/query.circom @@ -20,6 +20,8 @@ include "comparators.circom"; 8 - greater than or equal 9 - between 10 - not between + 11 - exist + 12 - not exist Modifier/computation operators: 16 - selective disclosure (16 = 10000 binary) */ @@ -76,8 +78,8 @@ 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[12] <== 0; // not used + queryOpSatisfied.c[11] <== 1; // exist; skip execution + queryOpSatisfied.c[12] <== 1; // not exist; skip execution queryOpSatisfied.c[13] <== 0; // not used queryOpSatisfied.c[14] <== 0; // not used queryOpSatisfied.c[15] <== 0; // not used diff --git a/circuits/lib/utils/arraySizeValidator.circom b/circuits/lib/utils/arraySizeValidator.circom index 8b188b9e..8fc4ce80 100644 --- a/circuits/lib/utils/arraySizeValidator.circom +++ b/circuits/lib/utils/arraySizeValidator.circom @@ -19,6 +19,8 @@ include "../query/comparators.circom"; 8 - greater than or equal - 1 element 9 - between - 2 elements 10 - not between - 2 elements + 11 - exist - 0 elements + 12 - not exist - 0 elements Modifier/computation operators: 16 - selective disclosure (16 = 10000 binary) - 0 elements 17-31 - 0 elements @@ -62,8 +64,8 @@ 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[12] <== sizeEqZero; // not used + mux.c[11] <== sizeEqZero; // exist + mux.c[12] <== sizeEqZero; // not exist mux.c[13] <== sizeEqZero; // not used mux.c[14] <== sizeEqZero; // not used mux.c[15] <== sizeEqZero; // not used diff --git a/circuits/lib/utils/queryHash.circom b/circuits/lib/utils/queryHash.circom new file mode 100644 index 00000000..7d6a5f81 --- /dev/null +++ b/circuits/lib/utils/queryHash.circom @@ -0,0 +1,41 @@ +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 claimPathNotExists; + signal input valueArraySize; + signal input merklized; + signal input verifierID; + signal input isRevocationChecked; + signal input nullifierSessionID; + + signal output out; + + ///////////////////////////////////////////////////////////////// + // 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, + verifierID, + isRevocationChecked, + nullifierSessionID + ]); +} \ No newline at end of file diff --git a/circuits/linked/multiQuery.circom b/circuits/linked/multiQuery.circom index ba5d4e99..03ebea8c 100644 --- a/circuits/linked/multiQuery.circom +++ b/circuits/linked/multiQuery.circom @@ -5,7 +5,7 @@ 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, maxValueArraySize) { @@ -15,9 +15,7 @@ template LinkedMultiQuery(N, claimLevels, maxValueArraySize) { 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 @@ -29,7 +27,6 @@ template LinkedMultiQuery(N, claimLevels, maxValueArraySize) { signal input value[N][maxValueArraySize]; signal input valueArraySize[N]; - // Outputs signal output linkID; signal output merklized; @@ -57,9 +54,6 @@ template LinkedMultiQuery(N, claimLevels, maxValueArraySize) { // 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 //////////////////////////////////////////////////////////////////////// @@ -67,15 +61,18 @@ template LinkedMultiQuery(N, claimLevels, maxValueArraySize) { //////////////////////////////////////////////////////////////////////// linkID <== LinkID()(issuerClaimHash, linkNonce); // 243 constraints + + signal operatorNotNoop[N]; + signal claimPathNotExists[N]; ///////////////////////////////////////////////////////////////// // Query Processing Loop ///////////////////////////////////////////////////////////////// for (var i=0; i Date: Fri, 23 Feb 2024 18:40:05 +0200 Subject: [PATCH 3/6] exists with true/false --- .../query/processQueryWithModifiers.circom | 2 +- circuits/lib/query/query.circom | 5 +- circuits/lib/utils/arraySizeValidator.circom | 7 +- circuits/lib/utils/queryHash.circom | 5 +- circuits/linked/multiQuery.circom | 3 - .../credentialAtomicQueryV3OnChain.circom | 1 - .../credentialAtomicQueryV3OnChain.test.ts | 2 +- test/query/query.test.ts | 2 +- .../credentials/onchain/v3/v3_test.go | 114 ++++++++++-------- testvectorgen/credentials/v3/v3_test.go | 30 ++--- testvectorgen/utils/constants.go | 1 + 11 files changed, 88 insertions(+), 84 deletions(-) diff --git a/circuits/lib/query/processQueryWithModifiers.circom b/circuits/lib/query/processQueryWithModifiers.circom index 56992917..4331d37a 100644 --- a/circuits/lib/query/processQueryWithModifiers.circom +++ b/circuits/lib/query/processQueryWithModifiers.circom @@ -29,7 +29,7 @@ template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){ signal operatorNotNoop <== NOT()(IsZero()(operator)); signal merklizedAndEnabled <== AND()(enabled, merklized); - signal claimPathNotExists <== IsEqual()([operator, 12]); // for non-exist operator 1, else 0 + 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)( diff --git a/circuits/lib/query/query.circom b/circuits/lib/query/query.circom index cb27338d..0cb2e59c 100644 --- a/circuits/lib/query/query.circom +++ b/circuits/lib/query/query.circom @@ -21,7 +21,6 @@ include "comparators.circom"; 9 - between 10 - not between 11 - exist - 12 - not exist Modifier/computation operators: 16 - selective disclosure (16 = 10000 binary) */ @@ -78,8 +77,8 @@ template Query (maxValueArraySize) { queryOpSatisfied.c[8] <== gte; // gte === !lt queryOpSatisfied.c[9] <== between; // between queryOpSatisfied.c[10] <== NOT()(between); // not between - queryOpSatisfied.c[11] <== 1; // exist; skip execution - queryOpSatisfied.c[12] <== 1; // not exist; skip execution + queryOpSatisfied.c[11] <== 1; // exists; + queryOpSatisfied.c[12] <== 0; // not used queryOpSatisfied.c[13] <== 0; // not used queryOpSatisfied.c[14] <== 0; // not used queryOpSatisfied.c[15] <== 0; // not used diff --git a/circuits/lib/utils/arraySizeValidator.circom b/circuits/lib/utils/arraySizeValidator.circom index 8fc4ce80..cbb2e1b5 100644 --- a/circuits/lib/utils/arraySizeValidator.circom +++ b/circuits/lib/utils/arraySizeValidator.circom @@ -19,8 +19,7 @@ include "../query/comparators.circom"; 8 - greater than or equal - 1 element 9 - between - 2 elements 10 - not between - 2 elements - 11 - exist - 0 elements - 12 - not exist - 0 elements + 11 - exists - 1 elements (true/false) Modifier/computation operators: 16 - selective disclosure (16 = 10000 binary) - 0 elements 17-31 - 0 elements @@ -64,8 +63,8 @@ template ArraySizeValidator (maxValueArraySize) { mux.c[8] <== sizeEqOne; // gte mux.c[9] <== sizeEqTwo; // between mux.c[10] <== sizeEqTwo; // not between - mux.c[11] <== sizeEqZero; // exist - mux.c[12] <== sizeEqZero; // not exist + mux.c[11] <== sizeEqOne; // exist + mux.c[12] <== sizeEqZero; // not used mux.c[13] <== sizeEqZero; // not used mux.c[14] <== sizeEqZero; // not used mux.c[15] <== sizeEqZero; // not used diff --git a/circuits/lib/utils/queryHash.circom b/circuits/lib/utils/queryHash.circom index 7d6a5f81..6ac87469 100644 --- a/circuits/lib/utils/queryHash.circom +++ b/circuits/lib/utils/queryHash.circom @@ -7,7 +7,6 @@ template QueryHash(maxValueArraySize) { signal input slotIndex; signal input operator; signal input claimPathKey; - signal input claimPathNotExists; signal input valueArraySize; signal input merklized; signal input verifierID; @@ -16,6 +15,8 @@ template QueryHash(maxValueArraySize) { signal output out; + signal claimPathNotExists <== AND()(IsZero()(value[0]), IsEqual()([operator, 11])); + ///////////////////////////////////////////////////////////////// // Calculate query hash ///////////////////////////////////////////////////////////////// @@ -34,8 +35,8 @@ template QueryHash(maxValueArraySize) { firstPartQueryHash, valueArraySize, merklized, - verifierID, isRevocationChecked, + verifierID, nullifierSessionID ]); } \ No newline at end of file diff --git a/circuits/linked/multiQuery.circom b/circuits/linked/multiQuery.circom index 03ebea8c..c38b6f7b 100644 --- a/circuits/linked/multiQuery.circom +++ b/circuits/linked/multiQuery.circom @@ -63,7 +63,6 @@ template LinkedMultiQuery(N, claimLevels, maxValueArraySize) { signal operatorNotNoop[N]; - signal claimPathNotExists[N]; ///////////////////////////////////////////////////////////////// // Query Processing Loop ///////////////////////////////////////////////////////////////// @@ -92,14 +91,12 @@ template LinkedMultiQuery(N, claimLevels, maxValueArraySize) { // Calculate query hash ///////////////////////////////////////////////////////////////// // 4950 constraints (SpongeHash+Poseidon) - claimPathNotExists[i] <== IsEqual()([operator[i], 12]); // for non-exist operator 1, else 0 circuitQueryHash[i] <== QueryHash(maxValueArraySize)( value[i], claimSchema, slotIndex[i], operator[i], claimPathKey[i], - claimPathNotExists[i], valueArraySize[i], merklized, 0, diff --git a/circuits/onchain/credentialAtomicQueryV3OnChain.circom b/circuits/onchain/credentialAtomicQueryV3OnChain.circom index 47cf9b23..bc852602 100644 --- a/circuits/onchain/credentialAtomicQueryV3OnChain.circom +++ b/circuits/onchain/credentialAtomicQueryV3OnChain.circom @@ -259,7 +259,6 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, maxValueArray ///////////////////////////////////////////////////////////////// // Verify query hash matches ///////////////////////////////////////////////////////////////// - signal claimPathNotExists <== IsEqual()([operator, 12]); // for non-exist operator 1, else 0 circuitQueryHash <== QueryHash(maxValueArraySize)( value, diff --git a/test/onchain/credentialAtomicQueryV3OnChain.test.ts b/test/onchain/credentialAtomicQueryV3OnChain.test.ts index 64e1d4b7..e4e29d71 100644 --- a/test/onchain/credentialAtomicQueryV3OnChain.test.ts +++ b/test/onchain/credentialAtomicQueryV3OnChain.test.ts @@ -45,7 +45,7 @@ describe("Test credentialAtomicQueryV3OnChain.circom", function () { require(`${sigBasePath}/auth_check_disabled.json`), require(`${sigBasePath}/noop_operator.json`), - // mtp + // // mtp require(`${mtpBasePath}/claimIssuedOnProfileID.json`), require(`${mtpBasePath}/claimIssuedOnProfileID2.json`), require(`${mtpBasePath}/claimIssuedOnUserID.json`), diff --git a/test/query/query.test.ts b/test/query/query.test.ts index e48746d5..b31e2f8f 100644 --- a/test/query/query.test.ts +++ b/test/query/query.test.ts @@ -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", diff --git a/testvectorgen/credentials/onchain/v3/v3_test.go b/testvectorgen/credentials/onchain/v3/v3_test.go index 15061994..c70ac84c 100644 --- a/testvectorgen/credentials/onchain/v3/v3_test.go +++ b/testvectorgen/credentials/onchain/v3/v3_test.go @@ -84,13 +84,12 @@ type Inputs struct { // Query // JSON path - ClaimPathNotExists string `json:"claimPathNotExists"` // 0 for inclusion, 1 for non-inclusion - ClaimPathMtp []string `json:"claimPathMtp"` - ClaimPathMtpNoAux string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs - ClaimPathMtpAuxHi string `json:"claimPathMtpAuxHi"` // 0 for inclusion proof - ClaimPathMtpAuxHv string `json:"claimPathMtpAuxHv"` // 0 for inclusion proof - ClaimPathKey string `json:"claimPathKey"` // hash of path in merklized json-ld document - ClaimPathValue string `json:"claimPathValue"` // value in this path in merklized json-ld document + ClaimPathMtp []string `json:"claimPathMtp"` + ClaimPathMtpNoAux string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs + ClaimPathMtpAuxHi string `json:"claimPathMtpAuxHi"` // 0 for inclusion proof + ClaimPathMtpAuxHv string `json:"claimPathMtpAuxHv"` // 0 for inclusion proof + ClaimPathKey string `json:"claimPathKey"` // hash of path in merklized json-ld document + ClaimPathValue string `json:"claimPathValue"` // value in this path in merklized json-ld document Operator int `json:"operator"` SlotIndex int `json:"slotIndex"` @@ -121,7 +120,7 @@ type Inputs struct { VerifierID string `json:"verifierID"` NullifierSessionID string `json:"nullifierSessionID"` - AuthEnabled int `json:"authEnabled"` + IsBJJAuthEnabled int `json:"isBJJAuthEnabled"` } type Outputs struct { @@ -134,15 +133,12 @@ type Outputs struct { Timestamp string `json:"timestamp"` Merklized string `json:"merklized"` ProofType string `json:"proofType"` // 1 for sig, 2 for mtp - IsRevocationChecked string `json:"isRevocationChecked"` Challenge string `json:"challenge"` IssuerState string `json:"issuerState"` LinkID string `json:"linkID"` - VerifierID string `json:"verifierID"` - NullifierSessionID string `json:"nullifierSessionID"` OperatorOutput string `json:"operatorOutput"` Nullifier string `json:"nullifier"` - AuthEnabled string `json:"authEnabled"` + IsBJJAuthEnabled string `json:"isBJJAuthEnabled"` } type TestData struct { @@ -300,8 +296,8 @@ func generateRevokedTestData(t *testing.T, desc string, isUserIDProfile, isSubje } func generateTestDataWithOperator(t *testing.T, desc string, isUserIDProfile, isSubjectIDProfile bool, - linkNonce string, fileName string, operator int, value *[]string, proofType ProofType, authEnabled int) { - generateTestDataWithOperatorAndRevCheck(t, desc, isUserIDProfile, isSubjectIDProfile, linkNonce, "0", fileName, operator, value, false, 1, false, proofType, authEnabled) + linkNonce string, fileName string, operator int, value *[]string, proofType ProofType, isBJJAuthEnabled int) { + generateTestDataWithOperatorAndRevCheck(t, desc, isUserIDProfile, isSubjectIDProfile, linkNonce, "0", fileName, operator, value, false, 1, false, proofType, isBJJAuthEnabled) } func generateJSONLDTestData(t *testing.T, desc string, isUserIDProfile, isSubjectIDProfile bool, fileName string, proofType ProofType) { @@ -310,7 +306,7 @@ func generateJSONLDTestData(t *testing.T, desc string, isUserIDProfile, isSubjec func generateTestDataWithOperatorAndRevCheck(t *testing.T, desc string, isUserIDProfile, isSubjectIDProfile bool, linkNonce, nullifierSessionID, fileName string, operator int, value *[]string, isRevoked bool, isRevocationChecked int, isJSONLD bool, testProofType ProofType, - authEnabled int) { + isBJJAuthEnabled int) { var err error valueInput := []string{"10"} @@ -521,7 +517,6 @@ func generateTestDataWithOperatorAndRevCheck(t *testing.T, desc string, isUserID IssuerClaimNonRevMtpAuxHv: issuerClaimNonRevAux.Value, IssuerClaimNonRevMtpNoAux: issuerClaimNonRevAux.NoAux, ClaimSchema: "180410020913331409885634153623124536270", - ClaimPathNotExists: "0", // 0 for inclusion, 1 for non-inclusion ClaimPathMtp: claimPathMtp, ClaimPathMtpNoAux: claimPathMtpNoAux, ClaimPathMtpAuxHi: claimPathMtpAuxHi, @@ -555,38 +550,27 @@ func generateTestDataWithOperatorAndRevCheck(t *testing.T, desc string, isUserID VerifierID: "21929109382993718606847853573861987353620810345503358891473103689157378049", NullifierSessionID: nullifierSessionID, - AuthEnabled: authEnabled, + IsBJJAuthEnabled: isBJJAuthEnabled, } valuesHash, err := utils.PoseidonHashValue(utils.FromStringArrayToBigIntArray(inputs.Value)) require.NoError(t, err) claimSchemaInt, ok := big.NewInt(0).SetString(inputs.ClaimSchema, 10) require.True(t, ok) - circuitQueryHash, err := poseidon.Hash([]*big.Int{ - claimSchemaInt, - big.NewInt(int64(inputs.SlotIndex)), - big.NewInt(int64(inputs.Operator)), - pathKey, - big.NewInt(0), - valuesHash, - }) - require.NoError(t, err) linkID, err := utils.CalculateLinkID(linkNonce, claim) require.NoError(t, err) operatorOutput := "0" nullifier := "0" + verifierID, ok := big.NewInt(0).SetString(inputs.VerifierID, 10) + require.True(t, ok) + nullifierSessionID_, ok := big.NewInt(0).SetString(inputs.NullifierSessionID, 10) + require.True(t, ok) if inputs.NullifierSessionID != "0" { claimSchema, ok := big.NewInt(0).SetString(inputs.ClaimSchema, 10) require.True(t, ok) - verifierID, ok := big.NewInt(0).SetString(inputs.VerifierID, 10) - require.True(t, ok) - - nullifierSessionID_, ok := big.NewInt(0).SetString(inputs.NullifierSessionID, 10) - require.True(t, ok) - nullifier, err = utils.CalculateNullify( user.ID.BigInt(), nonceSubject, @@ -597,6 +581,27 @@ func generateTestDataWithOperatorAndRevCheck(t *testing.T, desc string, isUserID require.NoError(t, err) } + firstPartQueryHash, err := poseidon.Hash([]*big.Int{ + claimSchemaInt, + big.NewInt(int64(inputs.SlotIndex)), + big.NewInt(int64(inputs.Operator)), + pathKey, + big.NewInt(0), + valuesHash, + }) + require.NoError(t, err) + merklizedBigInt, ok := big.NewInt(0).SetString(merklized, 10) + require.True(t, ok) + circuitQueryHash, err := poseidon.Hash([]*big.Int{ + firstPartQueryHash, + big.NewInt(int64(valueArraySize)), + merklizedBigInt, + big.NewInt(int64(isRevocationChecked)), + verifierID, + nullifierSessionID_, + }) + require.NoError(t, err) + if operator == utils.SD { operatorOutput = big.NewInt(10).String() } @@ -620,15 +625,12 @@ func generateTestDataWithOperatorAndRevCheck(t *testing.T, desc string, isUserID Merklized: merklized, Challenge: challenge.String(), GistRoot: gistRoot.BigInt().String(), - IsRevocationChecked: strconv.Itoa(isRevocationChecked), ProofType: proofType, IssuerState: issuerState, LinkID: linkID, OperatorOutput: operatorOutput, - VerifierID: inputs.VerifierID, - NullifierSessionID: inputs.NullifierSessionID, Nullifier: nullifier, - AuthEnabled: strconv.Itoa(authEnabled), + IsBJJAuthEnabled: strconv.Itoa(isBJJAuthEnabled), } jsonData, err := json.Marshal(TestData{ @@ -673,6 +675,7 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj require.NoError(t, err) jsonP, _, err := mz.Proof(context.Background(), path) + require.NoError(t, err) claimJSONLDProof, claimJSONLDProofAux := utils.PrepareProof(jsonP, utils.ClaimLevels) @@ -758,16 +761,15 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj IssuerAuthState: issuer.State(t).String(), ClaimSchema: "180410020913331409885634153623124536270", - ClaimPathNotExists: "1", // 0 for inclusion, 1 for non-inclusion - ClaimPathMtp: claimJSONLDProof, - ClaimPathMtpNoAux: claimJSONLDProofAux.NoAux, // 1 if aux node is empty, 0 if non-empty or for inclusion proofs - ClaimPathMtpAuxHi: claimJSONLDProofAux.Key, // 0 for inclusion proof - ClaimPathMtpAuxHv: claimJSONLDProofAux.Value, // 0 for inclusion proof - ClaimPathKey: pathKey.String(), // hash of path in merklized json-ld document - ClaimPathValue: "0", // value in this path in merklized json-ld document + ClaimPathMtp: claimJSONLDProof, + ClaimPathMtpNoAux: claimJSONLDProofAux.NoAux, // 1 if aux node is empty, 0 if non-empty or for inclusion proofs + ClaimPathMtpAuxHi: claimJSONLDProofAux.Key, // 0 for inclusion proof + ClaimPathMtpAuxHv: claimJSONLDProofAux.Value, // 0 for inclusion proof + ClaimPathKey: pathKey.String(), // hash of path in merklized json-ld document + ClaimPathValue: "0", // value in this path in merklized json-ld document // value in this path in merklized json-ld document - Operator: utils.NOOP, + Operator: utils.NOT_EXISTS, SlotIndex: 0, Timestamp: timestamp, IsRevocationChecked: 1, @@ -788,7 +790,7 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj VerifierID: "21929109382993718606847853573861987353620810345503358891473103689157378049", NullifierSessionID: "0", - AuthEnabled: 1, + IsBJJAuthEnabled: 1, } issuerAuthState := issuer.State(t) @@ -797,7 +799,8 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj require.NoError(t, err) claimSchemaInt, ok := big.NewInt(0).SetString(inputs.ClaimSchema, 10) require.True(t, ok) - circuitQueryHash, err := poseidon.Hash([]*big.Int{ + + firstPartQueryHash, err := poseidon.Hash([]*big.Int{ claimSchemaInt, big.NewInt(int64(inputs.SlotIndex)), big.NewInt(int64(inputs.Operator)), @@ -806,6 +809,20 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj valuesHash, }) require.NoError(t, err) + verifierID, ok := big.NewInt(0).SetString(inputs.VerifierID, 10) + require.True(t, ok) + nullifierSessionID_, ok := big.NewInt(0).SetString(inputs.NullifierSessionID, 10) + require.True(t, ok) + + circuitQueryHash, err := poseidon.Hash([]*big.Int{ + firstPartQueryHash, + big.NewInt(int64(valueArraySize)), + big.NewInt(1), + big.NewInt(1), + verifierID, + nullifierSessionID_, + }) + require.NoError(t, err) out := Outputs{ RequestID: requestID.String(), @@ -818,14 +835,11 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj Challenge: challenge.String(), GistRoot: gistRoot.BigInt().String(), IssuerState: issuerAuthState.String(), - IsRevocationChecked: "1", ProofType: "1", LinkID: "0", - VerifierID: inputs.VerifierID, - NullifierSessionID: inputs.NullifierSessionID, OperatorOutput: "0", Nullifier: "0", - AuthEnabled: "1", + IsBJJAuthEnabled: "1", } jsonData, err := json.Marshal(TestData{ diff --git a/testvectorgen/credentials/v3/v3_test.go b/testvectorgen/credentials/v3/v3_test.go index 78e08cac..799c3323 100644 --- a/testvectorgen/credentials/v3/v3_test.go +++ b/testvectorgen/credentials/v3/v3_test.go @@ -60,13 +60,12 @@ type Inputs struct { // Query // JSON path - ClaimPathNotExists string `json:"claimPathNotExists"` // 0 for inclusion, 1 for non-inclusion - ClaimPathMtp []string `json:"claimPathMtp"` - ClaimPathMtpNoAux string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs - ClaimPathMtpAuxHi string `json:"claimPathMtpAuxHi"` // 0 for inclusion proof - ClaimPathMtpAuxHv string `json:"claimPathMtpAuxHv"` // 0 for inclusion proof - ClaimPathKey string `json:"claimPathKey"` // hash of path in merklized json-ld document - ClaimPathValue string `json:"claimPathValue"` // value in this path in merklized json-ld document + ClaimPathMtp []string `json:"claimPathMtp"` + ClaimPathMtpNoAux string `json:"claimPathMtpNoAux"` // 1 if aux node is empty, 0 if non-empty or for inclusion proofs + ClaimPathMtpAuxHi string `json:"claimPathMtpAuxHi"` // 0 for inclusion proof + ClaimPathMtpAuxHv string `json:"claimPathMtpAuxHv"` // 0 for inclusion proof + ClaimPathKey string `json:"claimPathKey"` // hash of path in merklized json-ld document + ClaimPathValue string `json:"claimPathValue"` // value in this path in merklized json-ld document Operator int `json:"operator"` SlotIndex int `json:"slotIndex"` @@ -107,7 +106,6 @@ type Outputs struct { SlotIndex string `json:"slotIndex"` Operator int `json:"operator"` ClaimPathKey string `json:"claimPathKey"` - ClaimPathNotExists string `json:"claimPathNotExists"` // 0 for inclusion, 1 for non-inclusion Value []string `json:"value"` ValueArraySize int `json:"valueArraySize"` Timestamp string `json:"timestamp"` @@ -483,7 +481,6 @@ func generateTestDataWithOperatorAndRevCheck(t *testing.T, desc string, isUserID IssuerClaimNonRevMtpAuxHv: issuerClaimNonRevAux.Value, IssuerClaimNonRevMtpNoAux: issuerClaimNonRevAux.NoAux, ClaimSchema: "180410020913331409885634153623124536270", - ClaimPathNotExists: "0", // 0 for inclusion, 1 for non-inclusion ClaimPathMtp: claimPathMtp, ClaimPathMtpNoAux: claimPathMtpNoAux, ClaimPathMtpAuxHi: claimPathMtpAuxHi, @@ -565,7 +562,6 @@ func generateTestDataWithOperatorAndRevCheck(t *testing.T, desc string, isUserID ClaimSchema: "180410020913331409885634153623124536270", SlotIndex: strconv.Itoa(slotIndex), ClaimPathKey: claimPathKey, - ClaimPathNotExists: "0", // 0 for inclusion, 1 for non-inclusion Operator: operator, Value: valueInput, ValueArraySize: valueArrSize, @@ -670,13 +666,12 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj IssuerAuthState: issuer.State(t).String(), ClaimSchema: "180410020913331409885634153623124536270", - ClaimPathNotExists: "1", // 0 for inclusion, 1 for non-inclusion - ClaimPathMtp: claimJSONLDProof, - ClaimPathMtpNoAux: claimJSONLDProofAux.NoAux, // 1 if aux node is empty, 0 if non-empty or for inclusion proofs - ClaimPathMtpAuxHi: claimJSONLDProofAux.Key, // 0 for inclusion proof - ClaimPathMtpAuxHv: claimJSONLDProofAux.Value, // 0 for inclusion proof - ClaimPathKey: pathKey.String(), // hash of path in merklized json-ld document - ClaimPathValue: "0", // value in this path in merklized json-ld document + ClaimPathMtp: claimJSONLDProof, + ClaimPathMtpNoAux: claimJSONLDProofAux.NoAux, // 1 if aux node is empty, 0 if non-empty or for inclusion proofs + ClaimPathMtpAuxHi: claimJSONLDProofAux.Key, // 0 for inclusion proof + ClaimPathMtpAuxHv: claimJSONLDProofAux.Value, // 0 for inclusion proof + ClaimPathKey: pathKey.String(), // hash of path in merklized json-ld document + ClaimPathValue: "0", // value in this path in merklized json-ld document // value in this path in merklized json-ld document Operator: utils.NOOP, @@ -712,7 +707,6 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj SlotIndex: "0", Operator: utils.NOOP, ClaimPathKey: pathKey.String(), - ClaimPathNotExists: "1", Value: utils.PrepareStrArray([]string{}, 64), ValueArraySize: 0, Timestamp: timestamp, diff --git a/testvectorgen/utils/constants.go b/testvectorgen/utils/constants.go index b288639b..67961766 100644 --- a/testvectorgen/utils/constants.go +++ b/testvectorgen/utils/constants.go @@ -15,6 +15,7 @@ const ( GTE BETWEEN NOT_BETWEEN + EXISTS SD = 16 ) From a83b3d28f7c0e5fc981a7ce90bdffd8a6f45f5ff Mon Sep 17 00:00:00 2001 From: vbasiuk Date: Fri, 23 Feb 2024 18:51:36 +0200 Subject: [PATCH 4/6] fix onchain --- circuits/linkedMultiQuery10.circom | 2 +- circuits/onchain/credentialAtomicQueryV3OnChain.circom | 1 - test/onchain/credentialAtomicQueryV3OnChain.test.ts | 2 +- testvectorgen/credentials/onchain/v3/v3_test.go | 4 ++-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/circuits/linkedMultiQuery10.circom b/circuits/linkedMultiQuery10.circom index 83ca75f3..3fb243af 100644 --- a/circuits/linkedMultiQuery10.circom +++ b/circuits/linkedMultiQuery10.circom @@ -2,4 +2,4 @@ pragma circom 2.1.1; include "linked/multiQuery.circom"; -component main {public [valueArraySize]} = LinkedMultiQuery(10, 32, 64); // 164791 constraints +component main {public [valueArraySize]} = LinkedMultiQuery(10, 32, 64); // 175331 constraints diff --git a/circuits/onchain/credentialAtomicQueryV3OnChain.circom b/circuits/onchain/credentialAtomicQueryV3OnChain.circom index bc852602..50ab9c4c 100644 --- a/circuits/onchain/credentialAtomicQueryV3OnChain.circom +++ b/circuits/onchain/credentialAtomicQueryV3OnChain.circom @@ -266,7 +266,6 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, maxValueArray slotIndex, operator, claimPathKey, - claimPathNotExists, valueArraySize, merklized, verifierID, diff --git a/test/onchain/credentialAtomicQueryV3OnChain.test.ts b/test/onchain/credentialAtomicQueryV3OnChain.test.ts index e4e29d71..cabef9a7 100644 --- a/test/onchain/credentialAtomicQueryV3OnChain.test.ts +++ b/test/onchain/credentialAtomicQueryV3OnChain.test.ts @@ -4,7 +4,7 @@ import {describe} from "mocha"; const path = require("path"); const wasmTester = require("circom_tester").wasm; -describe("Test credentialAtomicQueryV3OnChain.circom", function () { +describe.only("Test credentialAtomicQueryV3OnChain.circom", function () { this.timeout(600000); diff --git a/testvectorgen/credentials/onchain/v3/v3_test.go b/testvectorgen/credentials/onchain/v3/v3_test.go index c70ac84c..76a77b91 100644 --- a/testvectorgen/credentials/onchain/v3/v3_test.go +++ b/testvectorgen/credentials/onchain/v3/v3_test.go @@ -769,11 +769,11 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj ClaimPathValue: "0", // value in this path in merklized json-ld document // value in this path in merklized json-ld document - Operator: utils.NOT_EXISTS, + Operator: utils.EXISTS, SlotIndex: 0, Timestamp: timestamp, IsRevocationChecked: 1, - Value: utils.PrepareStrArray([]string{}, 64), + Value: utils.PrepareStrArray([]string{"0"}, 64), ValueArraySize: valueArraySize, // additional mtp inputs From f3e767221c93ce9fcc55cc36e06b030f834dc023 Mon Sep 17 00:00:00 2001 From: vbasiuk Date: Fri, 23 Feb 2024 19:01:16 +0200 Subject: [PATCH 5/6] fix arr size and op 12 --- circuits/lib/query/processQueryWithModifiers.circom | 4 ++-- test/onchain/credentialAtomicQueryV3OnChain.test.ts | 4 ++-- testvectorgen/credentials/onchain/v3/v3_test.go | 2 +- testvectorgen/utils/utils.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/circuits/lib/query/processQueryWithModifiers.circom b/circuits/lib/query/processQueryWithModifiers.circom index 4331d37a..769aa1da 100644 --- a/circuits/lib/query/processQueryWithModifiers.circom +++ b/circuits/lib/query/processQueryWithModifiers.circom @@ -56,10 +56,10 @@ template ProcessQueryWithModifiers(claimLevels, maxValueArraySize){ ); // For non-merklized credentials exists / non-exist operators don't work - signal operatorNotEqExistOrNotExist <== NOT()(OR()(IsEqual()([operator, 11]), IsEqual()([operator, 12]))); + signal operatorNotExists <== NOT()(IsEqual()([operator, 11])); ForceEqualIfEnabled()( AND()(enabled, NOT()(merklized)), - [1, operatorNotEqExistOrNotExist] + [1, operatorNotExists] ); ///////////////////////////////////////////////////////////////// diff --git a/test/onchain/credentialAtomicQueryV3OnChain.test.ts b/test/onchain/credentialAtomicQueryV3OnChain.test.ts index cabef9a7..64e1d4b7 100644 --- a/test/onchain/credentialAtomicQueryV3OnChain.test.ts +++ b/test/onchain/credentialAtomicQueryV3OnChain.test.ts @@ -4,7 +4,7 @@ import {describe} from "mocha"; const path = require("path"); const wasmTester = require("circom_tester").wasm; -describe.only("Test credentialAtomicQueryV3OnChain.circom", function () { +describe("Test credentialAtomicQueryV3OnChain.circom", function () { this.timeout(600000); @@ -45,7 +45,7 @@ describe.only("Test credentialAtomicQueryV3OnChain.circom", function () { require(`${sigBasePath}/auth_check_disabled.json`), require(`${sigBasePath}/noop_operator.json`), - // // mtp + // mtp require(`${mtpBasePath}/claimIssuedOnProfileID.json`), require(`${mtpBasePath}/claimIssuedOnProfileID2.json`), require(`${mtpBasePath}/claimIssuedOnUserID.json`), diff --git a/testvectorgen/credentials/onchain/v3/v3_test.go b/testvectorgen/credentials/onchain/v3/v3_test.go index 76a77b91..2f936d39 100644 --- a/testvectorgen/credentials/onchain/v3/v3_test.go +++ b/testvectorgen/credentials/onchain/v3/v3_test.go @@ -710,7 +710,7 @@ func generateJSONLD_NON_INCLUSION_TestData(t *testing.T, isUserIDProfile, isSubj gistRoot := gisTree.Root() gistProof, gistNodAux := utils.PrepareProof(gistProofRaw, utils.GistLevels) - valueArraySize := utils.GetValueArraySizeForOperator(utils.NOOP) + valueArraySize := utils.GetValueArraySizeForOperator(utils.EXISTS) inputs := Inputs{ RequestID: requestID.String(), diff --git a/testvectorgen/utils/utils.go b/testvectorgen/utils/utils.go index 1597c7cd..7a982c09 100644 --- a/testvectorgen/utils/utils.go +++ b/testvectorgen/utils/utils.go @@ -333,7 +333,7 @@ func CalculateNullify(genesisID, claimSubjectProfileNonce, claimSchema, verifier func GetValueArraySizeForOperator(operator int) int { result := 0 - oneArrLengthOps := []int{1, 2, 3, 6, 7, 8} + oneArrLengthOps := []int{1, 2, 3, 6, 7, 8, 11} twoArrLengthOps := []int{9, 10} maxArrLengthOps := []int{4, 5} From a1de18609fbceac440ab09e027b74f51ced4b364 Mon Sep 17 00:00:00 2001 From: vbasiuk Date: Fri, 23 Feb 2024 19:08:00 +0200 Subject: [PATCH 6/6] fix order --- circuits/lib/utils/queryHash.circom | 2 +- circuits/onchain/credentialAtomicQueryV3OnChain.circom | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/lib/utils/queryHash.circom b/circuits/lib/utils/queryHash.circom index 6ac87469..f21f53e0 100644 --- a/circuits/lib/utils/queryHash.circom +++ b/circuits/lib/utils/queryHash.circom @@ -9,8 +9,8 @@ template QueryHash(maxValueArraySize) { signal input claimPathKey; signal input valueArraySize; signal input merklized; - signal input verifierID; signal input isRevocationChecked; + signal input verifierID; signal input nullifierSessionID; signal output out; diff --git a/circuits/onchain/credentialAtomicQueryV3OnChain.circom b/circuits/onchain/credentialAtomicQueryV3OnChain.circom index 50ab9c4c..b3aca1b5 100644 --- a/circuits/onchain/credentialAtomicQueryV3OnChain.circom +++ b/circuits/onchain/credentialAtomicQueryV3OnChain.circom @@ -268,8 +268,8 @@ template credentialAtomicQueryV3OnChain(issuerLevels, claimLevels, maxValueArray claimPathKey, valueArraySize, merklized, - verifierID, isRevocationChecked, + verifierID, nullifierSessionID );