From 11ecaec1183eccba8ce2a75e9e7d366fe717521f Mon Sep 17 00:00:00 2001 From: Oleg Lomaka Date: Fri, 10 Jan 2025 05:52:30 -0500 Subject: [PATCH] Add statesInfo into circuit inputs response. Fix cacheDir handling. --- cmd/polygonid/polygonid.go | 55 ++++-- cmd/polygonid/polygonid_test.go | 87 ++++++++ .../atomic_query_v3_on_chain_mtp_inputs.json | 139 +++++++++++++ .../atomic_query_v3_on_chain_mtp_output.json | 1 + cmd/polygonid/testdata/auth_v2_inputs_in.json | 44 +++++ .../testdata/auth_v2_inputs_out.json | 185 ++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- inputs_sig.go | 109 ++++++++--- inputs_sig_test.go | 15 +- 10 files changed, 586 insertions(+), 55 deletions(-) create mode 100644 cmd/polygonid/testdata/atomic_query_v3_on_chain_mtp_inputs.json create mode 100644 cmd/polygonid/testdata/atomic_query_v3_on_chain_mtp_output.json create mode 100644 cmd/polygonid/testdata/auth_v2_inputs_in.json create mode 100644 cmd/polygonid/testdata/auth_v2_inputs_out.json diff --git a/cmd/polygonid/polygonid.go b/cmd/polygonid/polygonid.go index c46f81c..c65b70a 100644 --- a/cmd/polygonid/polygonid.go +++ b/cmd/polygonid/polygonid.go @@ -158,6 +158,11 @@ func maybeCreateStatus(status **C.PLGNStatus, code C.PLGNStatusCode, *status = s } +// Deprecated: Use PLGNAGenerateInputs with additional +// `"request": {"circuitId": "authV2"}` in the request json. This function +// does not support `statsInfo` in response and returns inputs +// on top level of response object. +// //export PLGNAuthV2InputsMarshal func PLGNAuthV2InputsMarshal(jsonResponse **C.char, in *C.char, status **C.PLGNStatus) bool { @@ -610,6 +615,7 @@ func marshalInputsResponse( var resp struct { Inputs json.RawMessage `json:"inputs"` VerifiablePresentation any `json:"verifiablePresentation,omitempty"` + StatesInfo json.RawMessage `json:"statesInfo,omitempty"` } if inputsResponse.VerifiablePresentation != nil { resp.VerifiablePresentation = inputsResponse.VerifiablePresentation @@ -620,6 +626,18 @@ func marshalInputsResponse( return "", err } + i, ok := inputsResponse.Inputs.(circuits.StatesInfoProvider) + if ok { + statesInfo, err := i.GetStatesInfo() + if err != nil { + return "", err + } + resp.StatesInfo, err = json.Marshal(statesInfo) + if err != nil { + return "", err + } + } + respBytes, err := json.Marshal(resp) if err != nil { return "", err @@ -751,17 +769,17 @@ func PLGNALinkedMultiQueryInputs(jsonResponse **C.char, in *C.char, jsonResponse, in, cfg, status) } -// PLGNAQueryInputs returns the inputs for the circuit based on the +// PLGNAGenerateInputs returns the inputs for the circuit based on the // request.circuitId field. // -//export PLGNAQueryInputs -func PLGNAQueryInputs(jsonResponse **C.char, in *C.char, +//export PLGNAGenerateInputs +func PLGNAGenerateInputs(jsonResponse **C.char, in *C.char, cfg *C.char, status **C.PLGNStatus) bool { ctx, cancel := logAPITime() defer cancel() - return prepareInputs(ctx, c_polygonid.GenericQueryInputsFromJson, + return prepareInputs(ctx, c_polygonid.GenericInputsFromJson, jsonResponse, in, cfg, status) } @@ -804,7 +822,7 @@ func PLGNCleanCache2(cfg *C.char, status **C.PLGNStatus) bool { _, cancel := logAPITime() defer cancel() - envCfg, err := createEnvConfig(cfg) + envCfg, err := c_polygonid.NewEnvConfigFromJSON(cStrToGoSlice(cfg)) if err != nil { maybeCreateStatus(status, C.PLGNSTATUSCODE_ERROR, "%v", err.Error()) return false @@ -829,7 +847,7 @@ func PLGNCacheCredentials(in *C.char, cfg *C.char, status **C.PLGNStatus) bool { inData := C.GoBytes(unsafe.Pointer(in), C.int(C.strlen(in))) - envCfg, err := createEnvConfig(cfg) + envCfg, err := c_polygonid.NewEnvConfigFromJSON(cStrToGoSlice(cfg)) if err != nil { maybeCreateStatus(status, C.PLGNSTATUSCODE_ERROR, "%v", err.Error()) return false @@ -882,7 +900,7 @@ func PLGNW3CCredentialFromOnchainHex(jsonResponse **C.char, in *C.char, inData := C.GoBytes(unsafe.Pointer(in), C.int(C.strlen(in))) - envCfg, err := createEnvConfig(cfg) + envCfg, err := c_polygonid.NewEnvConfigFromJSON(cStrToGoSlice(cfg)) if err != nil { maybeCreateStatus(status, C.PLGNSTATUSCODE_ERROR, "%v", err.Error()) return false @@ -939,7 +957,7 @@ func PLGNDescribeID(jsonResponse **C.char, in *C.char, cfg *C.char, return false } - envCfg, err := createEnvConfig(cfg) + envCfg, err := c_polygonid.NewEnvConfigFromJSON(cStrToGoSlice(cfg)) if err != nil { maybeCreateStatus(status, C.PLGNSTATUSCODE_ERROR, "%v", err.Error()) return false @@ -1002,15 +1020,6 @@ func PLGNBabyJubJubPublicCompress(jsonResponse **C.char, in *C.char, in, cfg, status) } -// createEnvConfig returns empty config if input json is nil. -func createEnvConfig(cfgJson *C.char) (c_polygonid.EnvConfig, error) { - var cfgData []byte - if cfgJson != nil { - cfgData = C.GoBytes(unsafe.Pointer(cfgJson), C.int(C.strlen(cfgJson))) - } - return c_polygonid.NewEnvConfigFromJSON(cfgData) -} - type atomicQueryInputsFn func(ctx context.Context, cfg c_polygonid.EnvConfig, in []byte) (c_polygonid.AtomicQueryInputsResponse, error) @@ -1029,7 +1038,7 @@ func prepareInputs(ctx context.Context, fn atomicQueryInputsFn, inData := C.GoBytes(unsafe.Pointer(in), C.int(C.strlen(in))) - envCfg, err := createEnvConfig(cfg) + envCfg, err := c_polygonid.NewEnvConfigFromJSON(cStrToGoSlice(cfg)) if err != nil { maybeCreateStatus(status, C.PLGNSTATUSCODE_ERROR, "%v", err.Error()) return false @@ -1108,6 +1117,14 @@ func statusFromError(err error) (C.PLGNStatusCode, string) { return C.PLGNSTATUSCODE_ERROR, err.Error() } +func cStrToGoSlice(in *C.char) []byte { + var out []byte + if in != nil { + out = C.GoBytes(unsafe.Pointer(in), C.int(C.strlen(in))) + } + return out +} + func callGenericFn[R any]( fn func(context.Context, c_polygonid.EnvConfig, []byte) (R, error), jsonResponse **C.char, in *C.char, cfg *C.char, @@ -1122,7 +1139,7 @@ func callGenericFn[R any]( return false } - envCfg, err := createEnvConfig(cfg) + envCfg, err := c_polygonid.NewEnvConfigFromJSON(cStrToGoSlice(cfg)) if err != nil { maybeCreateStatus(status, C.PLGNSTATUSCODE_ERROR, "%v", err.Error()) return false diff --git a/cmd/polygonid/polygonid_test.go b/cmd/polygonid/polygonid_test.go index 79e7001..ee264bb 100644 --- a/cmd/polygonid/polygonid_test.go +++ b/cmd/polygonid/polygonid_test.go @@ -1,14 +1,18 @@ package main import ( + "context" "encoding/hex" "encoding/json" "math/big" "math/rand" + "os" "strings" "testing" "time" + c_polygonid "github.com/0xPolygonID/c-polygonid" + httpmock "github.com/0xPolygonID/c-polygonid/testing" core "github.com/iden3/go-iden3-core/v2" "github.com/iden3/go-iden3-crypto/poseidon" "github.com/stretchr/testify/require" @@ -127,3 +131,86 @@ func TestCreateClaimAllFields2(t *testing.T) { t.Log(string(cBytes)) } + +func readFixtureFile(name string) []byte { + fileBytes, err := os.ReadFile("testdata/" + name) + if err != nil { + panic(err) + } + return fileBytes +} + +func TestGenrateInputs(t *testing.T) { + type PrepareInputsFn func( + ctx context.Context, cfg c_polygonid.EnvConfig, in []byte) ( + c_polygonid.AtomicQueryInputsResponse, error) + + cacheDir, err := os.MkdirTemp("", "") + require.NoError(t, err) + t.Cleanup(func() { + err := os.RemoveAll(cacheDir) + require.NoError(t, err) + }) + + doTest := func(t testing.TB, inFile, wantOutFile string, + fn PrepareInputsFn, wantVR map[string]any, cfg c_polygonid.EnvConfig, + wantErr string) { + + err := c_polygonid.CleanCache(cacheDir) + require.NoError(t, err) + + ctx := context.Background() + out, err := fn(ctx, cfg, readFixtureFile(inFile)) + if wantErr != "" { + require.EqualError(t, err, wantErr) + return + } + require.NoError(t, err) + + resp, err := marshalInputsResponse(out) + require.NoError(t, err) + + assertEqualWithoutTimestamp(t, wantOutFile, resp) + } + + env := c_polygonid.EnvConfig{CacheDir: cacheDir} + t.Run("atomic_query_v3_on_chain_mtp_inputs", func(t *testing.T) { + defer httpmock.MockHTTPClient(t, map[string]string{ + "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", + })() + + doTest(t, "atomic_query_v3_on_chain_mtp_inputs.json", + "atomic_query_v3_on_chain_mtp_output.json", + c_polygonid.AtomicQueryV3OnChainInputsFromJson, nil, env, "") + }) + t.Run("auth_v2_inputs", func(t *testing.T) { + doTest(t, "auth_v2_inputs_in.json", "auth_v2_inputs_out.json", + c_polygonid.AuthV2InputsFromJson, nil, env, "") + }) + +} + +func assertEqualWithoutTimestamp(t testing.TB, wantFName string, + actual string) { + + jsonWant := readFixtureFile(wantFName) + var wantObj map[string]any + err := json.Unmarshal(jsonWant, &wantObj) + require.NoError(t, err) + + var actualObj map[string]any + err = json.Unmarshal([]byte(actual), &actualObj) + require.NoError(t, err) + + actualInputsObj, ok := actualObj["inputs"].(map[string]any) + require.True(t, ok) + + if ts, ok := actualInputsObj["timestamp"]; ok { + wantObj["inputs"].(map[string]any)["timestamp"] = ts + } + + require.Equal(t, wantObj, actualObj, "file name: %s\nwant: %s\ngot: %s", + wantFName, jsonWant, actual) +} diff --git a/cmd/polygonid/testdata/atomic_query_v3_on_chain_mtp_inputs.json b/cmd/polygonid/testdata/atomic_query_v3_on_chain_mtp_inputs.json new file mode 100644 index 0000000..807dd34 --- /dev/null +++ b/cmd/polygonid/testdata/atomic_query_v3_on_chain_mtp_inputs.json @@ -0,0 +1,139 @@ +{ + "id": "2qNcq2LGHFyikZaWfsif1vjrpKFuTowsRV9U1oEhkB", + "profileNonce": "0", + "claimSubjectProfileNonce": "0", + "authClaim":[ + "80551937543569765027552589160822318028", + "0", + "18241173998748741404449730252371072752192413092443487065695081933963692076033", + "1330367256434394070988833218825135639784691088078528177530136343975207856992", + "0","0","0","0" + ], + "authClaimIncMtp":{ + "existence":true, + "siblings":[ + "0", + "16122227591077608214426811451297936630776316583414054146380942393644089006753" + ] + }, + "authClaimNonRevMtp":{"existence":false,"siblings":[]}, + "treeState":{ + "state":"3455793648389793511224972913807237799755511487265044435383221641855224272477", + "claimsRoot":"12863526460000963806360638100765589244767101189459134829137262186265339590400", + "revocationRoot":"0", + "rootOfRoots":"0" + }, + "gistProof": { + "root": "5005919421435686441886912154983595081356506147906956636160716123399604497694", + "proof": { + "existence": false, + "siblings": [ + "9572034982910400342435969278331518000622332242067560582395787734704675688171", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", + "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", + "0", "0", "0", "0", "0", "0", "0" + ] + } + }, + + "signature": "a373921f2be69febb33730a0ce85864476364317d51df12a4d051da5180a3c02c1051aa3a5405538d26c998d34ed865065d73685bc7e8cf2546f87de2adbf703", + "challenge": "14274525809225776254148766756521966776753328068184040579440171048150881324976", + + "verifiableCredentials": { + "id": "http://localhost:8001/api/v1/identities/did:polygonid:polygon:mumbai:2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV/claims/63d05676-b22b-11ed-b489-e24d9cbdb31c", + "@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-21T15:14:48-04:00", + "issuanceDate": "2023-02-21T16:04:54.628883-05:00", + "credentialSubject": { + "birthday": 19960424, + "documentType": 2, + "id": "did:polygonid:polygon:mumbai:2qNcq2LGHFyikZaWfsif1vjrpKFuTowsRV9U1oEhkB", + "type": "KYCAgeCredential" + }, + "credentialStatus": { + "id": "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV/claims/revocation/status/3972757", + "revocationNonce": 3972757, + "type": "SparseMerkleTreeProof" + }, + "issuer": "did:polygonid:polygon:mumbai:2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV", + "credentialSchema": { + "id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCAgeCredential-v3.json", + "type": "JsonSchemaValidator2018" + }, + "proof": [ + { + "type": "BJJSignature2021", + "issuerData": { + "id": "did:polygonid:polygon:mumbai:2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV", + "state": { + "claimsTreeRoot": "4c4eb593366ca7ba87c8c39678324cfc50c088d1714cb2bfb1d4198f3fb48b0c", + "value": "e05968ec751d34825931e5faae3b1946af92386f7a41db02cb6acfd8f12e2029" + }, + "authCoreClaim": "cca3371a6cb1b715004407e325bd993c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe4494aaaef099b11a5cdd64c486d213e389338be963e7858d8ecf6773b8af14ac5981df12305e138b45f3985565852db666e4419ee07487c1a75b447a52ff050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "mtp": { + "existence": true, + "siblings": [ + "8492005947035117331601304230085928449440142032894061581492108583460376442873" + ] + }, + "credentialStatus": { + "id": "http://localhost:8001/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV/claims/revocation/status/0", + "revocationNonce": 0, + "type": "SparseMerkleTreeProof" + } + }, + "coreClaim": "c9b2370371b7fa8b3dab2a5ba81b68382a0000000000000000000000000000000212df9ac65c2ec1e545f9fa614fccfaba60435189f3d5a68feee8a307e51000e0209be826b8670e7c970d2eca0632123c9cbb6b5f5a5cf1480ad2b3f62b05180000000000000000000000000000000000000000000000000000000000000000959e3c0000000000281cdcdf0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "signature": "d608a6be79730a6bf873438ff23b31b9e1d3caa5d2a30470ec3b2ff3633e4798262e192336b0b4588cc0c80417b4cd6e89182451f20cfddc77d784022f566300" + }, + { + "type": "Iden3SparseMerkleProof", + "issuerData": { + "id": "did:polygonid:polygon:mumbai:2qDnyCaxj4zdYmj6LbegYMjWSnkbKAyqtq31YeuyZV", + "state": { + "txId": "0x51633300d6d5fb013134d4ea48663b7246a6b333c09bfafe4c440226b79ba903", + "blockTimestamp": 1677013536, + "blockNumber": 208660, + "rootOfRoots": "411df2b18d24592fd0730cbdb2425894cb4a24dac85328188f891333a311b315", + "claimsTreeRoot": "57b358eaacc24c2563f003a748a5b7f45b2b9ae1cd83e70085bfe0dcf9e8b918", + "revocationTreeRoot": "0000000000000000000000000000000000000000000000000000000000000000", + "value": "4646aede7443039a4bfd8f069d8f7f74f5075f6b794fb04663ab02fb76ba0c26" + } + }, + "coreClaim": "c9b2370371b7fa8b3dab2a5ba81b68382a0000000000000000000000000000000212df9ac65c2ec1e545f9fa614fccfaba60435189f3d5a68feee8a307e51000e0209be826b8670e7c970d2eca0632123c9cbb6b5f5a5cf1480ad2b3f62b05180000000000000000000000000000000000000000000000000000000000000000959e3c0000000000281cdcdf0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "mtp": { + "existence": true, + "siblings": [ + "3356738306440460467584170579991940197172182577060925476949151659410412574707", + "0", + "8492005947035117331601304230085928449440142032894061581492108583460376442873" + ] + } + } + ] + }, + "request": { + "id": 84239, + "circuitId": "credentialAtomicQueryV3OnChain-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": { + "birthday": { + "$gt": 1 + } + }, + "proofType": "Iden3SparseMerkleTreeProof" + } + } +} diff --git a/cmd/polygonid/testdata/atomic_query_v3_on_chain_mtp_output.json b/cmd/polygonid/testdata/atomic_query_v3_on_chain_mtp_output.json new file mode 100644 index 0000000..f244264 --- /dev/null +++ b/cmd/polygonid/testdata/atomic_query_v3_on_chain_mtp_output.json @@ -0,0 +1 @@ +{"inputs":{"requestID":"84239","userGenesisID":"29850258931222017705467685171096861881207969140433234245484437588206883330","profileNonce":"0","claimSubjectProfileNonce":"0","issuerID":"21838234188363965811194222691354401595924521809699081663778070280584106498","issuerClaim":["14366836738280263696847396792315741188809","29850258931222017705467685171096861881207969140433234245484437588206883330","10864646027499383081088961255934500336998198319784699191293859938525393920224","0","227737578863135127229601455765","0","0","0"],"issuerClaimNonRevClaimsTreeRoot":"7068285887070269919744619817939427362270424612960356565961095251320521860039","issuerClaimNonRevRevTreeRoot":"0","issuerClaimNonRevRootsTreeRoot":"6658769487718742664201419516702702972752809392331568580084074484906569715043","issuerClaimNonRevState":"684102056806145688850264533373905046865931700337702524047991423734848000844","issuerClaimNonRevMtp":["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],"issuerClaimNonRevMtpAuxHi":"0","issuerClaimNonRevMtpAuxHv":"0","issuerClaimNonRevMtpNoAux":"1","claimSchema":"74977327600848231385663280181476307657","issuerClaimSignatureR8x":"0","issuerClaimSignatureR8y":"0","issuerClaimSignatureS":"0","issuerAuthClaim":["0","0","0","0","0","0","0","0"],"issuerAuthClaimMtp":["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],"issuerAuthClaimNonRevMtp":["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],"issuerAuthClaimNonRevMtpAuxHi":"0","issuerAuthClaimNonRevMtpAuxHv":"0","issuerAuthClaimNonRevMtpNoAux":"0","issuerAuthClaimsTreeRoot":"0","issuerAuthRevTreeRoot":"0","issuerAuthRootsTreeRoot":"0","issuerAuthState":"0","isRevocationChecked":1,"claimPathMtp":["20339377203772305341811217028433821450488614130701398378692634277562001985608","11933107200150122400824598729420157563957281318882971696220077028927460055808","7519717914785235098147247580991543123760904594098768992380227396525519134082","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"],"claimPathMtpNoAux":"0","claimPathMtpAuxHi":"0","claimPathMtpAuxHv":"0","claimPathKey":"20376033832371109177683048456014525905119173674985843915445634726167450989630","claimPathValue":"19960424","operator":3,"slotIndex":0,"timestamp":1736328366,"value":["1","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","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,"issuerClaimMtp":["3356738306440460467584170579991940197172182577060925476949151659410412574707","0","8492005947035117331601304230085928449440142032894061581492108583460376442873","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],"issuerClaimClaimsTreeRoot":"11183983014422730135576411221308508161718614147165981937885222857422656811863","issuerClaimRevTreeRoot":"0","issuerClaimRootsTreeRoot":"9814957174382091206447535304534337089274740570836732274494171347479415627073","issuerClaimIdenState":"17210377343470156509439713038934318940268975754635034654510710013642161407558","proofType":"2","authClaim":["80551937543569765027552589160822318028","0","18241173998748741404449730252371072752192413092443487065695081933963692076033","1330367256434394070988833218825135639784691088078528177530136343975207856992","0","0","0","0"],"authClaimIncMtp":["0","16122227591077608214426811451297936630776316583414054146380942393644089006753","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],"authClaimNonRevMtp":["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],"authClaimNonRevMtpAuxHi":"0","authClaimNonRevMtpAuxHv":"0","authClaimNonRevMtpNoAux":"1","challenge":"14274525809225776254148766756521966776753328068184040579440171048150881324976","challengeSignatureR8x":"7946547749202203153722495838633053001554440836922580938487145942616579191846","challengeSignatureR8y":"1010706202943890306207376437846808611140904467814086285233664632781903393699","challengeSignatureS":"1794862408952810680899390709999774819913937156125801964108882723761943086529","userClaimsTreeRoot":"12863526460000963806360638100765589244767101189459134829137262186265339590400","userRevTreeRoot":"0","userRootsTreeRoot":"0","userState":"3455793648389793511224972913807237799755511487265044435383221641855224272477","gistRoot":"5005919421435686441886912154983595081356506147906956636160716123399604497694","gistMtp":["9572034982910400342435969278331518000622332242067560582395787734704675688171","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],"gistMtpAuxHi":"0","gistMtpAuxHv":"0","gistMtpNoAux":"1","linkNonce":"0","verifierID":"0","nullifierSessionID":"0","isBJJAuthEnabled":"1"},"statesInfo":{"states":[{"id":"21838234188363965811194222691354401595924521809699081663778070280584106498","state":"17210377343470156509439713038934318940268975754635034654510710013642161407558"},{"id":"21838234188363965811194222691354401595924521809699081663778070280584106498","state":"684102056806145688850264533373905046865931700337702524047991423734848000844"}],"gists":[{"id":"29850258931222017705467685171096861881207969140433234245484437588206883330","root":"5005919421435686441886912154983595081356506147906956636160716123399604497694"}]}} diff --git a/cmd/polygonid/testdata/auth_v2_inputs_in.json b/cmd/polygonid/testdata/auth_v2_inputs_in.json new file mode 100644 index 0000000..3adc1ce --- /dev/null +++ b/cmd/polygonid/testdata/auth_v2_inputs_in.json @@ -0,0 +1,44 @@ +{ + "genesisDID": "did:iden3:readonly:tT2t3b685r2dKsjo4MioyKeceFT4mQEYfDd69EY5Y", + "profileNonce": "0", + "authClaim": [ + "304427537360709784173770334266246861770", + "0", + "17640206035128972995519606214765283372613874593503528180869261482403155458945", + "20634138280259599560273310290025659992320584624461316485434108770067472477956", + "15930428023331155902", + "0", + "0", + "0" + ], + "authClaimIncMtp": { + "existence": true, + "siblings": [] + }, + "authClaimNonRevMtp": { + "existence": false, + "siblings": [] + }, + "treeState": { + "state": "18656147546666944484453899241916469544090258810192803949522794490493271005313", + "claimsRoot": "9763429684850732628215303952870004997159843236039795272605841029866455670219", + "revocationRoot": "0", + "rootOfRoots": "0" + }, + "gistProof": { + "root": "4924303677736085224554833340748086265406229626627819375177261957522622163007", + "proof": { + "existence": false, + "siblings": [], + "node_aux": { + "key": "24846663430375341177084327381366271031641225773947711007341346118923321345", + "value": "6317996369756476782464660619835940615734517981889733696047139451453239145426" + } + } + }, + "signature": "fccc15d7aed2bf4f5d7dbe55c81087970344d13e5d9f348e61965ac364f41d29b366b52bc0820c603877352054833da083f5595c29c881ccd8ee47aa639aa103", + "challenge": "10", + "request": { + "circuitId": "authV2" + } +} diff --git a/cmd/polygonid/testdata/auth_v2_inputs_out.json b/cmd/polygonid/testdata/auth_v2_inputs_out.json new file mode 100644 index 0000000..87c690f --- /dev/null +++ b/cmd/polygonid/testdata/auth_v2_inputs_out.json @@ -0,0 +1,185 @@ +{ + "inputs": { + "genesisID": "20927206916516385762021045711373308484593551383318447051738793701319835649", + "profileNonce": "0", + "authClaim": [ + "304427537360709784173770334266246861770", + "0", + "17640206035128972995519606214765283372613874593503528180869261482403155458945", + "20634138280259599560273310290025659992320584624461316485434108770067472477956", + "15930428023331155902", + "0", + "0", + "0" + ], + "authClaimIncMtp": [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "authClaimNonRevMtp": [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "authClaimNonRevMtpAuxHi": "0", + "authClaimNonRevMtpAuxHv": "0", + "authClaimNonRevMtpNoAux": "1", + "challenge": "10", + "challengeSignatureR8x": "2436614617352067078274240654647841101298221663194055411539273018411814965042", + "challengeSignatureR8y": "18597752099468941062473075570139025288787892531282848931228194191266230422780", + "challengeSignatureS": "1642466479083925938589665711747519202726798003514101885795868643287098549939", + "claimsTreeRoot": "9763429684850732628215303952870004997159843236039795272605841029866455670219", + "revTreeRoot": "0", + "rootsTreeRoot": "0", + "state": "18656147546666944484453899241916469544090258810192803949522794490493271005313", + "gistRoot": "4924303677736085224554833340748086265406229626627819375177261957522622163007", + "gistMtp": [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "gistMtpAuxHi": "24846663430375341177084327381366271031641225773947711007341346118923321345", + "gistMtpAuxHv": "6317996369756476782464660619835940615734517981889733696047139451453239145426", + "gistMtpNoAux": "0" + }, + "statesInfo":{ + "states":[], + "gists":[{"id":"20927206916516385762021045711373308484593551383318447051738793701319835649","root":"4924303677736085224554833340748086265406229626627819375177261957522622163007"}] + } +} diff --git a/go.mod b/go.mod index 60b9bb3..c3aec9e 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22 require ( github.com/dgraph-io/badger/v4 v4.5.0 github.com/ethereum/go-ethereum v1.14.12 - github.com/iden3/go-circuits/v2 v2.4.0 + github.com/iden3/go-circuits/v2 v2.4.1-0.20250107112156-39609341164c github.com/iden3/go-iden3-core/v2 v2.3.1 github.com/iden3/go-iden3-crypto v0.0.17 github.com/iden3/go-merkletree-sql/v2 v2.0.6 diff --git a/go.sum b/go.sum index 86df240..9503be7 100644 --- a/go.sum +++ b/go.sum @@ -137,8 +137,8 @@ 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 v1.0.1 h1:FsaLJSy3NSyJl5k1yfDxc5DhUHRY7Z/UCj0/1YueMrY= github.com/iden3/contracts-abi/state/go/abi v1.0.1/go.mod h1:TxgIrXCvxms3sbOdsy8kTvffUCIpEEifNy0fSXdkU4w= -github.com/iden3/go-circuits/v2 v2.4.0 h1:m+7uYtrvJKuc+gVhbXDXl1BJQyK7sWdW7OWttM3R/8I= -github.com/iden3/go-circuits/v2 v2.4.0/go.mod h1:k0uYx/ZdZPiDEIy7kI3MAixnREKcc7NdCKDRw8Q+iFA= +github.com/iden3/go-circuits/v2 v2.4.1-0.20250107112156-39609341164c h1:RUByWy0WKaE8ojxmbtztOOx8RARdBzSzHC45jnIDn3M= +github.com/iden3/go-circuits/v2 v2.4.1-0.20250107112156-39609341164c/go.mod h1:kzZTeqVRr0SuTMj2Dj9OM60kZzHf4FfaetLgrlnxz94= github.com/iden3/go-iden3-core/v2 v2.3.1 h1:ytQqiclnVAIWyRKR2LF31hfz4DGRBD6nMjiPILXGSKk= github.com/iden3/go-iden3-core/v2 v2.3.1/go.mod h1:8vmG6y8k9VS7iNoxuiKukKbRQFsMyabCc+i8er07zOs= github.com/iden3/go-iden3-crypto v0.0.17 h1:NdkceRLJo/pI4UpcjVah4lN/a3yzxRUGXqxbWcYh9mY= diff --git a/inputs_sig.go b/inputs_sig.go index e111495..31e10e3 100644 --- a/inputs_sig.go +++ b/inputs_sig.go @@ -605,7 +605,7 @@ func AtomicQueryMtpV2InputsFromJson(ctx context.Context, cfg EnvConfig, start := time.Now() inpMarsh.Query, out.VerifiablePresentation, queryErr = queryFromObj( ctx, w3cCred, obj.Request, claim, cfg.documentLoader(), - circuitID) + circuitID, cfg.CacheDir) slog.Debug("query done in", "time", time.Since(start)) }() } @@ -761,7 +761,8 @@ func AtomicQuerySigV2InputsFromJson(ctx context.Context, cfg EnvConfig, } inpMarsh.Query, out.VerifiablePresentation, err = queryFromObj(ctx, w3cCred, - obj.Request, inpMarsh.Claim.Claim, cfg.documentLoader(), circuitID) + obj.Request, inpMarsh.Claim.Claim, cfg.documentLoader(), circuitID, + cfg.CacheDir) if err != nil { return out, err } @@ -845,7 +846,7 @@ func AtomicQueryMtpV2OnChainInputsFromJson(ctx context.Context, cfg EnvConfig, defer wg.Done() inpMarsh.Query, out.VerifiablePresentation, queryErr = queryFromObj( ctx, w3cCred, obj.Request, claim, cfg.documentLoader(), - circuitID) + circuitID, cfg.CacheDir) }() } @@ -938,7 +939,8 @@ func AtomicQuerySigV2OnChainInputsFromJson(ctx context.Context, cfg EnvConfig, } inpMarsh.Query, out.VerifiablePresentation, err = queryFromObj(ctx, w3cCred, - obj.Request, inpMarsh.Claim.Claim, cfg.documentLoader(), circuitID) + obj.Request, inpMarsh.Claim.Claim, cfg.documentLoader(), circuitID, + cfg.CacheDir) if err != nil { return out, err } @@ -1024,7 +1026,8 @@ func AtomicQueryV3OnChainInputsFromJson(ctx context.Context, cfg EnvConfig, } inpMarsh.Query, out.VerifiablePresentation, err = queryFromObj(ctx, w3cCred, - obj.Request, inpMarsh.Claim.Claim, cfg.documentLoader(), circuitID) + obj.Request, inpMarsh.Claim.Claim, cfg.documentLoader(), circuitID, + cfg.CacheDir) if err != nil { return out, err } @@ -1104,7 +1107,8 @@ func AtomicQueryV3InputsFromJson(ctx context.Context, cfg EnvConfig, } inpMarsh.Query, out.VerifiablePresentation, err = queryFromObj(ctx, w3cCred, - obj.Request, inpMarsh.Claim.Claim, cfg.documentLoader(), circuitID) + obj.Request, inpMarsh.Claim.Claim, cfg.documentLoader(), circuitID, + cfg.CacheDir) if err != nil { return out, err } @@ -1134,7 +1138,7 @@ func AtomicQueryV3InputsFromJson(ctx context.Context, cfg EnvConfig, return out, nil } -func GenericQueryInputsFromJson(ctx context.Context, cfg EnvConfig, +func GenericInputsFromJson(ctx context.Context, cfg EnvConfig, in []byte) (AtomicQueryInputsResponse, error) { var req struct { Request struct { @@ -1162,6 +1166,8 @@ func GenericQueryInputsFromJson(ctx context.Context, cfg EnvConfig, return AtomicQueryV3OnChainInputsFromJson(ctx, cfg, in) case circuits.LinkedMultiQuery10CircuitID: return LinkedMultiQueryInputsFromJson(ctx, cfg, in) + case circuits.AuthV2CircuitID: + return AuthV2InputsFromJson(ctx, cfg, in) } return AtomicQueryInputsResponse{}, errors.New("unknown circuit") @@ -1212,7 +1218,8 @@ func LinkedMultiQueryInputsFromJson(ctx context.Context, cfg EnvConfig, inpMarsh.Claim = claim.Claim inpMarsh.Query, out.VerifiablePresentation, err = queriesFromObj(ctx, - w3cCred, obj.Request, inpMarsh.Claim, cfg.documentLoader(), circuitID) + w3cCred, obj.Request, inpMarsh.Claim, cfg.documentLoader(), circuitID, + cfg.CacheDir) if err != nil { return out, err } @@ -1303,7 +1310,7 @@ func querySkipRevocation(requestObj jsonObj) (bool, error) { func queryFromObj(ctx context.Context, w3cCred verifiable.W3CCredential, requestObj jsonObj, claim *core.Claim, documentLoader ld.DocumentLoader, - circuitID circuits.CircuitID) (out circuits.Query, + circuitID circuits.CircuitID, cacheDir string) (out circuits.Query, verifiablePresentation jsonObj, err error) { merklizePosition, err := claim.GetMerklizedPosition() @@ -1315,10 +1322,10 @@ func queryFromObj(ctx context.Context, w3cCred verifiable.W3CCredential, var vp jsonObj if merklizePosition == core.MerklizedRootPositionNone { queries, vp, err = queriesFromObjNonMerklized(ctx, w3cCred, requestObj, - documentLoader, circuitID) + documentLoader, circuitID, cacheDir) } else { queries, vp, err = queriesFromObjMerklized(ctx, w3cCred, requestObj, - documentLoader, circuitID, claim) + documentLoader, circuitID, claim, cacheDir) } if err != nil { return circuits.Query{}, nil, err @@ -1341,7 +1348,7 @@ func queryFromObj(ctx context.Context, w3cCred verifiable.W3CCredential, func queriesFromObj(ctx context.Context, w3cCred verifiable.W3CCredential, requestObj jsonObj, claim *core.Claim, documentLoader ld.DocumentLoader, - circuitID circuits.CircuitID) ([]*circuits.Query, jsonObj, error) { + circuitID circuits.CircuitID, cacheDir string) ([]*circuits.Query, jsonObj, error) { merklizePosition, err := claim.GetMerklizedPosition() if err != nil { @@ -1350,21 +1357,21 @@ func queriesFromObj(ctx context.Context, w3cCred verifiable.W3CCredential, if merklizePosition == core.MerklizedRootPositionNone { return queriesFromObjNonMerklized(ctx, w3cCred, requestObj, - documentLoader, circuitID) + documentLoader, circuitID, cacheDir) } return queriesFromObjMerklized(ctx, w3cCred, requestObj, documentLoader, - circuitID, claim) + circuitID, claim, cacheDir) } func wrapMerklizeWithRegion(ctx context.Context, - w3cCred verifiable.W3CCredential, - documentLoader ld.DocumentLoader) (*merklize.Merklizer, error) { + w3cCred verifiable.W3CCredential, documentLoader ld.DocumentLoader, + cacheDir string) (*merklize.Merklizer, error) { var mz *merklize.Merklizer var err error trace.WithRegion(ctx, "merklize", func() { - mz, err = merklizeCred(ctx, w3cCred, documentLoader, true) + mz, err = merklizeCred(ctx, w3cCred, documentLoader, true, cacheDir) }) return mz, err } @@ -1397,8 +1404,8 @@ func opName(opID int) string { func queriesFromObjNonMerklized(ctx context.Context, w3cCred verifiable.W3CCredential, requestObj jsonObj, - documentLoader ld.DocumentLoader, - circuitID circuits.CircuitID) ([]*circuits.Query, jsonObj, error) { + documentLoader ld.DocumentLoader, circuitID circuits.CircuitID, + cacheDir string) ([]*circuits.Query, jsonObj, error) { var err error @@ -1440,7 +1447,7 @@ func queriesFromObjNonMerklized(ctx context.Context, } var mz *merklize.Merklizer - mz, err = wrapMerklizeWithRegion(ctx, w3cCred, documentLoader) + mz, err = wrapMerklizeWithRegion(ctx, w3cCred, documentLoader, cacheDir) if err != nil { return nil, nil, err } @@ -1666,12 +1673,12 @@ func sortedKeys(m jsonObj) []string { func queriesFromObjMerklized(ctx context.Context, w3cCred verifiable.W3CCredential, requestObj jsonObj, documentLoader ld.DocumentLoader, circuitID circuits.CircuitID, - claim *core.Claim) ([]*circuits.Query, jsonObj, error) { + claim *core.Claim, cacheDir string) ([]*circuits.Query, jsonObj, error) { region := trace.StartRegion(ctx, "queryFromObjMerklized") defer region.End() - mz, err := wrapMerklizeWithRegion(ctx, w3cCred, documentLoader) + mz, err := wrapMerklizeWithRegion(ctx, w3cCred, documentLoader, cacheDir) if err != nil { return nil, nil, err } @@ -2166,8 +2173,8 @@ func newChainIDFromString(in string) (core.ChainID, error) { } func merklizeCred(ctx context.Context, w3cCred verifiable.W3CCredential, - documentLoader ld.DocumentLoader, - ignoreCacheErrors bool) (*merklize.Merklizer, error) { + documentLoader ld.DocumentLoader, ignoreCacheErrors bool, + cacheDir string) (*merklize.Merklizer, error) { w3cCred.Proof = nil credentialBytes, err := json.Marshal(w3cCred) @@ -2177,7 +2184,7 @@ func merklizeCred(ctx context.Context, w3cCred verifiable.W3CCredential, cacheKey := sha256.Sum256(credentialBytes) - db, cleanup, err := getCacheDB("") + db, cleanup, err := getCacheDB(cacheDir) if err != nil { if !ignoreCacheErrors { return nil, err @@ -2383,7 +2390,8 @@ func PreCacheVC(ctx context.Context, cfg EnvConfig, in []byte) error { return err } - _, err = merklizeCred(ctx, w3cCred, cfg.documentLoader(), false) + _, err = merklizeCred(ctx, w3cCred, cfg.documentLoader(), false, + cfg.CacheDir) return err } @@ -2600,3 +2608,52 @@ func DescribeID(ctx context.Context, cfg EnvConfig, IDAsInt: id.BigInt().String(), }, nil } + +// AuthV2InputsFromJson converts JSON input to AuthV2Inputs response. +func AuthV2InputsFromJson(_ context.Context, _ EnvConfig, + in []byte) (AtomicQueryInputsResponse, error) { + + var out AtomicQueryInputsResponse + + var obj map[string]any + err := json.Unmarshal(in, &obj) + if err != nil { + return out, err + } + + didI, ok := obj["genesisDID"] + if !ok { + return out, errors.New("no genesisDID field found") + } + + didS, ok := didI.(string) + if !ok { + return out, errors.New("genesisDID is not a string") + } + + did, err := w3c.ParseDID(didS) + if err != nil { + return out, fmt.Errorf("failed to parse genesisDID: %w", err) + } + + id, err := core.IDFromDID(*did) + if err != nil { + return out, fmt.Errorf("failed to get ID from genesisDID: %w", err) + } + obj["genesisID"] = id.String() + + authV2InputsData, err := json.Marshal(obj) + if err != nil { + return out, fmt.Errorf("failed to marshal data: %w", err) + } + + var inputs circuits.AuthV2Inputs + err = json.Unmarshal(authV2InputsData, &inputs) + if err != nil { + return out, fmt.Errorf("failed to re-unmarshal authV2 inputs: %w", err) + } + + out.Inputs = inputs + + return out, nil +} diff --git a/inputs_sig_test.go b/inputs_sig_test.go index 55fa049..5c067a1 100644 --- a/inputs_sig_test.go +++ b/inputs_sig_test.go @@ -137,7 +137,7 @@ func TestPrepareInputs(t *testing.T) { nil, cfg, "") }) - t.Run("GenericQueryInputsFromJson — AtomicQueryMtpV2Onchain", func(t *testing.T) { + t.Run("GenericInputsFromJson — AtomicQueryMtpV2Onchain", func(t *testing.T) { defer httpmock.MockHTTPClient(t, map[string]string{ `http://localhost:8545%%%{"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0x0000000000000000000000000000000000000000","input":"0xb4bdea55000e5102b2f7a54e61db03f6c656f65062f4b11b9dd52a1702c2bfdc379d1202","to":"0x134b1be34911e39a8397ec6289782989729807a4"},"latest"]}`: "testdata/httpresp_eth_state_2qKc2ns18nV6uDSfaR1RVd7zF1Nm9vfeNZuvuEXQ3X.json", @@ -159,7 +159,7 @@ func TestPrepareInputs(t *testing.T) { doTest(t, "atomic_query_mtp_v2_on_chain_status_inputs.json", "atomic_query_mtp_v2_on_chain_status_output.json", - GenericQueryInputsFromJson, + GenericInputsFromJson, nil, cfg, "") }) @@ -1105,7 +1105,6 @@ func (c *countingDocumentLoader) reset() { func TestMerklizeCred(t *testing.T) { mockBadgerLog(t) - flushCacheDB(t) defer httpmock.MockHTTPClient(t, map[string]string{ "https://schema.iden3.io/core/jsonld/iden3proofs.jsonld": "testdata/httpresp_iden3proofs.jsonld", @@ -1120,7 +1119,11 @@ func TestMerklizeCred(t *testing.T) { } ctx := context.Background() - mz, err := merklizeCred(ctx, w3cCred, documentLoader, true) + cacheDir, err := os.MkdirTemp("", "") + require.NoError(t, err) + defer os.RemoveAll(cacheDir) + + mz, err := merklizeCred(ctx, w3cCred, documentLoader, true, cacheDir) require.NoError(t, err) require.Equal(t, wantRoot, mz.Root().BigInt().String()) @@ -1131,12 +1134,10 @@ func TestMerklizeCred(t *testing.T) { // test that following call to merklizeCred does not make any HTTP calls documentLoader.reset() - mz, err = merklizeCred(ctx, w3cCred, documentLoader, true) + mz, err = merklizeCred(ctx, w3cCred, documentLoader, true, cacheDir) require.NoError(t, err) require.Equal(t, wantRoot, mz.Root().BigInt().String()) require.Equal(t, 0, documentLoader.counter()) - - flushCacheDB(t) } func vcCredChecksum(in []byte) []byte {