diff --git a/auth.go b/auth.go index e81df67..46a0cba 100644 --- a/auth.go +++ b/auth.go @@ -310,6 +310,83 @@ func CreateContractInvokeRequestWithMessage( } } +// ValidateAuthRequest verifies auth request message +func ValidateAuthRequest(request protocol.AuthorizationRequestMessage) error { + groupIDValidationMap := make(map[int][]pubsignals.Query) + + for _, proofRequest := range request.Body.Scope { + proofRequestQuery, err := unmarshalQuery(proofRequest.Query) + if err != nil { + return err + } + groupID := proofRequestQuery.GroupID + if groupID != 0 { + existingQueries := groupIDValidationMap[groupID] + + // Validate that all requests in the group have the same schema, issuer, and circuit + for _, existingQuery := range existingQueries { + if existingQuery.Type != proofRequestQuery.Type { + return errors.New("all requests in the group should have the same type") + } + + if existingQuery.Context != proofRequestQuery.Context { + return errors.New("all requests in the group should have the same context") + } + + allowedIssuers := proofRequestQuery.AllowedIssuers + existingRequestAllowedIssuers := existingQuery.AllowedIssuers + if !checkIssuersEquality(allowedIssuers, existingRequestAllowedIssuers) { + return errors.New("all requests in the group should have the same issuer") + } + } + + groupIDValidationMap[groupID] = append(existingQueries, proofRequestQuery) + } + } + + return nil +} + +func unmarshalQuery(queryMap map[string]interface{}) (out pubsignals.Query, err error) { + // prepare query from request + queryBytes, err := json.Marshal(queryMap) + if err != nil { + return out, err + } + err = json.Unmarshal(queryBytes, &out) + if err != nil { + return out, err + } + return out, nil +} + +func checkIssuersEquality(issuers1, issuers2 []string) bool { + if len(issuers1) != len(issuers2) { + return false + } + + for _, issuer := range issuers1 { + found := false + for _, existingIssuer := range issuers2 { + if issuer == existingIssuer || existingIssuer == "*" { + found = true + break + } + } + + if !found { + return false + } + } + + return true +} + +type linkIDRequestID struct { + linkID *big.Int + requestID uint32 +} + // VerifyAuthResponse performs verification of auth response based on auth request func (v *Verifier) VerifyAuthResponse( ctx context.Context, @@ -326,7 +403,23 @@ func (v *Verifier) VerifyAuthResponse( return errors.Errorf("sender of the request is not a target of response - expected %s, given %s", request.From, response.To) } + if response.From == "" { + return errors.Errorf("proof response doesn't contain from field") + } + + err := ValidateAuthRequest(request) + if err != nil { + return err + } + + groupIDToLinkIDMap := make(map[int][]linkIDRequestID) for _, proofRequest := range request.Body.Scope { + // prepare query from request + query, err := unmarshalQuery(proofRequest.Query) + if err != nil { + return err + } + proofResponse := findProofByRequestID(response.Body.Scope, proofRequest.ID) if proofResponse == nil { return errors.Errorf("proof for zk request id %v is presented not found", proofRequest.ID) @@ -349,17 +442,6 @@ func (v *Verifier) VerifyAuthResponse( return errors.Wrap(err, fmt.Sprintf("circuit with id %s is not supported by library", proofRequest.CircuitID)) } - // prepare query from request - queryBytes, err := json.Marshal(proofRequest.Query) - if err != nil { - return err - } - var query pubsignals.Query - err = json.Unmarshal(queryBytes, &query) - if err != nil { - return err - } - // verify proof author err = cv.VerifyIDOwnership(response.From, big.NewInt(int64(proofResponse.ID))) @@ -384,7 +466,7 @@ func (v *Verifier) VerifyAuthResponse( } proofRequest.Params[pubsignals.ParamNameVerifierDID] = verifierDID - err = cv.VerifyQuery(ctx, query, v.documentLoader, rawMessage, proofRequest.Params, opts...) + verifyResult, err := cv.VerifyQuery(ctx, query, v.documentLoader, rawMessage, proofRequest.Params, opts...) if err != nil { return err } @@ -394,8 +476,44 @@ func (v *Verifier) VerifyAuthResponse( return err } + err = verifyGroupIDMathch(verifyResult.LinkID, query.GroupID, proofResponse.ID, groupIDToLinkIDMap) + if err != nil { + return err + } + + } + + return nil +} + +func verifyGroupIDMathch(linkID *big.Int, groupID int, requestID uint32, groupIDToLinkIDMap map[int][]linkIDRequestID) error { + if groupID == 0 { + return nil + } + + if linkID == nil { + return errors.Errorf("Link id is not found for groupID %d", groupID) } + if existingLinks, exists := groupIDToLinkIDMap[groupID]; exists { + linkIDMap := linkIDRequestID{linkID: linkID, requestID: requestID} + groupIDToLinkIDMap[groupID] = append(existingLinks, linkIDMap) + } else { + linkIDMap := linkIDRequestID{linkID: linkID, requestID: requestID} + groupIDToLinkIDMap[groupID] = []linkIDRequestID{linkIDMap} + } + // verify grouping links + for groupIDfromMap, metas := range groupIDToLinkIDMap { + // Check that all linkIDs are the same + if len(metas) > 1 { + firstLinkID := metas[0].linkID + for _, meta := range metas[1:] { + if meta.linkID.Cmp(firstLinkID) != 0 { + return errors.Errorf("Link id validation failed for group %d, request linkID to requestIds info: %v", groupIDfromMap, metas) + } + } + } + } return nil } diff --git a/auth_test.go b/auth_test.go index faa856c..bba6de7 100644 --- a/auth_test.go +++ b/auth_test.go @@ -1140,3 +1140,83 @@ func TestVerifyV3MessageWithMtpProof_Merkalized(t *testing.T) { require.Nil(t, err) schemaLoader.assert(t) } + +func TestFullVerifyLinkedProofsVerification(t *testing.T) { + verifierID := "did:iden3:polygon:mumbai:wzokvZ6kMoocKJuSbftdZxTD6qvayGpJb3m4FVXth" + callbackURL := "https://test.com/callback" + reason := "test" + + request := CreateAuthorizationRequestWithMessage(reason, "mesage", verifierID, callbackURL) + + var mtpProofRequest1 protocol.ZeroKnowledgeProofRequest + mtpProofRequest1.ID = 1 + mtpProofRequest1.CircuitID = string(circuits.AtomicQueryV3CircuitID) + opt := false + mtpProofRequest1.Optional = &opt + mtpProofRequest1.Query = map[string]interface{}{ + "allowedIssuers": []string{"*"}, + "credentialSubject": map[string]interface{}{ + "documentType": map[string]interface{}{ + "$eq": 99, + }, + }, + "context": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld", + "type": "KYCAgeCredential", + "proofType": "BJJSignature2021", + } + + var mtpProofRequest2 protocol.ZeroKnowledgeProofRequest + mtpProofRequest2.ID = 2 + mtpProofRequest2.CircuitID = string(circuits.LinkedMultiQuery10CircuitID) + mtpProofRequest2.Optional = &opt + mtpProofRequest2.Query = map[string]interface{}{ + "groupId": 1, + "allowedIssuers": []string{"*"}, + "credentialSubject": map[string]interface{}{ + "documentType": map[string]interface{}{ + "$eq": 1, + }, + "position": map[string]interface{}{ + "$eq": "boss", + "$ne": "employee", + }, + }, + "context": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld", + "type": "KYCEmployee", + "proofType": "Iden3SparseMerkleTreeProof", + } + + var mtpProofRequest3 protocol.ZeroKnowledgeProofRequest + mtpProofRequest3.ID = 3 + mtpProofRequest3.CircuitID = string(circuits.AtomicQueryV3CircuitID) + mtpProofRequest3.Optional = &opt + mtpProofRequest3.Query = map[string]interface{}{ + "groupId": 1, + "allowedIssuers": []string{"*"}, + "credentialSubject": map[string]interface{}{ + "hireDate": map[string]interface{}{ + "$eq": "2023-12-11", + }, + }, + "context": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld", + "type": "KYCEmployee", + "proofType": "BJJSignature2021", + } + request.Body.Scope = append(append(append(request.Body.Scope, mtpProofRequest1), mtpProofRequest2), mtpProofRequest3) + + schemaLoader := &mockJSONLDSchemaLoader{ + schemas: map[string]string{ + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld": loadSchema("kyc-v101.json-ld"), + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld": loadSchema("kyc-nonmerklized.jsonld"), + }, + } + authInstance, err := NewVerifier(verificationKeyloader, stateResolvers, + WithDocumentLoader(schemaLoader)) + require.NoError(t, err) + + tokenString := "eyJhbGciOiJncm90aDE2IiwiY2lyY3VpdElkIjoiYXV0aFYyIiwiY3JpdCI6WyJjaXJjdWl0SWQiXSwidHlwIjoiYXBwbGljYXRpb24vaWRlbjMtemtwLWpzb24ifQ.eyJpZCI6IjUxMmRhMWVlLWQwODctNGEwMC1hMGYzLTZjNmZmYjI0Zjc5NyIsInR5cCI6ImFwcGxpY2F0aW9uL2lkZW4zLXprcC1qc29uIiwidHlwZSI6Imh0dHBzOi8vaWRlbjMtY29tbXVuaWNhdGlvbi5pby9hdXRob3JpemF0aW9uLzEuMC9yZXNwb25zZSIsInRoaWQiOiJmNWJjZGZjOS0zODE5LTQwNTItYWQ5Ny1jMDU5MTE5ZTU2M2MiLCJib2R5Ijp7Im1lc3NhZ2UiOiJtZXNhZ2UiLCJzY29wZSI6W3siaWQiOjEsImNpcmN1aXRJZCI6ImNyZWRlbnRpYWxBdG9taWNRdWVyeVYzLWJldGEuMCIsInByb29mIjp7InBpX2EiOlsiMzQxMzAwMzkwODI2MDM4MTU5MDE1NTM0Mzg4NjE2NjE0NDkxMzc2NTIyMDc1NTg2MzU1NjkyODI0Mzk1ODEzMDAxNzk5Mzg1NDM0OCIsIjE1MTQ3MDY1Mjk0ODU1Nzk2MTkzMTU3ODA0MzE5MDA1MTkyNzUyODEyNTIzOTIyMTg1ODQ5NjQ3MTY1NDUyNjQyNzc4NTYzMjE1NDgiLCIxIl0sInBpX2IiOltbIjE0NzU2MjM2MzIzNDQzMzU0OTE5MTA5MzMwNDIzMTAzMDE4ODQ4MjIwMDc1ODMyNzMwNDg4MzU0NTYzNjg5Njk1MDgxNjE2MzY4MzM5IiwiMTM1MTQyODk2NTg3NDM0MTk1NDYyNTQ3MzM1NDA5NzM0NjUzMjY5MTYyNzI3ODQ2MjUxMzE0NTE5MzEzOTM1MTE4MTU3MzA1NjMxMTEiXSxbIjgzOTQzODkxMzY2MTI1NTYxNDgzMzA3NDUyMjg3MTE3NTg4NDU4MTE0NjE4MTU4NDM2NzY0MDc4NzA2MTg3ODUzMzEwMDE5NzI3MzkiLCI1MTY0NjI0OTc0OTg4NDMwMDI3OTk2MjM3MDQyOTYyNDI2NzA3Mjc0Nzc3Mzg2ODU2NTY0Njk5MDU5MTU0NzA2MzQ1OTI1MjY3MjE5Il0sWyIxIiwiMCJdXSwicGlfYyI6WyI3NDI3NTQ4ODA3ODI1ODU1MDU3NjI1MTIxMjM4OTQxNjEzMjA4NDAzNTc5MzEwOTY3MDY4Mjk2OTMxNzQ3MTQ5Njc5NzA3ODg0OTEiLCIxNzI5ODE3NTY2NzMzNTMyNDk4ODM4NzM0Nzk3MTIxNDY1MzMxOTQwNjY1NzA1MDI5NjExMTg2NTc2MjQzMzAzMjAzMzQ2OTU1MTU0NiIsIjEiXSwicHJvdG9jb2wiOiJncm90aDE2IiwiY3VydmUiOiJibjEyOCJ9LCJwdWJfc2lnbmFscyI6WyIwIiwiMjE1NjgyMjU0Njk4ODk0NTgzMDU5MTQ4NDE0OTAxNzUyODAwOTM1NTUwMTUwNzEzMjk3ODczNzU2NDE0MzEyNjI1MDkyMDgwNjUiLCI0NDg3Mzg2MzMyNDc5NDg5MTU4MDAzNTk3ODQ0OTkwNDg3OTg0OTI1NDcxODEzOTA3NDYyNDgzOTA3MDU0NDI1NzU5NTY0MTc1MzQxIiwiMCIsIjAiLCIwIiwiMSIsIjEiLCIyNTE5MTY0MTYzNDg1Mzg3NTIwNzAxODM4MTI5MDQwOTMxNzg2MDE1MTU1MTMzNjEzMzU5NzI2NzA2MTcxNTY0MzYwMzA5NjA2NSIsIjEiLCI0NDg3Mzg2MzMyNDc5NDg5MTU4MDAzNTk3ODQ0OTkwNDg3OTg0OTI1NDcxODEzOTA3NDYyNDgzOTA3MDU0NDI1NzU5NTY0MTc1MzQxIiwiMTcwNTYwMDE0OCIsIjE5ODI4NTcyNjUxMDY4ODIwMDMzNTIwNzI3MzgzNjEyMzMzODY5OSIsIjEiLCIwIiwiMyIsIjEiLCI5OSIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIl19LHsiaWQiOjIsImNpcmN1aXRJZCI6ImxpbmtlZE11bHRpUXVlcnkxMC1iZXRhLjAiLCJwcm9vZiI6eyJwaV9hIjpbIjE1MzY2OTk0OTcyNzMzNTM0MTA2ODUwOTk5MDI2MjgzODkwMTgyMjcyOTQyNjQxNzUyMzc1MDM4ODcwMjc3Mzg4MDIxNTI5MDk0MDMiLCIxMTE1ODIyMzYwNTY3NTg2NTgyNTc3ODU4ODM2MTk1Nzc5MzMxMDg5MDA1MTkwNTg0NDk4MTM4MzA5OTcxNDA1NjY1Mjg4MjU2MTEzNCIsIjEiXSwicGlfYiI6W1siMTAxODU0OTk2NTE1MzUxODUzMDI5MzEwMjI4NTA5MTM1NTkyOTU5MDQ1ODIwNDY5NzkzNDQyMjQ4MDA1MTQyNTM1NTE3MDA5MTM0NTUiLCIyMTMxMzYwNDY4Mzk4MjY3MDA0MzUyMzE3ODg4NzQ3OTI4NDc3MjczOTkxMDEzNTUwNDE1ODcxODM5NjczMjAxOTI4ODE4MzIzMTM2MCJdLFsiMTM1MTYxNTAyNDI5NzEyMDYzOTEzNzMzNTEyMzMxMjg3NjE3OTg3MDExOTYzNzI0MjE1NTk1NDMzNzY3MjgwOTI4OTI2NzQ5MTU4OTciLCIyMDkxMzI4MzY1MTk3NjkzMjQ4MzQyNTQ3NDQyNzE1ODQ1MzA1OTU0MzExMjA3MTEzNTc1Mjc2MjE0OTMzODI3NDMzNzUxNTI5NTgyMCJdLFsiMSIsIjAiXV0sInBpX2MiOlsiMTY1OTg2NDcwNzIyMTczMjMzNDQzMTYzNjcwMjk0Mzc3MDE5ODA2MDU1NDg0MTExOTIwODQ1OTYzNDQ1NDkwNzA1MzU1MDcyNjIxOTQiLCIzMTUxMzY4NDcyNzA2NDA0MDY2NzgxMTgyODQyNzM1Mzk3NDQyNjE0MTgyMjc4NzM2NDA4NzExMTI5MTI2MzEwNDQ4NTg5ODU3NDYyIiwiMSJdLCJwcm90b2NvbCI6Imdyb3RoMTYiLCJjdXJ2ZSI6ImJuMTI4In0sInB1Yl9zaWduYWxzIjpbIjYxMjA0MzM3MDM3NzE4MjE2NjUyOTkxMjI4NjM4MTA2NjIzNTg0NzA1OTMzOTMxMDA2NDI2NjkzMjEyOTY0MzM0OTE0MTEwNjA4NjgiLCIxIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjEwMzQxNTc0NDQ4Mzg2NDg1MzM4MTI2MjEyNjk0Nzg5MjI0Njc2MjYxNzk4MTQwMTMyMDQ2NDk2MjA0NzMwNDQyNzQ2NzA3NzQzMzUwIiwiMTQ0NjA3Njc5OTUwMjA0NzgwOTM1MzMxNDE2MzExODMwNjM4MTMyMTk4Njk1OTI0NDcwMzgzODE1MTE4ODEyMzM3NjA2MjIyMDg3MiIsIjM2NDI3NzM5NDA2MDE5NzI0MDg2NzI5OTM0ODE0MDU2MjgxNjE4Mjc1MTE2MjI3MDE1ODAxNDIyNDI2OTExMjcwMjExMTk4MTA1OTYiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMSIsIjEiLCIxIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCJdfSx7ImlkIjozLCJjaXJjdWl0SWQiOiJjcmVkZW50aWFsQXRvbWljUXVlcnlWMy1iZXRhLjAiLCJwcm9vZiI6eyJwaV9hIjpbIjIxMTgyODU0ODU2MDM1Mzc4NjU2NTQwNzI0ODM2MDk1NTcxMzQxNjg1OTg4NDU2NjI1OTgwNjQxNzE2OTA0NDYwMjY0MjYzODg3Nzc0IiwiMTM3NDk1NDgyMjUzODgxMzQzNjU5NDE1MTAxNjIwNzI2NzU0MTQ0NDcyMDIyOTU2MzAwNTczMDE1ODM3NTg1MTc2NjA0NDk3MjY5MjgiLCIxIl0sInBpX2IiOltbIjE1MTY4NjIwNTc0NTI5OTQ2Mjg2OTkyOTQwOTkwMTc4Mjg0NzMzNjIxODYxNDYzMDA5ODk0OTY1MjcyMDI1MDY0NzU0NjM3NTM2MDc5IiwiMTM2ODUwOTA1MzU4Nzk2OTY0MTk3OTk1MjIzODIzMTU5NzY4NjIwNDg0NzI1NjU4OTg4MzE5MDY0MjkwNzY2MTI2MTg5NDg1MjIzNDEiXSxbIjEwNzA1MzI1MzQyMjA4NzU2NjIxMDUzNTEyODI3OTM5MzAzMTQwNjMxMDUxMjY2MjQ1MTQ3NDYwNDc5NzYxNjY5MTg0NDEzMzYzMDciLCIxOTcwODUxMDAzNjUzNDU4ODA2OTg2NTY0OTM2NjA3Mjk1ODA2OTE2NjA5Mjc0OTYwNDI4Njc0MzkzMDA0OTY3ODMwNzY5OTA5NzU3NyJdLFsiMSIsIjAiXV0sInBpX2MiOlsiMTE3ODg3MjY5MDE3ODMzNTY1ODI2MDY5NjQ0NDkzNzM1MDU5NzMyOTU1MTM4MTUzNDg4NTE5NzMzNjI2MzY0NzExNjU0NTk3MjMxNTkiLCIxODczNzU1MTI2Nzg0NTUxMjgxMzY0MDY4MzcwNTY3MTEzODM2MDM1MDgwNDE5NTc4MzE3NzM1NDEzOTc3OTg0OTE3NTIyODE5NjI3MyIsIjEiXSwicHJvdG9jb2wiOiJncm90aDE2IiwiY3VydmUiOiJibjEyOCJ9LCJwdWJfc2lnbmFscyI6WyIxIiwiMjE1NjgyMjU0Njk4ODk0NTgzMDU5MTQ4NDE0OTAxNzUyODAwOTM1NTUwMTUwNzEzMjk3ODczNzU2NDE0MzEyNjI1MDkyMDgwNjUiLCI0NDg3Mzg2MzMyNDc5NDg5MTU4MDAzNTk3ODQ0OTkwNDg3OTg0OTI1NDcxODEzOTA3NDYyNDgzOTA3MDU0NDI1NzU5NTY0MTc1MzQxIiwiNjEyMDQzMzcwMzc3MTgyMTY2NTI5OTEyMjg2MzgxMDY2MjM1ODQ3MDU5MzM5MzEwMDY0MjY2OTMyMTI5NjQzMzQ5MTQxMTA2MDg2OCIsIjAiLCIwIiwiMSIsIjMiLCIyNTE5MTY0MTYzNDg1Mzg3NTIwNzAxODM4MTI5MDQwOTMxNzg2MDE1MTU1MTMzNjEzMzU5NzI2NzA2MTcxNTY0MzYwMzA5NjA2NSIsIjEiLCI0NDg3Mzg2MzMyNDc5NDg5MTU4MDAzNTk3ODQ0OTkwNDg3OTg0OTI1NDcxODEzOTA3NDYyNDgzOTA3MDU0NDI1NzU5NTY0MTc1MzQxIiwiMTcwNTYwMDE3MSIsIjIxOTU3ODYxNzA2NDU0MDAxNjIzNDE2MTY0MDM3NTc1NTg2NTQxMiIsIjAiLCIxMjk2MzUxNzU4MjY5MDYxMTczMzE3MTA1MDQxOTY4MDY3MDc3NDUxOTE0Mzg2MDg2MjIyOTMxNTE2MTk5MTk0OTU5ODY5NDYzODgyIiwiMCIsIjEiLCIxNzAyMjUyODAwMDAwMDAwMDAwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiXX1dfSwiZnJvbSI6ImRpZDppZGVuMzpwb2x5Z29uOm11bWJhaTp3dXc1dHlkWjdBQWQzZWZ3RXFQcHJucWppTkhSMjRqcXJ1U1BLbVYxViIsInRvIjoiZGlkOmlkZW4zOnBvbHlnb246bXVtYmFpOnd6b2t2WjZrTW9vY0tKdVNiZnRkWnhURDZxdmF5R3BKYjNtNEZWWHRoIn0.eyJwcm9vZiI6eyJwaV9hIjpbIjQyOTY1NTE0NjUxMDkzODE5NjQ2MDgzOTYwNDcyMDA2MDc1NjQ5MzgwODE4NjA0NjQ0MTIwMDEzOTE4MjYyMTM4NTU0MjMyNTc4OCIsIjIwODAxMjYwNTAyNzg2MTM4MDA3MjY1NDY1MjI3MjkzNzIyNDQ3ODkzNDEwMzYxODk4MzYxNTg4NTMyODU2MTg4NTM2NTI0NzE3NzciLCIxIl0sInBpX2IiOltbIjczNDIyNDI5NDI4NzE5Njc3NTc5NDg5ODIzMzE2MDgwMjk4OTkwMjg1OTM5NDgwMTExMzA4MjY3NzU4NjA0MTExMTUxMTYwMjkxMiIsIjE5NTcxMTQxMTAzOTIzMTg0ODMxNjUzMTI2MDAzNTg5MTI2NjcwMjIyNjg3Mzk3MTU0NjEyMzkxMDQzMjY3ODk5MDUyNTEwOTg3ODU1Il0sWyIyOTYyNDc2MDY4MTYwNzIzNzQ1MTE1Mjk4MDM0NDMxOTE5OTA4MzcyNDI1ODgwMjAzMjY0MTU2NjM5NDY0NzE3NjM4MDI2MTQwMTIyIiwiMTE3MzgyMTk0NDEwNzI1OTEzODY0NzAwMDQ4ODMzNDcwNDc2MDg2NDQ2MjM5OTI3NTI0NTg3NzYyNjgwOTIyMDQ1MDA0MDU5OTE0NzAiXSxbIjEiLCIwIl1dLCJwaV9jIjpbIjE5MDQ0MjA1NDU2OTM1NDYwNDE1NDE1MzQ0MTE5ODAzMjM1Mjc4MDQ3NzEwMTczODQyNzk0ODU4MDE4Mzg2NzQ2MDg4MzgwMTIyODk0IiwiNjk4MjExMjI1ODEyMzY4OTU4NjE0MDgzNzkxMzkzMTc5NzM1NDY2ODQwMTU4NzEyMTIyMjY3NzExMTQ1NzYxNzI3Mjc4NTk2ODM5OSIsIjEiXSwicHJvdG9jb2wiOiJncm90aDE2IiwiY3VydmUiOiJibjEyOCJ9LCJwdWJfc2lnbmFscyI6WyIyMTU2ODIyNTQ2OTg4OTQ1ODMwNTkxNDg0MTQ5MDE3NTI4MDA5MzU1NTAxNTA3MTMyOTc4NzM3NTY0MTQzMTI2MjUwOTIwODA2NSIsIjM1Mzk1NDg1NTE2OTc5MzEyNzQzMzU0OTg0NTU3NDYyMTcyMTczMDI0OTc3NTUyNjM4OTMzNjY2Mzk1NDU0NTk0ODQzODUxMzA1MDciLCIwIl19" + returnMsg, err := authInstance.FullVerify(context.Background(), tokenString, request, pubsignals.WithAcceptedProofGenerationDelay(proofGenerationDelay)) + require.Nil(t, err) + require.NotNil(t, returnMsg) + schemaLoader.assert(t) +} diff --git a/go.mod b/go.mod index f13713a..d2c6a10 100644 --- a/go.mod +++ b/go.mod @@ -8,12 +8,13 @@ require ( github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 github.com/iden3/contracts-abi/state/go/abi v1.0.0-beta.3 - github.com/iden3/go-circuits/v2 v2.0.1 + github.com/iden3/go-circuits/v2 v2.0.2-0.20240131165639-deb061a1b3e6 github.com/iden3/go-iden3-core/v2 v2.0.3 + github.com/iden3/go-iden3-crypto v0.0.15 github.com/iden3/go-jwz/v2 v2.0.1 github.com/iden3/go-rapidsnark/types v0.0.3 github.com/iden3/go-rapidsnark/verifier v0.0.5 - github.com/iden3/go-schema-processor/v2 v2.1.1 + github.com/iden3/go-schema-processor/v2 v2.3.1 github.com/iden3/iden3comm/v2 v2.1.0 github.com/ipfs/go-ipfs-api v0.7.0 github.com/piprate/json-gold v0.5.1-0.20230111113000-6ddbe6e6f19f @@ -39,7 +40,6 @@ require ( github.com/goccy/go-json v0.10.2 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect - github.com/iden3/go-iden3-crypto v0.0.15 // indirect github.com/iden3/go-merkletree-sql/v2 v2.0.4 // indirect github.com/iden3/go-rapidsnark/prover v0.0.10 // indirect github.com/iden3/go-rapidsnark/witness/v2 v2.0.0 // indirect @@ -78,7 +78,7 @@ require ( github.com/tklauser/numcpus v0.6.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect golang.org/x/crypto v0.12.0 // indirect - golang.org/x/sys v0.11.0 // indirect + golang.org/x/sys v0.15.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.1 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect diff --git a/go.sum b/go.sum index 9392cec..8f88ec8 100644 --- a/go.sum +++ b/go.sum @@ -109,8 +109,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= github.com/iden3/contracts-abi/state/go/abi v1.0.0-beta.3 h1:ZHFnK2dU3NJglY+igY48JLHWtNGN/Vhf5/L/qrFk/tM= github.com/iden3/contracts-abi/state/go/abi v1.0.0-beta.3/go.mod h1:TxgIrXCvxms3sbOdsy8kTvffUCIpEEifNy0fSXdkU4w= -github.com/iden3/go-circuits/v2 v2.0.1 h1:tcJtBE8aLJsf9qpBoTUKE143Mne025cunQnSExMXaKo= -github.com/iden3/go-circuits/v2 v2.0.1/go.mod h1:VIFIp51+IH0hOzjnKhb84bCeyq7hq76zX/C14ua6zh4= +github.com/iden3/go-circuits/v2 v2.0.2-0.20240131165639-deb061a1b3e6 h1:DoyzPqOZWkUBGAQc2UQbddWAD3HYF5QX1zP9b+KmSH8= +github.com/iden3/go-circuits/v2 v2.0.2-0.20240131165639-deb061a1b3e6/go.mod h1:VIFIp51+IH0hOzjnKhb84bCeyq7hq76zX/C14ua6zh4= github.com/iden3/go-iden3-core/v2 v2.0.3 h1:ce9Jbw10zDsinWXFc05SiK2Hof/wu4zV4/ai5gQy29k= github.com/iden3/go-iden3-core/v2 v2.0.3/go.mod h1:L9PxhWPvoS9qTb3inEkZBm1RpjHBt+VTwvxssdzbAdw= github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4= @@ -129,8 +129,8 @@ github.com/iden3/go-rapidsnark/witness/v2 v2.0.0 h1:mkY6VDfwKVJc83QGKmwVXY2LYepi github.com/iden3/go-rapidsnark/witness/v2 v2.0.0/go.mod h1:3JRjqUfW1hgI9hzLDO0v8z/DUkR0ZUehhYLlnIfRxnA= github.com/iden3/go-rapidsnark/witness/wazero v0.0.0-20230524142950-0986cf057d4e h1:WeiFCrpj5pLRtSA4Mg03yTrSZhHHqN/k5b6bwxd9/tY= github.com/iden3/go-rapidsnark/witness/wazero v0.0.0-20230524142950-0986cf057d4e/go.mod h1:UEBifEzw62T6VzIHJeHuUgeLg2U/J9ttf7hOwQEqnYk= -github.com/iden3/go-schema-processor/v2 v2.1.1 h1:kS9D2ynuF2hgLM9e+IHV0kt6Tz4W/wXv+TXwUVQQi6M= -github.com/iden3/go-schema-processor/v2 v2.1.1/go.mod h1:wIa6h8BPWnXBImIIElYu5eLVW513pHjyTOj6KyVHenQ= +github.com/iden3/go-schema-processor/v2 v2.3.1 h1:cjsfUZNgyPoHQDEES4vuVod948QC9l35QkoEIat0ghc= +github.com/iden3/go-schema-processor/v2 v2.3.1/go.mod h1:BcHVDZyn8q8vUlL+XpOo7hpwXmEjxzO8ao1LkvFsM+k= github.com/iden3/iden3comm/v2 v2.1.0 h1:op2X3y/H9khizcdoYKf3iRAQFt/l5dsip47sJu1kv7Q= github.com/iden3/iden3comm/v2 v2.1.0/go.mod h1:G+ufR/M28O3PKMVrkUqCuoYfjiEkGFWvf8oF2BmFC6c= github.com/ipfs/boxo v0.12.0 h1:AXHg/1ONZdRQHQLgG5JHsSC3XoE4DjCAMgK+asZvUcQ= @@ -305,8 +305,9 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -339,8 +340,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-jose/go-jose.v2 v2.6.1 h1:qEzJlIDmG9q5VO0M/o8tGS65QMHMS1w01TQJB1VPJ4U= gopkg.in/go-jose/go-jose.v2 v2.6.1/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= diff --git a/pubsignals/atomicMtpV2.go b/pubsignals/atomicMtpV2.go index f430565..43d1608 100644 --- a/pubsignals/atomicMtpV2.go +++ b/pubsignals/atomicMtpV2.go @@ -27,8 +27,8 @@ func (c *AtomicQueryMTPV2) VerifyQuery( verifiablePresentation json.RawMessage, _ map[string]interface{}, opts ...VerifyOpt, -) error { - return query.Check(ctx, schemaLoader, &CircuitOutputs{ +) (CircuitVerificationResult, error) { + pubSig := CircuitOutputs{ IssuerID: c.IssuerID, ClaimSchema: c.ClaimSchema, SlotIndex: c.SlotIndex, @@ -40,7 +40,10 @@ func (c *AtomicQueryMTPV2) VerifyQuery( ClaimPathNotExists: c.ClaimPathNotExists, ValueArraySize: c.ValueArraySize, IsRevocationChecked: c.IsRevocationChecked, - }, verifiablePresentation, false, opts...) + } + + err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, false, opts...) + return CircuitVerificationResult{}, err } // VerifyStates verifies user state and issuer claim issuance state in the smart contract. diff --git a/pubsignals/atomicSigV2.go b/pubsignals/atomicSigV2.go index b8ac6d1..49c814d 100644 --- a/pubsignals/atomicSigV2.go +++ b/pubsignals/atomicSigV2.go @@ -27,8 +27,8 @@ func (c *AtomicQuerySigV2) VerifyQuery( verifiablePresentation json.RawMessage, _ map[string]interface{}, opts ...VerifyOpt, -) error { - err := query.Check(ctx, schemaLoader, &CircuitOutputs{ +) (CircuitVerificationResult, error) { + pubSig := CircuitOutputs{ IssuerID: c.IssuerID, ClaimSchema: c.ClaimSchema, SlotIndex: c.SlotIndex, @@ -40,11 +40,9 @@ func (c *AtomicQuerySigV2) VerifyQuery( ClaimPathNotExists: c.ClaimPathNotExists, ValueArraySize: c.ValueArraySize, IsRevocationChecked: c.IsRevocationChecked, - }, verifiablePresentation, false, opts...) - if err != nil { - return err } - return nil + err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, false, opts...) + return CircuitVerificationResult{}, err } // VerifyStates verifies user state and issuer auth claim state in the smart contract. diff --git a/pubsignals/atomicV3.go b/pubsignals/atomicV3.go index 2d8057b..5149296 100644 --- a/pubsignals/atomicV3.go +++ b/pubsignals/atomicV3.go @@ -28,8 +28,11 @@ func (c *AtomicQueryV3) VerifyQuery( verifiablePresentation json.RawMessage, params map[string]interface{}, opts ...VerifyOpt, -) error { - err := query.Check(ctx, schemaLoader, &CircuitOutputs{ +) (CircuitVerificationResult, error) { + output := CircuitVerificationResult{ + LinkID: c.LinkID, + } + pubSig := CircuitOutputs{ IssuerID: c.IssuerID, ClaimSchema: c.ClaimSchema, SlotIndex: c.SlotIndex, @@ -48,20 +51,21 @@ func (c *AtomicQueryV3) VerifyQuery( OperatorOutput: c.OperatorOutput, Nullifier: c.Nullifier, ProofType: c.ProofType, - }, verifiablePresentation, true, opts...) + } + err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, true, opts...) if err != nil { - return err + return output, err } // V3 NEW switch query.ProofType { case string(verifiable.BJJSignatureProofType): if c.ProofType != 1 { - return ErrWronProofType + return output, ErrWronProofType } case string(verifiable.Iden3SparseMerkleTreeProofType): if c.ProofType != 2 { - return ErrWronProofType + return output, ErrWronProofType } default: } @@ -71,35 +75,35 @@ func (c *AtomicQueryV3) VerifyQuery( if ok { verifierDID, ok := params[ParamNameVerifierDID].(*w3c.DID) if !ok { - return errors.New("verifier did is mandatory if nullifier session is set in the request") + return output, errors.New("verifier did is mandatory if nullifier session is set in the request") } id, err := core.IDFromDID(*verifierDID) if err != nil { - return err + return output, err } if c.VerifierID.BigInt().Cmp(id.BigInt()) != 0 { - return errors.New("wrong verifier is used for nullification") + return output, errors.New("wrong verifier is used for nullification") } nullifierSessionID, ok := new(big.Int).SetString(nullifierSessionIDparam, 10) if !ok { - return errors.New("nullifier session is not a valid big integer") + return output, errors.New("nullifier session is not a valid big integer") } if c.NullifierSessionID.Cmp(nullifierSessionID) != 0 { - return errors.Errorf("wrong verifier session id is used for nullification: expected %s given %s,", nullifierSessionID.String(), c.NullifierSessionID.String()) + return output, errors.Errorf("wrong verifier session id is used for nullification: expected %s given %s,", nullifierSessionID.String(), c.NullifierSessionID.String()) } } else if c.NullifierSessionID != nil && c.NullifierSessionID.Int64() != 0 { // if no nullifierSessionID in params - we need to verify that nullifier is zero - return errors.New("nullifier id is generated but wasn't requested") + return output, errors.New("nullifier id is generated but wasn't requested") } } if query.GroupID != 0 && c.LinkID == nil { - return errors.New("proof doesn't contain link id, but group id is provided") + return output, errors.New("proof doesn't contain link id, but group id is provided") } - return nil + return output, nil } // VerifyStates verifies user state and issuer auth claim state in the smart contract. diff --git a/pubsignals/authV2.go b/pubsignals/authV2.go index 40cfd95..22337ef 100644 --- a/pubsignals/authV2.go +++ b/pubsignals/authV2.go @@ -26,8 +26,8 @@ func (c *AuthV2) VerifyQuery( _ ld.DocumentLoader, _ json.RawMessage, _ map[string]interface{}, - _ ...VerifyOpt) error { - return errors.New("authV2 circuit doesn't support queries") + _ ...VerifyOpt) (CircuitVerificationResult, error) { + return CircuitVerificationResult{}, errors.New("authV2 circuit doesn't support queries") } // VerifyStates verify AuthV2 tests. diff --git a/pubsignals/circuitsVerifier.go b/pubsignals/circuitsVerifier.go index 7fc6c3d..e0c89de 100644 --- a/pubsignals/circuitsVerifier.go +++ b/pubsignals/circuitsVerifier.go @@ -18,7 +18,7 @@ type StateResolver interface { // Verifier is interface for verification of public signals of zkp type Verifier interface { - VerifyQuery(ctx context.Context, query Query, schemaLoader ld.DocumentLoader, verifiablePresentation json.RawMessage, circuitParams map[string]interface{}, opts ...VerifyOpt) error + VerifyQuery(ctx context.Context, query Query, schemaLoader ld.DocumentLoader, verifiablePresentation json.RawMessage, circuitParams map[string]interface{}, opts ...VerifyOpt) (CircuitVerificationResult, error) VerifyStates(ctx context.Context, resolvers map[string]StateResolver, opts ...VerifyOpt) error VerifyIDOwnership(userIdentifier string, challenge *big.Int) error diff --git a/pubsignals/common.go b/pubsignals/common.go new file mode 100644 index 0000000..e724a57 --- /dev/null +++ b/pubsignals/common.go @@ -0,0 +1,239 @@ +package pubsignals + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + + "github.com/iden3/go-circuits/v2" + "github.com/iden3/go-iden3-crypto/poseidon" + parser "github.com/iden3/go-schema-processor/v2/json" + "github.com/iden3/go-schema-processor/v2/merklize" + "github.com/iden3/go-schema-processor/v2/verifiable" + "github.com/piprate/json-gold/ld" + "github.com/pkg/errors" +) + +// PropertyQuery struct +type PropertyQuery struct { + FieldName string + Operator int + OperatorValue any +} + +// QueryMetadata struct describe query metadata +type QueryMetadata struct { + PropertyQuery + SlotIndex int + Values []*big.Int + Path *merklize.Path + ClaimPathKey *big.Int + Datatype string + MerklizedSchema bool +} + +const credentialSubjectFullKey = "https://www.w3.org/2018/credentials#credentialSubject" // #nosec G101 + +// ParseCredentialSubject parse credential subject and return array of property queries +func ParseCredentialSubject(_ context.Context, credentialSubject any) (out []PropertyQuery, err error) { + if credentialSubject == nil { + return []PropertyQuery{ + { + Operator: circuits.NOOP, + FieldName: "", + }, + }, nil + } + + out = []PropertyQuery{} + + jsonObject, ok := credentialSubject.(map[string]interface{}) + if !ok { + return nil, errors.New("Failed to convert credential subject to JSONObject") + } + + for fieldName, fieldReq := range jsonObject { + fieldReqEntries, ok := fieldReq.(map[string]interface{}) + if !ok { + return nil, errors.New("failed cast type map[string]interface") + } + isSelectiveDisclosure := len(fieldReqEntries) == 0 + + if isSelectiveDisclosure { + out = append(out, PropertyQuery{Operator: circuits.SD, FieldName: fieldName}) + continue + } + + for operatorName, operatorValue := range fieldReqEntries { + if _, exists := circuits.QueryOperators[operatorName]; !exists { + return nil, errors.New("operator is not supported by lib") + } + operator := circuits.QueryOperators[operatorName] + out = append(out, PropertyQuery{Operator: operator, FieldName: fieldName, OperatorValue: operatorValue}) + } + } + + return out, nil +} + +// ParseQueryMetadata parse property query and return query metadata +func ParseQueryMetadata(ctx context.Context, propertyQuery PropertyQuery, ldContextJSON, credentialType string, options merklize.Options) (query *QueryMetadata, err error) { + datatype, err := options.TypeFromContext([]byte(ldContextJSON), fmt.Sprintf("%s.%s", credentialType, propertyQuery.FieldName)) + if err != nil { + return nil, err + } + + query = &QueryMetadata{ + PropertyQuery: propertyQuery, + SlotIndex: 0, + MerklizedSchema: false, + Datatype: datatype, + ClaimPathKey: big.NewInt(0), + Values: []*big.Int{}, + Path: &merklize.Path{}, + } + + var ctxObj map[string]interface{} + err = json.Unmarshal([]byte(ldContextJSON), &ctxObj) + if err != nil { + return nil, err + } + + ldCtx, err := ld.NewContext(nil, nil).Parse(ctxObj["@context"]) + if err != nil { + return nil, err + } + + serAttr, err := verifiable.GetSerializationAttrFromParsedContext(ldCtx, credentialType) + if err != nil { + return nil, err + } + if serAttr == "" { + query.MerklizedSchema = true + } + + if !query.MerklizedSchema { + query.SlotIndex, err = parser.Parser{}.GetFieldSlotIndex(propertyQuery.FieldName, credentialType, []byte(ldContextJSON)) + if err != nil { + return nil, err + } + } else { + path := merklize.Path{} + if query.FieldName != "" { + path, err = options.FieldPathFromContext([]byte(ldContextJSON), credentialType, propertyQuery.FieldName) + if err != nil { + return nil, err + } + } + + err = path.Prepend(credentialSubjectFullKey) + if err != nil { + return nil, err + } + + query.ClaimPathKey, err = path.MtEntry() + if err != nil { + return nil, err + } + query.Path = &path + } + + if propertyQuery.OperatorValue != nil { + if !IsValidOperation(datatype, propertyQuery.Operator) { + operatorName, _ := getKeyByValue(circuits.QueryOperators, propertyQuery.Operator) + return nil, fmt.Errorf("invalid operation '%s' for field type '%s'", operatorName, datatype) + } + } + + query.Values, err = transformQueryValueToBigInts(ctx, propertyQuery.OperatorValue, datatype) + if err != nil { + return nil, err + } + + return query, err +} + +// ParseQueriesMetadata parse credential subject and return array of query metadata +func ParseQueriesMetadata(ctx context.Context, credentialType, ldContextJSON string, credentialSubject any, options merklize.Options) (out []QueryMetadata, err error) { + queriesMetadata, err := ParseCredentialSubject(ctx, credentialSubject) + if err != nil { + return nil, err + } + out = []QueryMetadata{} + for i := 0; i < len(queriesMetadata); i++ { + queryMetadata, err := ParseQueryMetadata(ctx, queriesMetadata[i], ldContextJSON, credentialType, options) + if err != nil { + return nil, err + } + out = append(out, *queryMetadata) + } + return out, err +} + +func transformQueryValueToBigInts(_ context.Context, value any, ldType string) (out []*big.Int, err error) { + if value == nil { + return out, nil + } + + listOfValues, ok := value.([]interface{}) + if ok { + out = make([]*big.Int, len(listOfValues)) + for i := 0; i < len(listOfValues); i++ { + if !isPositiveInteger(listOfValues[i]) { + return nil, ErrNegativeValue + } + out[i], err = merklize.HashValue(ldType, listOfValues[i]) + if err != nil { + return nil, err + } + } + return out, err + } + if !isPositiveInteger(value) { + return nil, ErrNegativeValue + } + hashValue, err := merklize.HashValue(ldType, value) + if err != nil { + return nil, err + } + + return []*big.Int{hashValue}, err +} + +func getKeyByValue(m map[string]int, targetValue int) (string, bool) { + for key, value := range m { + if value == targetValue { + return key, true + } + } + return "", false +} + +// CalculateQueryHash calculates query hash +func CalculateQueryHash( + values []*big.Int, + schemaHash *big.Int, + slotIndex int, + operator int, + claimPathKey *big.Int, + claimPathNotExists *big.Int) (*big.Int, error) { + circuitValues, err := circuits.PrepareCircuitArrayValues(values, 64) + if err != nil { + return nil, err + } + + valueHash, err := poseidon.SpongeHashX(circuitValues, 6) + if err != nil { + return nil, err + } + return poseidon.Hash([]*big.Int{ + schemaHash, + big.NewInt(int64(slotIndex)), + big.NewInt(int64(operator)), + claimPathKey, + claimPathNotExists, + valueHash, + }) + +} diff --git a/pubsignals/linkedMultiQuery.go b/pubsignals/linkedMultiQuery.go new file mode 100644 index 0000000..84762c3 --- /dev/null +++ b/pubsignals/linkedMultiQuery.go @@ -0,0 +1,126 @@ +package pubsignals + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "sort" + + "github.com/iden3/go-circuits/v2" + "github.com/iden3/go-schema-processor/v2/merklize" + "github.com/iden3/go-schema-processor/v2/utils" + "github.com/piprate/json-gold/ld" +) + +// LinkedMultiQuery is a wrapper for circuits.LinkedMultiQueryPubSignals. +type LinkedMultiQuery struct { + circuits.LinkedMultiQueryPubSignals +} + +// VerifyQuery verifies query for linked multi query 10 circuit. +func (c *LinkedMultiQuery) VerifyQuery( + ctx context.Context, + query Query, + schemaLoader ld.DocumentLoader, + _ json.RawMessage, + _ map[string]interface{}, + _ ...VerifyOpt, +) (CircuitVerificationResult, error) { + var outputs CircuitVerificationResult + schemaDoc, err := schemaLoader.LoadDocument(query.Context) + if err != nil { + return outputs, fmt.Errorf("failed load schema by context: %w", err) + } + + schemaBytes, err := json.Marshal(schemaDoc.Document) + if err != nil { + return outputs, fmt.Errorf("failed jsonify schema document: %w", err) + } + + schemaID, err := merklize.Options{DocumentLoader: schemaLoader}. + TypeIDFromContext(schemaBytes, query.Type) + if err != nil { + return outputs, err + } + schemaHash := utils.CreateSchemaHash([]byte(schemaID)) + + if schemaHash.BigInt() == nil { + return outputs, fmt.Errorf("query schema error") + } + + merkOption := merklize.Options{ + DocumentLoader: schemaLoader, + } + queriesMetadata, err := ParseQueriesMetadata(ctx, query.Type, string(schemaBytes), query.CredentialSubject, merkOption) + if err != nil { + return outputs, err + } + + queryHashes := []*big.Int{} + for i := 0; i < circuits.LinkedMultiQueryLength; i++ { + if i >= len(queriesMetadata) { + queryHashes = append(queryHashes, big.NewInt(0)) + continue + } + + merklizedSchema := big.NewInt(0) + if !queriesMetadata[i].MerklizedSchema { + merklizedSchema = big.NewInt(1) + } + + queryHash, err := CalculateQueryHash( + queriesMetadata[i].Values, + schemaHash.BigInt(), + queriesMetadata[i].SlotIndex, + queriesMetadata[i].Operator, + queriesMetadata[i].ClaimPathKey, + merklizedSchema) + + if err != nil { + return outputs, err + } + + queryHashes = append(queryHashes, queryHash) + } + + circuitQueryHashArray := make(bigIntArray, len(c.CircuitQueryHash)) + copy(circuitQueryHashArray, c.CircuitQueryHash) + sort.Sort(circuitQueryHashArray) + + calcQueryHashArray := make(bigIntArray, len(queryHashes)) + copy(calcQueryHashArray, queryHashes) + sort.Sort(calcQueryHashArray) + + if circuitQueryHashArray.Len() != calcQueryHashArray.Len() { + return outputs, fmt.Errorf("query hashes do not match") + } + + for i := 0; i < circuitQueryHashArray.Len(); i++ { + if circuitQueryHashArray[i].Cmp(calcQueryHashArray[i]) != 0 { + return outputs, fmt.Errorf("query hashes do not match") + } + } + + outputs = CircuitVerificationResult{ + LinkID: c.LinkID, + } + + return outputs, nil +} + +type bigIntArray []*big.Int + +func (a bigIntArray) Len() int { return len(a) } +func (a bigIntArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a bigIntArray) Less(i, j int) bool { return a[i].Cmp(a[j]) < 0 } + +// VerifyStates verifies user state and issuer auth claim state in the smart contract. +func (c *LinkedMultiQuery) VerifyStates(_ context.Context, _ map[string]StateResolver, _ ...VerifyOpt) error { + return nil +} + +// VerifyIDOwnership returns error if ownership id wasn't verified in circuit. +func (c *LinkedMultiQuery) VerifyIDOwnership(_ string, _ *big.Int) error { + return nil +} diff --git a/pubsignals/query.go b/pubsignals/query.go index b066970..3a06ab8 100644 --- a/pubsignals/query.go +++ b/pubsignals/query.go @@ -71,6 +71,11 @@ type Query struct { GroupID int `json:"groupId"` } +// CircuitVerificationResult struct for verification result. +type CircuitVerificationResult struct { + LinkID *big.Int +} + // CircuitOutputs pub signals from circuit. type CircuitOutputs struct { IssuerID *core.ID @@ -229,59 +234,56 @@ func (q Query) verifyCredentialSubject( schemaLoader ld.DocumentLoader, supportSdOperator bool, ) error { - fieldName, predicate, err := extractQueryFields(q.CredentialSubject) + + ctx := context.Background() + + queriesMetadata, err := ParseQueriesMetadata(ctx, q.Type, string(ctxBytes), q.CredentialSubject, merklize.Options{DocumentLoader: schemaLoader}) if err != nil { return err } - var fieldType string - if fieldName != "" { - fieldType, err = merklize.Options{DocumentLoader: schemaLoader}. - TypeFromContext(ctxBytes, fmt.Sprintf("%s.%s", q.Type, fieldName)) - if err != nil { - return err - } + if len(queriesMetadata) > 1 { + return errors.New("multiple requests not supported") + } + + var metadata QueryMetadata + if len(queriesMetadata) == 1 { + metadata = queriesMetadata[0] } // validate selectivity disclosure request - if q.isSelectivityDisclosure(predicate) { - ctx := context.Background() - return q.validateDisclosure(ctx, pubSig, fieldName, + if metadata.Operator == circuits.SD { + return q.validateDisclosure(ctx, pubSig, metadata.FieldName, verifiablePresentation, schemaLoader, supportSdOperator) } // validate empty credential subject request - if q.isEmptyCredentialSubject(predicate, pubSig.Merklized) { + if q.isEmptyCredentialSubject(metadata.Operator, pubSig.Merklized) { return q.verifyEmptyCredentialSubject(pubSig) } - values, operator, err := parseFieldPredicate(fieldType, predicate) - if err != nil { - return err - } - - if operator != pubSig.Operator { + if metadata.Operator != pubSig.Operator { return ErrRequestOperator } - if operator == circuits.NOOP { + if metadata.Operator == circuits.NOOP { return nil } - if len(values) > len(pubSig.Value) { + if len(metadata.Values) > len(pubSig.Value) { return ErrValuesSize } - if len(values) < pubSig.ValueArraySize { - diff := pubSig.ValueArraySize - len(values) + if len(metadata.Values) < pubSig.ValueArraySize { + diff := pubSig.ValueArraySize - len(metadata.Values) for diff > 0 { - values = append(values, big.NewInt(0)) + metadata.Values = append(metadata.Values, big.NewInt(0)) diff-- } } - for i := 0; i < len(values); i++ { - if values[i].Cmp(pubSig.Value[i]) != 0 { + for i := 0; i < len(metadata.Values); i++ { + if metadata.Values[i].Cmp(pubSig.Value[i]) != 0 { return ErrInvalidValues } } @@ -387,46 +389,11 @@ func (q Query) verifyEmptyCredentialSubject( return nil } -func (q Query) isSelectivityDisclosure( - predicate map[string]interface{}) bool { - return q.CredentialSubject != nil && len(predicate) == 0 -} - func (q Query) isEmptyCredentialSubject( - predicate map[string]interface{}, + operator, isMerklized int, ) bool { - return q.CredentialSubject == nil && len(predicate) == 0 && isMerklized == 1 -} - -func parseFieldPredicate( - fieldType string, - fieldPredicate map[string]interface{}, -) ( - values []*big.Int, - operator int, - err error, -) { - for op, v := range fieldPredicate { - var ok bool - operator, ok = circuits.QueryOperators[op] - if !ok { - return nil, 0, errors.New("query operator is not supported") - } - - if !isValidOperation(fieldType, operator) { - return nil, 0, errors.Errorf("invalid operation '%s' for field type '%s'", op, fieldType) - } - - values, err = getValuesAsArray(v, fieldType) - if err != nil { - return nil, 0, err - } - - // only one predicate for field is supported - break - } - return values, operator, nil + return q.CredentialSubject == nil && operator == circuits.NOOP && isMerklized == 1 } func extractQueryFields(req map[string]interface{}) (fieldName string, fieldPredicate map[string]interface{}, err error) { @@ -450,37 +417,6 @@ func extractQueryFields(req map[string]interface{}) (fieldName string, fieldPred return fieldName, fieldPredicate, nil } -func getValuesAsArray(v interface{}, valueType string) ([]*big.Int, error) { - var values []*big.Int - - listOfValues, ok := v.([]interface{}) - if ok { - values = make([]*big.Int, len(listOfValues)) - for i, item := range listOfValues { - if !isPositiveInteger(item) { - return nil, ErrNegativeValue - } - hashedValue, err := merklize.HashValue(valueType, item) - if err != nil { - return nil, err - } - values[i] = hashedValue - } - return values, nil - } - - if !isPositiveInteger(v) { - return nil, ErrNegativeValue - } - hashedValue, err := merklize.HashValue(valueType, v) - if err != nil { - return nil, err - } - values = append(values, hashedValue) - - return values, nil -} - func isPositiveInteger(v interface{}) bool { number, err := strconv.ParseFloat(fmt.Sprintf("%v", v), 64) if err != nil { @@ -490,7 +426,8 @@ func isPositiveInteger(v interface{}) bool { return number >= 0 } -func isValidOperation(typ string, op int) bool { +// IsValidOperation checks if operation and type are supported. +func IsValidOperation(typ string, op int) bool { if op == circuits.NOOP { return true } diff --git a/pubsignals/query_test.go b/pubsignals/query_test.go index 94bf65a..6e7fd5c 100644 --- a/pubsignals/query_test.go +++ b/pubsignals/query_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/iden3/go-circuits/v2" core "github.com/iden3/go-iden3-core/v2" "github.com/iden3/go-schema-processor/v2/utils" "github.com/piprate/json-gold/ld" @@ -114,8 +115,11 @@ func TestCheckRequest_Success(t *testing.T) { v, _ := big.NewInt(0).SetString("17002437119434618783545694633038537380726339994244684348913844923422470806844", 10) return v }(), - Operator: 5, - Value: []*big.Int{big.NewInt(800)}, + Operator: 5, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(800)}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: now, @@ -143,8 +147,11 @@ func TestCheckRequest_Success(t *testing.T) { v, _ := big.NewInt(0).SetString("17002437119434618783545694633038537380726339994244684348913844923422470806844", 10) return v }(), - Operator: 1, - Value: []*big.Int{big.NewInt(800)}, + Operator: 1, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(800)}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: now, @@ -176,8 +183,11 @@ func TestCheckRequest_Success(t *testing.T) { v, _ := big.NewInt(0).SetString("1944808975288007371356450257872165609440470546066507760733183342797918372827", 10) return v }(), - Operator: 1, - Value: []*big.Int{bigIntTrueHash}, + Operator: 1, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{bigIntTrueHash}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: now, @@ -208,7 +218,8 @@ func TestCheckRequest_Success(t *testing.T) { Operator: 1, Value: func() []*big.Int { v, _ := big.NewInt(0).SetString("957410455271905675920624030785024750144198809104092676617070098470852489834", 10) - return []*big.Int{v} + r, _ := circuits.PrepareCircuitArrayValues([]*big.Int{v}, 64) + return r }(), Merklized: 1, IsRevocationChecked: 1, @@ -244,7 +255,8 @@ func TestCheckRequest_Success(t *testing.T) { Operator: 1, Value: func() []*big.Int { v, _ := big.NewInt(0).SetString("7481731651336040098616464366227645531920423822088928207225802836605991806542", 10) - return []*big.Int{v} + r, _ := circuits.PrepareCircuitArrayValues([]*big.Int{v}, 64) + return r }(), Merklized: 1, IsRevocationChecked: 1, @@ -270,10 +282,13 @@ func TestCheckRequest_Success(t *testing.T) { Type: "KYCAgeCredential", }, pubSig: &CircuitOutputs{ - IssuerID: &issuerID, - ClaimSchema: utils.CreateSchemaHash([]byte("https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld#KYCAgeCredential")), - Operator: 1, - Value: []*big.Int{big.NewInt(19960424)}, + IssuerID: &issuerID, + ClaimSchema: utils.CreateSchemaHash([]byte("https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld#KYCAgeCredential")), + Operator: 1, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(19960424)}, 64) + return v + }(), Merklized: 0, SlotIndex: 2, IsRevocationChecked: 1, @@ -327,8 +342,11 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) { v, _ := big.NewInt(0).SetString("17002437119434618783545694633038537380726339994244684348913844923422470806844", 10) return v }(), - Operator: 5, - Value: []*big.Int{big.NewInt(800)}, + Operator: 5, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(800)}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: dayAndMinuteAgo, @@ -358,8 +376,11 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) { v, _ := big.NewInt(0).SetString("17002437119434618783545694633038537380726339994244684348913844923422470806844", 10) return v }(), - Operator: 1, - Value: []*big.Int{big.NewInt(800)}, + Operator: 1, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(800)}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: now, @@ -389,8 +410,11 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) { v, _ := big.NewInt(0).SetString("17002437119434618783545694633038537380726339994244684348913844923422470806844", 10) return v }(), - Operator: 5, - Value: []*big.Int{big.NewInt(800)}, + Operator: 5, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(800)}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: now, @@ -421,8 +445,11 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) { v, _ := big.NewInt(0).SetString("17002437119434618783545694633038537380726339994244684348913844923422470806844", 10) return v }(), - Operator: 1, - Value: []*big.Int{big.NewInt(800), big.NewInt(801)}, + Operator: 1, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(800), big.NewInt(801)}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: now, @@ -453,8 +480,11 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) { v, _ := big.NewInt(0).SetString("17002437119434618783545694633038537380726339994244684348913844923422470806844", 10) return v }(), - Operator: 1, - Value: []*big.Int{big.NewInt(1)}, + Operator: 1, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(1)}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: now, @@ -485,8 +515,11 @@ func TestCheckRequest_SelectiveDisclosure_Error(t *testing.T) { v, _ := big.NewInt(0).SetString("17002437119434618783545694633038537380726339994244684348913844923422470806844", 10) return v }(), - Operator: 1, - Value: []*big.Int{big.NewInt(800)}, + Operator: 1, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(800)}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: now, @@ -556,8 +589,12 @@ func TestCheckRequest_Error(t *testing.T) { Context: "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld", Type: "KYCCountryOfResidenceCredential", CredentialSubject: map[string]interface{}{ - "req1": struct{}{}, - "req2": struct{}{}, + "countryCode": map[string]interface{}{ + "$nin": []interface{}{float64(800)}, + }, + "documentType": map[string]interface{}{ + "$eq": []interface{}{float64(1)}, + }, }, }, pubSig: &CircuitOutputs{ @@ -612,7 +649,7 @@ func TestCheckRequest_Error(t *testing.T) { ClaimSchema: utils.CreateSchemaHash([]byte("https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCCountryOfResidenceCredential")), Timestamp: now, }, - expErr: errors.New("multiple predicates for one field not supported"), + expErr: errors.New("multiple requests not supported"), loader: &mockJSONLDSchemaLoader{ schemas: map[string]string{ "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": loadSchema("kyc-v3.json-ld"), @@ -683,11 +720,14 @@ func TestCheckRequest_Error(t *testing.T) { }, }, pubSig: &CircuitOutputs{ - IssuerID: &issuerID, - ClaimSchema: utils.CreateSchemaHash([]byte("https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCCountryOfResidenceCredential")), - ClaimPathKey: big.NewInt(0), - Operator: 5, - Value: []*big.Int{big.NewInt(20)}, + IssuerID: &issuerID, + ClaimSchema: utils.CreateSchemaHash([]byte("https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCCountryOfResidenceCredential")), + ClaimPathKey: big.NewInt(0), + Operator: 5, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(20)}, 64) + return v + }(), Merklized: 1, IsRevocationChecked: 1, Timestamp: now, @@ -713,10 +753,13 @@ func TestCheckRequest_Error(t *testing.T) { SkipClaimRevocationCheck: false, }, pubSig: &CircuitOutputs{ - IssuerID: &issuerID, - ClaimSchema: utils.CreateSchemaHash([]byte("https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCCountryOfResidenceCredential")), - Operator: 5, - Value: []*big.Int{big.NewInt(20)}, + IssuerID: &issuerID, + ClaimSchema: utils.CreateSchemaHash([]byte("https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCCountryOfResidenceCredential")), + Operator: 5, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(20)}, 64) + return v + }(), Merklized: 0, SlotIndex: 0, IsRevocationChecked: 0, @@ -773,10 +816,13 @@ func TestCheckRequest_Error(t *testing.T) { SkipClaimRevocationCheck: false, }, pubSig: &CircuitOutputs{ - IssuerID: &issuerID, - ClaimSchema: utils.CreateSchemaHash([]byte("https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCEmployee")), - Operator: 1, - Value: []*big.Int{big.NewInt(-1)}, + IssuerID: &issuerID, + ClaimSchema: utils.CreateSchemaHash([]byte("https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCEmployee")), + Operator: 1, + Value: func() []*big.Int { + v, _ := circuits.PrepareCircuitArrayValues([]*big.Int{big.NewInt(-1)}, 64) + return v + }(), Merklized: 0, SlotIndex: 0, IsRevocationChecked: 0, diff --git a/pubsignals/signals.go b/pubsignals/signals.go index 1cd8adf..62d7e9b 100644 --- a/pubsignals/signals.go +++ b/pubsignals/signals.go @@ -39,6 +39,7 @@ func init() { RegisterVerifier(circuits.AtomicQuerySigV2CircuitID, reflect.TypeOf(AtomicQuerySigV2{})) RegisterVerifier(circuits.AtomicQueryMTPV2CircuitID, reflect.TypeOf(AtomicQueryMTPV2{})) RegisterVerifier(circuits.AtomicQueryV3CircuitID, reflect.TypeOf(AtomicQueryV3{})) + RegisterVerifier(circuits.LinkedMultiQuery10CircuitID, reflect.TypeOf(LinkedMultiQuery{})) } // GetVerifier return specific public signals verifier diff --git a/testdata/linkedMultiQuery10-beta.0.json b/testdata/linkedMultiQuery10-beta.0.json new file mode 100644 index 0000000..46ae7b7 --- /dev/null +++ b/testdata/linkedMultiQuery10-beta.0.json @@ -0,0 +1,249 @@ +{ + "protocol": "groth16", + "curve": "bn128", + "nPublic": 32, + "vk_alpha_1": [ + "20491192805390485299153009773594534940189261866228447918068658471970481763042", + "9383485363053290200918347156157836566562967994039712273449902621266178545958", + "1" + ], + "vk_beta_2": [ + [ + "6375614351688725206403948262868962793625744043794305715222011528459656738731", + "4252822878758300859123897981450591353533073413197771768651442665752259397132" + ], + [ + "10505242626370262277552901082094356697409835680220590971873171140371331206856", + "21847035105528745403288232691147584728191162732299865338377159692350059136679" + ], + [ + "1", + "0" + ] + ], + "vk_gamma_2": [ + [ + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + "11559732032986387107991004021392285783925812861821192530917403151452391805634" + ], + [ + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + "4082367875863433681332203403145435568316851327593401208105741076214120093531" + ], + [ + "1", + "0" + ] + ], + "vk_delta_2": [ + [ + "2025301863353232000972013557240148309214422648242279421706934248620545048185", + "3551619600991808388357165180788781746313251517891101323663177158010950752217" + ], + [ + "17583332576285310883608873974388941733637842531453940965578108779722230390927", + "8482107556219683638671195415676667428287733488840146328098864921260483220214" + ], + [ + "1", + "0" + ] + ], + "vk_alphabeta_12": [ + [ + [ + "2029413683389138792403550203267699914886160938906632433982220835551125967885", + "21072700047562757817161031222997517981543347628379360635925549008442030252106" + ], + [ + "5940354580057074848093997050200682056184807770593307860589430076672439820312", + "12156638873931618554171829126792193045421052652279363021382169897324752428276" + ], + [ + "7898200236362823042373859371574133993780991612861777490112507062703164551277", + "7074218545237549455313236346927434013100842096812539264420499035217050630853" + ] + ], + [ + [ + "7077479683546002997211712695946002074877511277312570035766170199895071832130", + "10093483419865920389913245021038182291233451549023025229112148274109565435465" + ], + [ + "4595479056700221319381530156280926371456704509942304414423590385166031118820", + "19831328484489333784475432780421641293929726139240675179672856274388269393268" + ], + [ + "11934129596455521040620786944827826205713621633706285934057045369193958244500", + "8037395052364110730298837004334506829870972346962140206007064471173334027475" + ] + ] + ], + "IC": [ + [ + "10541428299192672828090146726310028144214115510043465603884001583956478733429", + "14328132802731818427319150206314497389123355110123928741488208992580841856174", + "1" + ], + [ + "4484772297774190750623733702547437770305308218349262680805791597413864664278", + "9598306942051399840850577448579181247393138994351754986337653603136701178911", + "1" + ], + [ + "6807202197420458315968368908975458563904216882973970114314426621295604767865", + "8245544555687995202365054959643868544511252857077680460626102987168216381848", + "1" + ], + [ + "18011444057994110318711949352711947469615610267740333073745530857224367586444", + "19487620324218326297149313027649958050079526129789007550303497455410884637231", + "1" + ], + [ + "14172067611424599901434744093758830350088287735420135896480515745151683109132", + "9027453179178371527625080833791886622005693948357347180279899567975544123053", + "1" + ], + [ + "10487062204675362135040711564126020828349619887409000980661757314247666071798", + "3236403349916311027771194187688348304561777123849595497572806285273411101608", + "1" + ], + [ + "8437340914702111117180917485977711912778685689045350815104324140157663843649", + "16888561924381927014588880447354520469724365291076527474369518015037845870367", + "1" + ], + [ + "11024482038988211616599971430597734530145332581598595162717049239685443877105", + "10477343271198572447416610543051460218709665544768709482087778401785191289217", + "1" + ], + [ + "12289349047469484970933461489859808856300333979400916245089659109078691001529", + "2040882573952436785601898395237342372100721718303896044205287178224234281750", + "1" + ], + [ + "18445469998803424477488768713893917822476976991577402888416529001797789541254", + "7307140467283558392922914986346250593977546447525874147606820138224445419964", + "1" + ], + [ + "11577362795304705740030513575344090675923356170029770308746220432813316848968", + "6417649708233753154799660669661920505205736755595594328905002175794372362285", + "1" + ], + [ + "15788514714985706570585228581857505150892415813189273702558709469027990436676", + "9054329931472395850744770783242443474998027457404036054466665632394543727202", + "1" + ], + [ + "3096371061983879397221583562928327860195155646839260188058908480252660571541", + "9215428768435464787862426613817269389571368147431280353673066183523757537823", + "1" + ], + [ + "1795446744600713275922828953462134097848976260670414954673261440809772263645", + "1203602467299039958337145345929711565950791172478667221214445371507004229806", + "1" + ], + [ + "15742854601374305692723804098693433266044934636553829415553928300979802762433", + "18238088839111904922515936483771872881825186098494031284801319683378322151431", + "1" + ], + [ + "10987636769482604623086626538628354587290130690788745243075480310878318269398", + "18199627450759601944676851409081867580552858188179806620100039041772905034440", + "1" + ], + [ + "10278134891451995949295380898622975025595164565923708535149758073759340840719", + "19035172759041807649546418090271465893006449719666662824510128011763835791681", + "1" + ], + [ + "14693977485951614471767666171010054810496139895591286002161811262075452650377", + "9815566195926528036390686842438921593190853361687826887676466690846477254217", + "1" + ], + [ + "3546376388516599852919894266030555397639743673491724322759941169697504606719", + "7479588901103304077186422360442171087305465172980091463525600513878079376021", + "1" + ], + [ + "19503085677141758776195821219694287239551512723820211109303752176248353237162", + "3601258460634290316129069172171935921269546967427607000719640836718054699915", + "1" + ], + [ + "8508432280375226894275190142315677968205629679526226815724601809613773765303", + "11429270299392931674600136809683805988114167808679561087550064954566768410711", + "1" + ], + [ + "13825332254901215576653293242014022176027474374549510717711961008337257225497", + "16049851022034262403736272323327724508534639988691274597750645166533757220595", + "1" + ], + [ + "20006664291074923277707122588127387511802594545820157530971681235766461748771", + "17473541667882116624915882937139442377133443783513561454760551389592708838910", + "1" + ], + [ + "11534601114937844212874274210776299336767926951578373365722544446443069567626", + "3288762580248623541314932376438775393042927795238883673294605787405803741771", + "1" + ], + [ + "13033349228446715227708983174962630359855099833946824324347890046482498192023", + "6421294974939765958693399139403364836236730937565965556934582902347210583662", + "1" + ], + [ + "11247057806045117168448120427081163906635319287767709787875241910037861458538", + "16637670705849046829316204969243986286576776498721277548012573053617450907511", + "1" + ], + [ + "559392299086149242612448391511384090938185097932213137491260656688434451148", + "9401148059581188462657007471430294041523537391080090455377147452460127371270", + "1" + ], + [ + "11734308416997179360452374191558926943900023358360267145684079964230083718457", + "16946911160806395496270122536331739523282671201632609363572899004300386048442", + "1" + ], + [ + "13382329293559377603829394693024291999330612026257830148396565915457054946525", + "6844598674009676962758767688837409872923009962872515636774655278370532334099", + "1" + ], + [ + "4432425973065755698058919463797706635349577437708227688469799596650014052480", + "8472893330782000140632217661937123102770078447141512396957441311551813589043", + "1" + ], + [ + "18794358216713956675861660792014654188648556376611639297240454573671569988400", + "2436930977657684111389210078785148679811016134515147190167225304016012616377", + "1" + ], + [ + "16631094635424758333192379063968709437699793182249756174576682222101204450204", + "9900333938138173456861736360226035975579787879763811722407191730737753204946", + "1" + ], + [ + "21774613710582603981030497221548871070638679440021134775994298865087881040692", + "7913255338081290925954848141597466754754039821689479678114745036632827081866", + "1" + ] + ] +} \ No newline at end of file