diff --git a/go.mod b/go.mod index 8b0555f..824b8da 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,12 @@ go 1.21.4 require ( github.com/dgraph-io/badger/v4 v4.2.0 github.com/ethereum/go-ethereum v1.13.14 - github.com/iden3/go-circuits/v2 v2.1.0 - github.com/iden3/go-iden3-core/v2 v2.0.4 + github.com/iden3/go-circuits/v2 v2.2.0 + github.com/iden3/go-iden3-core/v2 v2.1.0 github.com/iden3/go-iden3-crypto v0.0.16 github.com/iden3/go-merkletree-sql/v2 v2.0.6 github.com/iden3/go-onchain-credential-adapter v0.0.0-20240223120548-5d8d1d28c6d1 - github.com/iden3/go-schema-processor/v2 v2.3.1 + github.com/iden3/go-schema-processor/v2 v2.3.3 github.com/iden3/merkletree-proof v0.1.0 github.com/piprate/json-gold v0.5.1-0.20230111113000-6ddbe6e6f19f github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index b0ed754..98266c7 100644 --- a/go.sum +++ b/go.sum @@ -160,18 +160,18 @@ github.com/iden3/contracts-abi/onchain-non-merklized-issuer-base/v0/go/abi v0.0. github.com/iden3/contracts-abi/onchain-non-merklized-issuer-base/v0/go/abi v0.0.0-20240222110004-06aa097d1318/go.mod h1:vMgeBNntJeIDZrIDY0d6sZQU+JigUo4h+m95qeU03ew= github.com/iden3/contracts-abi/state/go/abi v0.0.0-20230405152923-4a25f6f1f0f4 h1:iPvYa/AhhGo3juoUFDm/fBE2CZKy4WfQu7JY90tRf9Q= github.com/iden3/contracts-abi/state/go/abi v0.0.0-20230405152923-4a25f6f1f0f4/go.mod h1:TxgIrXCvxms3sbOdsy8kTvffUCIpEEifNy0fSXdkU4w= -github.com/iden3/go-circuits/v2 v2.1.0 h1:Dk+noXGXOJYFjj2iWu3KLPd/KLoIhZ3eT6qYEfKyocc= -github.com/iden3/go-circuits/v2 v2.1.0/go.mod h1:VIFIp51+IH0hOzjnKhb84bCeyq7hq76zX/C14ua6zh4= -github.com/iden3/go-iden3-core/v2 v2.0.4 h1:ggzC2zgOWgJAAcuG9X8bQG1r4gAoHZWqY7aLV8b1qgc= -github.com/iden3/go-iden3-core/v2 v2.0.4/go.mod h1:L9PxhWPvoS9qTb3inEkZBm1RpjHBt+VTwvxssdzbAdw= +github.com/iden3/go-circuits/v2 v2.2.0 h1:qJeySVPG9vxZwJyL/CsvXdUhccWOctXQUYGnyX5p2Kc= +github.com/iden3/go-circuits/v2 v2.2.0/go.mod h1:1LET+T8i9Rkfx+RNj2BBHKAPGDODEWWwSEFjR6g3h6c= +github.com/iden3/go-iden3-core/v2 v2.1.0 h1:R1s7Tj3tIx5lDy8S7OJrSNuxXIFeRzWRmTBaQoQHJps= +github.com/iden3/go-iden3-core/v2 v2.1.0/go.mod h1:L9PxhWPvoS9qTb3inEkZBm1RpjHBt+VTwvxssdzbAdw= github.com/iden3/go-iden3-crypto v0.0.16 h1:zN867xiz6HgErXVIV/6WyteGcOukE9gybYTorBMEdsk= github.com/iden3/go-iden3-crypto v0.0.16/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= github.com/iden3/go-merkletree-sql/v2 v2.0.6 h1:vsVDImnvnHf7Ggr45ptFOXJyWNA/8IwVQO1jzRLUlY8= github.com/iden3/go-merkletree-sql/v2 v2.0.6/go.mod h1:kRhHKYpui5DUsry5RpveP6IC4XMe6iApdV9VChRYuEk= github.com/iden3/go-onchain-credential-adapter v0.0.0-20240223120548-5d8d1d28c6d1 h1:xpKhrLYi0s6ocUCrFwkjG0YQjndDGMW7/cgU9KjLyig= github.com/iden3/go-onchain-credential-adapter v0.0.0-20240223120548-5d8d1d28c6d1/go.mod h1:1RVClY0JdWmzgx3ZBvy0Z2bNyPg2iz+0R9Ryl2Z3s64= -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/go-schema-processor/v2 v2.3.3 h1:GfChxMZHG4miA3p/5rLIrM7TGmKu/oAAXgLloYTBHSI= +github.com/iden3/go-schema-processor/v2 v2.3.3/go.mod h1:8y/R0iQpYhyhRQ3sL4F5Aja3+1T68M6uwGQdC4pQ4X0= github.com/iden3/merkletree-proof v0.1.0 h1:AHmpkbCTLKv1MWWt6YwogB65E4y6UZthbZYPed81w4U= github.com/iden3/merkletree-proof v0.1.0/go.mod h1:ul0HDU6/eVNX++u/PWScY7pTXiFjqM5kA6vl1wEoTUU= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= diff --git a/inputs_sig.go b/inputs_sig.go index 6011dc7..2ac7814 100644 --- a/inputs_sig.go +++ b/inputs_sig.go @@ -12,6 +12,7 @@ import ( "log/slog" "math/big" "runtime/trace" + "sort" "strconv" "strings" "sync" @@ -469,6 +470,11 @@ type v3InputsRequest struct { LinkNonce JsonBigInt `json:"linkNonce"` } +type linkedMultiQueryInputsRequest struct { + inputsRequest + LinkNonce *JsonBigInt `json:"linkNonce"` +} + type onChainInputsRequest struct { ID *core.ID `json:"id"` ProfileNonce *JsonBigInt `json:"profileNonce"` @@ -584,71 +590,57 @@ func AtomicQueryMtpV2InputsFromJson(ctx context.Context, cfg EnvConfig, return out, nil } -func verifiablePresentationFromCred(ctx context.Context, - w3cCred verifiable.W3CCredential, requestObj jsonObj, field string, - documentLoader ld.DocumentLoader) (verifiablePresentation map[string]any, - mzValue merklize.Value, datatype string, hasher merklize.Hasher, - err error) { - - var mz *merklize.Merklizer - mz, err = wrapMerklizeWithRegion(ctx, w3cCred, documentLoader) - if err != nil { - return nil, nil, datatype, hasher, err - } - - hasher = mz.Hasher() +type objEntry struct { + key string + value any +} - var contextType string - contextType, err = stringByPath(requestObj, "query.type") - if err != nil { - return nil, nil, datatype, hasher, err +func mkVPObj(tp string, kvs ...objEntry) (jsonObj, error) { + out := jsonObj{"@type": tp} + for _, kv := range kvs { + err := insertKV(out, kv) + if err != nil { + return nil, err + } } + return out, nil +} - var contextURL string - contextURL, err = stringByPath(requestObj, "query.context") - if err != nil { - return nil, nil, datatype, hasher, err +func insertKV(obj jsonObj, kv objEntry) error { + if kv.key == "" { + return errors.New("empty key") } - path, err := buildQueryPath(ctx, contextURL, contextType, field, - documentLoader) - if err != nil { - return nil, nil, datatype, hasher, err - } + idx := strings.Index(kv.key, ".") + if idx == -1 { + if _, ok := obj[kv.key]; ok { + return fmt.Errorf("key already exists: %v", kv.key) + } - datatype, err = mz.JSONLDType(path) - if err != nil { - return nil, nil, datatype, hasher, err + obj[kv.key] = kv.value + return nil } - rawValue, err := mz.RawValue(path) - if err != nil { - return nil, nil, datatype, hasher, err + if idx == 0 || idx == len(kv.key)-1 { + return fmt.Errorf("invalid key with an empty part: %v", kv.key) } - _, mzValue, err = mz.Proof(ctx, path) - if err != nil { - return nil, nil, datatype, hasher, err - } - - verifiablePresentation = fmtVerifiablePresentation(contextURL, - contextType, field, rawValue) - - return -} - -func mkVPObj(field string, value any) (string, any) { - idx := strings.Index(field, ".") - if idx == -1 { - return field, value + var nestedObj jsonObj + nestedObjI, ok := obj[kv.key[:idx]] + if !ok { + nestedObj = make(jsonObj) + obj[kv.key[:idx]] = nestedObj + } else { + nestedObj, ok = nestedObjI.(jsonObj) + if !ok { + return fmt.Errorf("not a json object: %v", kv.key[:idx]) + } } - - nestedField, value := mkVPObj(field[idx+1:], value) - return field[:idx], map[string]any{nestedField: value} + return insertKV(nestedObj, objEntry{key: kv.key[idx+1:], value: kv.value}) } -func fmtVerifiablePresentation(context string, tp string, field string, - value any) map[string]any { +func fmtVerifiablePresentation(context string, tp string, + kvs ...objEntry) (map[string]any, error) { var ldContext any @@ -664,21 +656,20 @@ func fmtVerifiablePresentation(context string, tp string, field string, vcTypes = append(vcTypes, tp) } - // if field name is a dot-separated path, create nested object from it. - field, value = mkVPObj(field, value) + credSubject, err := mkVPObj(tp, kvs...) + if err != nil { + return nil, err + } return map[string]any{ "@context": baseContext, "@type": "VerifiablePresentation", "verifiableCredential": map[string]any{ - "@context": ldContext, - "@type": vcTypes, - "credentialSubject": map[string]any{ - "@type": tp, - field: value, - }, + "@context": ldContext, + "@type": vcTypes, + "credentialSubject": credSubject, }, - } + }, nil } func AtomicQuerySigV2InputsFromJson(ctx context.Context, cfg EnvConfig, @@ -1099,6 +1090,61 @@ func AtomicQueryV3InputsFromJson(ctx context.Context, cfg EnvConfig, return out, nil } +func LinkedMultiQueryInputsFromJson(ctx context.Context, cfg EnvConfig, + in []byte) (AtomicQueryInputsResponse, error) { + + var out AtomicQueryInputsResponse + var inpMarsh circuits.LinkedMultiQueryInputs + + var obj linkedMultiQueryInputsRequest + err := json.Unmarshal(in, &obj) + if err != nil { + return out, err + } + + if obj.LinkNonce == nil { + return out, errors.New(`"linkNonce" field is required`) + } + inpMarsh.LinkNonce = obj.LinkNonce.BigInt() + + circuitID, err := getCircuitID(obj.Request) + if err != nil { + return out, err + } + if circuitID != circuits.LinkedMultiQuery10CircuitID { + return out, errors.New("wrong circuit") + } + + var w3cCred verifiable.W3CCredential + err = json.Unmarshal(obj.VerifiableCredentials, &w3cCred) + if err != nil { + return out, err + } + + reqProofType, err := queryProofType(obj.Request) + if err != nil { + return out, err + } + + claim, _, err := claimWithSigAndMtpProofFromObj(ctx, cfg, w3cCred, true, + reqProofType) + if err != nil { + return out, err + } + + inpMarsh.Claim = claim.Claim + + inpMarsh.Query, out.VerifiablePresentation, err = queriesFromObj(ctx, + w3cCred, obj.Request, inpMarsh.Claim, cfg.documentLoader(), circuitID) + if err != nil { + return out, err + } + + out.Inputs = inpMarsh + + return out, nil +} + // return empty circuits.ProofType if not found func queryProofType(requestObj jsonObj) (circuits.ProofType, error) { result, err := getByPath(requestObj, "query.proofType") @@ -1143,7 +1189,7 @@ func buildQueryPath(ctx context.Context, contextURL string, contextType string, return } // took from identity-server prepareMerklizedQuery func - err = path.Prepend("https://www.w3.org/2018/credentials#credentialSubject") + err = path.Prepend(iriCredentialSubject) if err != nil { return } @@ -1177,13 +1223,50 @@ func queryFromObj(ctx context.Context, w3cCred verifiable.W3CCredential, return out, nil, err } + var queries []*circuits.Query + var vp jsonObj if merklizePosition == core.MerklizedRootPositionNone { - return queryFromObjNonMerklized(ctx, w3cCred, requestObj, + queries, vp, err = queriesFromObjNonMerklized(ctx, w3cCred, requestObj, documentLoader, circuitID) + } else { + queries, vp, err = queriesFromObjMerklized(ctx, w3cCred, requestObj, + documentLoader, circuitID, claim) + } + if err != nil { + return circuits.Query{}, nil, err + } + + for i := 1; i < len(queries); i++ { + if queries[i] != nil { + return circuits.Query{}, nil, + errors.New("multiple queries are not supported") + } + } + + if len(queries) == 0 || queries[0] == nil { + // we should not reach here + return circuits.Query{}, nil, errors.New("[assertion] no query found") } - return queryFromObjMerklized(ctx, w3cCred, requestObj, documentLoader, - circuitID) + return *queries[0], vp, nil +} + +func queriesFromObj(ctx context.Context, w3cCred verifiable.W3CCredential, + requestObj jsonObj, claim *core.Claim, documentLoader ld.DocumentLoader, + circuitID circuits.CircuitID) ([]*circuits.Query, jsonObj, error) { + + merklizePosition, err := claim.GetMerklizedPosition() + if err != nil { + return nil, nil, err + } + + if merklizePosition == core.MerklizedRootPositionNone { + return queriesFromObjNonMerklized(ctx, w3cCred, requestObj, + documentLoader, circuitID) + } + + return queriesFromObjMerklized(ctx, w3cCred, requestObj, documentLoader, + circuitID, claim) } func wrapMerklizeWithRegion(ctx context.Context, @@ -1198,11 +1281,38 @@ func wrapMerklizeWithRegion(ctx context.Context, return mz, err } -func queryFromObjNonMerklized(ctx context.Context, +func isV2Circuit(circuitID circuits.CircuitID) bool { + return circuitID == circuits.AtomicQueryMTPV2CircuitID || + circuitID == circuits.AtomicQueryMTPV2OnChainCircuitID || + circuitID == circuits.AtomicQuerySigV2CircuitID || + circuitID == circuits.AtomicQuerySigV2OnChainCircuitID +} + +var sdOperator = map[circuits.CircuitID]int{ + circuits.AtomicQueryMTPV2CircuitID: circuits.EQ, + circuits.AtomicQueryMTPV2OnChainCircuitID: circuits.EQ, + circuits.AtomicQuerySigV2CircuitID: circuits.EQ, + circuits.AtomicQuerySigV2OnChainCircuitID: circuits.EQ, + circuits.AtomicQueryV3CircuitID: circuits.SD, + circuits.AtomicQueryV3OnChainCircuitID: circuits.SD, + circuits.LinkedMultiQuery10CircuitID: circuits.SD, +} + +func opName(opID int) string { + for name, id := range circuits.QueryOperators { + if id == opID { + return name + } + } + return fmt.Sprintf("Operator<%d>", opID) +} + +func queriesFromObjNonMerklized(ctx context.Context, w3cCred verifiable.W3CCredential, requestObj jsonObj, documentLoader ld.DocumentLoader, - circuitID circuits.CircuitID) (out circuits.Query, - verifiablePresentation jsonObj, err error) { + circuitID circuits.CircuitID) ([]*circuits.Query, jsonObj, error) { + + var err error region := trace.StartRegion(ctx, "queryFromObjNonMerklized") defer region.End() @@ -1212,81 +1322,162 @@ func queryFromObjNonMerklized(ctx context.Context, Parser: json2.Parser{}, }) - field, op, err := getQueryFieldAndOperator(requestObj) + var queries = make([]*circuits.Query, circuits.LinkedMultiQueryLength) + var queryIndex = 0 + credSubjObj, err := objByBath(requestObj, "query.credentialSubject") if errors.As(err, &errPathNotFound{}) { - if circuitID == circuits.AtomicQueryMTPV2CircuitID || - circuitID == circuits.AtomicQueryMTPV2OnChainCircuitID || - circuitID == circuits.AtomicQuerySigV2CircuitID || - circuitID == circuits.AtomicQuerySigV2OnChainCircuitID { - return out, nil, errors.New( + + queries[0] = new(circuits.Query) + + if isV2Circuit(circuitID) { + return nil, nil, errors.New( "credentialSubject field is not found in query") } - out.Operator = circuits.NOOP - out.Values = []*big.Int{} - return out, nil, nil + queries[0].Operator = circuits.NOOP + queries[0].Values = []*big.Int{} + return queries, nil, nil } else if err != nil { - return out, nil, - fmt.Errorf("unable to extract field from query: %w", err) + return nil, nil, fmt.Errorf( + "unable to extract credentialSubject field from query: %w", err) } - schemaURL, typeName, err := getQuerySchemaAndType(requestObj) + contextURL, contextType, err := getQuerySchemaAndType(requestObj) if err != nil { - return out, nil, err + return nil, nil, err } - schema, err := pr.Load(ctx, schemaURL) + schema, err := pr.Load(ctx, contextURL) if err != nil { - return out, nil, err + return nil, nil, err } - out.SlotIndex, err = pr.GetFieldSlotIndex(field, typeName, schema) + var mz *merklize.Merklizer + mz, err = wrapMerklizeWithRegion(ctx, w3cCred, documentLoader) if err != nil { - return out, nil, err + return nil, nil, err } - var opObj jsonObj - var ok bool - opObj, ok = op.(jsonObj) - if !ok { - return out, nil, errors.New("operation on field is not a json object") - } + var vpEntries []objEntry + fields := sortedKeys(credSubjObj) + for _, field := range fields { + var slotIndex int + slotIndex, err = pr.GetFieldSlotIndex(field, contextType, schema) + if err != nil { + return nil, nil, err + } - vp, mzValue, datatype, hasher, err := verifiablePresentationFromCred(ctx, - w3cCred, requestObj, field, documentLoader) - if err != nil { - return out, nil, err - } + var path merklize.Path + path, err = buildQueryPath(ctx, contextURL, contextType, field, + documentLoader) + if err != nil { + return nil, nil, err + } - opStr, val, err := extractSingleEntry(opObj) - switch err { - case errMultipleEntries: - return out, nil, errors.New("only one operation per field is supported") - case errNoEntry: - // handle selective disclosure - var valueEntry *big.Int - valueEntry, err = mzValue.MtEntry() + var datatype string + datatype, err = mz.JSONLDType(path) if err != nil { - return out, nil, err + return nil, nil, err } - verifiablePresentation = vp - if circuitID == circuits.AtomicQueryV3CircuitID || - circuitID == circuits.AtomicQueryV3OnChainCircuitID { - out.Operator = circuits.SD - out.Values = []*big.Int{} + ops, ok := credSubjObj[field].(jsonObj) + if !ok { + return nil, nil, fmt.Errorf( + "for query field '%v' the operator object is of incorrect type: %T", + field, credSubjObj[field]) + } + + if len(ops) == 0 { + // handle selective disclosure + + if queryIndex >= circuits.LinkedMultiQueryLength { + return nil, nil, errors.New("too many queries") + } + + query := circuits.Query{SlotIndex: slotIndex} + + var sdOp int + sdOp, ok = sdOperator[circuitID] + if !ok { + return nil, nil, errSDCircuitNotSupported{circuitID} + } + + switch sdOp { + case circuits.SD: + query.Operator = sdOp + query.Values = []*big.Int{} + case circuits.EQ: + var mzValue merklize.Value + var p *merkletree.Proof + p, mzValue, err = mz.Proof(ctx, path) + if err != nil { + return nil, nil, err + } + if !p.Existence { + return nil, nil, fmt.Errorf( + "value not found in verifiable credential by path %v", + fmtPath(path)) + } + if mzValue == nil { + // should not happen because of the existence check previously + return nil, nil, fmt.Errorf( + "[assertion] merklized value is nil for path %v", + fmtPath(path)) + } + + var valueEntry *big.Int + valueEntry, err = mzValue.MtEntry() + if err != nil { + return nil, nil, err + } + query.Operator = sdOp + query.Values = []*big.Int{valueEntry} + default: + return nil, nil, errSDOperatorNotSupported{sdOp} + } + + queries[queryIndex] = &query + queryIndex++ + + vpEntry := objEntry{key: field} + vpEntry.value, err = mz.RawValue(path) + if err != nil { + return nil, nil, err + } + vpEntries = append(vpEntries, vpEntry) + } else { - out.Operator = circuits.EQ - out.Values = []*big.Int{valueEntry} + sortedOps := sortedKeys(ops) + for _, op := range sortedOps { + val := ops[op] + + if queryIndex >= circuits.LinkedMultiQueryLength { + return nil, nil, errors.New("too many queries") + } + + query := circuits.Query{SlotIndex: slotIndex} + query.Operator, query.Values, err = unpackOperatorWithArgs(op, + val, datatype, mz.Hasher()) + if err != nil { + return nil, nil, err + } + + queries[queryIndex] = &query + queryIndex++ + } } - default: - out.Operator, out.Values, err = unpackOperatorWithArgs(opStr, val, - datatype, hasher) + + } + + var verifiablePresentation jsonObj + if len(vpEntries) > 0 { + verifiablePresentation, err = fmtVerifiablePresentation(contextURL, + contextType, vpEntries...) if err != nil { - return out, nil, err + return nil, nil, err } } - return out, verifiablePresentation, nil + return queries, verifiablePresentation, nil } func getQuerySchemaAndType(requestObj jsonObj) (string, string, error) { @@ -1309,144 +1500,244 @@ func getCircuitID(requestObj jsonObj) (circuits.CircuitID, error) { return circuits.CircuitID(circuitID), nil } -func queryFromObjMerklized(ctx context.Context, - w3cCred verifiable.W3CCredential, requestObj jsonObj, - documentLoader ld.DocumentLoader, - circuitID circuits.CircuitID) (out circuits.Query, - verifiablePresentation jsonObj, err error) { +const iriCredentialSubject = "https://www.w3.org/2018/credentials#credentialSubject" - region := trace.StartRegion(ctx, "queryFromObjMerklized") - defer region.End() +func mkValueProof(ctx context.Context, mz *merklize.Merklizer, + path merklize.Path) (*circuits.ValueProof, error) { - mz, err := wrapMerklizeWithRegion(ctx, w3cCred, documentLoader) + existenceProof, mzValue, err := mz.Proof(ctx, path) if err != nil { - return out, nil, err + return nil, err } - var contextURL string - contextURL, err = stringByPath(requestObj, "query.context") - if err != nil { - return out, nil, err + if !existenceProof.Existence { + return nil, fmt.Errorf( + "value not found in verifiable credential by path %v", + fmtPath(path)) } - var contextType string - contextType, err = stringByPath(requestObj, "query.type") + + var valueEntry *big.Int + valueEntry, err = mzValue.MtEntry() if err != nil { - return out, nil, err + return nil, err } - field, op, err := getQueryFieldAndOperator(requestObj) - if errors.As(err, &errPathNotFound{}) { - if circuitID == circuits.AtomicQueryV3CircuitID || - circuitID == circuits.AtomicQueryV3OnChainCircuitID { - out.Operator = circuits.NOOP - out.Values = []*big.Int{} - return out, nil, nil - } + var pathEntry *big.Int + pathEntry, err = path.MtEntry() + if err != nil { + return nil, err + } - out.Operator = circuits.EQ - var path merklize.Path - path, err = merklize.NewPath( - "https://www.w3.org/2018/credentials#credentialSubject") - if err != nil { - return out, nil, err - } - out.ValueProof = new(circuits.ValueProof) - var mzValue merklize.Value - out.ValueProof.MTP, mzValue, err = mz.Proof(ctx, path) - if err != nil { - return out, nil, err - } + return &circuits.ValueProof{ + Path: pathEntry, + Value: valueEntry, + MTP: existenceProof, + }, nil +} - if !out.ValueProof.MTP.Existence { - return out, nil, fmt.Errorf( - "value not found in verifiable credential by path %v", - fmtPath(path)) - } +func mkEqQuery(ctx context.Context, mz *merklize.Merklizer, + path merklize.Path) (circuits.Query, error) { - var val *big.Int - val, err = mzValue.MtEntry() - if err != nil { - return out, nil, err - } - out.Values = []*big.Int{val} - out.ValueProof.Value = val - out.ValueProof.Path, err = path.MtEntry() - if err != nil { - return out, nil, err - } - return out, nil, nil - } else if err != nil { - return out, nil, - fmt.Errorf("unable to extract field from query: %w", err) - } - path, err := buildQueryPath(ctx, contextURL, contextType, field, - documentLoader) + valueProof, err := mkValueProof(ctx, mz, path) if err != nil { - return out, nil, err + return circuits.Query{}, err } - out.ValueProof = new(circuits.ValueProof) - out.ValueProof.Path, err = path.MtEntry() - if err != nil { - return out, nil, err + return circuits.Query{ + Operator: circuits.EQ, + Values: []*big.Int{valueProof.Value}, + ValueProof: valueProof, + }, nil +} + +type errSDCircuitNotSupported struct { + circuitID circuits.CircuitID +} + +func (e errSDCircuitNotSupported) Error() string { + return fmt.Sprintf("selective disclosure is not supported by circuit %v", + e.circuitID) +} + +type errSDOperatorNotSupported struct { + operator int +} + +func (e errSDOperatorNotSupported) Error() string { + return fmt.Sprintf("operator %v is not supported for selective disclosure", + opName(e.operator)) +} + +func sortedKeys(m jsonObj) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) } - var mzValue merklize.Value - out.ValueProof.MTP, mzValue, err = mz.Proof(ctx, path) + sort.Strings(keys) + return keys +} + +func queriesFromObjMerklized(ctx context.Context, + w3cCred verifiable.W3CCredential, requestObj jsonObj, + documentLoader ld.DocumentLoader, circuitID circuits.CircuitID, + claim *core.Claim) ([]*circuits.Query, jsonObj, error) { + + region := trace.StartRegion(ctx, "queryFromObjMerklized") + defer region.End() + + mz, err := wrapMerklizeWithRegion(ctx, w3cCred, documentLoader) if err != nil { - return out, nil, err + return nil, nil, err } - if !out.ValueProof.MTP.Existence { - return out, nil, fmt.Errorf( - "value not found in verifiable credential by path %v", - fmtPath(path)) - } + // TODO uncomment this on tests fixes + //mzRoot, err := claim.GetMerklizedRoot() + //if err != nil { + // return out, nil, err + //} + //if mzRoot.Cmp(mz.Root().BigInt()) != 0 { + // return out, nil, fmt.Errorf( + // "claim's merklized root does not match calculated merklized "+ + // "credential root. Claim's merklized root: %v, "+ + // "credential merklized croot: %v", + // mzRoot.String(), mz.Root().BigInt().String()) + //} - out.ValueProof.Value, err = mzValue.MtEntry() + var contextURL, contextType string + contextURL, contextType, err = getQuerySchemaAndType(requestObj) if err != nil { - return out, nil, err + return nil, nil, err } - var opObj jsonObj - var ok bool - opObj, ok = op.(jsonObj) - if !ok { - return out, nil, errors.New("operation on field is not a json object") - } - opStr, val, err := extractSingleEntry(opObj) - switch err { - case errMultipleEntries: - return out, nil, errors.New("only one operation per field is supported") - case errNoEntry: - // handle selective disclosure + var queries = make([]*circuits.Query, circuits.LinkedMultiQueryLength) + var queryIndex = 0 + var credSubjObj jsonObj + credSubjObj, err = objByBath(requestObj, "query.credentialSubject") + if errors.As(err, &errPathNotFound{}) { + + queries[0] = new(circuits.Query) + if circuitID == circuits.AtomicQueryV3CircuitID || - circuitID == circuits.AtomicQueryV3OnChainCircuitID { - out.Operator = circuits.SD - out.Values = []*big.Int{} + circuitID == circuits.AtomicQueryV3OnChainCircuitID || + circuitID == circuits.LinkedMultiQuery10CircuitID { + queries[0].Operator = circuits.NOOP + queries[0].Values = []*big.Int{} } else { - out.Operator = circuits.EQ - out.Values = []*big.Int{out.ValueProof.Value} + var path merklize.Path + path, err = merklize.NewPath(iriCredentialSubject) + if err != nil { + return nil, nil, err + } + *queries[0], err = mkEqQuery(ctx, mz, path) + if err != nil { + return nil, nil, err + } + } + + return queries, nil, nil + } else if err != nil { + return nil, nil, + fmt.Errorf("unable to extract field from query: %w", err) + } + + var vpEntries []objEntry + fields := sortedKeys(credSubjObj) + for _, field := range fields { + ops, ok := credSubjObj[field].(jsonObj) + if !ok { + return nil, nil, fmt.Errorf( + "for query field '%v' the operator object is of incorrect type: %T", + field, credSubjObj[field]) + } - rawValue, err := mz.RawValue(path) + var path merklize.Path + path, err = buildQueryPath(ctx, contextURL, contextType, field, + documentLoader) if err != nil { - return out, nil, err + return nil, nil, err } - verifiablePresentation = fmtVerifiablePresentation(contextURL, - contextType, field, rawValue) - default: - fieldDatatype, err := mz.JSONLDType(path) + + var valueProof *circuits.ValueProof + valueProof, err = mkValueProof(ctx, mz, path) if err != nil { - return out, nil, err + return nil, nil, err } - out.Operator, out.Values, err = unpackOperatorWithArgs(opStr, val, - fieldDatatype, mz.Hasher()) + if len(ops) == 0 { + + // Handle selective disclosure + + if queryIndex >= circuits.LinkedMultiQueryLength { + return nil, nil, errors.New("too many queries") + } + + var query = circuits.Query{ValueProof: valueProof} + var sdOp int + sdOp, ok = sdOperator[circuitID] + if !ok { + return nil, nil, errSDCircuitNotSupported{circuitID} + } + + switch sdOp { + case circuits.SD: + query.Operator = circuits.SD + query.Values = []*big.Int{} + case circuits.EQ: + query.Operator = circuits.EQ + query.Values = []*big.Int{query.ValueProof.Value} + default: + return nil, nil, errSDOperatorNotSupported{sdOp} + } + + queries[queryIndex] = &query + queryIndex++ + + vpEntry := objEntry{key: field} + vpEntry.value, err = mz.RawValue(path) + if err != nil { + return nil, nil, err + } + vpEntries = append(vpEntries, vpEntry) + + } else { + + sortedOps := sortedKeys(ops) + for _, op := range sortedOps { + val := ops[op] + + var fieldDatatype string + fieldDatatype, err = mz.JSONLDType(path) + if err != nil { + return nil, nil, err + } + + var query = circuits.Query{ValueProof: valueProof} + query.Operator, query.Values, err = unpackOperatorWithArgs(op, + val, fieldDatatype, mz.Hasher()) + if err != nil { + return nil, nil, err + } + + if queryIndex >= circuits.LinkedMultiQueryLength { + return nil, nil, errors.New("too many queries") + } + queries[queryIndex] = &query + queryIndex++ + } + } + } + + var verifiablePresentation jsonObj + if len(vpEntries) > 0 { + verifiablePresentation, err = fmtVerifiablePresentation(contextURL, + contextType, vpEntries...) if err != nil { - return out, nil, err + return nil, nil, err } } - return out, verifiablePresentation, nil + + return queries, verifiablePresentation, nil } // Return int operator value by its name and arguments as big.Ints array. @@ -1499,27 +1790,6 @@ func unpackOperatorWithArgs(opStr string, opValue any, } } -func getQueryFieldAndOperator(requestObj jsonObj) (string, any, error) { - credSubjObj, err := objByBath(requestObj, "query.credentialSubject") - if err != nil { - return "", nil, err - } - return extractSingleEntry(credSubjObj) -} - -var errNoEntry = errors.New("no entry") -var errMultipleEntries = errors.New("multiple entries") - -func extractSingleEntry(obj jsonObj) (key string, val any, err error) { - if len(obj) > 1 { - return key, val, errMultipleEntries - } - for key, val = range obj { - return key, val, nil - } - return key, val, errNoEntry -} - type hexHash merkletree.Hash func (h *hexHash) UnmarshalJSON(i []byte) error { diff --git a/inputs_sig_test.go b/inputs_sig_test.go index f8b6421..a7ab740 100644 --- a/inputs_sig_test.go +++ b/inputs_sig_test.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path" + "strconv" "sync" "testing" @@ -90,6 +91,9 @@ func TestPrepareInputs(t *testing.T) { fn PrepareInputsFn, wantVR map[string]any, cfg EnvConfig, wantErr string) { + err := CleanCache() + require.NoError(t, err) + ctx := context.Background() out, err := fn(ctx, cfg, readFixtureFile(inFile)) if wantErr != "" { @@ -162,7 +166,7 @@ func TestPrepareInputs(t *testing.T) { "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qFuKxq6iPem5w2U6T6druwGFjqTinE1kqNkSN7oo9/claims/revocation/status/380518664": "testdata/httpresp_rev_status_380518664.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_mtp_v2_inputs.json", "atomic_query_mtp_v2_output.json", AtomicQueryMtpV2InputsFromJson, @@ -174,7 +178,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3-non-merklized.json-ld": "testdata/httpresp_kyc-v3-non-merklized.json-ld", "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qFuKxq6iPem5w2U6T6druwGFjqTinE1kqNkSN7oo9/claims/revocation/status/118023115": "testdata/httpresp_rev_status_118023115.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_mtp_v2_non_merklized_inputs.json", "atomic_query_mtp_v2_non_merklized_output.json", @@ -187,7 +191,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3-non-merklized.json-ld": "testdata/httpresp_kyc-v3-non-merklized.json-ld", "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qFuKxq6iPem5w2U6T6druwGFjqTinE1kqNkSN7oo9/claims/revocation/status/118023115": "testdata/httpresp_rev_status_118023115.json", - }, httpmock.IgnoreUntouchedURLs())() + })() wantVerifiablePresentation := map[string]any{ "@context": []any{"https://www.w3.org/2018/credentials/v1"}, @@ -218,7 +222,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() wantVerifiablePresentation := map[string]any{ "@context": []any{"https://www.w3.org/2018/credentials/v1"}, @@ -248,7 +252,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_sig_v2_merklized_inputs.json", "atomic_query_sig_v2_merklized_output.json", @@ -272,7 +276,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_sig_v2_merklized_ipfs_inputs.json", "atomic_query_sig_v2_merklized_output.json", @@ -286,7 +290,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_sig_v2_merklized_noop_inputs.json", "atomic_query_sig_v2_merklized_noop_output.json", @@ -296,7 +300,7 @@ func TestPrepareInputs(t *testing.T) { t.Run("AtomicQuerySigV2InputsFromJson - revoked", func(t *testing.T) { defer httpmock.MockHTTPClient(t, map[string]string{ "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/105": "testdata/httpresp_rev_status_105.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_sig_v2_merklized_revoked_inputs.json", "", AtomicQuerySigV2InputsFromJson, nil, EnvConfig{}, @@ -310,7 +314,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/105": "testdata/httpresp_rev_status_105.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_sig_v2_merklized_skip_revocation_check_inputs.json", @@ -325,7 +329,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3-non-merklized.json-ld": "testdata/httpresp_kyc-v3-non-merklized.json-ld", "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/3878863870": "testdata/httpresp_rev_status_3878863870.json", "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/0": "testdata/httpresp_rev_status_2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_sig_v2_non_merklized_inputs.json", "atomic_query_sig_v2_non_merklized_output.json", @@ -337,7 +341,7 @@ func TestPrepareInputs(t *testing.T) { defer httpmock.MockHTTPClient(t, map[string]string{ "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/3878863870": "testdata/httpresp_rev_status_3878863870.json", "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/0": "testdata/httpresp_rev_status_2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_sig_v2_non_merklized_noop_inputs.json", "", AtomicQuerySigV2InputsFromJson, nil, EnvConfig{}, "credentialSubject field is not found in query") @@ -348,7 +352,9 @@ func TestPrepareInputs(t *testing.T) { defer httpmock.MockHTTPClient(t, map[string]string{ "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/3878863870": "testdata/httpresp_rev_status_3878863870.json", "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/0": "testdata/httpresp_rev_status_2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui_0.json", - }, httpmock.IgnoreUntouchedURLs())() + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3-non-merklized.json-ld": "testdata/httpresp_kyc-v3-non-merklized.json-ld", + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", + })() wantVerifiablePresentation := map[string]any{ "@context": []any{"https://www.w3.org/2018/credentials/v1"}, @@ -380,7 +386,7 @@ func TestPrepareInputs(t *testing.T) { "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV/claims/revocation/status/0": "testdata/httpresp_rev_status_qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV_0.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_sig_v2_on_chain_input.json", @@ -394,7 +400,7 @@ func TestPrepareInputs(t *testing.T) { "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV/claims/revocation/status/3972757": "testdata/httpresp_rev_status_3972757.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_mtp_v2_on_chain_input.json", @@ -402,15 +408,14 @@ func TestPrepareInputs(t *testing.T) { AtomicQueryMtpV2OnChainInputsFromJson, nil, EnvConfig{}, "") }) - t.Run("AtomicQuerySigV2InputsFromJson - RHS - empty revocation tree", + t.Run("AtomicQuerySigV2InputsFromJson__RHS__empty_revocation_tree", func(t *testing.T) { defer httpmock.MockHTTPClient(t, map[string]string{ `http://localhost:8545%%%{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","input":"0xb4bdea55000d5228592025eac998034e2c03f242819d84806687a3b0c95eefa295ca1202","to":"0x6f0a444df4d231d85f66e4836f836034f0fefe24"},"latest"]}`: "testdata/httpresp_eth_resp1.json", "http://localhost:8003/node/8ef2ce21e01d86ec2376fe28bf6b47a84d08f8628d970474a2698cebf94bca1c": "testdata/httpresp_rhs_8ef2ce21e01d86ec2376fe28bf6b47a84d08f8628d970474a2698cebf94bca1c.json", - "http://localhost:8003/node/8ef2e21e01d86ec2376fe28bf6b47a84d08f8628d970474a2698cebf94bca1c": "testdata/httpresp_rhs_8ef2ce21e01d86ec2376fe28bf6b47a84d08f8628d970474a2698cebf94bca1c.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", - }, httpmock.IgnoreUntouchedURLs())() + })() cfg := EnvConfig{ ChainConfigs: map[core.ChainID]ChainConfig{ @@ -439,7 +444,7 @@ func TestPrepareInputs(t *testing.T) { "http://localhost:8003/node/d543edb99a153f54e1338f3c9515bc49ccc4c468433de880c7299b1b0fc16017": "testdata/httpresp_rhs_d543edb99a153f54e1338f3c9515bc49ccc4c468433de880c7299b1b0fc16017.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", - }, httpmock.IgnoreUntouchedURLs())() + })() cfg := EnvConfig{ ChainConfigs: map[core.ChainID]ChainConfig{ @@ -464,7 +469,7 @@ func TestPrepareInputs(t *testing.T) { "http://localhost:8003/node/a75cc7f84f279f758427e8f1ec26d2d7dcac0fd545098ef668dde0d2f90ca809": "testdata/httpresp_rhs_a75cc7f84f279f758427e8f1ec26d2d7dcac0fd545098ef668dde0d2f90ca809.json", "http://localhost:8003/node/ce051a956948154312d91a406b52120fd689376c1b675699053cc1d7cafa4f04": "testdata/httpresp_rhs_ce051a956948154312d91a406b52120fd689376c1b675699053cc1d7cafa4f04.json", "http://localhost:8003/node/3ecaca31559a389adb870fa1347b8487dee24406a7c9959334d3f36b65c3ba1d": "testdata/httpresp_rhs_3ecaca31559a389adb870fa1347b8487dee24406a7c9959334d3f36b65c3ba1d.json", - }, httpmock.IgnoreUntouchedURLs())() + })() cfg := EnvConfig{ ChainConfigs: map[core.ChainID]ChainConfig{ @@ -497,7 +502,7 @@ func TestPrepareInputs(t *testing.T) { "https://dev.polygonid.me/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qLPqvayNQz9TA2r5VPxUugoF18teGU583zJ859wfy/claims/revocation/status/214490175": "testdata/httpresp_rev_status_214490175.json", "https://dev.polygonid.me/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qLPqvayNQz9TA2r5VPxUugoF18teGU583zJ859wfy/claims/revocation/status/2575161389": "testdata/httpresp_rev_status_2575161389.json", "https://schema.iden3.io/core/jsonld/iden3proofs.jsonld": "testdata/httpresp_iden3proofs.jsonld", - }, httpmock.IgnoreUntouchedURLs())() + })() wantVerifiablePresentation := map[string]any{ "@context": []any{"https://www.w3.org/2018/credentials/v1"}, @@ -531,7 +536,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", //"http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_v3_mtp_inputs.json", "atomic_query_v3_mtp_output.json", @@ -544,7 +549,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_v3_sig_inputs.json", "atomic_query_v3_sig_output.json", @@ -557,7 +562,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_v3_sig_empty_query_inputs.json", "atomic_query_v3_sig_empty_query_output.json", @@ -570,7 +575,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_v3_no_proof_type_both_have_inputs.json", "atomic_query_v3_mtp_output.json", @@ -584,7 +589,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_v3_no_proof_type_sig_only_inputs.json", "atomic_query_v3_sig_output.json", @@ -596,7 +601,7 @@ func TestPrepareInputs(t *testing.T) { "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV/claims/revocation/status/3972757": "testdata/httpresp_rev_status_3972757.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_v3_on_chain_mtp_inputs.json", "atomic_query_v3_on_chain_mtp_output.json", @@ -609,7 +614,7 @@ func TestPrepareInputs(t *testing.T) { "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV/claims/revocation/status/3972757": "testdata/httpresp_rev_status_3972757.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_v3_on_chain_sig_inputs.json", "atomic_query_v3_on_chain_sig_output.json", @@ -623,7 +628,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", - }, httpmock.IgnoreUntouchedURLs())() + })() wantVerifiablePresentation := map[string]any{ "@context": []any{"https://www.w3.org/2018/credentials/v1"}, @@ -652,7 +657,7 @@ func TestPrepareInputs(t *testing.T) { "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV/claims/revocation/status/3972757": "testdata/httpresp_rev_status_3972757.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", - }, httpmock.IgnoreUntouchedURLs())() + })() doTest(t, "atomic_query_v3_on_chain_tx_data_inputs.json", "atomic_query_v3_on_chain_tx_data_output.json", @@ -671,6 +676,7 @@ func TestPrepareInputs(t *testing.T) { require.Equal(t, "QmcvoKLc742CyVH2Cnw6X95b4c8VdABqNPvTyAHEeaK1aP", cid) defer httpmock.MockHTTPClient(t, map[string]string{ + "https://schema.iden3.io/core/jsonld/iden3proofs.jsonld": "testdata/httpresp_iden3proofs.jsonld", `http://127.0.0.1:8545%%%{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","input":"0xb4bdea55000e02195fa99cf8975171e88a411bff99da7548cd4576ba2d102cf77ec31202","to":"0x134b1be34911e39a8397ec6289782989729807a4"},"latest"]}`: "testdata/httpresp_eth_resp3.json", "https://rhs-staging.polygonid.me/node/34f9500218a054d58347b848dae17d07602b9320143c79e2786ff3aa97254f29": "testdata/httpresp_rhs_34f9500218a054d58347b848dae17d07602b9320143c79e2786ff3aa97254f29.json", "https://rhs-staging.polygonid.me/node/d469d1307ba23faae8eef13d90031c981e4d2c36977b0422e669e5ef7b891205": "testdata/httpresp_rhs_d469d1307ba23faae8eef13d90031c981e4d2c36977b0422e669e5ef7b891205.json", @@ -682,7 +688,7 @@ func TestPrepareInputs(t *testing.T) { "https://rhs-staging.polygonid.me/node/c5b8691380634bd9c0f928da490f684579a2b51de1ee52028b74d83f461d0208": "testdata/httpresp_rhs_c5b8691380634bd9c0f928da490f684579a2b51de1ee52028b74d83f461d0208.json", "https://rhs-staging.polygonid.me/node/1aefa6dd321a42685112bf762d7dc17a6fb51e5521a819f6d5c8a09681932913": "testdata/httpresp_rhs_1aefa6dd321a42685112bf762d7dc17a6fb51e5521a819f6d5c8a09681932913.json", "https://rhs-staging.polygonid.me/node/d2e4c97c4fc3e83521a8b7910765ac62a7171f9120be3c3b854d48cd510e6f0a": "testdata/httpresp_rhs_d2e4c97c4fc3e83521a8b7910765ac62a7171f9120be3c3b854d48cd510e6f0a.json", - }, httpmock.IgnoreUntouchedURLs())() + })() cfg := EnvConfig{ IPFSNodeURL: ipfsURL, @@ -712,6 +718,7 @@ func TestPrepareInputs(t *testing.T) { require.Equal(t, "QmcvoKLc742CyVH2Cnw6X95b4c8VdABqNPvTyAHEeaK1aP", cid) defer httpmock.MockHTTPClient(t, map[string]string{ + "https://schema.iden3.io/core/jsonld/iden3proofs.jsonld": "testdata/httpresp_iden3proofs.jsonld", `http://127.0.0.1:8545%%%{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","input":"0xb4bdea55000e02195fa99cf8975171e88a411bff99da7548cd4576ba2d102cf77ec31202","to":"0x134b1be34911e39a8397ec6289782989729807a4"},"latest"]}`: "testdata/httpresp_eth_resp3.json", "https://rhs-staging.polygonid.me/node/34f9500218a054d58347b848dae17d07602b9320143c79e2786ff3aa97254f29": "testdata/httpresp_rhs_34f9500218a054d58347b848dae17d07602b9320143c79e2786ff3aa97254f29.json", "https://rhs-staging.polygonid.me/node/d469d1307ba23faae8eef13d90031c981e4d2c36977b0422e669e5ef7b891205": "testdata/httpresp_rhs_d469d1307ba23faae8eef13d90031c981e4d2c36977b0422e669e5ef7b891205.json", @@ -749,7 +756,7 @@ func TestPrepareInputs(t *testing.T) { "%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata" + "/httpresp_rev_status_2376431481_empty_rev_root.json", "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0_empty_roots.json", - }, httpmock.IgnoreUntouchedURLs())() + })() wantVerifiablePresentation := map[string]any{ "@context": []any{"https://www.w3.org/2018/credentials/v1"}, @@ -779,7 +786,7 @@ func TestPrepareInputs(t *testing.T) { "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3-non-merklized.json-ld": "testdata/httpresp_kyc-v3-non-merklized.json-ld", "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qFuKxq6iPem5w2U6T6druwGFjqTinE1kqNkSN7oo9/claims/revocation/status/118023115": "testdata/httpresp_rev_status_118023115_empty_roots.json", - }, httpmock.IgnoreUntouchedURLs())() + })() wantVerifiablePresentation := map[string]any{ "@context": []any{"https://www.w3.org/2018/credentials/v1"}, @@ -804,6 +811,49 @@ func TestPrepareInputs(t *testing.T) { EnvConfig{}, "") }) + t.Run("LinkedMultiQueryInputsFromJson_Merklized", func(t *testing.T) { + defer httpmock.MockHTTPClient(t, map[string]string{ + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld": "testdata/httpresp_kyc-v3.json-ld", + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", + "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481": "testdata/httpresp_rev_status_2376431481.json", + "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0": "testdata/httpresp_rev_status_wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU_0.json", + })() + + doTest(t, "linked_multi_query_inputs.json", + "linked_multi_query_output.json", + LinkedMultiQueryInputsFromJson, nil, EnvConfig{}, "") + }) + + t.Run("LinkedMultiQueryInputsFromJson_NonMerklized", func(t *testing.T) { + defer httpmock.MockHTTPClient(t, map[string]string{ + "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/3878863870": "testdata/httpresp_rev_status_3878863870.json", + "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/0": "testdata/httpresp_rev_status_2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui_0.json", + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3-non-merklized.json-ld": "testdata/httpresp_kyc-v3-non-merklized.json-ld", + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld": "testdata/httpresp_iden3credential_v2.json", + })() + + wantVerifiablePresentation := map[string]any{ + "@context": []any{"https://www.w3.org/2018/credentials/v1"}, + "@type": "VerifiablePresentation", + "verifiableCredential": map[string]any{ + "@context": []any{ + "https://www.w3.org/2018/credentials/v1", + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3-non-merklized.json-ld", + }, + "@type": []any{"VerifiableCredential", "KYCAgeCredential"}, + "credentialSubject": map[string]any{ + "@type": "KYCAgeCredential", + "documentType": float64(99), + }, + }, + } + + doTest(t, + "linked_multi_query_non_merklized_inputs.json", + "linked_multi_query_non_merklized_output.json", + LinkedMultiQueryInputsFromJson, wantVerifiablePresentation, + EnvConfig{}, "") + }) } func TestEnvConfig_UnmarshalJSON(t *testing.T) { @@ -917,7 +967,9 @@ func assertEqualWithoutTimestamp(t testing.TB, wantFName string, err = json.Unmarshal(inputsBytes, &inputsObj) require.NoError(t, err) - wantObj["timestamp"] = inputsObj["timestamp"] + if ts, ok := inputsObj["timestamp"]; ok { + wantObj["timestamp"] = ts + } require.Equal(t, wantObj, inputsObj, "file name: %s\nwant: %s\ngot: %s", wantFName, jsonWant, inputsBytes) @@ -1295,3 +1347,67 @@ func TestDescribeID(t *testing.T) { _, err = DescribeID(ctx, cfg, []byte(in)) require.EqualError(t, err, "id and idAsInt are different") } + +func TestMkVPObj(t *testing.T) { + const tp = "tp" + + testCases := []struct { + in []objEntry + want jsonObj + wantErr string + }{ + { + in: []objEntry{{}}, + wantErr: "empty key", + }, + { + in: []objEntry{}, + want: jsonObj{"@type": tp}, + }, + { + in: []objEntry{ + {"x.y1.z1", 3}, + {"x.y1.z2", 4}, + {"x.y2", 5}, + }, + want: jsonObj{ + "@type": "tp", + "x": jsonObj{ + "y1": jsonObj{ + "z1": 3, + "z2": 4, + }, + "y2": 5, + }, + }, + }, + { + in: []objEntry{ + {"x.y1.z1", 3}, + {"x.y1.z2", 4}, + {"x.y1", 5}, + }, + wantErr: "key already exists: y1", + }, + { + in: []objEntry{ + {"x.y1", 5}, + {"x.y1.z1", 3}, + {"x.y1.z2", 4}, + }, + wantErr: "not a json object: y1", + }, + } + + for i, tc := range testCases { + t.Run(strconv.Itoa(i), func(t *testing.T) { + out, err := mkVPObj(tp, tc.in...) + if tc.wantErr != "" { + require.EqualError(t, err, tc.wantErr) + return + } + require.NoError(t, err) + require.Equal(t, tc.want, out) + }) + } +} diff --git a/testdata/linked_multi_query_inputs.json b/testdata/linked_multi_query_inputs.json new file mode 100644 index 0000000..6285d78 --- /dev/null +++ b/testdata/linked_multi_query_inputs.json @@ -0,0 +1,104 @@ +{ + "id": "x1QQ78ktjAmia48pyEZENyurZhpRSdPMWmtv1zbsi", + "linkNonce": "456", + "profileNonce": "123", + "claimSubjectProfileNonce": "234", + "verifiableCredentials": { + "id": "http://localhost:8001/api/v1/claim/98781b98-73c9-11ed-9818-3a0197678785", + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld", + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld" + ], + "type": [ + "VerifiableCredential", + "KYCAgeCredential" + ], + "expirationDate": "2361-03-21T21:14:48+02:00", + "issuanceDate": "2022-12-04T13:48:40.198183+02:00", + "credentialSubject": { + "birthday": 19960424, + "documentType": 2, + "id": "did:iden3:polygon:mumbai:x1QQ78ktjAmia48pyEZENyurZhpRSdPMWmtv1zbsi", + "type": "KYCAgeCredential" + }, + "credentialStatus": { + "id": "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/2376431481", + "revocationNonce": 2376431481, + "type": "SparseMerkleTreeProof" + }, + "issuer": "did:iden3:polygon:mumbai:wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU", + "credentialSchema": { + "id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCAgeCredential-v3.json", + "type": "JsonSchemaValidator2018" + }, + "proof": [ + { + "type": "BJJSignature2021", + "issuerData": { + "id": "did:iden3:polygon:mumbai:wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU", + "state": { + "claimsTreeRoot": "11185c59b43208eeb4fb732f20ece73d6d440c64c4b52422bf1a6deeafe68f05", + "value": "3a5ca99f6701addce176e9a9de1980cbc41034e75b24c3a2b04fd4cb4b3d2810" + }, + "authCoreClaim": "013fd3f623559d850fb5b02ff012d0e2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bf3d1641ec4e00d087f2480cc65a6ea9b211aace253182ebb81240d9d368fc2d2fee435fc728f05c6979b226f42958c84aa86b4ba54a77b72fc00e6e9265ff1d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "mtp": { + "existence": true, + "siblings": [] + }, + "credentialStatus": { + "id": "http://localhost:8001/api/v1/identities/did%3Aiden3%3Apolygon%3Amumbai%3AwuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU/claims/revocation/status/0", + "revocationNonce": 0, + "type": "SparseMerkleTreeProof" + } + }, + "coreClaim": "c9b2370371b7fa8b3dab2a5ba81b68382a000000000000000000000000000000011285d39f7e4e930bf6621fd141407299cf5fba8829960dfe83ce5b23510d00304987e6a4740b263819a852beca7ac47b74ba515b57f873654b6cc2182ac22500000000000000000000000000000000000000000000000000000000000000007977a58d00000000281cdcdf0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "signature": "f0b19b1c5d5317535f5f3647f6c644294c8dfc3c4ef057a323b54e3ce8945d20a6fbd5ba9c8a1e5e87267e4f604818447148af6f51ac6cd10c1a10ca20396e02" + }, + { + "type": "Iden3SparseMerkleProof", + "issuerData": { + "id": "did:iden3:polygon:mumbai:wuQT8NtFq736wsJahUuZpbA8otTzjKGyKj4i4yWtU", + "state": { + "txId": "0x1cb9fed0226d628ed39d8cbdbc71c81246b6032eb3f31d8abcfca8e9c790d2c0", + "blockTimestamp": 1670154663, + "blockNumber": 29484252, + "rootOfRoots": "10d1069175d39632f025e200d441eea466ee9e71e0ad5a3841d5ecea6646f116", + "claimsTreeRoot": "06008861f3bbaf33062ba867480cd9becc14817433369b6edd306f747818fb14", + "revocationTreeRoot": "0000000000000000000000000000000000000000000000000000000000000000", + "value": "29810ec2eccf276d101a8ba9b4fa4c53d00f795413bfe2682c64c627184c1721" + } + }, + "coreClaim": "c9b2370371b7fa8b3dab2a5ba81b68382a000000000000000000000000000000011285d39f7e4e930bf6621fd141407299cf5fba8829960dfe83ce5b23510d00304987e6a4740b263819a852beca7ac47b74ba515b57f873654b6cc2182ac22500000000000000000000000000000000000000000000000000000000000000007977a58d00000000281cdcdf0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "mtp": { + "existence": true, + "siblings": [ + "21766464054775500261540970596627132740681360541808718916226684581420553493829", + "0", + "0", + "2515815517939277878486495591852893192186484331807066957639537744648750241809" + ] + } + } + ] + }, + "request": { + "id": 84239, + "circuitId": "linkedMultiQuery10-beta.1", + "query": { + "allowedIssuers": "unused", + "context": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld", + "type": "KYCAgeCredential", + "credentialSubject": { + "documentType": { + "$eq": 2 + }, + "birthday": { + "$gt": 19960000, + "$eq": 19960424 + } + }, + "proofType": "BJJSignature2021" + } + } +} diff --git a/testdata/linked_multi_query_non_merklized_inputs.json b/testdata/linked_multi_query_non_merklized_inputs.json new file mode 100644 index 0000000..d8adae9 --- /dev/null +++ b/testdata/linked_multi_query_non_merklized_inputs.json @@ -0,0 +1,73 @@ +{ + "id": "2qHcRLuHY8xh8EXWxe9TvanKfficNDXUWyYkot6hVX", + "linkNonce": "456", + "profileNonce": "0", + "claimSubjectProfileNonce": "0", + "verifiableCredentials": { + "id": "http://localhost:8001/api/v1/identities/did:polygonid:polygon:mumbai:2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/b8c93a08-9b3d-11ed-a382-e24d9cbdb31b", + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/iden3credential-v2.json-ld", + "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3-non-merklized.json-ld" + ], + "type": [ + "VerifiableCredential", + "KYCAgeCredential" + ], + "expirationDate": "2361-03-21T15:14:48-04:00", + "issuanceDate": "2023-01-23T11:48:11.385823-05:00", + "credentialSubject": { + "birthday": 19960424, + "documentType": 99, + "id": "did:polygonid:polygon:mumbai:2qHcRLuHY8xh8EXWxe9TvanKfficNDXUWyYkot6hVX", + "type": "KYCAgeCredential" + }, + "credentialStatus": { + "id": "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/3878863870", + "revocationNonce": 3878863870, + "type": "SparseMerkleTreeProof" + }, + "issuer": "did:polygonid:polygon:mumbai:2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui", + "credentialSchema": { + "id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCAgeCredential-v2.json", + "type": "JsonSchemaValidator2018" + }, + "proof": [ + { + "type": "BJJSignature2021", + "issuerData": { + "id": "did:polygonid:polygon:mumbai:2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui", + "state": { + "claimsTreeRoot": "fd3fdadc9005124113da683a90acfc2ecf3c0b07a9dc9c38475000edd4fb0b0a", + "value": "895766625913e26382af1bd1f6fc9cb85105b89cd071336d9c1c6af672d70001" + }, + "authCoreClaim": "cca3371a6cb1b715004407e325bd993c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0c9a5c5cd3997958d1fa2fe042db3cc0876b1283e1af2ccfd8366fe1110a11c85f11bbc255d6be2e550d1f809acc4e29b6038811d3c3982f3e8878240645d220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "mtp": { + "existence": true, + "siblings": [] + }, + "credentialStatus": { + "id": "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui/claims/revocation/status/0", + "revocationNonce": 0, + "type": "SparseMerkleTreeProof" + } + }, + "coreClaim": "c9b2370371b7fa8b3dab2a5ba81b68380a0000000000000000000000000000000212714f646d1d7ba66d15e15b8b36bd81becee64dd0efd431c3d67c144c0e0068923001000000000000000000000000000000000000000000000000000000006300000000000000000000000000000000000000000000000000000000000000fec332e700000000281cdcdf0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "signature": "0ee68e96b47d98968138b94111d086d47da057cde140ae66434669ff5fd0ad1f799e7db54cecca0de03c17ef4cc7cfea5a13113c520acea8cd720065daf47a04" + } + ] + }, + "request": { + "id": 84239, + "circuitId": "linkedMultiQuery10-beta.1", + "query": { + "allowedIssuers": "2qDNRmjPHUrtnPWfXQ4kKwZfarfsSYoiFBxB9tDkui", + "context": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3-non-merklized.json-ld", + "type": "KYCAgeCredential", + "credentialSubject": { + "documentType": {}, + "birthday": {"$eq": "19960424", "$lt": "19960425"} + } + } + } +} diff --git a/testdata/linked_multi_query_non_merklized_output.json b/testdata/linked_multi_query_non_merklized_output.json new file mode 100644 index 0000000..ac8a986 --- /dev/null +++ b/testdata/linked_multi_query_non_merklized_output.json @@ -0,0 +1,1114 @@ +{ + "linkNonce": "456", + "issuerClaim": [ + "3477800996810232866019409354499158422217", + "25260943975259132910392773295718367206218859286129377425053195525747184130", + "19960424", + "99", + "227737578863135127233476346878", + "0", + "0", + "0" + ], + "claimSchema": "74977327600848231385663280181476307657", + "claimPathMtp": [ + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ] + ], + "claimPathMtpNoAux": [ + "1", + "1", + "1", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "claimPathMtpAuxHi": [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "claimPathMtpAuxHv": [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "claimPathKey": [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "claimPathValue": [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "slotIndex": [ + 2, + 2, + 3, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "operator": [ + 1, + 2, + 16, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "value": [ + [ + "19960424", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "19960425", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ] + ], + "valueArraySize": [ + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] +} diff --git a/testdata/linked_multi_query_output.json b/testdata/linked_multi_query_output.json new file mode 100644 index 0000000..c8c23ba --- /dev/null +++ b/testdata/linked_multi_query_output.json @@ -0,0 +1 @@ +{"linkNonce":"456","issuerClaim":["14366836738280263696847396792315741188809","23529006562716512365284470649701500265624720888290140936730678617958584833","17078634269008282508978520614899691176511963995966531315408520179071582685488","0","227737578863135127231973914489","0","0","0"],"claimSchema":"74977327600848231385663280181476307657","claimPathMtp":[["12517150030576619527252492821655890410294919107657416409973519542186017163807","11933107200150122400824598729420157563957281318882971696220077028927460055808","13748716966604096441336188506766329119346066422143435538531763565408555859415","0","7234734700882409562051669071537722159277854149198231521046768401160975042526","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["12517150030576619527252492821655890410294919107657416409973519542186017163807","11933107200150122400824598729420157563957281318882971696220077028927460055808","13748716966604096441336188506766329119346066422143435538531763565408555859415","0","7234734700882409562051669071537722159277854149198231521046768401160975042526","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["12517150030576619527252492821655890410294919107657416409973519542186017163807","11933107200150122400824598729420157563957281318882971696220077028927460055808","13748716966604096441336188506766329119346066422143435538531763565408555859415","0","20486600725567702962288985115041578424966996747359110560639957588130104510049","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"]],"claimPathMtpNoAux":["0","0","0","0","0","0","0","0","0","0"],"claimPathMtpAuxHi":["0","0","0","0","0","0","0","0","0","0"],"claimPathMtpAuxHv":["0","0","0","0","0","0","0","0","0","0"],"claimPathKey":["20376033832371109177683048456014525905119173674985843915445634726167450989630","20376033832371109177683048456014525905119173674985843915445634726167450989630","17040667407194471738958340146498954457187839778402591036538781364266841966","0","0","0","0","0","0","0"],"claimPathValue":["19960424","19960424","2","0","0","0","0","0","0","0"],"slotIndex":[0,0,0,0,0,0,0,0,0,0],"operator":[1,3,1,0,0,0,0,0,0,0],"value":[["19960424","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["19960000","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["2","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"]],"valueArraySize":[1,1,1,0,0,0,0,0,0,0]}