Skip to content

Commit

Permalink
Fix exp boolean representation; Support empty credential Subject requ…
Browse files Browse the repository at this point in the history
…est (#39)

support empty credentialSubject request; use latest atomicSigv2 vk
  • Loading branch information
ilya-korotya committed Apr 24, 2023
1 parent 178d046 commit 56947a6
Show file tree
Hide file tree
Showing 3 changed files with 622 additions and 513 deletions.
140 changes: 101 additions & 39 deletions auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (

var verificationKeyloader = &loaders.FSKeyLoader{Dir: "./testdata"}
var schemaLoader = &mockMemorySchemaLoader{}

//nolint:unused // since we use the disabled unit tests
var nonMerklizedSchemaLoader = &mockMemoryNonMerklizedSchemaLoader{}

/*
Expand All @@ -34,53 +36,84 @@ type mockMemorySchemaLoader struct {

func (r *mockMemorySchemaLoader) Load(_ context.Context, _ string) (schema []byte, ext string, err error) {
return []byte(`{
"@context": [
{
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"KYCAgeCredential": {
"@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCAgeCredential",
"@context": {
"@context": [
{
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"birthday": {
"@id": "kyc-vocab:birthday",
"@type": "xsd:integer"
"KYCAgeCredential": {
"@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCAgeCredential",
"@context": {
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"birthday": {
"@id": "kyc-vocab:birthday",
"@type": "xsd:integer"
},
"documentType": {
"@id": "kyc-vocab:documentType",
"@type": "xsd:integer"
}
}
},
"documentType": {
"@id": "kyc-vocab:documentType",
"@type": "xsd:integer"
}
}
},
"KYCCountryOfResidenceCredential": {
"@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCCountryOfResidenceCredential",
"@context": {
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"countryCode": {
"@id": "kyc-vocab:countryCode",
"@type": "xsd:integer"
"KYCCountryOfResidenceCredential": {
"@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCCountryOfResidenceCredential",
"@context": {
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"countryCode": {
"@id": "kyc-vocab:countryCode",
"@type": "xsd:integer"
},
"documentType": {
"@id": "kyc-vocab:documentType",
"@type": "xsd:integer"
}
}
},
"documentType": {
"@id": "kyc-vocab:documentType",
"@type": "xsd:integer"
"KYCEmployee": {
"@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCEmployee",
"@context": {
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"documentType": {
"@id": "kyc-vocab:documentType",
"@type": "xsd:integer"
},
"ZKPexperiance": {
"@id": "kyc-vocab:hasZKPexperiance",
"@type": "xsd:boolean"
},
"hireDate": {
"@id": "kyc-vocab:hireDate",
"@type": "xsd:dateTime"
},
"position": {
"@id": "kyc-vocab:position",
"@type": "xsd:string"
},
"salary": {
"@id": "kyc-vocab:salary",
"@type": "xsd:double"
}
}
}
}
}
}
]
}`), "json-ld", nil
]
}`), "json-ld", nil
}

type mockMemoryNonMerklizedSchemaLoader struct {
Expand Down Expand Up @@ -523,6 +556,7 @@ func TestVerifier_FullVerify(t *testing.T) {
}

func TestVerifyAuthResponseWithEmptyReq(t *testing.T) {
t.Skip("non-merklized claims are not supported")

verifierID := "did:polygonid:polygon:mumbai:2qEevY9VnKdNsVDdXRv3qSLHRqoMGMRRdE5Gmc6iA7"
callbackURL := "https://test.com/callback"
Expand Down Expand Up @@ -735,3 +769,31 @@ func TestVerifier_FullVerifySelectiveDisclosure(t *testing.T) {
_, err := authInstance.FullVerify(context.Background(), token, request)
require.NoError(t, err)
}

func TestEmptyCredentialSubject(t *testing.T) {
// request
verifierID := "did:polygonid:polygon:mumbai:2qEevY9VnKdNsVDdXRv3qSLHRqoMGMRRdE5Gmc6iA7"
callbackURL := "https://test.com/callback"
reason := "age verification"

var mtpProofRequest protocol.ZeroKnowledgeProofRequest
mtpProofRequest.ID = 1
mtpProofRequest.CircuitID = string(circuits.AtomicQuerySigV2CircuitID)
opt := true
mtpProofRequest.Optional = &opt
mtpProofRequest.Query = map[string]interface{}{
"allowedIssuers": []string{"*"},
"context": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld",
"type": "KYCEmployee",
}
request := CreateAuthorizationRequestWithMessage(reason, "", verifierID, callbackURL)
request.Body.Scope = append(request.Body.Scope, mtpProofRequest)
request.ID = "28494007-9c49-4f1a-9694-7700c08865bf"
request.ThreadID = "ee92ab12-2671-457e-aa5e-8158c205a985" // because it's used in the response

token := `eyJhbGciOiJncm90aDE2IiwiY2lyY3VpdElkIjoiYXV0aFYyIiwiY3JpdCI6WyJjaXJjdWl0SWQiXSwidHlwIjoiYXBwbGljYXRpb24vaWRlbjMtemtwLWpzb24ifQ.eyJpZCI6Ijc0MWU2MTA4LTM4MzgtNDFiYS1hMGIwLTlhZmZkZjY1NTg2YSIsInR5cCI6ImFwcGxpY2F0aW9uL2lkZW4zY29tbS1wbGFpbi1qc29uIiwidHlwZSI6Imh0dHBzOi8vaWRlbjMtY29tbXVuaWNhdGlvbi5pby9hdXRob3JpemF0aW9uLzEuMC9yZXNwb25zZSIsInRoaWQiOiIxNjEwN2QwYi01ZDU3LTQ1OWEtYWJiMi00OWE2Mjg2YTA5NTMiLCJmcm9tIjoiZGlkOnBvbHlnb25pZDpwb2x5Z29uOm11bWJhaToycUd5VDhtTUdydlRqTVdDelRHOE1YVG9neGp6UFRVYjJMa2tMM0FKMTEiLCJ0byI6ImRpZDpwb2x5Z29uaWQ6cG9seWdvbjptdW1iYWk6MnFKNjg5a3BvSnhjU3pCNXNBRkp0UHNTQlNySEY1ZHE3MjJCSE1xVVJMIiwiYm9keSI6eyJkaWRfZG9jIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy9ucy9kaWQvdjEiXSwiaWQiOiJkaWQ6cG9seWdvbmlkOnBvbHlnb246bXVtYmFpOjJxR3lUOG1NR3J2VGpNV0N6VEc4TVhUb2d4anpQVFViMkxra0wzQUoxMSIsInNlcnZpY2UiOlt7ImlkIjoiZGlkOnBvbHlnb25pZDpwb2x5Z29uOm11bWJhaToycUd5VDhtTUdydlRqTVdDelRHOE1YVG9neGp6UFRVYjJMa2tMM0FKMTEjcHVzaCIsInR5cGUiOiJwdXNoLW5vdGlmaWNhdGlvbiIsInNlcnZpY2VFbmRwb2ludCI6Imh0dHBzOi8vcHVzaC1zdGFnaW5nLnBvbHlnb25pZC5jb20vYXBpL3YxIiwibWV0YWRhdGEiOnsiZGV2aWNlcyI6W3siY2lwaGVydGV4dCI6IkMxRU9BNGViOUh6RC9QREtPeHlaazZaYjBaUzlvSlR1RmgyTi8xaTJ3TWxrdFJ4bzhteGJmMnN2Nk14OFl1SGRLbVo4eVJWbE9CSmpqOGRDckxDRHplYjJPREs2ZDVsanN0S05GTUlhOFh6aW1DV2I5eXoyN0h6Tm1EbTJWdGtJQWxaSjB6cEJFdnZlSWNUVVVodmNXeFkzQnVRRnpYdmJHL2lIYnUxcWRkdUh3L3JVMmJoTE9jdDN1bnpXVnB3T1pVYXg5TExTWk9zSGVyR0hZM1JJWUp5ZCtDcVV3TU5DQWJHYlJFcjlUU1pGdU1HbzZ1NGVRSlBOOURGQ09NaXdCdS9UOW5vMTNCZ1NIcDhHSlV6eFc1YTg4Z0FXQUZjVE5hSDVkOUdoamlERXp4NDUyV291Wms0Zloxd1BVd3lPUHJsaCt2QjVDd05jejRpWXNZK0ZPZEFMdDdyRUZ1RWhLZXhCVlp5VmYxckFLUDhOdi83YWtHdCtaWlZJY3RsRHRTUGUwYXpseW9TYTFKVVo2a0JLclJWdmUvL1pWdVRSMm81VHRXN2I2SlJVZ2w2S2IrVEhiN3V1OWlRcDN5ODAvWTVtMXpiSzNyUnlLTjM0U0YwMmpkY2JkZWVoeWNRc1NTMmRscm1oODZ6MWRvUS9XMVlXQ0Zzam1PazNQdnZxVU8rSXRPSnhVYURNcWVlZXE2QldldUxxd01oZE5KRVRBN3BIRzhES1JFdDZZLzNXRlNaOFF0aWdVWU9XQUplVXNHRzh1SFRSeSt3aVVKV1NIcVFTSmZHdXFOakFLa05mVFVYeDNqWmhOYmEveEFtUXV0bkxQQjJpbXowNHNSRFhTUzNYMUFmSnVSdUp6Wk1lTUE3MXM2TEZaS01Iakw4cXBENzI0L21OcEVFPSIsImFsZyI6IlJTQS1PQUVQLTUxMiJ9XX19XX0sIm1lc3NhZ2UiOm51bGwsInNjb3BlIjpbeyJpZCI6MSwiY2lyY3VpdElkIjoiY3JlZGVudGlhbEF0b21pY1F1ZXJ5U2lnVjIiLCJwcm9vZiI6eyJwaV9hIjpbIjE4MjgxMDIzOTY3MTY3MTQ4Mjg0MDc3ODUyNzI1MjU0MzY3MjM3MTQ5Mzc4MDY0MjY1ODIyMDc2OTM3MDQ0NDc5NDE2OTM1NDk1MDE1IiwiMTY0NzkyMzExMjExNDA2NjU4MDc0MTMzOTI1NTIzNzEzMjAxNjcxNTcwOTc5MTIxNjU4NjE5MDk0MDYwNzkzMjYzOTUyOTM5OTUwODIiLCIxIl0sInBpX2IiOltbIjEwOTE5MzU4Njg1NTY1NzQzODkzMzg3Mjk1NjgwNzk0OTY2Njg0OTQ0NjQ1ODQ3OTMyNzI4MDEzMzI1OTgxOTY5MjY4ODk1MTkxMDI2IiwiMjEwMzk4NDgwMTE3Mzc1OTUxMDM0NjYxODQ4MTIyMzI5MDk1NDE4MTAwNDY5NzE4OTY1NjE3ODAwMzg3ODMzODk0NjA2MzkxNTQ5MTMiXSxbIjI1NDUyMzEzNzU3NDU3MDM4OTY0Mzg4NjU4ODEwNjYwMjYzMTg2NzM4NTc4MzQyNDIzNDg0MDc4OTYzMzg4MDE3MjI3MjA3NDIzNzgiLCIxNzE1NTc4OTMxNzg4MDI3MDc3NzUyMDM2OTc1MDM3NzAyODk1NDA1MTQ2OTY2Mzk1MTczMDQxMTkyMzE0NDIwODc4NDQ5MzgyNzYxMSJdLFsiMSIsIjAiXV0sInBpX2MiOlsiNDYxODI0NjU0NzkwMjkzMDE3MTYwMTM5MTUyOTAxNzk5OTMyNjcyOTkyMzUyNzA1MDE4NTAwNTE2OTI5NjUxOTI3NDQ4NTA2OTQ5OCIsIjgyMDg2Njc2OTM0Njg1OTQyMzczMTU2OTY3NjQ2Njg5NTI3MzE3MDk3MjA4Nzc5OTAxMjUyNTgzNDU2MDMwMzIyNjc0NjUzMTQ4MzkiLCIxIl0sInByb3RvY29sIjoiZ3JvdGgxNiIsImN1cnZlIjoiYm4xMjgifSwicHViX3NpZ25hbHMiOlsiMSIsIjIxNDA0MDQxODQxNjkwMTMwOTA4NTk1NTI1NjA1Njk1NjY0OTY4NTAwODc3NjE3MDU2MDY0MjY5MTkyODk1NTQxNTU3NzkzMjgyIiwiMTQxNzI3NzAwODg2MDIyNTU4MjU3MzM2MTEzNjUzOTg3MTg5MzUzNzEyNDQ1NzUyNTMwNTYzNjEzMDc4MjMzMDMwMjg0NDI5MDc5NTAiLCIxIiwiMjc3NTI3NjY4MjMzNzE0NzE0MDgyNDgyMjU3MDg2ODEzMTM3NjQ4NjYyMzE2NTUxODczNjYwNzE4ODEwNzA5MTg5ODQ0NzEwNDIiLCIxIiwiNjczMjk4MjYxNjY0NzgxMTc1NDExOTc5NjE4NjQ3NDI2MTQxNzgxOTM3MDI3NzE4NzI3OTkzMzQ2OTM2MDY0NTE0OTM5NzkzNjAzMiIsIjE2ODIzMzU0OTMiLCIyMTk1Nzg2MTcwNjQ1NDAwMTYyMzQxNjE2NDAzNzU3NTU4NjU0MTIiLCIwIiwiNDc5MjEzMDA3OTQ2MjY4MTE2NTQyODUxMTIwMTI1MzIzNTg1MDAxNTY0ODM1Mjg4MzI0MDU3NzMxNTAyNjQ3Nzc4MDQ5MzExMDY3NSIsIjAiLCIxIiwiNjIyMjQ4NzU0NTgyMTgxMjYxOTMwNTEzNjkwMTc5MDI1MTc3MDM5MDY4NDEwNTI4MTkxNTcxODk5NTY4MjQ5MTkzNzA0MTc1ODc2IiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIiwiMCIsIjAiLCIwIl19XX19.eyJwcm9vZiI6eyJwaV9hIjpbIjc3NjY1ODUzMDg2MjIxMTI5MDQ1MzQ0NjQ2MDY4NTg2NDk2MzUyNTA2MzY5NDQ5NTU0MjQzMTE0MDUzODc0NjkxMDk0MDIzMzM3NTkiLCI1OTc2MDc4NDg2NzExMTUzOTk2OTYzMDQ0NDU5NjY5MzcyNjgwMTgwMjQwNDk4MTgwOTI0ODE3MjE3MTM5NjE4MzMwMDQwMTc0MTIiLCIxIl0sInBpX2IiOltbIjEyMzg2MjU2MTc1Njk4NjIwMTY5ODAxMTMwNDEyNzEyNzgwOTYyNjIwNjY5NzIxNzc1NDcyODQ4OTY2NzEwNzI1MjQ3NjczNDk0NzExIiwiOTk3NTE0NzcyMDc3ODgzNjc1MTE4NDUzMzM0ODUzMDgyMTQ0OTk3MjM4NTUzOTE4NTk0MDUxNTg4Nzk1ODgyMjczMzg1ODQ4Nzk4MCJdLFsiMzI2Njg2MDAwNjYwNzg5ODg1MzQ4NjE3OTg1NTQ4OTA3NDc4Nzg5NjQ2NjQ1ODgyNTM1ODI2OTUxMjAxNTA5MjY3OTEwMzU5NjIwNiIsIjEwMjg0MTc1Nzg2ODM3MTg4MzEzMTQ3ODY5MzY2NTU1MDU1NTMzMDU5NjI4OTUwMDI0ODk5OTAwNzQwNDM4ODYwMTU1ODYxMTM4MjAiXSxbIjEiLCIwIl1dLCJwaV9jIjpbIjEyMDg2ODY2OTk3NjY3NDIwMDg1MDIxNTkwODY4NTA3NjYzNjk3OTQwMjA2MTk1NzQyOTIxNjM1MjI0MzAwODIyMjAzMjkxNTU1NjgyIiwiODM5ODExNDQ3NjE2OTc0NDYyODgzODA0NTE2NDk0NzkxNDA4MDUzOTQ2NjQwNTU5MDU0NzY4NTgyMzI3NzgxMzc3ODk0NDE2ODA1OCIsIjEiXSwicHJvdG9jb2wiOiJncm90aDE2IiwiY3VydmUiOiJibjEyOCJ9LCJwdWJfc2lnbmFscyI6WyIyMTQwNDA0MTg0MTY5MDEzMDkwODU5NTUyNTYwNTY5NTY2NDk2ODUwMDg3NzYxNzA1NjA2NDI2OTE5Mjg5NTU0MTU1Nzc5MzI4MiIsIjIwOTQ1MjY4MTg3NDg3NzkzMjI5NDU5NDkwMTk1MzIzMzk3NzY2ODIzNjQwNTU1ODU0NjMxNDI2NDE0MTgyOTU4NDk2Mjg3MTUwMDY4IiwiMTA1MjI5NTY0NzMwODM3MjU4OTA1Nzk2ODUxMjM2NzgyNTYxNzQ5MTMyOTY0MTI5MTIzMDE0MzU0NTIwNjAyOTQ2ODI1MTEzODU0NzMiXX0`

authInstance := NewVerifier(verificationKeyloader, schemaLoader, stateResolvers)
_, err := authInstance.FullVerify(context.Background(), token, request)
require.NoError(t, err)
}
49 changes: 48 additions & 1 deletion pubsignals/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ func (q Query) verifyCredentialSubject(
}
}

if q.CredentialSubject != nil && len(predicate) == 0 {
// validate selectivity disclosure request
if q.isSelectivityDisclosure(predicate) {
ctx := context.Background()
return q.validateDisclosure(
ctx,
Expand All @@ -212,6 +213,11 @@ func (q Query) verifyCredentialSubject(
)
}

// validate empty credential subject request
if q.isEmptyCredentialSubject(predicate, pubSig.Merklized) {
return q.verifyEmptyCredentialSubject(pubSig)
}

values, operator, err := parseFieldPredicate(fieldType, predicate)
if err != nil {
return err
Expand Down Expand Up @@ -296,6 +302,47 @@ func (q Query) validateDisclosure(
return nil
}

func (q Query) verifyEmptyCredentialSubject(
pubSig *CircuitOutputs,
) error {
if pubSig.Operator != circuits.EQ {
return errors.New("empty credentialSubject request available only for equal operation")
}

for i := 1; i < len(pubSig.Value); i++ {
if pubSig.Value[i].Cmp(big.NewInt(0)) != 0 {
return errors.New("empty credentialSubject request not available for array of values")
}
}

p, err := merklize.NewPath("https://www.w3.org/2018/credentials#credentialSubject")
if err != nil {
return err
}
bi, err := p.MtEntry()
if err != nil {
return err
}

if pubSig.ClaimPathKey.Cmp(bi) != 0 {
return errors.New("proof doesn't contain credentialSubject in claimPathKey")
}

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{},
isMerklized int,
) bool {
return q.CredentialSubject == nil && len(predicate) == 0 && isMerklized == 1
}

func parseFieldPredicate(
fieldType string,
fieldPredicate map[string]interface{},
Expand Down
Loading

0 comments on commit 56947a6

Please sign in to comment.