├── .gitignore ├── pubsignals ├── authV3.go ├── circuitsVerifier.go ├── verifyopts.go ├── signals.go ├── authV2.go ├── atomicSigV2.go ├── queryCredentialSubjectV3.go ├── atomicMtpV2.go ├── queryCredentialSubjectV2.go ├── linkedMultiQuery.go ├── atomicV3.go ├── query.go └── common.go ├── Makefile ├── .github └── workflows │ ├── ci-lint.yaml │ └── ci-test.yaml ├── proofs ├── zk.go └── zk_test.go ├── loaders ├── key.go ├── verification_keys │ ├── authV2.json │ ├── authV3-8-32.json │ ├── authV3.json │ ├── credentialAtomicQuerySigV2OnChain.json │ ├── credentialAtomicQueryMTPV2OnChain.json │ ├── credentialAtomicQueryV3OnChain-beta.1.json │ ├── linkedMultiQuery10-beta.1.json │ └── credentialAtomicQueryMTPV2.json ├── embededKeyLoader.go └── embededKeyLoader_test.go ├── LICENSE-MIT ├── transport └── notification.go ├── constants └── constants.go ├── state ├── resolver-cache_test.go ├── mock │ ├── GISTGetterMock.go │ └── StateGetterMock.go ├── state.go ├── resolver.go └── state_test.go ├── testdata ├── kyc-v3.json-ld ├── kyc-v4.json-ld ├── kyc-v2.json-ld ├── kyc-nonmerklized.jsonld ├── kyc-v101.json-ld └── credentials-v1.json-ld ├── .golangci.yml ├── cache ├── cache.go └── cache_test.go ├── go.mod ├── README.md └── LICENSE-APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | -------------------------------------------------------------------------------- /pubsignals/authV3.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | // AuthV3 is a wrapper for circuits.AuthV3PubSignals. 4 | type AuthV3 = AuthV2 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | #Unit tests 4 | test: 5 | go test -v -race -count=1 -timeout=60s ./... 6 | 7 | lint: 8 | golangci-lint --config .golangci.yml run 9 | -------------------------------------------------------------------------------- /.github/workflows/ci-lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - develop 7 | pull_request: 8 | jobs: 9 | lint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v5 14 | - name: Install Go 15 | uses: actions/setup-go@v6 16 | with: 17 | go-version-file: go.mod 18 | cache: true 19 | - name: golangci-lint 20 | uses: golangci/golangci-lint-action@v8 21 | with: 22 | version: v2.1 -------------------------------------------------------------------------------- /proofs/zk.go: -------------------------------------------------------------------------------- 1 | package proofs 2 | 3 | import ( 4 | "github.com/iden3/go-rapidsnark/verifier" 5 | "github.com/iden3/iden3comm/v2/protocol" 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | // VerifyProof performs protocol proof response verification 10 | func VerifyProof(resp protocol.ZeroKnowledgeProofResponse, verificationKey []byte) (err error) { 11 | switch resp.Proof.Protocol { 12 | case "groth16": 13 | return verifier.VerifyGroth16(resp.ZKProof, verificationKey) 14 | default: 15 | return errors.Errorf("%s protocol is not supported", resp.Proof.Protocol) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /loaders/key.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/iden3/go-circuits/v2" 9 | ) 10 | 11 | // VerificationKeyLoader load verification key bytes for specific circuit 12 | type VerificationKeyLoader interface { 13 | Load(id circuits.CircuitID) ([]byte, error) 14 | } 15 | 16 | // FSKeyLoader read keys from filesystem 17 | type FSKeyLoader struct { 18 | Dir string 19 | } 20 | 21 | // Load keys from embedded FS 22 | func (m FSKeyLoader) Load(id circuits.CircuitID) ([]byte, error) { 23 | file, err := os.ReadFile(fmt.Sprintf("%s/%v.json", m.Dir, id)) 24 | if errors.Is(err, os.ErrNotExist) { 25 | return nil, ErrKeyNotFound 26 | } 27 | return file, err 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/ci-test.yaml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | jobs: 10 | test: 11 | strategy: 12 | matrix: 13 | containers: [ 1.24, 1.25 ] 14 | runs-on: ubuntu-latest 15 | container: golang:${{ matrix.containers }} 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v3 19 | - uses: actions/cache@v3 20 | with: 21 | path: | 22 | ~/.cache/go-build 23 | /go/pkg/mod 24 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 25 | restore-keys: | 26 | ${{ runner.os }}-go- 27 | - name: Update go modules 28 | run: go mod tidy 29 | - name: Unit Tests 30 | env: 31 | RPC_URL: ${{ secrets.RPC_URL }} 32 | run: go test -race -timeout=60s ./... 33 | -------------------------------------------------------------------------------- /pubsignals/circuitsVerifier.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "math/big" 7 | 8 | "github.com/iden3/go-circuits/v2" 9 | "github.com/iden3/go-iden3-auth/v2/state" 10 | "github.com/piprate/json-gold/ld" 11 | ) 12 | 13 | // StateResolver is a state resolver interface 14 | type StateResolver interface { 15 | Resolve(ctx context.Context, id *big.Int, state *big.Int) (*state.ResolvedState, error) 16 | ResolveGlobalRoot(ctx context.Context, state *big.Int) (*state.ResolvedState, error) 17 | } 18 | 19 | // Verifier is interface for verification of public signals of zkp 20 | type Verifier interface { 21 | VerifyQuery(ctx context.Context, query Query, schemaLoader ld.DocumentLoader, verifiablePresentation json.RawMessage, circuitParams map[string]interface{}, opts ...VerifyOpt) (CircuitVerificationResult, error) 22 | VerifyStates(ctx context.Context, resolvers map[string]StateResolver, opts ...VerifyOpt) error 23 | VerifyIDOwnership(userIdentifier string, challenge *big.Int) error 24 | 25 | circuits.PubSignalsUnmarshaller 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2023 0kims Association. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /transport/notification.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/iden3/go-schema-processor/v2/verifiable" 8 | "github.com/iden3/iden3comm/v2/protocol" 9 | "github.com/iden3/iden3comm/v2/transport/notification" 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | // SendPushAuthRequest sends authorization request to the user via a push notification. 14 | func SendPushAuthRequest( 15 | ctx context.Context, 16 | diddoc verifiable.DIDDocument, 17 | authMsg protocol.AuthorizationRequestMessage, 18 | ) (*notification.UserNotificationResult, error) { 19 | authMsgBytes, err := json.Marshal(authMsg) 20 | if err != nil { 21 | return nil, errors.WithStack(err) 22 | } 23 | return notification.Notify( 24 | ctx, 25 | authMsgBytes, 26 | diddoc, 27 | nil, 28 | ) 29 | } 30 | 31 | // SendPushContractInvokeRequest sends a contract invoke request to the user via a push notification. 32 | func SendPushContractInvokeRequest( 33 | ctx context.Context, 34 | diddoc verifiable.DIDDocument, 35 | contractInvokeMsg protocol.ContractInvokeRequestMessage, 36 | ) (*notification.UserNotificationResult, error) { 37 | ciMsgBytes, err := json.Marshal(contractInvokeMsg) 38 | if err != nil { 39 | return nil, errors.WithStack(err) 40 | } 41 | return notification.Notify( 42 | ctx, 43 | ciMsgBytes, 44 | diddoc, 45 | nil, 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /constants/constants.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | import "time" 4 | 5 | const ( 6 | // DefaultCacheMaxSize is the default maximum size for caches. 7 | DefaultCacheMaxSize int64 = 10_000 8 | // AcceptedProofGenerationDelay is the accepted delay of the proof generation. 9 | AcceptedProofGenerationDelay = time.Hour * 24 // 24 hours 10 | // AcceptedStateTransitionDelay is the accepted delay of state transition. 11 | AcceptedStateTransitionDelay = time.Hour // 1 hour 12 | // AuthAcceptedStateTransitionDelay is the accepted delay of state transition for auth circuit. 13 | AuthAcceptedStateTransitionDelay = 5 * time.Minute // 5 minutes 14 | ) 15 | 16 | var ( 17 | // StateCacheOptions defines the TTL options for state cache entries. 18 | StateCacheOptions = CacheTTLOptions{ 19 | NotReplacedTTL: AcceptedStateTransitionDelay / 2, // 30 minutes 20 | ReplacedTTL: AcceptedStateTransitionDelay, // 1 hour 21 | } 22 | 23 | // GistRootCacheOptions defines the TTL options for GIST root cache entries. 24 | GistRootCacheOptions = CacheTTLOptions{ 25 | NotReplacedTTL: AuthAcceptedStateTransitionDelay / 2, // 2.5 minutes 26 | ReplacedTTL: AuthAcceptedStateTransitionDelay, // 5 minutes 27 | } 28 | ) 29 | 30 | // CacheTTLOptions defines the TTL options for cache entries. 31 | type CacheTTLOptions struct { 32 | NotReplacedTTL time.Duration 33 | ReplacedTTL time.Duration 34 | } 35 | -------------------------------------------------------------------------------- /state/resolver-cache_test.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import ( 4 | "context" 5 | "math/big" 6 | "testing" 7 | "time" 8 | 9 | "github.com/iden3/go-iden3-auth/v2/cache" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | func newTestResolverWithCache(stateCache, rootCache cache.Cache[ResolvedState]) *ETHResolver { 14 | return ÐResolver{ 15 | stateResolveCache: stateCache, 16 | rootResolveCache: rootCache, 17 | cfg: Config{ 18 | StateCacheOptions: &CacheOptions{ 19 | Cache: stateCache, 20 | }, 21 | RootCacheOptions: &CacheOptions{ 22 | Cache: rootCache, 23 | }, 24 | }, 25 | } 26 | } 27 | 28 | func TestResolve_UsesCacheIfPresent(t *testing.T) { 29 | mock := cache.NewInMemoryCache[ResolvedState](10, time.Minute) 30 | key := "1-2" 31 | expected := ResolvedState{Latest: true} 32 | mock.Set(key, expected) 33 | 34 | resolver := newTestResolverWithCache(mock, nil) 35 | 36 | result, err := resolver.Resolve(context.Background(), big.NewInt(1), big.NewInt(2)) 37 | require.NoError(t, err, "expected no error") 38 | require.True(t, result.Latest, "expected result to be marked as latest") 39 | } 40 | 41 | func TestGistResolve_UsesCacheIfPresent(t *testing.T) { 42 | mock := cache.NewInMemoryCache[ResolvedState](10, time.Minute) 43 | key := "123" 44 | expected := ResolvedState{Latest: true} 45 | mock.Set(key, expected) 46 | 47 | resolver := newTestResolverWithCache(nil, mock) 48 | 49 | result, err := resolver.ResolveGlobalRoot(context.Background(), big.NewInt(123)) 50 | require.NoError(t, err, "expected no error") 51 | require.True(t, result.Latest, "expected result to be marked as latest") 52 | } 53 | -------------------------------------------------------------------------------- /testdata/kyc-v3.json-ld: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | { 4 | "@version": 1.1, 5 | "@protected": true, 6 | "id": "@id", 7 | "type": "@type", 8 | "KYCAgeCredential": { 9 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCAgeCredential", 10 | "@context": { 11 | "@version": 1.1, 12 | "@protected": true, 13 | "id": "@id", 14 | "type": "@type", 15 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 16 | "xsd": "http://www.w3.org/2001/XMLSchema#", 17 | "birthday": { 18 | "@id": "kyc-vocab:birthday", 19 | "@type": "xsd:integer" 20 | }, 21 | "documentType": { 22 | "@id": "kyc-vocab:documentType", 23 | "@type": "xsd:integer" 24 | } 25 | } 26 | }, 27 | "KYCCountryOfResidenceCredential": { 28 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld#KYCCountryOfResidenceCredential", 29 | "@context": { 30 | "@version": 1.1, 31 | "@protected": true, 32 | "id": "@id", 33 | "type": "@type", 34 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 35 | "xsd": "http://www.w3.org/2001/XMLSchema#", 36 | "countryCode": { 37 | "@id": "kyc-vocab:countryCode", 38 | "@type": "xsd:integer" 39 | }, 40 | "documentType": { 41 | "@id": "kyc-vocab:documentType", 42 | "@type": "xsd:integer" 43 | } 44 | } 45 | } 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /testdata/kyc-v4.json-ld: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | { 4 | "@version": 1.1, 5 | "@protected": true, 6 | "id": "@id", 7 | "type": "@type", 8 | "KYCAgeCredential": { 9 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v4.jsonld#KYCAgeCredential", 10 | "@context": { 11 | "@version": 1.1, 12 | "@protected": true, 13 | "id": "@id", 14 | "type": "@type", 15 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 16 | "xsd": "http://www.w3.org/2001/XMLSchema#", 17 | "birthday": { 18 | "@id": "kyc-vocab:birthday", 19 | "@type": "xsd:integer" 20 | }, 21 | "documentType": { 22 | "@id": "kyc-vocab:documentType", 23 | "@type": "xsd:integer" 24 | } 25 | } 26 | }, 27 | "KYCCountryOfResidenceCredential": { 28 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v4.jsonld#KYCCountryOfResidenceCredential", 29 | "@context": { 30 | "@version": 1.1, 31 | "@protected": true, 32 | "id": "@id", 33 | "type": "@type", 34 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 35 | "xsd": "http://www.w3.org/2001/XMLSchema#", 36 | "countryCode": { 37 | "@id": "kyc-vocab:countryCode", 38 | "@type": "xsd:integer" 39 | }, 40 | "documentType": { 41 | "@id": "kyc-vocab:documentType", 42 | "@type": "xsd:integer" 43 | } 44 | } 45 | } 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 5m 3 | 4 | version: "2" 5 | linters: 6 | default: none 7 | enable: 8 | - bodyclose 9 | - dupl 10 | - gocritic 11 | - gocyclo 12 | - gosec 13 | - govet 14 | - ineffassign 15 | - misspell 16 | - nakedret 17 | - prealloc 18 | - revive 19 | - staticcheck 20 | - unconvert 21 | - unparam 22 | - unused 23 | - gochecknoinits 24 | - errcheck 25 | - copyloopvar 26 | settings: 27 | govet: 28 | enable: 29 | - shadow 30 | revive: 31 | confidence: 0.1 32 | goconst: 33 | min-len: 2 34 | min-occurrences: 2 35 | gocritic: 36 | disabled-checks: 37 | - hugeParam 38 | enabled-tags: 39 | - performance 40 | - style 41 | - experimental 42 | lll: 43 | line-length: 140 44 | misspell: 45 | locale: US 46 | staticcheck: 47 | checks: 48 | - "all" 49 | - "-QF1007" 50 | exclusions: 51 | generated: lax 52 | rules: 53 | - linters: 54 | - staticcheck 55 | text: at least one file in a package should have a package comment 56 | - linters: 57 | - revive 58 | text: 'package-comments: should have a package comment' 59 | - linters: 60 | - govet 61 | text: 'shadow: declaration of "err"' 62 | - linters: 63 | - dupl 64 | path: _test\.go 65 | - linters: 66 | - dupl 67 | path: 'atomic.*\.go' 68 | - linters: 69 | - gosec 70 | path: auth_test\.go 71 | formatters: 72 | enable: 73 | - gci 74 | - gofmt 75 | - goimports 76 | settings: 77 | gci: 78 | sections: 79 | - standard 80 | - default 81 | -------------------------------------------------------------------------------- /state/mock/GISTGetterMock.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: github.com/iden3/go-iden3-auth/state (interfaces: GISTGetter) 3 | 4 | // Package mock_state is a generated GoMock package. 5 | package mock_state 6 | 7 | import ( 8 | big "math/big" 9 | reflect "reflect" 10 | 11 | bind "github.com/ethereum/go-ethereum/accounts/abi/bind" 12 | gomock "github.com/golang/mock/gomock" 13 | abi "github.com/iden3/contracts-abi/state/go/abi" 14 | ) 15 | 16 | // MockGISTGetter is a mock of GISTGetter interface. 17 | type MockGISTGetter struct { 18 | ctrl *gomock.Controller 19 | recorder *MockGISTGetterMockRecorder 20 | } 21 | 22 | // MockGISTGetterMockRecorder is the mock recorder for MockGISTGetter. 23 | type MockGISTGetterMockRecorder struct { 24 | mock *MockGISTGetter 25 | } 26 | 27 | // NewMockGISTGetter creates a new mock instance. 28 | func NewMockGISTGetter(ctrl *gomock.Controller) *MockGISTGetter { 29 | mock := &MockGISTGetter{ctrl: ctrl} 30 | mock.recorder = &MockGISTGetterMockRecorder{mock} 31 | return mock 32 | } 33 | 34 | // EXPECT returns an object that allows the caller to indicate expected use. 35 | func (m *MockGISTGetter) EXPECT() *MockGISTGetterMockRecorder { 36 | return m.recorder 37 | } 38 | 39 | // GetGISTRootInfo mocks base method. 40 | func (m *MockGISTGetter) GetGISTRootInfo(arg0 *bind.CallOpts, arg1 *big.Int) (abi.IStateGistRootInfo, error) { 41 | m.ctrl.T.Helper() 42 | ret := m.ctrl.Call(m, "GetGISTRootInfo", arg0, arg1) 43 | ret0, _ := ret[0].(abi.IStateGistRootInfo) 44 | ret1, _ := ret[1].(error) 45 | return ret0, ret1 46 | } 47 | 48 | // GetGISTRootInfo indicates an expected call of GetGISTRootInfo. 49 | func (mr *MockGISTGetterMockRecorder) GetGISTRootInfo(arg0, arg1 interface{}) *gomock.Call { 50 | mr.mock.ctrl.T.Helper() 51 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGISTRootInfo", reflect.TypeOf((*MockGISTGetter)(nil).GetGISTRootInfo), arg0, arg1) 52 | } 53 | -------------------------------------------------------------------------------- /pubsignals/verifyopts.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/iden3/go-iden3-auth/v2/constants" 7 | ) 8 | 9 | var ( 10 | defaultAuthVerifyOpts = VerifyConfig{AcceptedStateTransitionDelay: constants.AuthAcceptedStateTransitionDelay} 11 | defaultProofVerifyOpts = VerifyConfig{AcceptedStateTransitionDelay: constants.AcceptedStateTransitionDelay, 12 | AcceptedProofGenerationDelay: constants.AcceptedProofGenerationDelay} 13 | ) 14 | 15 | // WithAcceptedStateTransitionDelay sets the delay of the revoked state. 16 | func WithAcceptedStateTransitionDelay(duration time.Duration) VerifyOpt { 17 | return func(v *VerifyConfig) { 18 | v.AcceptedStateTransitionDelay = duration 19 | } 20 | } 21 | 22 | // WithAcceptedProofGenerationDelay sets the delay of the proof generation. 23 | func WithAcceptedProofGenerationDelay(duration time.Duration) VerifyOpt { 24 | return func(v *VerifyConfig) { 25 | v.AcceptedProofGenerationDelay = duration 26 | } 27 | } 28 | 29 | // WithAllowExpiredMessages sets the allow expired messages option. 30 | func WithAllowExpiredMessages(allowExpiredMessages bool) VerifyOpt { 31 | return func(v *VerifyConfig) { 32 | v.AllowExpiredMessages = &allowExpiredMessages 33 | } 34 | } 35 | 36 | // VerifyOpt sets options. 37 | type VerifyOpt func(v *VerifyConfig) 38 | 39 | // VerifyConfig verifiers options. 40 | type VerifyConfig struct { 41 | // is the period of time that a revoked state remains valid. 42 | AcceptedStateTransitionDelay time.Duration 43 | AcceptedProofGenerationDelay time.Duration 44 | AllowExpiredMessages *bool 45 | } 46 | 47 | // ParamNameVerifierDID is a verifier did - specific circuit param for V3, but can be utilized by other circuits 48 | const ParamNameVerifierDID = "verifierDid" 49 | 50 | // ParamNameNullifierSessionID is a nullifier session id - specific circuit param for V3 to generate nullifier 51 | const ParamNameNullifierSessionID = "nullifierSessionId" 52 | -------------------------------------------------------------------------------- /testdata/kyc-v2.json-ld: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | { 4 | "@version": 1.1, 5 | "@protected": true, 6 | "id": "@id", 7 | "type": "@type", 8 | "KYCAgeCredential": { 9 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v2.json-ld#KYCAgeCredential", 10 | "@context": { 11 | "@version": 1.1, 12 | "@protected": true, 13 | "id": "@id", 14 | "type": "@type", 15 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 16 | "serialization": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/serialization.md#", 17 | "birthday": { 18 | "@id": "kyc-vocab:birthday", 19 | "@type": "serialization:IndexDataSlotA" 20 | }, 21 | "documentType": { 22 | "@id": "kyc-vocab:documentType", 23 | "@type": "serialization:IndexDataSlotB" 24 | } 25 | } 26 | }, 27 | "KYCCountryOfResidenceCredential": { 28 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v2.json-ld#KYCCountryOfResidenceCredential", 29 | "@context": { 30 | "@version": 1.1, 31 | "@protected": true, 32 | "id": "@id", 33 | "type": "@type", 34 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 35 | "serialization": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/serialization.md#", 36 | "countryCode": { 37 | "@id": "kyc-vocab:countryCode", 38 | "@type": "serialization:IndexDataSlotA" 39 | }, 40 | "documentType": { 41 | "@id": "kyc-vocab:documentType", 42 | "@type": "serialization:IndexDataSlotB" 43 | } 44 | } 45 | } 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /state/mock/StateGetterMock.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: github.com/iden3/go-iden3-auth/state (interfaces: StateGetter) 3 | 4 | // Package mock_state is a generated GoMock package. 5 | package mock_state 6 | 7 | import ( 8 | big "math/big" 9 | reflect "reflect" 10 | 11 | bind "github.com/ethereum/go-ethereum/accounts/abi/bind" 12 | gomock "github.com/golang/mock/gomock" 13 | abi "github.com/iden3/contracts-abi/state/go/abi" 14 | ) 15 | 16 | // MockStateGetter is a mock of StateGetter interface. 17 | type MockStateGetter struct { 18 | ctrl *gomock.Controller 19 | recorder *MockStateGetterMockRecorder 20 | } 21 | 22 | // MockStateGetterMockRecorder is the mock recorder for MockStateGetter. 23 | type MockStateGetterMockRecorder struct { 24 | mock *MockStateGetter 25 | } 26 | 27 | // NewMockStateGetter creates a new mock instance. 28 | func NewMockStateGetter(ctrl *gomock.Controller) *MockStateGetter { 29 | mock := &MockStateGetter{ctrl: ctrl} 30 | mock.recorder = &MockStateGetterMockRecorder{mock} 31 | return mock 32 | } 33 | 34 | // EXPECT returns an object that allows the caller to indicate expected use. 35 | func (m *MockStateGetter) EXPECT() *MockStateGetterMockRecorder { 36 | return m.recorder 37 | } 38 | 39 | // GetStateInfoByIdAndState mocks base method. 40 | func (m *MockStateGetter) GetStateInfoByIdAndState(arg0 *bind.CallOpts, arg1, arg2 *big.Int) (abi.IStateStateInfo, error) { 41 | m.ctrl.T.Helper() 42 | ret := m.ctrl.Call(m, "GetStateInfoByIdAndState", arg0, arg1, arg2) 43 | ret0, _ := ret[0].(abi.IStateStateInfo) 44 | ret1, _ := ret[1].(error) 45 | return ret0, ret1 46 | } 47 | 48 | // GetStateInfoByIdAndState indicates an expected call of GetStateInfoByIdAndState. 49 | func (mr *MockStateGetterMockRecorder) GetStateInfoByIdAndState(arg0, arg1, arg2 interface{}) *gomock.Call { 50 | mr.mock.ctrl.T.Helper() 51 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStateInfoByIdAndState", reflect.TypeOf((*MockStateGetter)(nil).GetStateInfoByIdAndState), arg0, arg1, arg2) 52 | } 53 | -------------------------------------------------------------------------------- /testdata/kyc-nonmerklized.jsonld: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | { 4 | "@version": 1.1, 5 | "@protected": true, 6 | "id": "@id", 7 | "type": "@type", 8 | "KYCAgeCredential": { 9 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld#KYCAgeCredential", 10 | "@context": { 11 | "@version": 1.1, 12 | "@protected": true, 13 | "id": "@id", 14 | "type": "@type", 15 | "iden3_serialization": "iden3:v1:slotIndexA=birthday&slotIndexB=documentType", 16 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 17 | "xsd": "http://www.w3.org/2001/XMLSchema#", 18 | "birthday": { 19 | "@id": "kyc-vocab:birthday", 20 | "@type": "xsd:integer" 21 | }, 22 | "documentType": { 23 | "@id": "kyc-vocab:documentType", 24 | "@type": "xsd:integer" 25 | } 26 | } 27 | }, 28 | "KYCCountryOfResidenceCredential": { 29 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld#KYCCountryOfResidenceCredential", 30 | "@context": { 31 | "@version": 1.1, 32 | "@protected": true, 33 | "id": "@id", 34 | "type": "@type", 35 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 36 | "iden3_serialization": "iden3:v1:slotIndexA=birthday&slotIndexB=documentType", 37 | "xsd": "http://www.w3.org/2001/XMLSchema#", 38 | "countryCode": { 39 | "@id": "kyc-vocab:countryCode", 40 | "@type": "xsd:integer" 41 | }, 42 | "documentType": { 43 | "@id": "kyc-vocab:documentType", 44 | "@type": "xsd:integer" 45 | } 46 | } 47 | } 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /cache/cache.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/karlseguin/ccache/v3" 7 | ) 8 | 9 | // Cache is a generic interface for a cache implementation. 10 | type Cache[T any] interface { 11 | Get(key string) (T, bool) 12 | Set(key string, value T, opts ...SetOptions) 13 | Delete(key string) 14 | Clear() 15 | Len() int 16 | } 17 | 18 | // InMemoryCache is an in-memory cache implementation using ccache. 19 | type InMemoryCache[T any] struct { 20 | cache *ccache.Cache[T] 21 | defaultTTL time.Duration 22 | } 23 | 24 | // SetConfig holds the configuration for setting cache items. 25 | type SetConfig struct { 26 | ttl time.Duration 27 | } 28 | 29 | // SetOptions is a function that modifies the SetConfig. 30 | type SetOptions func(*SetConfig) 31 | 32 | // WithTTL is an option for Set that allows specifying a custom TTL for the cache item. 33 | func WithTTL(ttl time.Duration) SetOptions { 34 | return func(cfg *SetConfig) { 35 | cfg.ttl = ttl 36 | } 37 | } 38 | 39 | // NewInMemoryCache creates a new in-memory cache with the specified size and default TTL. 40 | func NewInMemoryCache[T any](size int64, defaultTTL time.Duration) *InMemoryCache[T] { 41 | cache := ccache.New(ccache.Configure[T]().MaxSize(size)) 42 | return &InMemoryCache[T]{ 43 | cache: cache, 44 | defaultTTL: defaultTTL, 45 | } 46 | } 47 | 48 | // Get retrieves an item from the cache by its key. 49 | func (c *InMemoryCache[T]) Get(key string) (T, bool) { 50 | item := c.cache.Get(key) 51 | if item == nil || item.Expired() { 52 | var zero T 53 | return zero, false 54 | } 55 | return item.Value(), true 56 | } 57 | 58 | // Set adds an item to the cache with a specified key and value and optional ttl. 59 | func (c *InMemoryCache[T]) Set(key string, value T, opts ...SetOptions) { 60 | cfg := SetConfig{} 61 | for _, opt := range opts { 62 | opt(&cfg) 63 | } 64 | 65 | expire := c.defaultTTL 66 | if cfg.ttl > 0 { 67 | expire = cfg.ttl 68 | } 69 | c.cache.Set(key, value, expire) 70 | } 71 | 72 | // Delete removes an item from the cache by its key. 73 | func (c *InMemoryCache[T]) Delete(key string) { 74 | c.cache.Delete(key) 75 | } 76 | 77 | // Clear removes all items from the cache. 78 | func (c *InMemoryCache[T]) Clear() { 79 | c.cache.Clear() 80 | } 81 | 82 | // Len returns the number of items currently in the cache. 83 | func (c *InMemoryCache[T]) Len() int { 84 | return c.cache.ItemCount() 85 | } 86 | -------------------------------------------------------------------------------- /pubsignals/signals.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "reflect" 5 | "sync" 6 | 7 | "github.com/iden3/go-circuits/v2" 8 | "github.com/pkg/errors" 9 | ) 10 | 11 | var signalsVerifierRegistry = map[circuits.CircuitID]reflect.Type{} 12 | var circuitsLock = new(sync.RWMutex) 13 | 14 | var ( 15 | // ErrGlobalStateIsNotValid invalid global state id. 16 | ErrGlobalStateIsNotValid = errors.New("global state is not valid") 17 | // ErrIssuerClaimStateIsNotValid declares that issuer state is invalid. 18 | ErrIssuerClaimStateIsNotValid = errors.New("issuer state is not valid") 19 | // ErrIssuerNonRevocationClaimStateIsNotValid declares that issuer non-revocation state is invalid. 20 | ErrIssuerNonRevocationClaimStateIsNotValid = errors.New("issuer state for non-revocation proofs is not valid") 21 | // ErrProofGenerationOutdated declares that generated proof is outdated. 22 | ErrProofGenerationOutdated = errors.New("generated proof is outdated") 23 | // ErrWronProofType declares that query proof type doesn't match circuit proof type 24 | ErrWronProofType = errors.New("invalid proof type") 25 | ) 26 | 27 | // RegisterVerifier is factory for public signals init. 28 | // This is done during init() in the method's implementation 29 | func RegisterVerifier(id circuits.CircuitID, t reflect.Type) { 30 | circuitsLock.Lock() 31 | defer circuitsLock.Unlock() 32 | 33 | signalsVerifierRegistry[id] = t 34 | } 35 | 36 | // nolint // register supported circuit 37 | func init() { 38 | RegisterVerifier(circuits.AuthV2CircuitID, reflect.TypeOf(AuthV2{})) 39 | RegisterVerifier(circuits.AuthV3CircuitID, reflect.TypeOf(AuthV3{})) 40 | RegisterVerifier(circuits.AuthV3_8_32CircuitID, reflect.TypeOf(AuthV3{})) 41 | RegisterVerifier(circuits.AtomicQuerySigV2CircuitID, reflect.TypeOf(AtomicQuerySigV2{})) 42 | RegisterVerifier(circuits.AtomicQueryMTPV2CircuitID, reflect.TypeOf(AtomicQueryMTPV2{})) 43 | RegisterVerifier(circuits.AtomicQueryV3CircuitID, reflect.TypeOf(AtomicQueryV3{})) 44 | RegisterVerifier(circuits.LinkedMultiQuery10CircuitID, reflect.TypeOf(LinkedMultiQuery{})) 45 | } 46 | 47 | // GetVerifier return specific public signals verifier 48 | func GetVerifier(id circuits.CircuitID) (Verifier, error) { 49 | verifierType, ok := signalsVerifierRegistry[id] 50 | if !ok { 51 | return nil, errors.New("public signals verifier for circuit is not registered") 52 | } 53 | 54 | return reflect.New(verifierType).Interface().(Verifier), nil 55 | } 56 | -------------------------------------------------------------------------------- /pubsignals/authV2.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "math/big" 8 | "time" 9 | 10 | "github.com/iden3/go-circuits/v2" 11 | core "github.com/iden3/go-iden3-core/v2" 12 | "github.com/iden3/go-iden3-core/v2/w3c" 13 | "github.com/piprate/json-gold/ld" 14 | "github.com/pkg/errors" 15 | ) 16 | 17 | // AuthV2 is a wrapper for circuits.AuthV2PubSignals. 18 | type AuthV2 struct { 19 | circuits.AuthV2PubSignals 20 | } 21 | 22 | // VerifyQuery is not implemented for authV2 circuit. 23 | func (c *AuthV2) VerifyQuery( 24 | _ context.Context, 25 | _ Query, 26 | _ ld.DocumentLoader, 27 | _ json.RawMessage, 28 | _ map[string]interface{}, 29 | _ ...VerifyOpt) (CircuitVerificationResult, error) { 30 | return CircuitVerificationResult{}, errors.New("authV2 circuit doesn't support queries") 31 | } 32 | 33 | // VerifyStates verify AuthV2 tests. 34 | func (c *AuthV2) VerifyStates(ctx context.Context, stateResolvers map[string]StateResolver, opts ...VerifyOpt) error { 35 | blockchain, err := core.BlockchainFromID(*c.UserID) 36 | if err != nil { 37 | return err 38 | } 39 | networkID, err := core.NetworkIDFromID(*c.UserID) 40 | if err != nil { 41 | return err 42 | } 43 | chainInfo := fmt.Sprintf("%s:%s", blockchain, networkID) 44 | resolver, ok := stateResolvers[chainInfo] 45 | if !ok { 46 | return errors.Errorf("%s resolver not found", chainInfo) 47 | } 48 | 49 | resolvedState, err := resolver.ResolveGlobalRoot(ctx, c.GISTRoot.BigInt()) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | cfg := defaultAuthVerifyOpts 55 | for _, o := range opts { 56 | o(&cfg) 57 | } 58 | 59 | if !resolvedState.Latest && time.Since(time.Unix(resolvedState.TransitionTimestamp, 0)) > cfg.AcceptedStateTransitionDelay { 60 | return ErrGlobalStateIsNotValid 61 | } 62 | return nil 63 | } 64 | 65 | // VerifyIDOwnership returns error if ownership id wasn't verified in circuit. 66 | func (c *AuthV2) VerifyIDOwnership(sender string, challenge *big.Int) error { 67 | if challenge.Cmp(c.Challenge) != 0 { 68 | return errors.Errorf("challenge is not used for proof creation, expected , expected %s, challenge from public signals: %s}", challenge.String(), c.Challenge.String()) 69 | } 70 | 71 | did, err := w3c.ParseDID(sender) 72 | if err != nil { 73 | return errors.Wrap(err, "sender must be a valid did") 74 | } 75 | senderID, err := core.IDFromDID(*did) 76 | if err != nil { 77 | return err 78 | } 79 | 80 | if senderID.String() != c.UserID.String() { 81 | return errors.Errorf("sender is not used for proof creation, expected %s, user from public signals: %s}", senderID.String(), c.UserID.String()) 82 | } 83 | 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /testdata/kyc-v101.json-ld: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | { 4 | "@version": 1.1, 5 | "@protected": true, 6 | "id": "@id", 7 | "type": "@type", 8 | "KYCAgeCredential": { 9 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCAgeCredential", 10 | "@context": { 11 | "@version": 1.1, 12 | "@protected": true, 13 | "id": "@id", 14 | "type": "@type", 15 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 16 | "xsd": "http://www.w3.org/2001/XMLSchema#", 17 | "birthday": { 18 | "@id": "kyc-vocab:birthday", 19 | "@type": "xsd:integer" 20 | }, 21 | "documentType": { 22 | "@id": "kyc-vocab:documentType", 23 | "@type": "xsd:integer" 24 | } 25 | } 26 | }, 27 | "KYCCountryOfResidenceCredential": { 28 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCCountryOfResidenceCredential", 29 | "@context": { 30 | "@version": 1.1, 31 | "@protected": true, 32 | "id": "@id", 33 | "type": "@type", 34 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 35 | "xsd": "http://www.w3.org/2001/XMLSchema#", 36 | "countryCode": { 37 | "@id": "kyc-vocab:countryCode", 38 | "@type": "xsd:integer" 39 | }, 40 | "documentType": { 41 | "@id": "kyc-vocab:documentType", 42 | "@type": "xsd:integer" 43 | } 44 | } 45 | }, 46 | "KYCEmployee": { 47 | "@id": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld#KYCEmployee", 48 | "@context": { 49 | "@version": 1.1, 50 | "@protected": true, 51 | "id": "@id", 52 | "type": "@type", 53 | "kyc-vocab": "https://github.com/iden3/claim-schema-vocab/blob/main/credentials/kyc.md#", 54 | "xsd": "http://www.w3.org/2001/XMLSchema#", 55 | "documentType": { 56 | "@id": "kyc-vocab:documentType", 57 | "@type": "xsd:integer" 58 | }, 59 | "ZKPexperiance": { 60 | "@id": "kyc-vocab:hasZKPexperiance", 61 | "@type": "xsd:boolean" 62 | }, 63 | "hireDate": { 64 | "@id": "kyc-vocab:hireDate", 65 | "@type": "xsd:dateTime" 66 | }, 67 | "position": { 68 | "@id": "kyc-vocab:position", 69 | "@type": "xsd:string" 70 | }, 71 | "salary": { 72 | "@id": "kyc-vocab:salary", 73 | "@type": "xsd:double" 74 | } 75 | } 76 | } 77 | } 78 | ] 79 | } 80 | -------------------------------------------------------------------------------- /cache/cache_test.go: -------------------------------------------------------------------------------- 1 | package cache_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | "github.com/iden3/go-iden3-auth/v2/cache" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestSetAndGetWithDefaultTTL(t *testing.T) { 13 | c := cache.NewInMemoryCache[string](10, 2*time.Second) 14 | 15 | c.Set("foo", "bar") 16 | 17 | val, ok := c.Get("foo") 18 | require.True(t, ok, "expected 'foo' to be set") 19 | require.Equal(t, "bar", val, "expected value for 'foo' to be 'bar'") 20 | } 21 | 22 | func TestSetAndGetWithCustomTTL(t *testing.T) { 23 | c := cache.NewInMemoryCache[string](10, 10*time.Second) 24 | 25 | c.Set("short", "life", cache.WithTTL(100*time.Millisecond)) 26 | 27 | time.Sleep(200 * time.Millisecond) 28 | 29 | _, ok := c.Get("short") 30 | require.False(t, ok, "expected 'short' to be expired") 31 | } 32 | 33 | func TestDelete(t *testing.T) { 34 | c := cache.NewInMemoryCache[string](10, 10*time.Second) 35 | 36 | c.Set("foo", "bar") 37 | c.Delete("foo") 38 | 39 | _, ok := c.Get("foo") 40 | require.False(t, ok, "expected 'foo' to be deleted") 41 | } 42 | 43 | func TestClear(t *testing.T) { 44 | c := cache.NewInMemoryCache[string](10, 10*time.Second) 45 | 46 | c.Set("a", "1") 47 | c.Set("b", "2") 48 | c.Clear() 49 | 50 | require.Equal(t, 0, c.Len(), "expected cache to be empty after Clear") 51 | 52 | _, ok := c.Get("a") 53 | require.False(t, ok, "expected 'a' to be cleared") 54 | 55 | _, ok = c.Get("b") 56 | require.False(t, ok, "expected 'b' to be cleared") 57 | } 58 | 59 | func TestMultipleKeys(t *testing.T) { 60 | c := cache.NewInMemoryCache[string](10, 5*time.Second) 61 | 62 | c.Set("key1", "val1") 63 | c.Set("key2", "val2") 64 | c.Set("key3", "val3") 65 | 66 | tests := map[string]string{ 67 | "key1": "val1", 68 | "key2": "val2", 69 | "key3": "val3", 70 | } 71 | 72 | for key, expected := range tests { 73 | val, ok := c.Get(key) 74 | require.True(t, ok, "expected key %s to exist", key) 75 | require.Equal(t, expected, val, "expected value %s for key %s, got %s", expected, key, val) 76 | } 77 | } 78 | 79 | func TestOverwriteValue(t *testing.T) { 80 | c := cache.NewInMemoryCache[string](10, 5*time.Second) 81 | 82 | c.Set("key1", "initial") 83 | val, ok := c.Get("key1") 84 | require.True(t, ok, "expected 'key1' to be set") 85 | require.Equal(t, "initial", val, "expected value for 'key1' to be 'initial'") 86 | 87 | c.Set("key1", "updated") 88 | val, ok = c.Get("key1") 89 | require.True(t, ok, "expected 'key1' to be updated") 90 | require.Equal(t, "updated", val, "expected value for 'key1' to be 'updated'") 91 | } 92 | 93 | func TestExpiredEntriesAreCleanedUp(t *testing.T) { 94 | c := cache.NewInMemoryCache[string](10, 100*time.Millisecond) 95 | 96 | // Insert many short-lived entries 97 | for i := 0; i < 20; i++ { 98 | c.Set(fmt.Sprintf("key-%d", i), "value", cache.WithTTL(50*time.Millisecond)) 99 | } 100 | 101 | time.Sleep(200 * time.Millisecond) // Wait for expiration 102 | 103 | // Access the expired entries to trigger lazy cleanup 104 | for i := 0; i < 20; i++ { 105 | c.Get(fmt.Sprintf("key-%d", i)) 106 | } 107 | 108 | require.LessOrEqual(t, c.Len(), 10, "expected cache to have <= 10 active items") 109 | } 110 | -------------------------------------------------------------------------------- /proofs/zk_test.go: -------------------------------------------------------------------------------- 1 | package proofs 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/iden3/go-circuits/v2" 8 | "github.com/iden3/go-rapidsnark/types" 9 | "github.com/iden3/iden3comm/v2/protocol" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestVerifyProof(t *testing.T) { 14 | 15 | var err error 16 | proofMessage := protocol.ZeroKnowledgeProofResponse{ 17 | ZKProof: types.ZKProof{ 18 | Proof: &types.ProofData{ 19 | A: []string{ 20 | "261068577516437401613944053873182458364288414130914048345483377226144652651", 21 | "14191260071695980011679501808453222267520721767757759150101974382053161674611", 22 | "1", 23 | }, 24 | B: [][]string{ 25 | { 26 | "7670847844015116957526183728196977957312627307797919554134684901401436021977", 27 | "14957845472630017095821833222580194061266186851634053897768738253663253650835", 28 | }, 29 | { 30 | "17835642458484628627556329876919077333912011235308758832172880012813397022104", 31 | "18100861130149678153133025031709897120097098591298817367491920553037011650228", 32 | }, 33 | { 34 | "1", 35 | "0", 36 | }}, 37 | C: []string{ 38 | "6217865949299990642832523256863048932210546049203189113362851476966824162191", 39 | "19016949225277755690019647385855936969928994210905992628301967883803670436510", 40 | "1", 41 | }, 42 | Protocol: "groth16", 43 | }, 44 | PubSignals: []string{ 45 | "1", 46 | "27152676987128542066808591998573000370436464722519513348891049644813718018", 47 | "23", 48 | "27752766823371471408248225708681313764866231655187366071881070918984471042", 49 | "21545768883509657340209171549441005603306012513932221371599501498534807719689", 50 | "1", 51 | "21545768883509657340209171549441005603306012513932221371599501498534807719689", 52 | "1679323038", 53 | "336615423900919464193075592850483704600", 54 | "0", 55 | "17002437119434618783545694633038537380726339994244684348913844923422470806844", 56 | "0", 57 | "5", 58 | "840", 59 | "120", 60 | "340", 61 | "509", 62 | "0", 63 | "0", 64 | "0", 65 | "0", 66 | "0", 67 | "0", 68 | "0", 69 | "0", 70 | "0", 71 | "0", 72 | "0", 73 | "0", 74 | "0", 75 | "0", 76 | "0", 77 | "0", 78 | "0", 79 | "0", 80 | "0", 81 | "0", 82 | "0", 83 | "0", 84 | "0", 85 | "0", 86 | "0", 87 | "0", 88 | "0", 89 | "0", 90 | "0", 91 | "0", 92 | "0", 93 | "0", 94 | "0", 95 | "0", 96 | "0", 97 | "0", 98 | "0", 99 | "0", 100 | "0", 101 | "0", 102 | "0", 103 | "0", 104 | "0", 105 | "0", 106 | "0", 107 | "0", 108 | "0", 109 | "0", 110 | "0", 111 | "0", 112 | "0", 113 | "0", 114 | "0", 115 | "0", 116 | "0", 117 | "0", 118 | "0", 119 | "0", 120 | "0", 121 | "0", 122 | }, 123 | }, 124 | } 125 | proofMessage.CircuitID = string(circuits.AtomicQueryMTPV2CircuitID) 126 | 127 | verificationKey, err := os.ReadFile("../loaders/verification_keys/credentialAtomicQueryMTPV2.json") 128 | assert.NoError(t, err) 129 | 130 | proofMessage.ID = 1 131 | 132 | err = VerifyProof(proofMessage, verificationKey) 133 | assert.Nil(t, err) 134 | } 135 | -------------------------------------------------------------------------------- /loaders/verification_keys/authV2.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "groth16", 3 | "curve": "bn128", 4 | "nPublic": 3, 5 | "vk_alpha_1": [ 6 | "20491192805390485299153009773594534940189261866228447918068658471970481763042", 7 | "9383485363053290200918347156157836566562967994039712273449902621266178545958", 8 | "1" 9 | ], 10 | "vk_beta_2": [ 11 | [ 12 | "6375614351688725206403948262868962793625744043794305715222011528459656738731", 13 | "4252822878758300859123897981450591353533073413197771768651442665752259397132" 14 | ], 15 | [ 16 | "10505242626370262277552901082094356697409835680220590971873171140371331206856", 17 | "21847035105528745403288232691147584728191162732299865338377159692350059136679" 18 | ], 19 | [ 20 | "1", 21 | "0" 22 | ] 23 | ], 24 | "vk_gamma_2": [ 25 | [ 26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 28 | ], 29 | [ 30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 32 | ], 33 | [ 34 | "1", 35 | "0" 36 | ] 37 | ], 38 | "vk_delta_2": [ 39 | [ 40 | "15934125614912710821614323121670433574627734468332981610453472911976383177228", 41 | "13386788725021602198567425385006899728203544659933593917276469726154154017730" 42 | ], 43 | [ 44 | "8759505107016263108323717548646403750748432711908544803866765373342463765424", 45 | "13205305607413475134301212820100793870092003365382735436692046794406857938024" 46 | ], 47 | [ 48 | "1", 49 | "0" 50 | ] 51 | ], 52 | "vk_alphabeta_12": [ 53 | [ 54 | [ 55 | "2029413683389138792403550203267699914886160938906632433982220835551125967885", 56 | "21072700047562757817161031222997517981543347628379360635925549008442030252106" 57 | ], 58 | [ 59 | "5940354580057074848093997050200682056184807770593307860589430076672439820312", 60 | "12156638873931618554171829126792193045421052652279363021382169897324752428276" 61 | ], 62 | [ 63 | "7898200236362823042373859371574133993780991612861777490112507062703164551277", 64 | "7074218545237549455313236346927434013100842096812539264420499035217050630853" 65 | ] 66 | ], 67 | [ 68 | [ 69 | "7077479683546002997211712695946002074877511277312570035766170199895071832130", 70 | "10093483419865920389913245021038182291233451549023025229112148274109565435465" 71 | ], 72 | [ 73 | "4595479056700221319381530156280926371456704509942304414423590385166031118820", 74 | "19831328484489333784475432780421641293929726139240675179672856274388269393268" 75 | ], 76 | [ 77 | "11934129596455521040620786944827826205713621633706285934057045369193958244500", 78 | "8037395052364110730298837004334506829870972346962140206007064471173334027475" 79 | ] 80 | ] 81 | ], 82 | "IC": [ 83 | [ 84 | "12385314984359904314257455036963499193805822249900169493212773820637861017270", 85 | "13455871848617958073752171682190449799364399689372987044617812281838570851280", 86 | "1" 87 | ], 88 | [ 89 | "1493564767784757620464057507283285365409721187164502463730502309417194080296", 90 | "6377944811748764752279954590131952700069491229367911408873461121555475171995", 91 | "1" 92 | ], 93 | [ 94 | "17810471156883173964067651564103955395454521925125801510057769541384109536787", 95 | "5548963437503981062668882632052452068705295424483999545932010198708798592260", 96 | "1" 97 | ], 98 | [ 99 | "13853274336731202523728826661915506795333516652854674163618978302237601632434", 100 | "15420320918214290109713867361085955935385737854012308761626909938871786338011", 101 | "1" 102 | ] 103 | ] 104 | } -------------------------------------------------------------------------------- /pubsignals/atomicSigV2.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "math/big" 8 | "time" 9 | 10 | "github.com/iden3/go-circuits/v2" 11 | core "github.com/iden3/go-iden3-core/v2" 12 | "github.com/iden3/go-iden3-core/v2/w3c" 13 | "github.com/piprate/json-gold/ld" 14 | "github.com/pkg/errors" 15 | ) 16 | 17 | // AtomicQuerySigV2 is a wrapper for circuits.AtomicQuerySigV2PubSignals. 18 | type AtomicQuerySigV2 struct { 19 | circuits.AtomicQuerySigV2PubSignals 20 | } 21 | 22 | // VerifyQuery verifies query for atomic query mtp circuit. 23 | func (c *AtomicQuerySigV2) VerifyQuery( 24 | ctx context.Context, 25 | query Query, 26 | schemaLoader ld.DocumentLoader, 27 | verifiablePresentation json.RawMessage, 28 | _ map[string]interface{}, 29 | opts ...VerifyOpt, 30 | ) (CircuitVerificationResult, error) { 31 | pubSig := CircuitOutputs{ 32 | IssuerID: c.IssuerID, 33 | ClaimSchema: c.ClaimSchema, 34 | SlotIndex: c.SlotIndex, 35 | Operator: c.Operator, 36 | Value: c.Value, 37 | Timestamp: c.Timestamp, 38 | Merklized: c.Merklized, 39 | ClaimPathKey: c.ClaimPathKey, 40 | ClaimPathNotExists: c.ClaimPathNotExists, 41 | IsRevocationChecked: c.IsRevocationChecked, 42 | } 43 | err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, circuits.AtomicQuerySigV2CircuitID, opts...) 44 | return CircuitVerificationResult{}, err 45 | } 46 | 47 | // VerifyStates verifies user state and issuer auth claim state in the smart contract. 48 | func (c *AtomicQuerySigV2) VerifyStates(ctx context.Context, stateResolvers map[string]StateResolver, opts ...VerifyOpt) error { 49 | blockchain, err := core.BlockchainFromID(*c.IssuerID) 50 | if err != nil { 51 | return err 52 | } 53 | networkID, err := core.NetworkIDFromID(*c.IssuerID) 54 | if err != nil { 55 | return err 56 | } 57 | resolver, ok := stateResolvers[fmt.Sprintf("%s:%s", blockchain, networkID)] 58 | if !ok { 59 | return errors.Errorf("%s resolver not found", resolver) 60 | } 61 | 62 | issuerStateResolved, err := resolver.Resolve(ctx, c.IssuerID.BigInt(), c.IssuerAuthState.BigInt()) 63 | if err != nil { 64 | return err 65 | } 66 | if issuerStateResolved == nil { 67 | return ErrIssuerClaimStateIsNotValid 68 | } 69 | 70 | // if IsRevocationChecked is set to 0. Skip validation revocation status of issuer. 71 | if c.IsRevocationChecked == 0 { 72 | return nil 73 | } 74 | issuerNonRevStateResolved, err := resolver.Resolve(ctx, c.IssuerID.BigInt(), c.IssuerClaimNonRevState.BigInt()) 75 | if err != nil { 76 | return err 77 | } 78 | 79 | cfg := defaultProofVerifyOpts 80 | for _, o := range opts { 81 | o(&cfg) 82 | } 83 | 84 | if !issuerNonRevStateResolved.Latest && time.Since( 85 | time.Unix(issuerNonRevStateResolved.TransitionTimestamp, 0), 86 | ) > cfg.AcceptedStateTransitionDelay { 87 | return ErrIssuerNonRevocationClaimStateIsNotValid 88 | } 89 | 90 | return nil 91 | } 92 | 93 | // VerifyIDOwnership returns error if ownership id wasn't verified in circuit. 94 | func (c *AtomicQuerySigV2) VerifyIDOwnership(sender string, requestID *big.Int) error { 95 | if c.RequestID.Cmp(requestID) != 0 { 96 | return errors.New("invalid requestID in proof") 97 | } 98 | 99 | did, err := w3c.ParseDID(sender) 100 | if err != nil { 101 | return errors.Wrap(err, "sender must be a valid did") 102 | } 103 | senderID, err := core.IDFromDID(*did) 104 | if err != nil { 105 | return err 106 | } 107 | 108 | if senderID.String() != c.UserID.String() { 109 | return errors.Errorf("sender is not used for proof creation, expected %s, user from public signals: %s}", senderID.String(), c.UserID.String()) 110 | } 111 | return nil 112 | } 113 | -------------------------------------------------------------------------------- /pubsignals/queryCredentialSubjectV3.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "math/big" 7 | 8 | "github.com/iden3/go-circuits/v2" 9 | "github.com/piprate/json-gold/ld" 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | func verifyCredentialSubjectV3( 14 | pubSig *CircuitOutputs, 15 | verifiablePresentation json.RawMessage, 16 | schemaLoader ld.DocumentLoader, 17 | metadata QueryMetadata, 18 | ) error { 19 | 20 | ctx := context.Background() 21 | 22 | // validate selectivity disclosure request 23 | if metadata.Operator == circuits.SD { 24 | return validateDisclosureV3(ctx, pubSig, metadata.FieldName, 25 | verifiablePresentation, schemaLoader) 26 | } 27 | 28 | // validate empty credential subject request 29 | if pubSig.Operator == circuits.NOOP && metadata.FieldName == "" { 30 | return verifyEmptyCredentialSubjectV3(pubSig) 31 | } 32 | 33 | if metadata.Operator != pubSig.Operator { 34 | return ErrRequestOperator 35 | } 36 | 37 | if len(metadata.Values) > len(pubSig.Value) { 38 | return ErrValuesSize 39 | } 40 | 41 | if pubSig.ValueArraySize != len(metadata.Values) { 42 | return errors.Errorf("values that used are not matching with expected in query. Size of value array size is different, expected %v, got %v ", len(metadata.Values), pubSig.ValueArraySize) 43 | } 44 | 45 | for i := 0; i < pubSig.ValueArraySize; i++ { 46 | if metadata.Values[i].Cmp(pubSig.Value[i]) != 0 { 47 | return ErrInvalidValues 48 | } 49 | } 50 | 51 | for i := pubSig.ValueArraySize; i < len(pubSig.Value); i++ { 52 | if pubSig.Value[i].Cmp(new(big.Int)) != 0 { 53 | return errors.New("signal values other then values queries must be set to zero") 54 | } 55 | } 56 | 57 | return nil 58 | } 59 | 60 | func validateDisclosureV3(ctx context.Context, pubSig *CircuitOutputs, 61 | key string, verifiablePresentation json.RawMessage, 62 | schemaLoader ld.DocumentLoader) error { 63 | 64 | mvBig, err2 := fieldValueFromVerifiablePresentation(ctx, verifiablePresentation, schemaLoader, key) 65 | if err2 != nil { 66 | return err2 67 | } 68 | 69 | if pubSig.Operator != circuits.SD { 70 | return errors.New("invalid pub signal operator for selective disclosure") 71 | } 72 | 73 | if pubSig.OperatorOutput == nil || pubSig.OperatorOutput.Cmp(mvBig) != 0 { 74 | return errors.New("operator output should be equal to disclosed value") 75 | } 76 | for i := 0; i < len(pubSig.Value); i++ { 77 | if pubSig.Value[i].Cmp(big.NewInt(0)) != 0 { 78 | return errors.New("public signal values must be zero") 79 | } 80 | } 81 | return nil 82 | } 83 | 84 | func verifyEmptyCredentialSubjectV3( 85 | pubSig *CircuitOutputs, 86 | ) error { 87 | if pubSig.Operator != circuits.NOOP { 88 | return errors.New("empty credentialSubject request available only for equal operation") 89 | } 90 | 91 | for i := 1; i < len(pubSig.Value); i++ { 92 | if pubSig.Value[i].Cmp(big.NewInt(0)) != 0 { 93 | return errors.New("empty credentialSubject request not available for array of values") 94 | } 95 | } 96 | return nil 97 | } 98 | 99 | func (q Query) verifyFieldValueInclusionV3(pubSig *CircuitOutputs, 100 | metadata QueryMetadata) error { 101 | 102 | if metadata.Operator == circuits.NOOP { 103 | return nil 104 | } 105 | if metadata.Operator == circuits.EXISTS && pubSig.Merklized == 0 { 106 | return errors.New("$exists operator is not supported for non-merklized credential") 107 | } 108 | if pubSig.Merklized == 1 { 109 | 110 | if metadata.ClaimPathKey.Cmp(pubSig.ClaimPathKey) != 0 { 111 | return errors.New("proof was generated for another path") 112 | } 113 | return nil 114 | } 115 | if metadata.SlotIndex != pubSig.SlotIndex { 116 | return errors.New("proof was generated for another slot") 117 | } 118 | 119 | return nil 120 | } 121 | -------------------------------------------------------------------------------- /pubsignals/atomicMtpV2.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "math/big" 8 | "time" 9 | 10 | "github.com/iden3/go-circuits/v2" 11 | core "github.com/iden3/go-iden3-core/v2" 12 | "github.com/iden3/go-iden3-core/v2/w3c" 13 | "github.com/piprate/json-gold/ld" 14 | "github.com/pkg/errors" 15 | ) 16 | 17 | // AtomicQueryMTPV2 is a wrapper for circuits.AtomicQueryMTPV2PubSignals. 18 | type AtomicQueryMTPV2 struct { 19 | circuits.AtomicQueryMTPV2PubSignals 20 | } 21 | 22 | // VerifyQuery checks whether the proof matches the query. 23 | func (c *AtomicQueryMTPV2) VerifyQuery( 24 | ctx context.Context, 25 | query Query, 26 | schemaLoader ld.DocumentLoader, 27 | verifiablePresentation json.RawMessage, 28 | _ map[string]interface{}, 29 | opts ...VerifyOpt, 30 | ) (CircuitVerificationResult, error) { 31 | pubSig := CircuitOutputs{ 32 | IssuerID: c.IssuerID, 33 | ClaimSchema: c.ClaimSchema, 34 | SlotIndex: c.SlotIndex, 35 | Operator: c.Operator, 36 | Value: c.Value, 37 | Timestamp: c.Timestamp, 38 | Merklized: c.Merklized, 39 | ClaimPathKey: c.ClaimPathKey, 40 | ClaimPathNotExists: c.ClaimPathNotExists, 41 | ValueArraySize: c.ValueArraySize, 42 | IsRevocationChecked: c.IsRevocationChecked, 43 | } 44 | 45 | err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, circuits.AtomicQueryMTPV2CircuitID, opts...) 46 | return CircuitVerificationResult{}, err 47 | } 48 | 49 | // VerifyStates verifies user state and issuer claim issuance state in the smart contract. 50 | func (c *AtomicQueryMTPV2) VerifyStates(ctx context.Context, 51 | stateResolvers map[string]StateResolver, opts ...VerifyOpt) error { 52 | 53 | blockchain, err := core.BlockchainFromID(*c.IssuerID) 54 | if err != nil { 55 | return err 56 | } 57 | networkID, err := core.NetworkIDFromID(*c.IssuerID) 58 | if err != nil { 59 | return err 60 | } 61 | resolver, ok := stateResolvers[fmt.Sprintf("%s:%s", blockchain, networkID)] 62 | if !ok { 63 | return errors.Errorf("%s resolver not found", resolver) 64 | } 65 | 66 | issuerStateResolved, err := resolver.Resolve(ctx, c.IssuerID.BigInt(), c.IssuerClaimIdenState.BigInt()) 67 | if err != nil { 68 | return err 69 | } 70 | if issuerStateResolved == nil { 71 | return ErrIssuerClaimStateIsNotValid 72 | } 73 | // if IsRevocationChecked is set to 0. Skip validation revocation status of issuer. 74 | if c.IsRevocationChecked == 0 { 75 | return nil 76 | } 77 | issuerNonRevStateResolved, err := resolver.Resolve(ctx, c.IssuerID.BigInt(), c.IssuerClaimNonRevState.BigInt()) 78 | if err != nil { 79 | return err 80 | } 81 | 82 | cfg := defaultProofVerifyOpts 83 | for _, o := range opts { 84 | o(&cfg) 85 | } 86 | 87 | if !issuerNonRevStateResolved.Latest && time.Since( 88 | time.Unix(issuerNonRevStateResolved.TransitionTimestamp, 0), 89 | ) > cfg.AcceptedStateTransitionDelay { 90 | return ErrIssuerNonRevocationClaimStateIsNotValid 91 | } 92 | 93 | return nil 94 | } 95 | 96 | // VerifyIDOwnership returns error if ownership id wasn't verified in circuit. 97 | func (c *AtomicQueryMTPV2) VerifyIDOwnership(sender string, requestID *big.Int) error { 98 | if c.RequestID.Cmp(requestID) != 0 { 99 | return errors.New("invalid requestID in proof") 100 | } 101 | 102 | did, err := w3c.ParseDID(sender) 103 | if err != nil { 104 | return errors.Wrap(err, "sender must be a valid did") 105 | } 106 | senderID, err := core.IDFromDID(*did) 107 | if err != nil { 108 | return err 109 | } 110 | 111 | if senderID.String() != c.UserID.String() { 112 | return errors.Errorf("sender is not used for proof creation, expected %s, user from public signals: %s}", senderID.String(), c.UserID.String()) 113 | } 114 | return nil 115 | } 116 | -------------------------------------------------------------------------------- /pubsignals/queryCredentialSubjectV2.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "math/big" 7 | 8 | "github.com/iden3/go-circuits/v2" 9 | "github.com/iden3/go-schema-processor/v2/merklize" 10 | "github.com/piprate/json-gold/ld" 11 | "github.com/pkg/errors" 12 | ) 13 | 14 | func verifyCredentialSubjectV2( 15 | pubSig *CircuitOutputs, 16 | verifiablePresentation json.RawMessage, 17 | schemaLoader ld.DocumentLoader, 18 | metadata QueryMetadata, 19 | ) error { 20 | 21 | ctx := context.Background() 22 | 23 | // validate selectivity disclosure request 24 | if metadata.Operator == circuits.SD { 25 | return validateDisclosureV2(ctx, pubSig, metadata.FieldName, 26 | verifiablePresentation, schemaLoader) 27 | } 28 | 29 | // validate empty credential subject request 30 | if metadata.Operator == circuits.NOOP && metadata.FieldName == "" && pubSig.Merklized == 1 { 31 | return verifyEmptyCredentialSubjectV2(pubSig, metadata.Path) 32 | } 33 | 34 | if metadata.Operator != pubSig.Operator { 35 | return ErrRequestOperator 36 | } 37 | 38 | if len(metadata.Values) > len(pubSig.Value) { 39 | return ErrValuesSize 40 | } 41 | 42 | if len(metadata.Values) < len(pubSig.Value) { 43 | diff := len(pubSig.Value) - len(metadata.Values) 44 | for diff > 0 { 45 | metadata.Values = append(metadata.Values, big.NewInt(0)) 46 | diff-- 47 | } 48 | } 49 | 50 | for i := 0; i < len(metadata.Values); i++ { 51 | if metadata.Values[i].Cmp(pubSig.Value[i]) != 0 { 52 | return ErrInvalidValues 53 | } 54 | } 55 | 56 | return nil 57 | } 58 | 59 | func validateDisclosureV2(ctx context.Context, pubSig *CircuitOutputs, 60 | key string, verifiablePresentation json.RawMessage, 61 | schemaLoader ld.DocumentLoader) error { 62 | 63 | mvBig, err := fieldValueFromVerifiablePresentation(ctx, verifiablePresentation, schemaLoader, key) 64 | if err != nil { 65 | return err 66 | } 67 | 68 | if pubSig.Operator != circuits.EQ { 69 | return errors.New("selective disclosure available only for equal operation") 70 | } 71 | 72 | for i := 1; i < len(pubSig.Value); i++ { 73 | if pubSig.Value[i].Cmp(big.NewInt(0)) != 0 { 74 | return errors.New("selective disclosure not available for array of values") 75 | } 76 | } 77 | 78 | if pubSig.Value[0].Cmp(mvBig) != 0 { 79 | return errors.New("different value between proof and disclosure value") 80 | } 81 | return nil 82 | } 83 | 84 | func verifyEmptyCredentialSubjectV2( 85 | pubSig *CircuitOutputs, 86 | credSubjectPath *merklize.Path, 87 | ) error { 88 | if pubSig.Operator != circuits.EQ { 89 | return errors.New("empty credentialSubject request available only for equal operation") 90 | } 91 | 92 | for i := 1; i < len(pubSig.Value); i++ { 93 | if pubSig.Value[i].Cmp(big.NewInt(0)) != 0 { 94 | return errors.New("empty credentialSubject request not available for array of values") 95 | } 96 | } 97 | 98 | bi, err := credSubjectPath.MtEntry() 99 | if err != nil { 100 | return err 101 | } 102 | 103 | if pubSig.ClaimPathKey.Cmp(bi) != 0 { 104 | return errors.New("proof doesn't contain credentialSubject in claimPathKey") 105 | } 106 | 107 | return nil 108 | } 109 | 110 | func (q Query) verifyFieldValueInclusionV2(pubSig *CircuitOutputs, 111 | metadata QueryMetadata) error { 112 | 113 | if metadata.Operator == circuits.NOOP { 114 | return nil 115 | } 116 | if pubSig.Merklized == 1 { 117 | 118 | if metadata.ClaimPathKey.Cmp(pubSig.ClaimPathKey) != 0 { 119 | return errors.New("proof was generated for another path") 120 | } 121 | if pubSig.ClaimPathNotExists == 1 { 122 | return errors.New("proof doesn't contains target query key") 123 | } 124 | return nil 125 | } 126 | if metadata.SlotIndex != pubSig.SlotIndex { 127 | return errors.New("proof was generated for another slot") 128 | } 129 | 130 | return nil 131 | } 132 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/iden3/go-iden3-auth/v2 2 | 3 | go 1.24.2 4 | 5 | require ( 6 | github.com/btcsuite/btcd/btcutil v1.1.6 7 | github.com/ethereum/go-ethereum v1.16.7 8 | github.com/golang/mock v1.6.0 9 | github.com/google/uuid v1.6.0 10 | github.com/iden3/contracts-abi/state/go/abi v1.1.0 11 | github.com/iden3/go-circuits/v2 v2.4.3 12 | github.com/iden3/go-iden3-core/v2 v2.4.0 13 | github.com/iden3/go-iden3-crypto v0.0.17 14 | github.com/iden3/go-jwz/v2 v2.2.5 15 | github.com/iden3/go-rapidsnark/types v0.0.3 16 | github.com/iden3/go-rapidsnark/verifier v0.0.5 17 | github.com/iden3/go-schema-processor/v2 v2.6.6 18 | github.com/iden3/iden3comm/v2 v2.12.1 19 | github.com/karlseguin/ccache/v3 v3.0.7 20 | github.com/piprate/json-gold v0.5.1-0.20241210232033-19254b3ec65b 21 | github.com/pkg/errors v0.9.1 22 | github.com/stretchr/testify v1.11.1 23 | ) 24 | 25 | require ( 26 | github.com/Microsoft/go-winio v0.6.2 // indirect 27 | github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251106012722-c7be33e82a11 // indirect 28 | github.com/bits-and-blooms/bitset v1.24.3 // indirect 29 | github.com/btcsuite/btcd v0.24.2 // indirect 30 | github.com/btcsuite/btcd/btcec/v2 v2.3.6 // indirect 31 | github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect 32 | github.com/consensys/gnark-crypto v0.19.2 // indirect 33 | github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect 34 | github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect 35 | github.com/davecgh/go-spew v1.1.1 // indirect 36 | github.com/dchest/blake512 v1.0.0 // indirect 37 | github.com/deckarep/golang-set/v2 v2.8.0 // indirect 38 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect 39 | github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564 // indirect 40 | github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect 41 | github.com/ethereum/go-verkle v0.2.2 // indirect 42 | github.com/fsnotify/fsnotify v1.9.0 // indirect 43 | github.com/go-jose/go-jose/v4 v4.1.3 // indirect 44 | github.com/go-ole/go-ole v1.3.0 // indirect 45 | github.com/goccy/go-json v0.10.5 // indirect 46 | github.com/gorilla/websocket v1.5.3 // indirect 47 | github.com/holiman/uint256 v1.3.2 // indirect 48 | github.com/iden3/contracts-abi/onchain-credential-status-resolver/go/abi v1.0.2 // indirect 49 | github.com/iden3/driver-did-iden3 v0.0.17 // indirect 50 | github.com/iden3/go-merkletree-sql/v2 v2.0.6 // indirect 51 | github.com/iden3/go-rapidsnark/prover v0.0.15 // indirect 52 | github.com/iden3/go-rapidsnark/witness/v2 v2.0.0 // indirect 53 | github.com/iden3/go-rapidsnark/witness/wazero v0.0.0-20230524142950-0986cf057d4e // indirect 54 | github.com/iden3/jose-primitives v0.0.5 // indirect 55 | github.com/iden3/merkletree-proof v1.0.1 // indirect 56 | github.com/lestrrat-go/blackmagic v1.0.4 // indirect 57 | github.com/lestrrat-go/httpcc v1.0.1 // indirect 58 | github.com/lestrrat-go/httprc/v3 v3.0.1 // indirect 59 | github.com/lestrrat-go/jwx/v3 v3.0.10 // indirect 60 | github.com/lestrrat-go/option v1.0.1 // indirect 61 | github.com/lestrrat-go/option/v2 v2.0.0 // indirect 62 | github.com/mr-tron/base58 v1.2.0 // indirect 63 | github.com/pmezard/go-difflib v1.0.0 // indirect 64 | github.com/pquerna/cachecontrol v0.2.0 // indirect 65 | github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect 66 | github.com/segmentio/asm v1.2.1 // indirect 67 | github.com/shirou/gopsutil v3.21.11+incompatible // indirect 68 | github.com/supranational/blst v0.3.16 // indirect 69 | github.com/tetratelabs/wazero v1.10.1 // indirect 70 | github.com/tklauser/go-sysconf v0.3.15 // indirect 71 | github.com/tklauser/numcpus v0.10.0 // indirect 72 | github.com/valyala/fastjson v1.6.4 // indirect 73 | github.com/yusufpapurcu/wmi v1.2.4 // indirect 74 | golang.org/x/crypto v0.44.0 // indirect 75 | golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect 76 | golang.org/x/net v0.46.0 // indirect 77 | golang.org/x/sync v0.18.0 // indirect 78 | golang.org/x/sys v0.38.0 // indirect 79 | golang.org/x/text v0.31.0 // indirect 80 | gopkg.in/yaml.v3 v3.0.1 // indirect 81 | ) 82 | -------------------------------------------------------------------------------- /loaders/embededKeyLoader.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "embed" 5 | "fmt" 6 | "sync" 7 | 8 | "github.com/iden3/go-circuits/v2" 9 | "github.com/pkg/errors" 10 | ) 11 | 12 | //go:embed verification_keys/*.json 13 | var defaultKeys embed.FS 14 | 15 | // ErrKeyNotFound is returned when key is not found 16 | var ErrKeyNotFound = errors.New("key not found") 17 | 18 | // EmbeddedKeyLoader load keys from embedded FS or filesystem. 19 | // Filesystem has priority if keyLoader specified. 20 | type EmbeddedKeyLoader struct { 21 | keyLoader VerificationKeyLoader 22 | cache map[circuits.CircuitID][]byte 23 | cacheMu *sync.RWMutex 24 | useCache bool 25 | } 26 | 27 | // NewEmbeddedKeyLoader creates a new loader with embedded keys 28 | // By default, it uses embedded keys with caching enabled 29 | // Use options to customize behavior: 30 | // - WithKeyLoader to set custom loader 31 | // - WithCacheDisabled to disable caching 32 | // 33 | // Example: 34 | // Default configuration (embedded keys and enabled cache): 35 | // 36 | // loader := NewEmbeddedKeyLoader() 37 | // 38 | // Custom filesystem loader: 39 | // 40 | // fsLoader := &FSKeyLoader{Dir: "/path/to/keys"} 41 | // loader := NewEmbeddedKeyLoader(WithKeyLoader(fsLoader)) 42 | // 43 | // Disabled cache: 44 | // 45 | // loader := NewEmbeddedKeyLoader(WithCacheDisabled()) 46 | func NewEmbeddedKeyLoader(opts ...Option) *EmbeddedKeyLoader { 47 | loader := &EmbeddedKeyLoader{ 48 | useCache: true, // enabled by default 49 | cache: make(map[circuits.CircuitID][]byte), 50 | cacheMu: &sync.RWMutex{}, 51 | } 52 | 53 | // Apply options 54 | for _, opt := range opts { 55 | opt(loader) 56 | } 57 | 58 | return loader 59 | } 60 | 61 | // Option defines functional option for configuring EmbeddedKeyLoader 62 | type Option func(*EmbeddedKeyLoader) 63 | 64 | // WithKeyLoader sets a custom primary loader that will be tried before falling back to embedded keys 65 | func WithKeyLoader(loader VerificationKeyLoader) Option { 66 | return func(e *EmbeddedKeyLoader) { 67 | e.keyLoader = loader 68 | } 69 | } 70 | 71 | // WithCacheDisabled disables caching of loaded keys 72 | func WithCacheDisabled() Option { 73 | return func(e *EmbeddedKeyLoader) { 74 | e.useCache = false 75 | e.cache = nil 76 | } 77 | } 78 | 79 | // Load attempts to load keys in the following order: 80 | // 1. From cache if enabled and available 81 | // 2. From keyLoader loader if provided 82 | // 3. From embedded default keys 83 | // IMPORTANT: If keyLoader is provided, embedded keys are used only if error `ErrKeyNotFound` return by keyLoader 84 | func (e *EmbeddedKeyLoader) Load(id circuits.CircuitID) ([]byte, error) { 85 | // Try cache if enabled 86 | if e.useCache { 87 | if key := e.getFromCache(id); key != nil { 88 | return key, nil 89 | } 90 | } 91 | 92 | // Try keyLoader loader if provided 93 | if e.keyLoader != nil { 94 | key, err := e.keyLoader.Load(id) 95 | if err == nil { 96 | if e.useCache { 97 | e.storeInCache(id, key) 98 | } 99 | return key, nil 100 | } 101 | if !errors.Is(err, ErrKeyNotFound) { 102 | return nil, err 103 | } 104 | // continue to embedded keys if key not found 105 | } 106 | 107 | // Embedded keys 108 | key, err := defaultKeys.ReadFile(fmt.Sprintf("verification_keys/%v.json", id)) 109 | if err != nil { 110 | return nil, fmt.Errorf("failed to load default key: %w", err) 111 | } 112 | 113 | if e.useCache { 114 | e.storeInCache(id, key) 115 | } 116 | return key, nil 117 | } 118 | 119 | // getFromCache returns key from cache if available 120 | func (e *EmbeddedKeyLoader) getFromCache(id circuits.CircuitID) []byte { 121 | e.cacheMu.RLock() 122 | defer e.cacheMu.RUnlock() 123 | return e.cache[id] 124 | } 125 | 126 | // storeInCache stores key in cache 127 | func (e *EmbeddedKeyLoader) storeInCache(id circuits.CircuitID, key []byte) { 128 | if !e.useCache { 129 | return 130 | } 131 | e.cacheMu.Lock() 132 | defer e.cacheMu.Unlock() 133 | e.cache[id] = key 134 | } 135 | -------------------------------------------------------------------------------- /loaders/verification_keys/authV3-8-32.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "groth16", 3 | "curve": "bn128", 4 | "nPublic": 3, 5 | "vk_alpha_1": [ 6 | "16428432848801857252194528405604668803277877773566238944394625302971855135431", 7 | "16846502678714586896801519656441059708016666274385668027902869494772365009666", 8 | "1" 9 | ], 10 | "vk_beta_2": [ 11 | [ 12 | "16348171800823588416173124589066524623406261996681292662100840445103873053252", 13 | "3182164110458002340215786955198810119980427837186618912744689678939861918171" 14 | ], 15 | [ 16 | "19687132236965066906216944365591810874384658708175106803089633851114028275753", 17 | "4920802715848186258981584729175884379674325733638798907835771393452862684714" 18 | ], 19 | [ 20 | "1", 21 | "0" 22 | ] 23 | ], 24 | "vk_gamma_2": [ 25 | [ 26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 28 | ], 29 | [ 30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 32 | ], 33 | [ 34 | "1", 35 | "0" 36 | ] 37 | ], 38 | "vk_delta_2": [ 39 | [ 40 | "4534021091663164337432155383156316458139689419442350046183424490102262285735", 41 | "3908085654487026977396320985966177043586942730752160089698565920271223232999" 42 | ], 43 | [ 44 | "3145729094617243420657431925053038769772855251849833591665122167640780462323", 45 | "7385428876531017749825334919112585397463072892214011091065814640218865661102" 46 | ], 47 | [ 48 | "1", 49 | "0" 50 | ] 51 | ], 52 | "vk_alphabeta_12": [ 53 | [ 54 | [ 55 | "5275725312362878540782176211860327475781113689246818544623830805017503247034", 56 | "700769043921060225711174322502145319612473365595920873303028146383045646735" 57 | ], 58 | [ 59 | "16577533945604560505206253312979863148043263406037367789711279754781525822966", 60 | "9408338099405950952721388539539775335199747835458172188116297223654842340186" 61 | ], 62 | [ 63 | "12663399896275491035004982800573482669934131767886952660443268164480899034271", 64 | "4432711152773877173921024337047412943791122852326272337530740732443732395954" 65 | ] 66 | ], 67 | [ 68 | [ 69 | "13121778684901402722679281862736806628725205381360313795132945954337708567513", 70 | "9534744673358550231812045647241180985734073058548683258847806241019905135720" 71 | ], 72 | [ 73 | "21329152369227346659770815132468371951064045353268189088026893413117512652875", 74 | "17209195434408943681049655974234541356066884378594227002358272904159790622854" 75 | ], 76 | [ 77 | "5346467096835895366917814311591075634165750361894629082277248282132405045579", 78 | "15508364027636868967189209273443690126627947943852338696115233789046842639684" 79 | ] 80 | ] 81 | ], 82 | "IC": [ 83 | [ 84 | "13011583270836167686324261752190504018063275612950450738626169091722414804257", 85 | "1029099495341479266210270378839590820534648405123671609698502061504440191231", 86 | "1" 87 | ], 88 | [ 89 | "20617074249182368407118181094484930866558607669582018513828974471281141588858", 90 | "11531928552481582751945985662977526005456640241208565455772867613668867812453", 91 | "1" 92 | ], 93 | [ 94 | "9603152717271275556190301485244332577342021007007114663679131065041438937037", 95 | "7265633507228466732411720543906062065778995154274990594076736366818239256205", 96 | "1" 97 | ], 98 | [ 99 | "19082522660616755047614875953388809523279285225802616344704230594691553081808", 100 | "20853591996193450418454999077770209683970956452786315383498055553743755110421", 101 | "1" 102 | ] 103 | ] 104 | } -------------------------------------------------------------------------------- /loaders/verification_keys/authV3.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "groth16", 3 | "curve": "bn128", 4 | "nPublic": 3, 5 | "vk_alpha_1": [ 6 | "16428432848801857252194528405604668803277877773566238944394625302971855135431", 7 | "16846502678714586896801519656441059708016666274385668027902869494772365009666", 8 | "1" 9 | ], 10 | "vk_beta_2": [ 11 | [ 12 | "16348171800823588416173124589066524623406261996681292662100840445103873053252", 13 | "3182164110458002340215786955198810119980427837186618912744689678939861918171" 14 | ], 15 | [ 16 | "19687132236965066906216944365591810874384658708175106803089633851114028275753", 17 | "4920802715848186258981584729175884379674325733638798907835771393452862684714" 18 | ], 19 | [ 20 | "1", 21 | "0" 22 | ] 23 | ], 24 | "vk_gamma_2": [ 25 | [ 26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 28 | ], 29 | [ 30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 32 | ], 33 | [ 34 | "1", 35 | "0" 36 | ] 37 | ], 38 | "vk_delta_2": [ 39 | [ 40 | "10281888910824309568173326785373346652221041760053997820078701647537804279935", 41 | "12129407587840805981070680636303451926238347878498110378339666122752357438048" 42 | ], 43 | [ 44 | "4364592268737381104572780263099098069929084670498468019962895235589315428368", 45 | "14781820383113899927223736916529455821239281677206770240674751525761651712773" 46 | ], 47 | [ 48 | "1", 49 | "0" 50 | ] 51 | ], 52 | "vk_alphabeta_12": [ 53 | [ 54 | [ 55 | "5275725312362878540782176211860327475781113689246818544623830805017503247034", 56 | "700769043921060225711174322502145319612473365595920873303028146383045646735" 57 | ], 58 | [ 59 | "16577533945604560505206253312979863148043263406037367789711279754781525822966", 60 | "9408338099405950952721388539539775335199747835458172188116297223654842340186" 61 | ], 62 | [ 63 | "12663399896275491035004982800573482669934131767886952660443268164480899034271", 64 | "4432711152773877173921024337047412943791122852326272337530740732443732395954" 65 | ] 66 | ], 67 | [ 68 | [ 69 | "13121778684901402722679281862736806628725205381360313795132945954337708567513", 70 | "9534744673358550231812045647241180985734073058548683258847806241019905135720" 71 | ], 72 | [ 73 | "21329152369227346659770815132468371951064045353268189088026893413117512652875", 74 | "17209195434408943681049655974234541356066884378594227002358272904159790622854" 75 | ], 76 | [ 77 | "5346467096835895366917814311591075634165750361894629082277248282132405045579", 78 | "15508364027636868967189209273443690126627947943852338696115233789046842639684" 79 | ] 80 | ] 81 | ], 82 | "IC": [ 83 | [ 84 | "14277823776830197574771954096807159048742552430864980382291208160345686737459", 85 | "19563052891738167620976449675821804781382715690949466647890218890966120930659", 86 | "1" 87 | ], 88 | [ 89 | "16243203637743349614259820504656391998927394499985234386991958925534495046770", 90 | "4272765338325283834621146650380840596565186839595836228597728078457233438298", 91 | "1" 92 | ], 93 | [ 94 | "11455003321478486365083041796363211165055133813310320662259320982295634437872", 95 | "18349392346836916480499191305753209245511623343247163986337354008758657191514", 96 | "1" 97 | ], 98 | [ 99 | "12519843165772371343681897509671484330613146220068775803468213608618678778490", 100 | "12515589608943770112163820545146541668479065714020322672219471649298688408692", 101 | "1" 102 | ] 103 | ] 104 | } -------------------------------------------------------------------------------- /state/state.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import ( 4 | "context" 5 | "math/big" 6 | "time" 7 | 8 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 9 | "github.com/iden3/contracts-abi/state/go/abi" 10 | core "github.com/iden3/go-iden3-core/v2" 11 | "github.com/pkg/errors" 12 | ) 13 | 14 | var zero = big.NewInt(0) 15 | 16 | // VerificationOptions is options for state verification 17 | type VerificationOptions struct { 18 | Contract string 19 | RPCUrl string 20 | } 21 | 22 | // ExtendedVerificationsOptions allows to set additional options 23 | type ExtendedVerificationsOptions struct { 24 | VerificationOptions 25 | OnlyLatestStates bool 26 | AcceptedStateTransitionDelay time.Duration 27 | } 28 | 29 | // StateGetter return user's state info by user's ID 30 | // 31 | //go:generate mockgen -destination=mock/StateGetterMock.go . StateGetter 32 | //nolint:revive // we have two different getters for the state in one pkg 33 | type StateGetter interface { 34 | GetStateInfoByIdAndState(opts *bind.CallOpts, id, state *big.Int) (abi.IStateStateInfo, error) 35 | } 36 | 37 | // GISTGetter return global state info by state 38 | // 39 | //go:generate mockgen -destination=mock/GISTGetterMock.go . GISTGetter 40 | type GISTGetter interface { 41 | GetGISTRootInfo(opts *bind.CallOpts, root *big.Int) (abi.IStateGistRootInfo, error) 42 | } 43 | 44 | // ResolvedState can be the state verification result 45 | type ResolvedState struct { 46 | State string `json:"state"` 47 | Latest bool `json:"latest"` 48 | Genesis bool `json:"genesis"` 49 | TransitionTimestamp int64 `json:"transition_timestamp"` 50 | } 51 | 52 | // Resolve is used to resolve identity state. 53 | func Resolve(ctx context.Context, getter StateGetter, id, state *big.Int) (*ResolvedState, error) { 54 | // сheck if id is genesis - then we do need to resolve it. 55 | isGenesis, err := CheckGenesisStateID(id, state) 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | stateInfo, err := getter.GetStateInfoByIdAndState(&bind.CallOpts{Context: ctx}, id, state) 61 | if abi.IsErrStateDoesNotExist(err) { 62 | if isGenesis { 63 | return &ResolvedState{Latest: true, Genesis: isGenesis, State: state.String()}, nil 64 | } 65 | return nil, errors.New("state is not genesis and not registered in the smart contract") 66 | } else if err != nil { 67 | return nil, err 68 | } 69 | 70 | if stateInfo.Id.Cmp(id) != 0 { 71 | return nil, errors.New("state has been saved for a different ID") 72 | } 73 | 74 | if stateInfo.ReplacedAtTimestamp.Cmp(zero) == 0 { 75 | return &ResolvedState{Latest: true, Genesis: isGenesis, State: state.String()}, nil 76 | } 77 | 78 | return &ResolvedState{ 79 | Latest: false, 80 | Genesis: isGenesis, 81 | State: state.String(), 82 | TransitionTimestamp: stateInfo.ReplacedAtTimestamp.Int64(), 83 | }, nil 84 | } 85 | 86 | // ResolveGlobalRoot is used to resolve global root. 87 | func ResolveGlobalRoot(ctx context.Context, getter GISTGetter, state *big.Int) (*ResolvedState, error) { 88 | globalStateInfo, err := getter.GetGISTRootInfo(&bind.CallOpts{Context: ctx}, state) 89 | if abi.IsErrRootDoesNotExist(err) { 90 | return nil, errors.New("gist state doesn't exist on smart contract") 91 | } else if err != nil { 92 | return nil, err 93 | } 94 | 95 | if globalStateInfo.Root.Cmp(state) != 0 { 96 | return nil, errors.New("gist info contains invalid state") 97 | } 98 | if globalStateInfo.ReplacedByRoot.Cmp(zero) != 0 { 99 | if globalStateInfo.ReplacedAtTimestamp.Cmp(zero) == 0 { 100 | return nil, errors.New("state was replaced, but replaced time unknown") 101 | } 102 | return &ResolvedState{ 103 | State: state.String(), 104 | Latest: false, 105 | TransitionTimestamp: globalStateInfo.ReplacedAtTimestamp.Int64(), 106 | }, nil 107 | } 108 | return &ResolvedState{ 109 | State: state.String(), 110 | Latest: true, 111 | TransitionTimestamp: 0, 112 | }, nil 113 | } 114 | 115 | // CheckGenesisStateID check if the state is genesis for the id. 116 | func CheckGenesisStateID(id, state *big.Int) (bool, error) { 117 | userID, err := core.IDFromInt(id) 118 | if err != nil { 119 | return false, err 120 | } 121 | identifier, err := core.NewIDFromIdenState(userID.Type(), state) 122 | if err != nil { 123 | return false, err 124 | } 125 | 126 | return id.Cmp(identifier.BigInt()) == 0, nil 127 | } 128 | -------------------------------------------------------------------------------- /loaders/verification_keys/credentialAtomicQuerySigV2OnChain.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "groth16", 3 | "curve": "bn128", 4 | "nPublic": 11, 5 | "vk_alpha_1": [ 6 | "20491192805390485299153009773594534940189261866228447918068658471970481763042", 7 | "9383485363053290200918347156157836566562967994039712273449902621266178545958", 8 | "1" 9 | ], 10 | "vk_beta_2": [ 11 | [ 12 | "6375614351688725206403948262868962793625744043794305715222011528459656738731", 13 | "4252822878758300859123897981450591353533073413197771768651442665752259397132" 14 | ], 15 | [ 16 | "10505242626370262277552901082094356697409835680220590971873171140371331206856", 17 | "21847035105528745403288232691147584728191162732299865338377159692350059136679" 18 | ], 19 | [ 20 | "1", 21 | "0" 22 | ] 23 | ], 24 | "vk_gamma_2": [ 25 | [ 26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 28 | ], 29 | [ 30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 32 | ], 33 | [ 34 | "1", 35 | "0" 36 | ] 37 | ], 38 | "vk_delta_2": [ 39 | [ 40 | "1710121669395829903049554646654548770025644546791991387060028241346751736139", 41 | "9233349870741476556654282208992970742179487991957579201151126362431960413225" 42 | ], 43 | [ 44 | "19046562201477515176875600774989213534306185878886204544239016053798985855692", 45 | "19704486125052989683894847401785081114275457166241990059352921424459992638027" 46 | ], 47 | [ 48 | "1", 49 | "0" 50 | ] 51 | ], 52 | "vk_alphabeta_12": [ 53 | [ 54 | [ 55 | "2029413683389138792403550203267699914886160938906632433982220835551125967885", 56 | "21072700047562757817161031222997517981543347628379360635925549008442030252106" 57 | ], 58 | [ 59 | "5940354580057074848093997050200682056184807770593307860589430076672439820312", 60 | "12156638873931618554171829126792193045421052652279363021382169897324752428276" 61 | ], 62 | [ 63 | "7898200236362823042373859371574133993780991612861777490112507062703164551277", 64 | "7074218545237549455313236346927434013100842096812539264420499035217050630853" 65 | ] 66 | ], 67 | [ 68 | [ 69 | "7077479683546002997211712695946002074877511277312570035766170199895071832130", 70 | "10093483419865920389913245021038182291233451549023025229112148274109565435465" 71 | ], 72 | [ 73 | "4595479056700221319381530156280926371456704509942304414423590385166031118820", 74 | "19831328484489333784475432780421641293929726139240675179672856274388269393268" 75 | ], 76 | [ 77 | "11934129596455521040620786944827826205713621633706285934057045369193958244500", 78 | "8037395052364110730298837004334506829870972346962140206007064471173334027475" 79 | ] 80 | ] 81 | ], 82 | "IC": [ 83 | [ 84 | "4329040981391513141295391766415175655220156497739526881302609278948222504970", 85 | "284608453342683033767670137533198892462004759449479316068661948021384180405", 86 | "1" 87 | ], 88 | [ 89 | "7902292650777562978905160367453874788768779199030594846897219439327408939067", 90 | "10012458713202587447931138874528085940712240664721354058270362630899015322036", 91 | "1" 92 | ], 93 | [ 94 | "11697814597341170748167341793832824505245257771165671796257313346092824905883", 95 | "5174781854368103007061208391170453909797905136821147372441461132562334328215", 96 | "1" 97 | ], 98 | [ 99 | "1726927835877229859131056157678822776962440564906076714962505486421376544987", 100 | "7352133740317971386526986860674287355620937922375271614467789385331477610856", 101 | "1" 102 | ], 103 | [ 104 | "9990035903997574691712818787908054784756674039249764811431700936009293741830", 105 | "4755447104942954158928166153067753327016299728030535979210293681329469052797", 106 | "1" 107 | ], 108 | [ 109 | "15940583140274302050208676622092202988851114679125808597061574700878232173357", 110 | "7533895757575770389928466511298564722397429905987255823784436733572909906714", 111 | "1" 112 | ], 113 | [ 114 | "5508259264227278997738923725524430810437674978357251435507761322739607112981", 115 | "14840270001783263053608712412057782257449606192737461326359694374707752442879", 116 | "1" 117 | ], 118 | [ 119 | "19432593446453142673661052218577694238117210547713431221983638840685247652932", 120 | "16697624670306221047608606229322371623883167253922210155632497282220974839920", 121 | "1" 122 | ], 123 | [ 124 | "6174854815751106275031120096370935217144939918507999853315484754500615715470", 125 | "3190247589562983462928111436181764721696742385815918920518303351200817921520", 126 | "1" 127 | ], 128 | [ 129 | "20417210161225663628251386960452026588766551723348342467498648706108529814968", 130 | "13308394646519897771630385644245620946922357621078786238887021263713833144471", 131 | "1" 132 | ], 133 | [ 134 | "1439721648429120110444974852972369847408183115096685822065827204634576313044", 135 | "7403516047177423709103114106022932360673171438277930001711953991194526055082", 136 | "1" 137 | ], 138 | [ 139 | "18655728389101903942401016308093091046804775184674794685591712671240928471338", 140 | "15349580464155803523251530156943886363594022485425879189715213626172422717967", 141 | "1" 142 | ] 143 | ] 144 | } -------------------------------------------------------------------------------- /loaders/verification_keys/credentialAtomicQueryMTPV2OnChain.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "groth16", 3 | "curve": "bn128", 4 | "nPublic": 11, 5 | "vk_alpha_1": [ 6 | "20491192805390485299153009773594534940189261866228447918068658471970481763042", 7 | "9383485363053290200918347156157836566562967994039712273449902621266178545958", 8 | "1" 9 | ], 10 | "vk_beta_2": [ 11 | [ 12 | "6375614351688725206403948262868962793625744043794305715222011528459656738731", 13 | "4252822878758300859123897981450591353533073413197771768651442665752259397132" 14 | ], 15 | [ 16 | "10505242626370262277552901082094356697409835680220590971873171140371331206856", 17 | "21847035105528745403288232691147584728191162732299865338377159692350059136679" 18 | ], 19 | [ 20 | "1", 21 | "0" 22 | ] 23 | ], 24 | "vk_gamma_2": [ 25 | [ 26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 28 | ], 29 | [ 30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 32 | ], 33 | [ 34 | "1", 35 | "0" 36 | ] 37 | ], 38 | "vk_delta_2": [ 39 | [ 40 | "21107007358082136795614874512538836487771939470796762405748007366166733704104", 41 | "10069053650952764050770858763214373754669660210324204774418789033662943009749" 42 | ], 43 | [ 44 | "8559222867245112767064473074858818732424559824983124225374445082554790506808", 45 | "4852486786898691455964846082763016922630372558821263656172370355988314898575" 46 | ], 47 | [ 48 | "1", 49 | "0" 50 | ] 51 | ], 52 | "vk_alphabeta_12": [ 53 | [ 54 | [ 55 | "2029413683389138792403550203267699914886160938906632433982220835551125967885", 56 | "21072700047562757817161031222997517981543347628379360635925549008442030252106" 57 | ], 58 | [ 59 | "5940354580057074848093997050200682056184807770593307860589430076672439820312", 60 | "12156638873931618554171829126792193045421052652279363021382169897324752428276" 61 | ], 62 | [ 63 | "7898200236362823042373859371574133993780991612861777490112507062703164551277", 64 | "7074218545237549455313236346927434013100842096812539264420499035217050630853" 65 | ] 66 | ], 67 | [ 68 | [ 69 | "7077479683546002997211712695946002074877511277312570035766170199895071832130", 70 | "10093483419865920389913245021038182291233451549023025229112148274109565435465" 71 | ], 72 | [ 73 | "4595479056700221319381530156280926371456704509942304414423590385166031118820", 74 | "19831328484489333784475432780421641293929726139240675179672856274388269393268" 75 | ], 76 | [ 77 | "11934129596455521040620786944827826205713621633706285934057045369193958244500", 78 | "8037395052364110730298837004334506829870972346962140206007064471173334027475" 79 | ] 80 | ] 81 | ], 82 | "IC": [ 83 | [ 84 | "1313452981527053129337572951247197324361989034671138626745310268341512913566", 85 | "15303507074060980322389491486850010383524156520378503449579570642767442684301", 86 | "1" 87 | ], 88 | [ 89 | "19469759548582862041953210077461806234755067239635831761330214958262728102210", 90 | "16182855449814336395630220912227600929619756764754084585163045607249874698864", 91 | "1" 92 | ], 93 | [ 94 | "5328220111696630739082100852965753471276442277347833726730125705096477686086", 95 | "18905255288005092837452154631677141443252188654645540166408868771529766552954", 96 | "1" 97 | ], 98 | [ 99 | "10933184819912527903586676306361564765563053120720138042486726178048079682568", 100 | "18280626518907496130958526005677563160967544228407334084744886760261543167298", 101 | "1" 102 | ], 103 | [ 104 | "11558797904750992453617754478260603596631069504995139547656018378652112039786", 105 | "7387560020132856716152855364841368262707029595898949014465420811988605836841", 106 | "1" 107 | ], 108 | [ 109 | "258345740540242369340676522345540363903777759573849221853370493977314124714", 110 | "8261745575084416750025555445617776886593428107172740509334601364674159098729", 111 | "1" 112 | ], 113 | [ 114 | "12229618381132244012134195568281704584580345418094236823704672151870483088680", 115 | "19652481126909183227792433955062439643525977794731426347743513078747968248518", 116 | "1" 117 | ], 118 | [ 119 | "21501269229626602828017941470237394838663343517747470934919163514713566489074", 120 | "10918047203423236169474519778878366520860074771272087858656960949070403283927", 121 | "1" 122 | ], 123 | [ 124 | "560417708851693272956571111854350209791303214876197214262570647517120871869", 125 | "188344482860559912840076092213437046073780559836275799283864998836054113147", 126 | "1" 127 | ], 128 | [ 129 | "12941763790218889190383140140219843141955553218417052891852216993045901023120", 130 | "12682291388476462975465775054567905896202239758296039216608811622228355512204", 131 | "1" 132 | ], 133 | [ 134 | "11112576039136275785110528933884279009037779878785871940581425517795519742410", 135 | "6613377654128709188004788921975143848004552607600543819185067176149822253345", 136 | "1" 137 | ], 138 | [ 139 | "13613305841160720689914712433320508347546323189059844660259139894452538774575", 140 | "5325101314795154200638690464360192908052407201796948025470533168336651686116", 141 | "1" 142 | ] 143 | ] 144 | } -------------------------------------------------------------------------------- /pubsignals/linkedMultiQuery.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "math/big" 8 | "sort" 9 | 10 | "github.com/iden3/go-circuits/v2" 11 | "github.com/iden3/go-schema-processor/v2/merklize" 12 | "github.com/iden3/go-schema-processor/v2/utils" 13 | "github.com/piprate/json-gold/ld" 14 | "github.com/pkg/errors" 15 | ) 16 | 17 | // LinkedMultiQuery is a wrapper for circuits.LinkedMultiQueryPubSignals. 18 | type LinkedMultiQuery struct { 19 | circuits.LinkedMultiQueryPubSignals 20 | } 21 | 22 | // VerifyQuery verifies query for linked multi query 10 circuit. 23 | func (c *LinkedMultiQuery) VerifyQuery( 24 | ctx context.Context, 25 | query Query, 26 | schemaLoader ld.DocumentLoader, 27 | vp json.RawMessage, 28 | _ map[string]interface{}, 29 | _ ...VerifyOpt, 30 | ) (CircuitVerificationResult, error) { 31 | var outputs CircuitVerificationResult 32 | schemaDoc, err := schemaLoader.LoadDocument(query.Context) 33 | if err != nil { 34 | return outputs, fmt.Errorf("failed load schema by context: %w", err) 35 | } 36 | 37 | schemaBytes, err := json.Marshal(schemaDoc.Document) 38 | if err != nil { 39 | return outputs, fmt.Errorf("failed jsonify schema document: %w", err) 40 | } 41 | 42 | schemaID, err := merklize.Options{DocumentLoader: schemaLoader}. 43 | TypeIDFromContext(schemaBytes, query.Type) 44 | if err != nil { 45 | return outputs, err 46 | } 47 | schemaHash := utils.CreateSchemaHash([]byte(schemaID)) 48 | 49 | if schemaHash.BigInt() == nil { 50 | return outputs, fmt.Errorf("query schema error") 51 | } 52 | 53 | merkOption := merklize.Options{ 54 | DocumentLoader: schemaLoader, 55 | } 56 | queriesMetadata, err := ParseQueriesMetadata(ctx, query.Type, string(schemaBytes), query.CredentialSubject, merkOption) 57 | if err != nil { 58 | return outputs, err 59 | } 60 | 61 | requests := []queryRequest{} 62 | querySignalsMeta := make(queriesMetaPubSignals, len(c.CircuitQueryHash)) 63 | for i, q := range c.CircuitQueryHash { 64 | querySignalsMeta[i] = struct { 65 | OperatorOutput *big.Int 66 | QueryHash *big.Int 67 | }{OperatorOutput: c.OperatorOutput[i], QueryHash: q} 68 | } 69 | 70 | merklized := false 71 | if len(queriesMetadata) > 0 && queriesMetadata[0].MerklizedSchema { 72 | merklized = true 73 | } 74 | for i := 0; i < circuits.LinkedMultiQueryLength; i++ { 75 | if i >= len(queriesMetadata) { 76 | queryHash, err := CalculateQueryHash( 77 | []*big.Int{}, 78 | schemaHash.BigInt(), 79 | 0, 80 | 0, 81 | big.NewInt(0), 82 | merklized) 83 | 84 | if err != nil { 85 | return outputs, err 86 | } 87 | 88 | requests = append(requests, struct { 89 | QueryMetadata *QueryMetadata 90 | QueryHash *big.Int 91 | }{QueryMetadata: nil, QueryHash: queryHash}) 92 | continue 93 | } 94 | 95 | queryHash, err := CalculateQueryHash( 96 | queriesMetadata[i].Values, 97 | schemaHash.BigInt(), 98 | queriesMetadata[i].SlotIndex, 99 | queriesMetadata[i].Operator, 100 | queriesMetadata[i].ClaimPathKey, 101 | merklized) 102 | 103 | if err != nil { 104 | return outputs, err 105 | } 106 | 107 | requests = append(requests, struct { 108 | QueryMetadata *QueryMetadata 109 | QueryHash *big.Int 110 | }{QueryMetadata: &queriesMetadata[i], QueryHash: queryHash}) 111 | } 112 | 113 | sortedPubsignalsMetadata := make(queriesMetaPubSignals, len(c.CircuitQueryHash)) 114 | copy(sortedPubsignalsMetadata, querySignalsMeta) 115 | sort.Sort(sortedPubsignalsMetadata) 116 | 117 | sortedRequests := make(queryRequests, len(requests)) 118 | copy(sortedRequests, requests) 119 | sort.Sort(sortedRequests) 120 | 121 | if sortedPubsignalsMetadata.Len() != sortedRequests.Len() { 122 | return outputs, fmt.Errorf("query hashes do not match") 123 | } 124 | 125 | for i := 0; i < sortedPubsignalsMetadata.Len(); i++ { 126 | if sortedPubsignalsMetadata[i].QueryHash.Cmp(sortedRequests[i].QueryHash) != 0 { 127 | return outputs, fmt.Errorf("query hashes do not match") 128 | } 129 | 130 | if sortedRequests[i].QueryMetadata != nil && sortedRequests[i].QueryMetadata.Operator == circuits.SD { 131 | disclosedValue, err2 := fieldValueFromVerifiablePresentation(ctx, vp, schemaLoader, sortedRequests[i].QueryMetadata.FieldName) 132 | if err2 != nil { 133 | return outputs, err2 134 | } 135 | if disclosedValue.Cmp(sortedPubsignalsMetadata[i].OperatorOutput) != 0 { 136 | return outputs, errors.New("disclosed value is not in the proof outputs") 137 | 138 | } 139 | } 140 | 141 | } 142 | 143 | outputs = CircuitVerificationResult{ 144 | LinkID: c.LinkID, 145 | } 146 | 147 | return outputs, nil 148 | } 149 | 150 | type queryRequest struct { 151 | QueryMetadata *QueryMetadata 152 | QueryHash *big.Int 153 | } 154 | type queryMetaPubSignals struct { 155 | OperatorOutput *big.Int 156 | QueryHash *big.Int 157 | } 158 | type queriesMetaPubSignals []queryMetaPubSignals 159 | 160 | func (q queriesMetaPubSignals) Len() int { return len(q) } 161 | func (q queriesMetaPubSignals) Swap(i, j int) { q[i], q[j] = q[j], q[i] } 162 | func (q queriesMetaPubSignals) Less(i, j int) bool { return q[i].QueryHash.Cmp(q[j].QueryHash) < 0 } 163 | 164 | type queryRequests []queryRequest 165 | 166 | func (q queryRequests) Len() int { return len(q) } 167 | func (q queryRequests) Swap(i, j int) { q[i], q[j] = q[j], q[i] } 168 | func (q queryRequests) Less(i, j int) bool { return q[i].QueryHash.Cmp(q[j].QueryHash) < 0 } 169 | 170 | // VerifyStates verifies user state and issuer auth claim state in the smart contract. 171 | func (c *LinkedMultiQuery) VerifyStates(_ context.Context, _ map[string]StateResolver, _ ...VerifyOpt) error { 172 | return nil 173 | } 174 | 175 | // VerifyIDOwnership returns error if ownership id wasn't verified in circuit. 176 | func (c *LinkedMultiQuery) VerifyIDOwnership(_ string, _ *big.Int) error { 177 | return nil 178 | } 179 | -------------------------------------------------------------------------------- /pubsignals/atomicV3.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "math/big" 8 | "time" 9 | 10 | "github.com/iden3/go-circuits/v2" 11 | core "github.com/iden3/go-iden3-core/v2" 12 | "github.com/iden3/go-iden3-core/v2/w3c" 13 | verifiable "github.com/iden3/go-schema-processor/v2/verifiable" 14 | "github.com/piprate/json-gold/ld" 15 | "github.com/pkg/errors" 16 | ) 17 | 18 | // AtomicQueryV3 is a wrapper for circuits.AtomicQueryV3PubSignals. 19 | type AtomicQueryV3 struct { 20 | circuits.AtomicQueryV3PubSignals 21 | } 22 | 23 | // VerifyQuery verifies query for atomic query V3 circuit. 24 | func (c *AtomicQueryV3) VerifyQuery( 25 | ctx context.Context, 26 | query Query, 27 | schemaLoader ld.DocumentLoader, 28 | verifiablePresentation json.RawMessage, 29 | params map[string]interface{}, 30 | opts ...VerifyOpt, 31 | ) (CircuitVerificationResult, error) { 32 | output := CircuitVerificationResult{ 33 | LinkID: c.LinkID, 34 | } 35 | pubSig := CircuitOutputs{ 36 | IssuerID: c.IssuerID, 37 | ClaimSchema: c.ClaimSchema, 38 | SlotIndex: c.SlotIndex, 39 | Operator: c.Operator, 40 | Value: c.Value, 41 | Timestamp: c.Timestamp, 42 | Merklized: c.Merklized, 43 | ClaimPathKey: c.ClaimPathKey, 44 | ValueArraySize: c.ActualValueArraySize, 45 | IsRevocationChecked: c.IsRevocationChecked, 46 | // V3 NEW 47 | LinkID: c.LinkID, 48 | VerifierID: c.VerifierID, 49 | NullifierSessionID: c.NullifierSessionID, 50 | OperatorOutput: c.OperatorOutput, 51 | Nullifier: c.Nullifier, 52 | ProofType: c.ProofType, 53 | } 54 | err := query.Check(ctx, schemaLoader, &pubSig, verifiablePresentation, circuits.AtomicQueryV3CircuitID, opts...) 55 | if err != nil { 56 | return output, err 57 | } 58 | 59 | // V3 NEW 60 | switch query.ProofType { 61 | case string(verifiable.BJJSignatureProofType): 62 | if c.ProofType != 1 { 63 | return output, ErrWronProofType 64 | } 65 | case string(verifiable.Iden3SparseMerkleTreeProofType): 66 | if c.ProofType != 2 { 67 | return output, ErrWronProofType 68 | } 69 | default: 70 | } 71 | 72 | if params != nil { 73 | nullifierSessionIDparam, ok := params[ParamNameNullifierSessionID].(string) 74 | if ok { 75 | verifierDID, ok := params[ParamNameVerifierDID].(*w3c.DID) 76 | if !ok { 77 | return output, errors.New("verifier did is mandatory if nullifier session is set in the request") 78 | } 79 | id, err := core.IDFromDID(*verifierDID) 80 | if err != nil { 81 | return output, err 82 | } 83 | if c.VerifierID.BigInt().Cmp(id.BigInt()) != 0 { 84 | return output, errors.New("wrong verifier is used for nullification") 85 | } 86 | 87 | nullifierSessionID, ok := new(big.Int).SetString(nullifierSessionIDparam, 10) 88 | if !ok { 89 | return output, errors.New("nullifier session is not a valid big integer") 90 | } 91 | if c.NullifierSessionID.Cmp(nullifierSessionID) != 0 { 92 | return output, errors.Errorf("wrong verifier session id is used for nullification: expected %s given %s,", nullifierSessionID.String(), c.NullifierSessionID.String()) 93 | } 94 | } else if c.NullifierSessionID != nil && c.NullifierSessionID.Int64() != 0 { 95 | // if no nullifierSessionID in params - we need to verify that nullifier is zero 96 | return output, errors.New("nullifier id is generated but wasn't requested") 97 | } 98 | 99 | } 100 | 101 | if query.GroupID != 0 && c.LinkID == nil { 102 | return output, errors.New("proof doesn't contain link id, but group id is provided") 103 | } 104 | 105 | return output, nil 106 | } 107 | 108 | // VerifyStates verifies user state and issuer auth claim state in the smart contract. 109 | func (c *AtomicQueryV3) VerifyStates(ctx context.Context, stateResolvers map[string]StateResolver, opts ...VerifyOpt) error { 110 | blockchain, err := core.BlockchainFromID(*c.IssuerID) 111 | if err != nil { 112 | return err 113 | } 114 | networkID, err := core.NetworkIDFromID(*c.IssuerID) 115 | if err != nil { 116 | return err 117 | } 118 | resolver, ok := stateResolvers[fmt.Sprintf("%s:%s", blockchain, networkID)] 119 | if !ok { 120 | return errors.Errorf("%s resolver not found", resolver) 121 | } 122 | 123 | issuerStateResolved, err := resolver.Resolve(ctx, c.IssuerID.BigInt(), c.IssuerState.BigInt()) 124 | if err != nil { 125 | return err 126 | } 127 | if issuerStateResolved == nil { 128 | return ErrIssuerClaimStateIsNotValid 129 | } 130 | 131 | // if IsRevocationChecked is set to 0. Skip validation revocation status of issuer. 132 | if c.IsRevocationChecked == 0 { 133 | return nil 134 | } 135 | issuerNonRevStateResolved, err := resolver.Resolve(ctx, c.IssuerID.BigInt(), c.IssuerClaimNonRevState.BigInt()) 136 | if err != nil { 137 | return err 138 | } 139 | 140 | cfg := defaultProofVerifyOpts 141 | for _, o := range opts { 142 | o(&cfg) 143 | } 144 | 145 | if !issuerNonRevStateResolved.Latest && time.Since( 146 | time.Unix(issuerNonRevStateResolved.TransitionTimestamp, 0), 147 | ) > cfg.AcceptedStateTransitionDelay { 148 | return ErrIssuerNonRevocationClaimStateIsNotValid 149 | } 150 | 151 | return nil 152 | } 153 | 154 | // VerifyIDOwnership returns error if ownership id wasn't verified in circuit. 155 | func (c *AtomicQueryV3) VerifyIDOwnership(sender string, requestID *big.Int) error { 156 | if c.RequestID.Cmp(requestID) != 0 { 157 | return errors.New("invalid requestID in proof") 158 | } 159 | 160 | did, err := w3c.ParseDID(sender) 161 | if err != nil { 162 | return errors.Wrap(err, "sender must be a valid did") 163 | } 164 | senderID, err := core.IDFromDID(*did) 165 | if err != nil { 166 | return err 167 | } 168 | 169 | if senderID.String() != c.UserID.String() { 170 | return errors.Errorf("sender is not used for proof creation, expected %s, user from public signals: %s}", senderID.String(), c.UserID.String()) 171 | } 172 | return nil 173 | } 174 | -------------------------------------------------------------------------------- /loaders/verification_keys/credentialAtomicQueryV3OnChain-beta.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "groth16", 3 | "curve": "bn128", 4 | "nPublic": 14, 5 | "vk_alpha_1": [ 6 | "20491192805390485299153009773594534940189261866228447918068658471970481763042", 7 | "9383485363053290200918347156157836566562967994039712273449902621266178545958", 8 | "1" 9 | ], 10 | "vk_beta_2": [ 11 | [ 12 | "6375614351688725206403948262868962793625744043794305715222011528459656738731", 13 | "4252822878758300859123897981450591353533073413197771768651442665752259397132" 14 | ], 15 | [ 16 | "10505242626370262277552901082094356697409835680220590971873171140371331206856", 17 | "21847035105528745403288232691147584728191162732299865338377159692350059136679" 18 | ], 19 | [ 20 | "1", 21 | "0" 22 | ] 23 | ], 24 | "vk_gamma_2": [ 25 | [ 26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 28 | ], 29 | [ 30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 32 | ], 33 | [ 34 | "1", 35 | "0" 36 | ] 37 | ], 38 | "vk_delta_2": [ 39 | [ 40 | "3095893755350579574084340768194859118060812980188883288691308871516619987178", 41 | "17600624336333298446927066138417040872190528073093145749627579436701486084810" 42 | ], 43 | [ 44 | "9709150562752353810497797932190603729039437671327101600791678478917273950037", 45 | "15624791261015486467281565536067431599059156328734464648234840158016173273434" 46 | ], 47 | [ 48 | "1", 49 | "0" 50 | ] 51 | ], 52 | "vk_alphabeta_12": [ 53 | [ 54 | [ 55 | "2029413683389138792403550203267699914886160938906632433982220835551125967885", 56 | "21072700047562757817161031222997517981543347628379360635925549008442030252106" 57 | ], 58 | [ 59 | "5940354580057074848093997050200682056184807770593307860589430076672439820312", 60 | "12156638873931618554171829126792193045421052652279363021382169897324752428276" 61 | ], 62 | [ 63 | "7898200236362823042373859371574133993780991612861777490112507062703164551277", 64 | "7074218545237549455313236346927434013100842096812539264420499035217050630853" 65 | ] 66 | ], 67 | [ 68 | [ 69 | "7077479683546002997211712695946002074877511277312570035766170199895071832130", 70 | "10093483419865920389913245021038182291233451549023025229112148274109565435465" 71 | ], 72 | [ 73 | "4595479056700221319381530156280926371456704509942304414423590385166031118820", 74 | "19831328484489333784475432780421641293929726139240675179672856274388269393268" 75 | ], 76 | [ 77 | "11934129596455521040620786944827826205713621633706285934057045369193958244500", 78 | "8037395052364110730298837004334506829870972346962140206007064471173334027475" 79 | ] 80 | ] 81 | ], 82 | "IC": [ 83 | [ 84 | "1849401186199415714446898249106577591306615685923904839181633252878837941933", 85 | "8035236471157680485161721241984762005637504948850275820115798152710625536247", 86 | "1" 87 | ], 88 | [ 89 | "13014997830273596592285363773482411364833060777316574595254714243319451100023", 90 | "1519901101875445601515316856892256956038434343549622995025824584830611451651", 91 | "1" 92 | ], 93 | [ 94 | "732732582635057379949953987814402537189204601949853687709907785684332179281", 95 | "15267834885791655535186049176331231861852959649470515212584851986795564940071", 96 | "1" 97 | ], 98 | [ 99 | "9413428211197628477997966317587862663576257057786341866558405375306699178832", 100 | "9957858962873131250541300734006023538936825353512626059208707657284699171797", 101 | "1" 102 | ], 103 | [ 104 | "12986373114412441171749127707526954452081739945328422037955795190935519073137", 105 | "10042992577696678090975108191439702978263418022150102345936639537894919467157", 106 | "1" 107 | ], 108 | [ 109 | "14632282924921566651272212498367331387343490740773759117100880016886604894196", 110 | "4277749322986801358683191509237839599482844948728393992697210911791412656195", 111 | "1" 112 | ], 113 | [ 114 | "1441054936562832268555350422182370011550042177033787109666558734462253707584", 115 | "16829620397614944708077481634445693362611923503396303383132466410898208014051", 116 | "1" 117 | ], 118 | [ 119 | "6176652832221910789870730784125076983423862419659805683319991100223742347114", 120 | "13903209722455355912147009957597983581222175564023286343407836006443217229621", 121 | "1" 122 | ], 123 | [ 124 | "21251630217617340659979674226727416299498007537318477922656566465715143379674", 125 | "7156892515590296043288653701817632814984504957024991151649222020749447613891", 126 | "1" 127 | ], 128 | [ 129 | "3285463171209035533413339107204403357789593049153314496671426701176285947339", 130 | "15432321439518281720367548789024134948240437030233551853245294206267289407563", 131 | "1" 132 | ], 133 | [ 134 | "10981447921802844802958651665822758038552958843994366194539354908944820098406", 135 | "5737139382091130478891785746518962705936480622882684617261902200965972697310", 136 | "1" 137 | ], 138 | [ 139 | "1055564097483057901323621655523495182585951695421836578967988879977473236224", 140 | "6635321359961998155772658737781723590688116335624873580852245564435090765407", 141 | "1" 142 | ], 143 | [ 144 | "11247265209401227121789916311585025222528461596265057477076085942787555894250", 145 | "3239306645033355625965845080452138972819866630085601440646008084108372766605", 146 | "1" 147 | ], 148 | [ 149 | "8341904782712852157216647366081403541791755640034846966966720247217837981863", 150 | "16850542577360504544581950457394181039162589721352350647649168440711788185329", 151 | "1" 152 | ], 153 | [ 154 | "11138492517332270162140210043827322847567560216712604094164393898942122324647", 155 | "11747486182329574056528505506898811175084134489980638362495009897146320854364", 156 | "1" 157 | ] 158 | ] 159 | } -------------------------------------------------------------------------------- /state/resolver.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "math/big" 7 | "time" 8 | 9 | "github.com/ethereum/go-ethereum/common" 10 | "github.com/ethereum/go-ethereum/ethclient" 11 | "github.com/iden3/contracts-abi/state/go/abi" 12 | "github.com/iden3/go-iden3-auth/v2/cache" 13 | "github.com/iden3/go-iden3-auth/v2/constants" 14 | ) 15 | 16 | // CacheOptions holds caching behavior configuration 17 | type CacheOptions struct { 18 | // TTL for latest (not replaced) entries 19 | NotReplacedTTL time.Duration 20 | // TTL for historical (replaced) entries 21 | ReplacedTTL time.Duration 22 | // Maximum number of entries in the cache 23 | MaxSize int64 24 | // Optional custom cache implementation 25 | Cache cache.Cache[ResolvedState] 26 | } 27 | 28 | // Options is a function that modifies the Config. 29 | type Options func(*Config) 30 | 31 | // Config is the full config for ETHResolver 32 | type Config struct { 33 | // Caching options for state resolution 34 | StateCacheOptions *CacheOptions 35 | // Caching options for GIST root resolution 36 | RootCacheOptions *CacheOptions 37 | } 38 | 39 | // WithStateCacheOptions creates a new ResolverConfig with default values for state cache options. 40 | func WithStateCacheOptions(opts *CacheOptions) Options { 41 | return func(cfg *Config) { 42 | cfg.StateCacheOptions = opts 43 | } 44 | } 45 | 46 | // WithRootCacheOptions creates a new ResolverConfig with default values for root cache options. 47 | func WithRootCacheOptions(opts *CacheOptions) Options { 48 | return func(cfg *Config) { 49 | cfg.RootCacheOptions = opts 50 | } 51 | } 52 | 53 | // ETHResolver must be created using NewETHResolverWithOpts or NewETHResolver. 54 | // Direct struct creation (e.g. ETHResolver{}) will result in uninitialized caches and undefined behavior. 55 | type ETHResolver struct { 56 | RPCUrl string 57 | ContractAddress common.Address 58 | ethClient *ethclient.Client 59 | stateCaller *abi.StateCaller 60 | cfg Config 61 | stateResolveCache cache.Cache[ResolvedState] 62 | rootResolveCache cache.Cache[ResolvedState] 63 | } 64 | 65 | // NewETHResolverWithOpts create ETH resolver for state or return error. 66 | func NewETHResolverWithOpts(url, contract string, opts ...Options) (*ETHResolver, error) { 67 | ethClient, err := ethclient.Dial(url) 68 | if err != nil { 69 | return nil, fmt.Errorf("failed to connect to Ethereum client: %w", err) 70 | } 71 | 72 | stateCaller, err := abi.NewStateCaller(common.HexToAddress(contract), ethClient) 73 | if err != nil { 74 | return nil, fmt.Errorf("failed to create state caller: %w", err) 75 | } 76 | 77 | cfg := Config{} 78 | for _, opt := range opts { 79 | opt(&cfg) 80 | } 81 | 82 | // ---- State Cache Options ---- 83 | stateOpts := &CacheOptions{} 84 | if cfg.StateCacheOptions != nil { 85 | stateOpts = cfg.StateCacheOptions 86 | } 87 | if stateOpts.NotReplacedTTL == 0 { 88 | stateOpts.NotReplacedTTL = constants.StateCacheOptions.NotReplacedTTL 89 | } 90 | if stateOpts.ReplacedTTL == 0 { 91 | stateOpts.ReplacedTTL = constants.StateCacheOptions.ReplacedTTL 92 | } 93 | if stateOpts.MaxSize == 0 { 94 | stateOpts.MaxSize = constants.DefaultCacheMaxSize 95 | } 96 | var stateCache cache.Cache[ResolvedState] 97 | if stateOpts.Cache != nil { 98 | stateCache = stateOpts.Cache 99 | } else { 100 | stateCache = cache.NewInMemoryCache[ResolvedState](stateOpts.MaxSize, stateOpts.ReplacedTTL) 101 | } 102 | 103 | // ---- Root Cache Options ---- 104 | rootOpts := &CacheOptions{} 105 | if cfg.RootCacheOptions != nil { 106 | rootOpts = cfg.RootCacheOptions 107 | } 108 | if rootOpts.NotReplacedTTL == 0 { 109 | rootOpts.NotReplacedTTL = constants.GistRootCacheOptions.NotReplacedTTL 110 | } 111 | if rootOpts.ReplacedTTL == 0 { 112 | rootOpts.ReplacedTTL = constants.GistRootCacheOptions.ReplacedTTL 113 | } 114 | if rootOpts.MaxSize == 0 { 115 | rootOpts.MaxSize = constants.DefaultCacheMaxSize 116 | } 117 | 118 | var rootCache cache.Cache[ResolvedState] 119 | if rootOpts.Cache != nil { 120 | rootCache = rootOpts.Cache 121 | } else { 122 | rootCache = cache.NewInMemoryCache[ResolvedState](rootOpts.MaxSize, rootOpts.ReplacedTTL) 123 | } 124 | 125 | cfg.StateCacheOptions = stateOpts 126 | cfg.RootCacheOptions = rootOpts 127 | 128 | return ÐResolver{ 129 | RPCUrl: url, 130 | ContractAddress: common.HexToAddress(contract), 131 | stateCaller: stateCaller, 132 | ethClient: ethClient, 133 | cfg: cfg, 134 | stateResolveCache: stateCache, 135 | rootResolveCache: rootCache, 136 | }, nil 137 | } 138 | 139 | // NewETHResolver creates ETH resolver for state or panics if error occurs. 140 | func NewETHResolver(url, contract string, opts ...Options) *ETHResolver { 141 | resolver, err := NewETHResolverWithOpts(url, contract, opts...) 142 | if err != nil { 143 | panic(fmt.Sprintf("NewETHResolver: %v", err)) 144 | } 145 | return resolver 146 | } 147 | 148 | // Resolve returns Resolved state from blockchain 149 | func (r ETHResolver) Resolve(ctx context.Context, id, state *big.Int) (*ResolvedState, error) { 150 | cacheKey := r.getCacheKey(id, state) 151 | if cached, ok := r.stateResolveCache.Get(cacheKey); ok { 152 | return &cached, nil 153 | } 154 | resolved, err := Resolve(ctx, r.stateCaller, id, state) 155 | if err != nil { 156 | return nil, err 157 | } 158 | // Store resolved state in cache 159 | ttl := r.cfg.StateCacheOptions.ReplacedTTL 160 | if resolved.TransitionTimestamp == 0 { 161 | ttl = r.cfg.StateCacheOptions.NotReplacedTTL 162 | } 163 | r.stateResolveCache.Set(cacheKey, *resolved, cache.WithTTL(ttl)) 164 | 165 | return resolved, nil 166 | } 167 | 168 | // ResolveGlobalRoot returns Resolved global state from blockchain 169 | func (r ETHResolver) ResolveGlobalRoot(ctx context.Context, state *big.Int) (*ResolvedState, error) { 170 | cacheKey := r.getRootCacheKey(state) 171 | if cached, ok := r.rootResolveCache.Get(cacheKey); ok { 172 | return &cached, nil 173 | } 174 | 175 | resolved, err := ResolveGlobalRoot(ctx, r.stateCaller, state) 176 | if err != nil { 177 | return nil, err 178 | } 179 | // Store resolved state in cache 180 | ttl := r.cfg.RootCacheOptions.ReplacedTTL 181 | if resolved.TransitionTimestamp == 0 { 182 | ttl = r.cfg.RootCacheOptions.NotReplacedTTL 183 | } 184 | r.rootResolveCache.Set(cacheKey, *resolved, cache.WithTTL(ttl)) 185 | return resolved, nil 186 | } 187 | 188 | func (r ETHResolver) getCacheKey(id, state *big.Int) string { 189 | return fmt.Sprintf("%s-%s", id.String(), state.String()) 190 | } 191 | 192 | func (r ETHResolver) getRootCacheKey(root *big.Int) string { 193 | return root.String() 194 | } 195 | 196 | // Close closes the ETHResolver and its underlying client. 197 | func (r *ETHResolver) Close() error { 198 | if r.ethClient != nil { 199 | r.ethClient.Close() 200 | } 201 | return nil 202 | } 203 | -------------------------------------------------------------------------------- /pubsignals/query.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "math/big" 8 | "time" 9 | 10 | "github.com/iden3/go-circuits/v2" 11 | core "github.com/iden3/go-iden3-core/v2" 12 | "github.com/iden3/go-schema-processor/v2/merklize" 13 | "github.com/iden3/go-schema-processor/v2/utils" 14 | "github.com/piprate/json-gold/ld" 15 | "github.com/pkg/errors" 16 | ) 17 | 18 | var allOperations = map[int]struct{}{ 19 | circuits.EQ: {}, 20 | circuits.LT: {}, 21 | circuits.LTE: {}, 22 | circuits.GT: {}, 23 | circuits.GTE: {}, 24 | circuits.IN: {}, 25 | circuits.NIN: {}, 26 | circuits.NE: {}, 27 | circuits.BETWEEN: {}, 28 | circuits.NULLIFY: {}, 29 | circuits.EXISTS: {}, 30 | circuits.NONBETWEEN: {}, 31 | } 32 | 33 | var availableTypesOperations = map[string]map[int]struct{}{ 34 | ld.XSDBoolean: {circuits.EQ: {}, circuits.NE: {}, circuits.EXISTS: {}}, 35 | ld.XSDInteger: allOperations, 36 | ld.XSDNS + "nonNegativeInteger": allOperations, 37 | ld.XSDNS + "positiveInteger": allOperations, 38 | ld.XSDString: {circuits.EQ: {}, circuits.NE: {}, circuits.IN: {}, circuits.NIN: {}, circuits.EXISTS: {}}, 39 | ld.XSDNS + "dateTime": allOperations, 40 | ld.XSDDouble: {circuits.EQ: {}, circuits.NE: {}, circuits.IN: {}, circuits.NIN: {}, circuits.EXISTS: {}}, 41 | } 42 | 43 | // PathToSubjectType path to description of subject type. 44 | const PathToSubjectType = "https://www.w3.org/2018/credentials#credentialSubject" 45 | 46 | var ( 47 | // ErrUnavailableIssuer issuer from proof not allowed. 48 | ErrUnavailableIssuer = errors.New("issuer not exists in query access list") 49 | // ErrSchemaID proof was created for different schema. 50 | ErrSchemaID = errors.New("proof was generated for another schema") 51 | // ErrRequestOperator proof was created for different query. 52 | ErrRequestOperator = errors.New("proof was generated for another query operator") 53 | // ErrValuesSize proof was created for different values. 54 | ErrValuesSize = errors.New("query asked proof about more values") 55 | // ErrInvalidValues proof was created for different values. 56 | ErrInvalidValues = errors.New("proof was generated for another values") 57 | // ErrNegativeValue only positive integers allowed. 58 | ErrNegativeValue = errors.New("negative values not supported") 59 | ) 60 | 61 | // Query represents structure for query to atomic circuit. 62 | type Query struct { 63 | AllowedIssuers []string `json:"allowedIssuers"` 64 | CredentialSubject map[string]interface{} `json:"credentialSubject,omitempty"` 65 | Context string `json:"context"` 66 | Type string `json:"type"` 67 | ClaimID string `json:"claimId,omitempty"` 68 | SkipClaimRevocationCheck bool `json:"skipClaimRevocationCheck,omitempty"` 69 | ProofType string `json:"proofType"` 70 | GroupID int `json:"groupId"` 71 | } 72 | 73 | // CircuitVerificationResult struct for verification result. 74 | type CircuitVerificationResult struct { 75 | LinkID *big.Int 76 | } 77 | 78 | // CircuitOutputs pub signals from circuit. 79 | type CircuitOutputs struct { 80 | IssuerID *core.ID 81 | ClaimSchema core.SchemaHash 82 | SlotIndex int 83 | Operator int 84 | Value []*big.Int 85 | Timestamp int64 86 | Merklized int 87 | ClaimPathKey *big.Int 88 | ClaimPathNotExists int 89 | ValueArraySize int 90 | IsRevocationChecked int 91 | // V3 NEW 92 | LinkID *big.Int 93 | VerifierID *core.ID 94 | NullifierSessionID *big.Int 95 | 96 | OperatorOutput *big.Int 97 | Nullifier *big.Int 98 | ProofType int 99 | } 100 | 101 | // Check checks if proof was created for this query. 102 | // Would be good to use ctx for external http requests, but current interfaces 103 | // doesn't allow to do it. Left it for future. 104 | func (q Query) Check( 105 | ctx context.Context, 106 | loader ld.DocumentLoader, 107 | pubSig *CircuitOutputs, 108 | verifiablePresentation json.RawMessage, 109 | circuitID circuits.CircuitID, 110 | opts ...VerifyOpt, 111 | ) error { 112 | if err := q.verifyIssuer(pubSig); err != nil { 113 | return err 114 | } 115 | 116 | schemaDoc, err := loader.LoadDocument(q.Context) 117 | if err != nil { 118 | return fmt.Errorf("failed load schema by context: %w", err) 119 | } 120 | 121 | schemaBytes, err := json.Marshal(schemaDoc.Document) 122 | if err != nil { 123 | return fmt.Errorf("failed jsonify schema document: %w", err) 124 | } 125 | 126 | if err := q.verifySchemaID(schemaBytes, pubSig, loader); err != nil { 127 | return err 128 | } 129 | if !q.SkipClaimRevocationCheck && pubSig.IsRevocationChecked == 0 { 130 | return errors.New("check revocation is required") 131 | } 132 | 133 | queriesMetadata, err := ParseQueriesMetadata(ctx, q.Type, string(schemaBytes), q.CredentialSubject, merklize.Options{DocumentLoader: loader}) 134 | if err != nil { 135 | return err 136 | } 137 | 138 | if len(queriesMetadata) > 1 { 139 | return errors.New("multiple requests not supported") 140 | } 141 | 142 | var metadata QueryMetadata 143 | if len(queriesMetadata) == 1 { 144 | metadata = queriesMetadata[0] 145 | } 146 | 147 | cfg := defaultProofVerifyOpts 148 | for _, o := range opts { 149 | o(&cfg) 150 | } 151 | 152 | if time.Since( 153 | time.Unix(pubSig.Timestamp, 0), 154 | ) > cfg.AcceptedProofGenerationDelay { 155 | return ErrProofGenerationOutdated 156 | } 157 | 158 | switch circuitID { 159 | case circuits.AtomicQueryV3CircuitID: 160 | err = verifyCredentialSubjectV3(pubSig, verifiablePresentation, loader, metadata) 161 | if err != nil { 162 | return err 163 | } 164 | return q.verifyFieldValueInclusionV2(pubSig, metadata) 165 | case circuits.AtomicQueryMTPV2CircuitID, circuits.AtomicQuerySigV2CircuitID: 166 | err = verifyCredentialSubjectV2(pubSig, verifiablePresentation, loader, metadata) 167 | if err != nil { 168 | return err 169 | } 170 | return q.verifyFieldValueInclusionV3(pubSig, metadata) 171 | 172 | default: 173 | return errors.Errorf("circuit id %s is not supported", circuitID) 174 | } 175 | 176 | } 177 | 178 | func (q Query) verifyIssuer(pubSig *CircuitOutputs) error { 179 | userDID, err := core.ParseDIDFromID(*pubSig.IssuerID) 180 | if err != nil { 181 | return err 182 | } 183 | for _, issuer := range q.AllowedIssuers { 184 | if issuer == "*" || issuer == userDID.String() { 185 | return nil 186 | } 187 | } 188 | return ErrUnavailableIssuer 189 | } 190 | 191 | func (q Query) verifySchemaID(schemaBytes []byte, pubSig *CircuitOutputs, 192 | schemaLoader ld.DocumentLoader) error { 193 | 194 | schemaID, err := merklize.Options{DocumentLoader: schemaLoader}. 195 | TypeIDFromContext(schemaBytes, q.Type) 196 | if err != nil { 197 | return err 198 | } 199 | querySchema := utils.CreateSchemaHash([]byte(schemaID)) 200 | if querySchema.BigInt().Cmp(pubSig.ClaimSchema.BigInt()) == 0 { 201 | return nil 202 | } 203 | return ErrSchemaID 204 | } 205 | -------------------------------------------------------------------------------- /loaders/verification_keys/linkedMultiQuery10-beta.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "groth16", 3 | "curve": "bn128", 4 | "nPublic": 22, 5 | "vk_alpha_1": [ 6 | "20491192805390485299153009773594534940189261866228447918068658471970481763042", 7 | "9383485363053290200918347156157836566562967994039712273449902621266178545958", 8 | "1" 9 | ], 10 | "vk_beta_2": [ 11 | [ 12 | "6375614351688725206403948262868962793625744043794305715222011528459656738731", 13 | "4252822878758300859123897981450591353533073413197771768651442665752259397132" 14 | ], 15 | [ 16 | "10505242626370262277552901082094356697409835680220590971873171140371331206856", 17 | "21847035105528745403288232691147584728191162732299865338377159692350059136679" 18 | ], 19 | [ 20 | "1", 21 | "0" 22 | ] 23 | ], 24 | "vk_gamma_2": [ 25 | [ 26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 28 | ], 29 | [ 30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 32 | ], 33 | [ 34 | "1", 35 | "0" 36 | ] 37 | ], 38 | "vk_delta_2": [ 39 | [ 40 | "13574129252125202270158307841999632289188481698271261939235393046564697547323", 41 | "4767756989901781990548811495555254021246964220885607355087778530306964004185" 42 | ], 43 | [ 44 | "20994491963918641855107870498261517959074286551785099903933200630273567734342", 45 | "11765493019200775638510616767809212227835759957683292721283970143875449362878" 46 | ], 47 | [ 48 | "1", 49 | "0" 50 | ] 51 | ], 52 | "vk_alphabeta_12": [ 53 | [ 54 | [ 55 | "2029413683389138792403550203267699914886160938906632433982220835551125967885", 56 | "21072700047562757817161031222997517981543347628379360635925549008442030252106" 57 | ], 58 | [ 59 | "5940354580057074848093997050200682056184807770593307860589430076672439820312", 60 | "12156638873931618554171829126792193045421052652279363021382169897324752428276" 61 | ], 62 | [ 63 | "7898200236362823042373859371574133993780991612861777490112507062703164551277", 64 | "7074218545237549455313236346927434013100842096812539264420499035217050630853" 65 | ] 66 | ], 67 | [ 68 | [ 69 | "7077479683546002997211712695946002074877511277312570035766170199895071832130", 70 | "10093483419865920389913245021038182291233451549023025229112148274109565435465" 71 | ], 72 | [ 73 | "4595479056700221319381530156280926371456704509942304414423590385166031118820", 74 | "19831328484489333784475432780421641293929726139240675179672856274388269393268" 75 | ], 76 | [ 77 | "11934129596455521040620786944827826205713621633706285934057045369193958244500", 78 | "8037395052364110730298837004334506829870972346962140206007064471173334027475" 79 | ] 80 | ] 81 | ], 82 | "IC": [ 83 | [ 84 | "12449886944142661472251059230965936349361235560943050777171852750972268056009", 85 | "5508789765348348011558576931625983265119736287691184278767289209256184182152", 86 | "1" 87 | ], 88 | [ 89 | "11354840822823409678846005531170154810223893374328536931571598076429246168962", 90 | "10243618321308788660349859395450060514823490518996600371300209313988271557806", 91 | "1" 92 | ], 93 | [ 94 | "7688841796121824588147585218713985820690021917094358723669767856390683928034", 95 | "15304029843415543132293541704424359450862448668530347048215672038580045683481", 96 | "1" 97 | ], 98 | [ 99 | "15990615657429515286876718277658019436828926204319889565777537283744068146700", 100 | "20265128390631794181627612941990068143695235211256419586038084564697570772459", 101 | "1" 102 | ], 103 | [ 104 | "16744634382041772612761056860980716914432614100602561913600347639646803828867", 105 | "9587909504738762931618416803620503763808524690654300610728307244650105345649", 106 | "1" 107 | ], 108 | [ 109 | "14498281259442737211687928465501452644380043044531604747511002130574576040500", 110 | "15178480169883279183083105005735414370343021495727319036601387862295433592890", 111 | "1" 112 | ], 113 | [ 114 | "181238700928172282344680236185737466543303371505875966182504955165221550787", 115 | "21622111637396317730948136644302630767714713068723532481132071344883159478317", 116 | "1" 117 | ], 118 | [ 119 | "8334117149439267478794081283986502998659211363774660979410854038645857015106", 120 | "3525586056545466424550069059261704178677653029630068235241952571550605630653", 121 | "1" 122 | ], 123 | [ 124 | "16676389244152071637547895889424069474191043909363062157910970100503924284824", 125 | "6293986690744783536251466348123663316687870380690807594123241364218706730246", 126 | "1" 127 | ], 128 | [ 129 | "12745671365224662776594194440156600675329812876347548121369698185420569095439", 130 | "11273088596548493444123027464142605382437970433270231501917065525393005894036", 131 | "1" 132 | ], 133 | [ 134 | "7732485931307476787148144929824683305147104743163709148772223736952704050567", 135 | "14991775678419768558530779568394256066852823412993601432448554479361118463299", 136 | "1" 137 | ], 138 | [ 139 | "13954475229491875183185146721491133006576631796979640931033593718558384269206", 140 | "20143678799568261548345812147552378448221261337943896478291695109662795302646", 141 | "1" 142 | ], 143 | [ 144 | "1588536655220107824895151554872386730171641945783207210783928981583577082720", 145 | "13908530648827733472139197820866316501402019214593222521521102979981263265396", 146 | "1" 147 | ], 148 | [ 149 | "12678767645933368864421466910761496605084347784517452696623065956846509548782", 150 | "21381570127686765465000169852593021495333227087229864265691446720659272361152", 151 | "1" 152 | ], 153 | [ 154 | "17922265673268483320025865036589139344955822363275373430719168065953761526520", 155 | "9242324301503892823219332201525279187476010610994752688104429744801597668285", 156 | "1" 157 | ], 158 | [ 159 | "19367539127735956732148435844861647320899694335953718141209016532640873590140", 160 | "12701104584447112200166345844417732176637947754547635778619790266357846083284", 161 | "1" 162 | ], 163 | [ 164 | "14931750548482966130586321361300230947899794584196248761236252137274123990811", 165 | "18907870831743031028168656813690968152456035625888662633278498386598866738708", 166 | "1" 167 | ], 168 | [ 169 | "21078326524345796712273699205406122410330437647297400186087773951320605894880", 170 | "6471701510558433137588469036231611931381433511837825536013781894924055589201", 171 | "1" 172 | ], 173 | [ 174 | "11616604898621091236885062107603844843578912315924240360909152763967953411071", 175 | "15567597962932438133376009485279673723080736998791665521084155531250437535832", 176 | "1" 177 | ], 178 | [ 179 | "16814378820042549514945932350142180953549065761435730844701764513083012014298", 180 | "9577851565990440995137571478255586121135591079059958395444685890902579770570", 181 | "1" 182 | ], 183 | [ 184 | "1093702848180480792269642835164492672016092778979951861285096707497432193760", 185 | "4063334433551442475817332481927046015343707417264061346417488535608502495218", 186 | "1" 187 | ], 188 | [ 189 | "7214731470556020664921656204545020072837783006969685612760693537299230135333", 190 | "8891562787830667150144624187125115054175583159717508708300614390764766181778", 191 | "1" 192 | ], 193 | [ 194 | "4041991063957841891847968885939221032895793579852508335899469034278358488695", 195 | "12929528695870206289536816082066059156374288392417066761527212742555189041207", 196 | "1" 197 | ] 198 | ] 199 | } -------------------------------------------------------------------------------- /loaders/embededKeyLoader_test.go: -------------------------------------------------------------------------------- 1 | package loaders 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "sync" 7 | "testing" 8 | 9 | "github.com/iden3/go-circuits/v2" 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | // MockKeyLoader implements VerificationKeyLoader for testing 15 | type MockKeyLoader struct { 16 | keys map[circuits.CircuitID][]byte 17 | err error 18 | } 19 | 20 | func (m *MockKeyLoader) Load(id circuits.CircuitID) ([]byte, error) { 21 | if m.err != nil { 22 | return nil, m.err 23 | } 24 | if key, ok := m.keys[id]; ok { 25 | return key, nil 26 | } 27 | return nil, errors.New("key not found") 28 | } 29 | 30 | func TestNewEmbeddedKeyLoader(t *testing.T) { 31 | t.Run("default configuration", func(t *testing.T) { 32 | loader := NewEmbeddedKeyLoader() 33 | assert.True(t, loader.useCache) 34 | assert.NotNil(t, loader.cache) 35 | assert.Nil(t, loader.keyLoader) 36 | }) 37 | 38 | t.Run("with custom loader", func(t *testing.T) { 39 | mockLoader := &MockKeyLoader{} 40 | loader := NewEmbeddedKeyLoader(WithKeyLoader(mockLoader)) 41 | assert.True(t, loader.useCache) 42 | assert.NotNil(t, loader.cache) 43 | assert.Equal(t, mockLoader, loader.keyLoader) 44 | }) 45 | 46 | t.Run("without cache", func(t *testing.T) { 47 | loader := NewEmbeddedKeyLoader(WithCacheDisabled()) 48 | assert.False(t, loader.useCache) 49 | assert.Nil(t, loader.cache) 50 | }) 51 | 52 | t.Run("multiple options", func(t *testing.T) { 53 | mockLoader := &MockKeyLoader{} 54 | loader := NewEmbeddedKeyLoader( 55 | WithKeyLoader(mockLoader), 56 | WithCacheDisabled(), 57 | ) 58 | assert.False(t, loader.useCache) 59 | assert.Nil(t, loader.cache) 60 | assert.Equal(t, mockLoader, loader.keyLoader) 61 | }) 62 | } 63 | 64 | func TestEmbeddedKeyLoader_Load(t *testing.T) { 65 | testKey := []byte("test-key-data") 66 | testID := circuits.CircuitID("test-circuit") 67 | 68 | t.Run("load from cache", func(t *testing.T) { 69 | loader := NewEmbeddedKeyLoader() 70 | loader.storeInCache(testID, testKey) 71 | 72 | key, err := loader.Load(testID) 73 | require.NoError(t, err) 74 | assert.Equal(t, testKey, key) 75 | }) 76 | 77 | t.Run("load from custom loader", func(t *testing.T) { 78 | mockLoader := &MockKeyLoader{ 79 | keys: map[circuits.CircuitID][]byte{ 80 | testID: testKey, 81 | }, 82 | } 83 | loader := NewEmbeddedKeyLoader(WithKeyLoader(mockLoader)) 84 | 85 | key, err := loader.Load(testID) 86 | require.NoError(t, err) 87 | assert.Equal(t, testKey, key) 88 | 89 | // Verify key was cached 90 | cachedKey := loader.getFromCache(testID) 91 | assert.Equal(t, testKey, cachedKey) 92 | }) 93 | 94 | t.Run("custom loader error fallback to embedded", func(t *testing.T) { 95 | mockLoader := &MockKeyLoader{ 96 | err: errors.New("mock error"), 97 | } 98 | loader := NewEmbeddedKeyLoader(WithKeyLoader(mockLoader)) 99 | 100 | _, err := loader.Load(circuits.AuthV2CircuitID) 101 | require.Error(t, err) 102 | }) 103 | 104 | t.Run("no cache", func(t *testing.T) { 105 | mockLoader := &MockKeyLoader{ 106 | keys: map[circuits.CircuitID][]byte{ 107 | testID: testKey, 108 | }, 109 | } 110 | loader := NewEmbeddedKeyLoader( 111 | WithKeyLoader(mockLoader), 112 | WithCacheDisabled(), 113 | ) 114 | 115 | key, err := loader.Load(testID) 116 | require.NoError(t, err) 117 | assert.Equal(t, testKey, key) 118 | 119 | // Verify key was not cached 120 | assert.Nil(t, loader.cache) 121 | }) 122 | 123 | t.Run("embedded key not found", func(t *testing.T) { 124 | loader := NewEmbeddedKeyLoader() 125 | 126 | _, err := loader.Load("non-existent-circuit") 127 | assert.ErrorContains(t, err, "failed to load default key") 128 | }) 129 | } 130 | 131 | func TestDefaultEmbeddedKeys(t *testing.T) { 132 | tests := []struct { 133 | name string 134 | id circuits.CircuitID 135 | }{ 136 | {"authV2", circuits.AuthV2CircuitID}, 137 | {"authV3", circuits.AuthV3CircuitID}, 138 | {"authV3-8-32", circuits.AuthV3_8_32CircuitID}, 139 | {"AtomicQueryMTPV2CircuitID", circuits.AtomicQueryMTPV2CircuitID}, 140 | {"AtomicQueryMTPV2OnChainCircuitID", circuits.AtomicQueryMTPV2OnChainCircuitID}, 141 | {"AtomicQuerySigV2CircuitID", circuits.AtomicQuerySigV2CircuitID}, 142 | {"AtomicQuerySigV2OnChainCircuitID", circuits.AtomicQuerySigV2OnChainCircuitID}, 143 | {"AtomicQueryV3CircuitID - beta.1", circuits.AtomicQueryV3CircuitID}, 144 | {"AtomicQueryV3OnChainCircuitID - beta.1", circuits.AtomicQueryV3OnChainCircuitID}, 145 | {"LinkedMultiQuery10CircuitID - beta.1", circuits.LinkedMultiQuery10CircuitID}, 146 | } 147 | 148 | for _, tt := range tests { 149 | t.Run(tt.name, func(t *testing.T) { 150 | loader := NewEmbeddedKeyLoader() 151 | key, err := loader.Load(tt.id) 152 | require.NoError(t, err) 153 | assert.NotNil(t, key) 154 | }) 155 | } 156 | } 157 | 158 | func TestEmbeddedKeyLoader_Load_EmbeddedKeys(t *testing.T) { 159 | t.Run("load embedded key", func(t *testing.T) { 160 | loader := NewEmbeddedKeyLoader() 161 | key, err := loader.Load(circuits.AuthV2CircuitID) 162 | require.NoError(t, err) 163 | assert.NotNil(t, key) 164 | }) 165 | 166 | t.Run("embedded key not found", func(t *testing.T) { 167 | loader := NewEmbeddedKeyLoader() 168 | _, err := loader.Load("non-existent-circuit") 169 | assert.Error(t, err) 170 | assert.Contains(t, err.Error(), "failed to load default key") 171 | }) 172 | } 173 | 174 | func TestEmbeddedKeyLoader_Load_CustomLoaderError(t *testing.T) { 175 | t.Run("custom loader error", func(t *testing.T) { 176 | mockLoader := &MockKeyLoader{ 177 | err: errors.New("mock error"), 178 | } 179 | loader := NewEmbeddedKeyLoader(WithKeyLoader(mockLoader)) 180 | 181 | _, err := loader.Load(circuits.CircuitID("any-circuit")) 182 | assert.Error(t, err) 183 | assert.Equal(t, "mock error", err.Error()) 184 | }) 185 | } 186 | 187 | func TestEmbeddedKeyLoader_Cache(t *testing.T) { 188 | t.Run("cache enabled", func(t *testing.T) { 189 | loader := NewEmbeddedKeyLoader() 190 | testID := circuits.CircuitID("test-circuit") 191 | testKey := []byte("test-key-data") 192 | 193 | loader.storeInCache(testID, testKey) 194 | cachedKey := loader.getFromCache(testID) 195 | assert.Equal(t, testKey, cachedKey) 196 | }) 197 | 198 | t.Run("cache disabled", func(t *testing.T) { 199 | loader := NewEmbeddedKeyLoader(WithCacheDisabled()) 200 | testID := circuits.CircuitID("test-circuit") 201 | testKey := []byte("test-key-data") 202 | 203 | loader.storeInCache(testID, testKey) 204 | cachedKey := loader.getFromCache(testID) 205 | assert.Nil(t, cachedKey) 206 | }) 207 | } 208 | 209 | func TestFSKeyLoader_Load_KeyNotFound(t *testing.T) { 210 | loader := FSKeyLoader{Dir: "/non/existent/path"} 211 | 212 | _, err := loader.Load(circuits.CircuitID("non-existent-circuit")) 213 | assert.Error(t, err) 214 | assert.Equal(t, ErrKeyNotFound, err) 215 | } 216 | 217 | func TestEmbeddedKeyLoader_CacheConcurrency(t *testing.T) { 218 | loader := NewEmbeddedKeyLoader() 219 | 220 | // Test concurrent writes 221 | t.Run("concurrent writes", func(t *testing.T) { 222 | var wg sync.WaitGroup 223 | for i := 0; i < 100; i++ { 224 | wg.Add(1) 225 | go func(i int) { 226 | defer wg.Done() 227 | id := circuits.CircuitID(fmt.Sprintf("circuit-%d", i)) 228 | key := []byte(fmt.Sprintf("key-%d", i)) 229 | loader.storeInCache(id, key) 230 | }(i) 231 | } 232 | wg.Wait() 233 | 234 | // Verify all writes succeeded 235 | for i := 0; i < 100; i++ { 236 | id := circuits.CircuitID(fmt.Sprintf("circuit-%d", i)) 237 | expected := []byte(fmt.Sprintf("key-%d", i)) 238 | actual := loader.getFromCache(id) 239 | assert.Equal(t, expected, actual) 240 | } 241 | }) 242 | } 243 | 244 | // Benchmark cache operations 245 | func BenchmarkEmbeddedKeyLoader_Cache(b *testing.B) { 246 | loader := NewEmbeddedKeyLoader() 247 | testID := circuits.CircuitID("test-circuit") 248 | testKey := []byte("test-key-data") 249 | 250 | b.Run("cache write", func(b *testing.B) { 251 | for i := 0; i < b.N; i++ { 252 | loader.storeInCache(testID, testKey) 253 | } 254 | }) 255 | 256 | b.Run("cache read", func(b *testing.B) { 257 | loader.storeInCache(testID, testKey) 258 | b.ResetTimer() 259 | for i := 0; i < b.N; i++ { 260 | _ = loader.getFromCache(testID) 261 | } 262 | }) 263 | } 264 | -------------------------------------------------------------------------------- /testdata/credentials-v1.json-ld: -------------------------------------------------------------------------------- 1 | { 2 | "@context": { 3 | "@version": 1.1, 4 | "@protected": true, 5 | 6 | "id": "@id", 7 | "type": "@type", 8 | 9 | "VerifiableCredential": { 10 | "@id": "https://www.w3.org/2018/credentials#VerifiableCredential", 11 | "@context": { 12 | "@version": 1.1, 13 | "@protected": true, 14 | 15 | "id": "@id", 16 | "type": "@type", 17 | 18 | "cred": "https://www.w3.org/2018/credentials#", 19 | "sec": "https://w3id.org/security#", 20 | "xsd": "http://www.w3.org/2001/XMLSchema#", 21 | 22 | "credentialSchema": { 23 | "@id": "cred:credentialSchema", 24 | "@type": "@id", 25 | "@context": { 26 | "@version": 1.1, 27 | "@protected": true, 28 | 29 | "id": "@id", 30 | "type": "@type", 31 | 32 | "cred": "https://www.w3.org/2018/credentials#", 33 | 34 | "JsonSchemaValidator2018": "cred:JsonSchemaValidator2018" 35 | } 36 | }, 37 | "credentialStatus": {"@id": "cred:credentialStatus", "@type": "@id"}, 38 | "credentialSubject": {"@id": "cred:credentialSubject", "@type": "@id"}, 39 | "evidence": {"@id": "cred:evidence", "@type": "@id"}, 40 | "expirationDate": {"@id": "cred:expirationDate", "@type": "xsd:dateTime"}, 41 | "holder": {"@id": "cred:holder", "@type": "@id"}, 42 | "issued": {"@id": "cred:issued", "@type": "xsd:dateTime"}, 43 | "issuer": {"@id": "cred:issuer", "@type": "@id"}, 44 | "issuanceDate": {"@id": "cred:issuanceDate", "@type": "xsd:dateTime"}, 45 | "proof": {"@id": "sec:proof", "@type": "@id", "@container": "@graph"}, 46 | "refreshService": { 47 | "@id": "cred:refreshService", 48 | "@type": "@id", 49 | "@context": { 50 | "@version": 1.1, 51 | "@protected": true, 52 | 53 | "id": "@id", 54 | "type": "@type", 55 | 56 | "cred": "https://www.w3.org/2018/credentials#", 57 | 58 | "ManualRefreshService2018": "cred:ManualRefreshService2018" 59 | } 60 | }, 61 | "termsOfUse": {"@id": "cred:termsOfUse", "@type": "@id"}, 62 | "validFrom": {"@id": "cred:validFrom", "@type": "xsd:dateTime"}, 63 | "validUntil": {"@id": "cred:validUntil", "@type": "xsd:dateTime"} 64 | } 65 | }, 66 | 67 | "VerifiablePresentation": { 68 | "@id": "https://www.w3.org/2018/credentials#VerifiablePresentation", 69 | "@context": { 70 | "@version": 1.1, 71 | "@protected": true, 72 | 73 | "id": "@id", 74 | "type": "@type", 75 | 76 | "cred": "https://www.w3.org/2018/credentials#", 77 | "sec": "https://w3id.org/security#", 78 | 79 | "holder": {"@id": "cred:holder", "@type": "@id"}, 80 | "proof": {"@id": "sec:proof", "@type": "@id", "@container": "@graph"}, 81 | "verifiableCredential": {"@id": "cred:verifiableCredential", "@type": "@id", "@container": "@graph"} 82 | } 83 | }, 84 | 85 | "EcdsaSecp256k1Signature2019": { 86 | "@id": "https://w3id.org/security#EcdsaSecp256k1Signature2019", 87 | "@context": { 88 | "@version": 1.1, 89 | "@protected": true, 90 | 91 | "id": "@id", 92 | "type": "@type", 93 | 94 | "sec": "https://w3id.org/security#", 95 | "xsd": "http://www.w3.org/2001/XMLSchema#", 96 | 97 | "challenge": "sec:challenge", 98 | "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, 99 | "domain": "sec:domain", 100 | "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, 101 | "jws": "sec:jws", 102 | "nonce": "sec:nonce", 103 | "proofPurpose": { 104 | "@id": "sec:proofPurpose", 105 | "@type": "@vocab", 106 | "@context": { 107 | "@version": 1.1, 108 | "@protected": true, 109 | 110 | "id": "@id", 111 | "type": "@type", 112 | 113 | "sec": "https://w3id.org/security#", 114 | 115 | "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, 116 | "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} 117 | } 118 | }, 119 | "proofValue": "sec:proofValue", 120 | "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} 121 | } 122 | }, 123 | 124 | "EcdsaSecp256r1Signature2019": { 125 | "@id": "https://w3id.org/security#EcdsaSecp256r1Signature2019", 126 | "@context": { 127 | "@version": 1.1, 128 | "@protected": true, 129 | 130 | "id": "@id", 131 | "type": "@type", 132 | 133 | "sec": "https://w3id.org/security#", 134 | "xsd": "http://www.w3.org/2001/XMLSchema#", 135 | 136 | "challenge": "sec:challenge", 137 | "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, 138 | "domain": "sec:domain", 139 | "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, 140 | "jws": "sec:jws", 141 | "nonce": "sec:nonce", 142 | "proofPurpose": { 143 | "@id": "sec:proofPurpose", 144 | "@type": "@vocab", 145 | "@context": { 146 | "@version": 1.1, 147 | "@protected": true, 148 | 149 | "id": "@id", 150 | "type": "@type", 151 | 152 | "sec": "https://w3id.org/security#", 153 | 154 | "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, 155 | "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} 156 | } 157 | }, 158 | "proofValue": "sec:proofValue", 159 | "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} 160 | } 161 | }, 162 | 163 | "Ed25519Signature2018": { 164 | "@id": "https://w3id.org/security#Ed25519Signature2018", 165 | "@context": { 166 | "@version": 1.1, 167 | "@protected": true, 168 | 169 | "id": "@id", 170 | "type": "@type", 171 | 172 | "sec": "https://w3id.org/security#", 173 | "xsd": "http://www.w3.org/2001/XMLSchema#", 174 | 175 | "challenge": "sec:challenge", 176 | "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, 177 | "domain": "sec:domain", 178 | "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, 179 | "jws": "sec:jws", 180 | "nonce": "sec:nonce", 181 | "proofPurpose": { 182 | "@id": "sec:proofPurpose", 183 | "@type": "@vocab", 184 | "@context": { 185 | "@version": 1.1, 186 | "@protected": true, 187 | 188 | "id": "@id", 189 | "type": "@type", 190 | 191 | "sec": "https://w3id.org/security#", 192 | 193 | "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, 194 | "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} 195 | } 196 | }, 197 | "proofValue": "sec:proofValue", 198 | "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} 199 | } 200 | }, 201 | 202 | "RsaSignature2018": { 203 | "@id": "https://w3id.org/security#RsaSignature2018", 204 | "@context": { 205 | "@version": 1.1, 206 | "@protected": true, 207 | 208 | "challenge": "sec:challenge", 209 | "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, 210 | "domain": "sec:domain", 211 | "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, 212 | "jws": "sec:jws", 213 | "nonce": "sec:nonce", 214 | "proofPurpose": { 215 | "@id": "sec:proofPurpose", 216 | "@type": "@vocab", 217 | "@context": { 218 | "@version": 1.1, 219 | "@protected": true, 220 | 221 | "id": "@id", 222 | "type": "@type", 223 | 224 | "sec": "https://w3id.org/security#", 225 | 226 | "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, 227 | "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} 228 | } 229 | }, 230 | "proofValue": "sec:proofValue", 231 | "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} 232 | } 233 | }, 234 | 235 | "proof": {"@id": "https://w3id.org/security#proof", "@type": "@id", "@container": "@graph"} 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-iden3-auth 2 | 3 | [![Go Reference](https://pkg.go.dev/badge/github.com/iden3/go-iden3-auth.svg)](https://pkg.go.dev/github.com/iden3/go-iden3-auth) 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/iden3/go-iden3-auth)](https://goreportcard.com/report/github.com/iden3/go-iden3-auth) 5 | [![Test](https://github.com/iden3/go-iden3-auth/actions/workflows/ci-test.yaml/badge.svg)](https://github.com/iden3/go-iden3-auth/actions/workflows/ci-test.yaml) 6 | [![Lint](https://github.com/iden3/go-iden3-auth/actions/workflows/ci-lint.yaml/badge.svg)](https://github.com/iden3/go-iden3-auth/actions/workflows/ci-lint.yaml) 7 | 8 | > Library for verification of authorization response messages of communication protocol in JWZ format 9 | > 10 | 11 | 12 | `go get github.com/iden3/go-iden3-auth/v2` 13 | 14 | ### General description: 15 | 16 | The goal of iden3auth libraries is to handle authentication messages of [communication protocol](https://iden3-communication.io/authorization/overview/). 17 | 18 | Currently, library implementation includes support of next message types 19 | 20 | 1. `https://iden3-communication.io/authorization/1.0/request` 21 | 2. `https://iden3-communication.io/authorization/1.0/response` 22 | 23 | 24 | --- 25 | 26 | Auth verification procedure: 27 | 28 | 1. [JWZ token](https://iden3-communication.io/proposals/jwz/overview/) verification 29 | 2. Zero-knowledge proof verification of request proofs 30 | 3. Query request verification for atomic circuits 31 | 4. Verification of identity and issuer states for atomic circuits 32 | 33 | ### Zero-knowledge proof verification 34 | 35 | > Groth16 proof are supported by auth library 36 | > 37 | 38 | Verification keys can be provided using `KeyLoader` interface or `EmbeddedKeyLoader` can be used to load keys embedded in the library `loaders/keys`. 39 | 40 | ### Query verification 41 | 42 | Proof for each atomic circuit contains public signals that allow extracting user and issuer identifiers, states, signature, challenges, etc. 43 | 44 | Circuit public signals marshallers are defined in the [go-circuits](https://github.com/iden3/go-circuits) library. 45 | 46 | ### Verification of user / issuer identity states 47 | 48 | The blockchain verification algorithm is used 49 | 50 | 1. Gets state from the blockchain ([address of id state contract](https://docs.iden3.io/contracts/contracts/) and RPC URL must be provided by the caller of the library): 51 | 1. Empty state is returned - it means that identity state hasn’t been updated or updated state hasn’t been published. We need to compare id and state. If they are different it’s not a genesis state of identity then it’s not valid. 52 | 2. The non-empty state is returned and equals to the state in provided proof which means that the user state is fresh enough and we work with the latest user state. 53 | 3. The non-empty state is returned and it’s not equal to the state that the user has provided. Gets the transition time of the state. The verification party can make a decision if it can accept this state based on that time frame. 54 | 55 | 2. Only latest states for user are valid. Any existing issuer state for claim issuance is valid. 56 | 57 | ### Verification of [Global Identities State Tree(GIST)](https://docs.iden3.io/protocol/spec/#gist-new) 58 | 59 | The blockchain verification algorithm is used 60 | 61 | 1. Get GIST from the blockchain (address of id state contract and URL must be provided by the caller of the library): 62 | 1. A non-empty GIST is returned, equal to the GIST is provided by the user, it means the user is using the latest state. 63 | 2. The non-empty GIST is returned and it’s not equal to the GIST is provided by a user. Gets the transition time of the GIST. The verification party can make a decision if it can accept this state based on that time frame. 64 | ## How to use: 65 | 1. `go get https://github.com/iden3/go-iden3-auth/v2` 66 | 2. Request generation: 67 | 68 | basic auth: 69 | ``` golang 70 | var request protocol.AuthorizationRequestMessage 71 | // if you need'message' to sign (e.g. vote) 72 | request = auth.CreateAuthorizationRequestWithMessage("test flow", "message to sign","verifier id", "callback url") 73 | // or if you don't need 'message' to sign 74 | request = auth.CreateAuthorizationRequest("test flow","verifier id", "callback url") 75 | ``` 76 | if you want request specific proof (example): 77 | ``` golang 78 | var mtpProofRequest protocol.ZeroKnowledgeProofRequest 79 | mtpProofRequest.ID = 1 80 | mtpProofRequest.CircuitID = string(circuits.AtomicQueryMTPV2CircuitID) 81 | mtpProofRequest.Query = map[string]interface{}{ 82 | "allowedIssuers": []string{"*"}, 83 | "credentialSubject": map[string]interface{}{ 84 | "countryCode": map[string]interface{}{ 85 | "$nin": []int{840, 120, 340, 509}, 86 | }, 87 | }, 88 | "context": "https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v2.json-ld", 89 | "type": "KYCCountryOfResidenceCredential", 90 | } 91 | request.Body.Scope = append(request.Body.Scope, mtpProofRequest) 92 | ``` 93 | 3. Token verification 94 | 95 | Init Verifier configuration with embeded keys: 96 | 97 | ```go 98 | resolvers := map[string]pubsignals.StateResolver{ 99 | "privado:main": state.NewETHResolver("https://rpc-mainnet.privado.id", "0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896"), 100 | } 101 | verifier, err := auth.NewVerifier(loaders.NewEmbeddedKeyLoader(), resolvers) 102 | 103 | ``` 104 | Init Verifier: 105 | 106 | ```go 107 | var verificationKeyloader = &loaders.FSKeyLoader{Dir: keyDIR} 108 | resolver := state.NewETHResolver(, ) 109 | 110 | resolvers := map[string]pubsignals.StateResolver{ 111 | "polygon:amoy": resolver, 112 | } 113 | verifier,err := auth.NewVerifierWithExplicitError(verificationKeyloader, loaders.DefaultSchemaLoader{IpfsURL: ""}, resolvers) 114 | // or use NewVerifier and check that verifier instance is not nil. IPFS merklization is not worked without setuping global loader 115 | // verifier := auth.NewVerifier(verificationKeyloader, loaders.DefaultSchemaLoader{IpfsURL: "ipfs.io"}, resolvers) 116 | ``` 117 | 118 | 4. FullVerify - verify JWZ token generated by the client: 119 | 120 | ```go 121 | authResponse, err := verifier.FullVerify( 122 | r.Context(), 123 | string(tokenBytes), 124 | authRequest.(protocolAuthorizationRequestMessage), 125 | ...VerifyOpt, 126 | ) 127 | userId = authResponse.from // msg sender 128 | ``` 129 | Verify manually if thread id is used a session id to match request with `VerifyJWZ / VerifyAuthResponse` functions 130 | 131 | 132 | ### Examples of various supported configurations for different networks 133 | 134 | - Addresses and networks of all supported state contracts can be found in the [iden3 documentation](https://docs.iden3.io/contracts/contracts/) 135 | - For custom implementations and private networks you can deploy you own state contract [Contracts repository](https://github.com/iden3/contracts) 136 | - It is recommended to use you own RPC nodes or third-party services like [Infura](https://infura.io) or [Alchemy](https://alchemyapi.io) 137 | 138 | ```go 139 | const COMMON_STATE_ADDRESS = "0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896" // Common state address. Ethereum, 140 | // Privado, Linea, zkEVM networks 141 | const POLYGON_MAIN_STATE_ADDRESS = "0x624ce98D2d27b20b8f8d521723Df8fC4db71D79D" // Polygon main state address 142 | const POLYGON_AMOY_STATE_ADDRESS = "0x1a4cC30f2aA0377b0c3bc9848766D90cb4404124" // // Polygon amoy state address 143 | 144 | resolvers := map[string]pubsignals.StateResolver{ 145 | // Privado Identity Chain 146 | "privado:main": state.NewETHResolver("https://rpc-mainnet.privado.id", COMMON_STATE_ADDRESS), 147 | // Ethereum main 148 | "ethereum:main": state.NewETHResolver("", COMMON_STATE_ADDRESS), 149 | // Polygon POS main 150 | "polygon:main": state.NewETHResolver("", COMMON_STATE_ADDRESS), 153 | // Linea main 154 | "linea:main": state.NewETHResolver("", COMMON_STATE_ADDRESS), 155 | // Ethereum Sepolia 156 | "ethereum:sepolia": state.NewETHResolver("", COMMON_STATE_ADDRESS), 157 | // Polygon Amoy 158 | "polygon:amoy": state.NewETHResolver("https://rpc-amoy.polygon.technology/", POLYGON_AMOY_STATE_ADDRESS), 159 | // Polygon zkEVM Cardona 160 | "zkevm:test": state.NewETHResolver("", COMMON_STATE_ADDRESS), 161 | // Linea-Sepolia 162 | "linea:sepolia": state.NewETHResolver("RPC URL Linea sepolia"), COMMON_STATE_ADDRESS), 163 | } 164 | 165 | ``` 166 | 167 | ### Notes on prover optimization for x86_64 hardware 168 | 169 | See readme in [iden3/go-rapidsnark/prover](https://github.com/iden3/go-rapidsnark/blob/main/prover/) 170 | 171 | ## Contributing 172 | 173 | Unless you explicitly state otherwise, any contribution intentionally submitted 174 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 175 | dual licensed as below, without any additional terms or conditions. 176 | 177 | ## License 178 | 179 | © 2023 0kims Association 180 | 181 | This project is licensed under either of 182 | 183 | - [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) ([`LICENSE-APACHE`](LICENSE-APACHE)) 184 | - [MIT license](https://opensource.org/licenses/MIT) ([`LICENSE-MIT`](LICENSE-MIT)) 185 | 186 | at your option. 187 | -------------------------------------------------------------------------------- /pubsignals/common.go: -------------------------------------------------------------------------------- 1 | package pubsignals 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "fmt" 8 | "math/big" 9 | "reflect" 10 | "strconv" 11 | 12 | "github.com/iden3/go-circuits/v2" 13 | "github.com/iden3/go-iden3-crypto/poseidon" 14 | parser "github.com/iden3/go-schema-processor/v2/json" 15 | "github.com/iden3/go-schema-processor/v2/merklize" 16 | "github.com/iden3/go-schema-processor/v2/verifiable" 17 | "github.com/piprate/json-gold/ld" 18 | "github.com/pkg/errors" 19 | ) 20 | 21 | // PropertyQuery struct 22 | type PropertyQuery struct { 23 | FieldName string 24 | Operator int 25 | OperatorValue any 26 | } 27 | 28 | // QueryMetadata struct describe query metadata 29 | type QueryMetadata struct { 30 | PropertyQuery 31 | SlotIndex int 32 | Values []*big.Int 33 | Path *merklize.Path 34 | ClaimPathKey *big.Int 35 | Datatype string 36 | MerklizedSchema bool 37 | } 38 | 39 | const credentialSubjectFullKey = "https://www.w3.org/2018/credentials#credentialSubject" // #nosec G101 40 | 41 | // ParseCredentialSubject parse credential subject and return array of property queries 42 | func ParseCredentialSubject(_ context.Context, credentialSubject any) (out []PropertyQuery, err error) { 43 | if credentialSubject == nil { 44 | return []PropertyQuery{ 45 | { 46 | Operator: circuits.NOOP, 47 | FieldName: "", 48 | }, 49 | }, nil 50 | } 51 | 52 | out = []PropertyQuery{} 53 | 54 | jsonObject, ok := credentialSubject.(map[string]interface{}) 55 | if !ok { 56 | return nil, errors.New("Failed to convert credential subject to JSONObject") 57 | } 58 | if len(jsonObject) == 0 { 59 | return []PropertyQuery{ 60 | { 61 | Operator: circuits.NOOP, 62 | FieldName: "", 63 | }, 64 | }, nil 65 | } 66 | 67 | for fieldName, fieldReq := range jsonObject { 68 | fieldReqEntries, ok := fieldReq.(map[string]interface{}) 69 | if !ok { 70 | return nil, errors.New("failed cast type map[string]interface") 71 | } 72 | isSelectiveDisclosure := len(fieldReqEntries) == 0 73 | 74 | if isSelectiveDisclosure { 75 | out = append(out, PropertyQuery{Operator: circuits.SD, FieldName: fieldName}) 76 | continue 77 | } 78 | 79 | for operatorName, operatorValue := range fieldReqEntries { 80 | if _, exists := circuits.QueryOperators[operatorName]; !exists { 81 | return nil, errors.New("operator is not supported by lib") 82 | } 83 | operator := circuits.QueryOperators[operatorName] 84 | out = append(out, PropertyQuery{Operator: operator, FieldName: fieldName, OperatorValue: operatorValue}) 85 | } 86 | } 87 | 88 | return out, nil 89 | } 90 | 91 | // ParseQueryMetadata parse property query and return query metadata 92 | func ParseQueryMetadata(ctx context.Context, propertyQuery PropertyQuery, ldContextJSON, credentialType string, options merklize.Options) (query *QueryMetadata, err error) { 93 | 94 | query = &QueryMetadata{ 95 | PropertyQuery: propertyQuery, 96 | SlotIndex: 0, 97 | MerklizedSchema: false, 98 | Datatype: "", 99 | ClaimPathKey: big.NewInt(0), 100 | Values: []*big.Int{}, 101 | Path: &merklize.Path{}, 102 | } 103 | 104 | if query.FieldName != "" { 105 | query.Datatype, err = options.TypeFromContext([]byte(ldContextJSON), fmt.Sprintf("%s.%s", credentialType, propertyQuery.FieldName)) 106 | if err != nil { 107 | return nil, err 108 | } 109 | } 110 | 111 | var ctxObj map[string]interface{} 112 | err = json.Unmarshal([]byte(ldContextJSON), &ctxObj) 113 | if err != nil { 114 | return nil, err 115 | } 116 | 117 | ldCtx, err := ld.NewContext(nil, nil).Parse(ctxObj["@context"]) 118 | if err != nil { 119 | return nil, err 120 | } 121 | 122 | serAttr, err := verifiable.GetSerializationAttrFromParsedContext(ldCtx, credentialType) 123 | if err != nil { 124 | return nil, err 125 | } 126 | if serAttr == "" { 127 | query.MerklizedSchema = true 128 | } 129 | 130 | if !query.MerklizedSchema { 131 | query.SlotIndex, err = parser.Parser{}.GetFieldSlotIndex(propertyQuery.FieldName, credentialType, []byte(ldContextJSON)) 132 | if err != nil { 133 | return nil, err 134 | } 135 | } else { 136 | path := merklize.Path{} 137 | if query.FieldName != "" { 138 | path, err = options.FieldPathFromContext([]byte(ldContextJSON), credentialType, propertyQuery.FieldName) 139 | if err != nil { 140 | return nil, err 141 | } 142 | } 143 | 144 | err = path.Prepend(credentialSubjectFullKey) 145 | if err != nil { 146 | return nil, err 147 | } 148 | 149 | query.ClaimPathKey, err = path.MtEntry() 150 | if err != nil { 151 | return nil, err 152 | } 153 | query.Path = &path 154 | } 155 | 156 | if propertyQuery.OperatorValue != nil && query.Datatype != "" { 157 | if !IsValidOperation(query.Datatype, propertyQuery.Operator) { 158 | operatorName, _ := getKeyByValue(circuits.QueryOperators, propertyQuery.Operator) 159 | return nil, fmt.Errorf("invalid operation '%s' for field type '%s'", operatorName, query.Datatype) 160 | } 161 | } 162 | if propertyQuery.Operator == circuits.EXISTS { 163 | query.Values, err = transformExistsOperatorValueToBigInt(ctx, propertyQuery.OperatorValue) 164 | } else { 165 | query.Values, err = transformQueryValueToBigInts(ctx, propertyQuery.OperatorValue, query.Datatype) 166 | } 167 | if err != nil { 168 | return nil, err 169 | } 170 | 171 | return query, err 172 | } 173 | 174 | // ParseQueriesMetadata parse credential subject and return array of query metadata 175 | func ParseQueriesMetadata(ctx context.Context, credentialType, ldContextJSON string, credentialSubject map[string]interface{}, options merklize.Options) (out []QueryMetadata, err error) { 176 | queriesMetadata, err := ParseCredentialSubject(ctx, credentialSubject) 177 | if err != nil { 178 | return nil, err 179 | } 180 | out = []QueryMetadata{} 181 | for i := 0; i < len(queriesMetadata); i++ { 182 | queryMetadata, err := ParseQueryMetadata(ctx, queriesMetadata[i], ldContextJSON, credentialType, options) 183 | if err != nil { 184 | return nil, err 185 | } 186 | out = append(out, *queryMetadata) 187 | } 188 | return out, err 189 | } 190 | 191 | func transformQueryValueToBigInts(_ context.Context, value any, ldType string) (out []*big.Int, err error) { 192 | if ldType == "" { 193 | return []*big.Int{}, nil 194 | } 195 | 196 | if value == nil { 197 | return make([]*big.Int, 0), nil 198 | } 199 | 200 | listOfValues, ok := value.([]interface{}) 201 | if ok { 202 | out = make([]*big.Int, len(listOfValues)) 203 | for i := 0; i < len(listOfValues); i++ { 204 | if !isPositiveInteger(listOfValues[i]) { 205 | return nil, ErrNegativeValue 206 | } 207 | out[i], err = merklize.HashValue(ldType, listOfValues[i]) 208 | if err != nil { 209 | return nil, err 210 | } 211 | } 212 | return out, err 213 | } 214 | if !isPositiveInteger(value) { 215 | return nil, ErrNegativeValue 216 | } 217 | hashValue, err := merklize.HashValue(ldType, value) 218 | if err != nil { 219 | return nil, err 220 | } 221 | 222 | return []*big.Int{hashValue}, err 223 | } 224 | 225 | func transformExistsOperatorValueToBigInt(_ context.Context, value any) (out []*big.Int, err error) { 226 | t := reflect.TypeOf(value).Kind() 227 | if t != reflect.Bool { 228 | return nil, errors.New("only boolean value is supported for operator $exists") 229 | } 230 | val := new(big.Int) 231 | if value == true { 232 | val.SetInt64(1) 233 | } 234 | return []*big.Int{val}, err 235 | } 236 | func isPositiveInteger(v interface{}) bool { 237 | number, err := strconv.ParseFloat(fmt.Sprintf("%v", v), 64) 238 | if err != nil { 239 | // value is not a number 240 | return true 241 | } 242 | return number >= 0 243 | } 244 | 245 | // IsValidOperation checks if operation and type are supported. 246 | func IsValidOperation(typ string, op int) bool { 247 | if op == circuits.NOOP { 248 | return true 249 | } 250 | 251 | ops, ok := availableTypesOperations[typ] 252 | if !ok { 253 | // by default all unknown types will be considered as string 254 | ops = availableTypesOperations[ld.XSDString] 255 | _, ok = ops[op] 256 | return ok 257 | } 258 | 259 | _, ok = ops[op] 260 | return ok 261 | } 262 | 263 | func getKeyByValue(m map[string]int, targetValue int) (string, bool) { 264 | for key, value := range m { 265 | if value == targetValue { 266 | return key, true 267 | } 268 | } 269 | return "", false 270 | } 271 | 272 | // CalculateQueryHash calculates query hash 273 | func CalculateQueryHash( 274 | values []*big.Int, 275 | schemaHash *big.Int, 276 | slotIndex int, 277 | operator int, 278 | claimPathKey *big.Int, 279 | isMerklized bool, 280 | ) (*big.Int, error) { 281 | merklized := big.NewInt(0) 282 | if isMerklized { 283 | merklized.SetInt64(1) 284 | } 285 | 286 | valArrSize := big.NewInt(int64(len(values))) 287 | circuitValues, err := circuits.PrepareCircuitArrayValues(values, 64) 288 | if err != nil { 289 | return nil, err 290 | } 291 | 292 | valueHash, err := poseidon.SpongeHashX(circuitValues, 6) 293 | if err != nil { 294 | return nil, err 295 | } 296 | firstPart, err := poseidon.Hash([]*big.Int{ 297 | schemaHash, 298 | big.NewInt(int64(slotIndex)), 299 | big.NewInt(int64(operator)), 300 | claimPathKey, 301 | merklized, 302 | valueHash, 303 | }) 304 | if err != nil { 305 | return nil, err 306 | } 307 | return poseidon.Hash([]*big.Int{ 308 | firstPart, 309 | valArrSize, 310 | big.NewInt(0), 311 | big.NewInt(0), 312 | big.NewInt(0), 313 | big.NewInt(0), 314 | }) 315 | 316 | } 317 | 318 | func fieldValueFromVerifiablePresentation(ctx context.Context, verifiablePresentation json.RawMessage, schemaLoader ld.DocumentLoader, key string) (*big.Int, error) { 319 | if verifiablePresentation == nil { 320 | return nil, errors.New("selective disclosure value is missed") 321 | } 322 | 323 | mz, err := merklize.MerklizeJSONLD(ctx, 324 | bytes.NewBuffer(verifiablePresentation), 325 | merklize.WithDocumentLoader(schemaLoader)) 326 | if err != nil { 327 | return nil, errors.Errorf("failed to merklize doc: %v", err) 328 | } 329 | 330 | merklizedPath, err := merklize.Options{DocumentLoader: schemaLoader}. 331 | NewPathFromDocument(verifiablePresentation, 332 | fmt.Sprintf("verifiableCredential.credentialSubject.%s", key)) 333 | if err != nil { 334 | return nil, errors.Errorf("failed build path to '%s' key: %v", key, err) 335 | } 336 | 337 | proof, valueByPath, err := mz.Proof(ctx, merklizedPath) 338 | if err != nil { 339 | return nil, errors.Errorf("failed get raw value: %v", err) 340 | } 341 | if !proof.Existence { 342 | return nil, errors.Errorf("path '%v' doesn't exist in document", merklizedPath.Parts()) 343 | } 344 | 345 | mvBig, err := valueByPath.MtEntry() 346 | if err != nil { 347 | return nil, errors.Errorf("failed to hash value: %v", err) 348 | } 349 | return mvBig, nil 350 | } 351 | -------------------------------------------------------------------------------- /state/state_test.go: -------------------------------------------------------------------------------- 1 | package state_test 2 | 3 | import ( 4 | "context" 5 | "math/big" 6 | "testing" 7 | 8 | "github.com/golang/mock/gomock" 9 | "github.com/iden3/contracts-abi/state/go/abi" 10 | "github.com/iden3/go-iden3-auth/v2/state" 11 | mock "github.com/iden3/go-iden3-auth/v2/state/mock" 12 | core "github.com/iden3/go-iden3-core/v2" 13 | "github.com/iden3/go-iden3-core/v2/w3c" 14 | "github.com/pkg/errors" 15 | "github.com/stretchr/testify/require" 16 | ) 17 | 18 | var ( 19 | userID, _ = new(big.Int).SetString("24046132560195495514376446225096639477630837244209093211332602837583401473", 10) 20 | userGenesisState, _ = new(big.Int).SetString("7521024223205616003431860562270429547098131848980857190502964780628723574810", 10) 21 | userFirstState, _ = new(big.Int).SetString("6017654403209798611575982337826892532952335378376369712724079246845524041042", 10) 22 | userSecondState, _ = new(big.Int).SetString("13855704302023058120516733700521568675871224145197005519251383340112309153100", 10) 23 | ) 24 | 25 | func TestResolve_Success(t *testing.T) { 26 | tests := []struct { 27 | name string 28 | contractResponse func(m *mock.MockStateGetter) 29 | userID *big.Int 30 | userState *big.Int 31 | expected *state.ResolvedState 32 | }{ 33 | { 34 | name: "verify genesis state for user", 35 | contractResponse: func(m *mock.MockStateGetter) { 36 | res := abi.IStateStateInfo{} 37 | err := errors.New("execution reverted: State does not exist") 38 | m.EXPECT().GetStateInfoByIdAndState( 39 | gomock.Any(), gomock.Any(), gomock.Any()).Return(res, err) 40 | }, 41 | userID: userID, 42 | userState: userGenesisState, 43 | expected: &state.ResolvedState{ 44 | State: userGenesisState.String(), 45 | Genesis: true, 46 | Latest: true, 47 | TransitionTimestamp: 0, 48 | }, 49 | }, 50 | { 51 | name: "local state is latest state", 52 | contractResponse: func(m *mock.MockStateGetter) { 53 | contractResponse := abi.IStateStateInfo{ 54 | Id: userID, 55 | State: userFirstState, 56 | ReplacedAtTimestamp: big.NewInt(0), 57 | } 58 | m.EXPECT().GetStateInfoByIdAndState( 59 | gomock.Any(), gomock.Any(), gomock.Any()).Return(contractResponse, nil) 60 | }, 61 | userID: userID, 62 | userState: userFirstState, 63 | expected: &state.ResolvedState{ 64 | State: userFirstState.String(), 65 | Latest: true, 66 | TransitionTimestamp: 0, 67 | }, 68 | }, 69 | { 70 | name: "latest state exists on blockchain", 71 | contractResponse: func(m *mock.MockStateGetter) { 72 | contractResponse := abi.IStateStateInfo{ 73 | Id: userID, 74 | State: userSecondState, 75 | ReplacedAtTimestamp: big.NewInt(1000), 76 | } 77 | m.EXPECT().GetStateInfoByIdAndState( 78 | gomock.Any(), gomock.Any(), gomock.Any()).Return(contractResponse, nil) 79 | }, 80 | userID: userID, 81 | userState: userFirstState, 82 | expected: &state.ResolvedState{ 83 | State: userFirstState.String(), 84 | Latest: false, 85 | TransitionTimestamp: big.NewInt(1000).Int64(), 86 | }, 87 | }, 88 | } 89 | 90 | for _, tt := range tests { 91 | t.Run(tt.name, func(t *testing.T) { 92 | ctrl := gomock.NewController(t) 93 | m := mock.NewMockStateGetter(ctrl) 94 | tt.contractResponse(m) 95 | 96 | resState, err := state.Resolve(context.Background(), m, tt.userID, tt.userState) 97 | require.NoError(t, err) 98 | require.Equal(t, tt.expected, resState) 99 | 100 | ctrl.Finish() 101 | }) 102 | } 103 | } 104 | 105 | func TestResolve_Error(t *testing.T) { 106 | tests := []struct { 107 | name string 108 | contractResponse func(m *mock.MockStateGetter) 109 | userID *big.Int 110 | userState *big.Int 111 | expectedError string 112 | }{ 113 | { 114 | name: "state is not genesis and not registered in the smart contract", 115 | contractResponse: func(m *mock.MockStateGetter) { 116 | err := errors.New("execution reverted: State does not exist") 117 | m.EXPECT().GetStateInfoByIdAndState( 118 | gomock.Any(), gomock.Any(), gomock.Any()).Return(abi.IStateStateInfo{}, err) 119 | }, 120 | userID: userID, 121 | userState: userFirstState, 122 | expectedError: "state is not genesis and not registered in the smart contract", 123 | }, 124 | { 125 | name: "state info in contract contains invalid id", 126 | contractResponse: func(m *mock.MockStateGetter) { 127 | contractResponse := abi.IStateStateInfo{ 128 | Id: userFirstState, // use like invalid user ID. 129 | State: userSecondState, 130 | } 131 | m.EXPECT().GetStateInfoByIdAndState( 132 | gomock.Any(), gomock.Any(), gomock.All()).Return(contractResponse, nil) 133 | }, 134 | userID: userID, 135 | userState: userFirstState, 136 | expectedError: "state has been saved for a different ID", 137 | }, 138 | { 139 | name: "unknown error", 140 | contractResponse: func(m *mock.MockStateGetter) { 141 | contractResponse := abi.IStateStateInfo{} 142 | err := errors.New("execution reverted: any reason") 143 | m.EXPECT().GetStateInfoByIdAndState( 144 | gomock.Any(), gomock.Any(), gomock.Any()).Return(contractResponse, err) 145 | }, 146 | userID: userID, 147 | userState: userFirstState, 148 | expectedError: "execution reverted: any reason", 149 | }, 150 | } 151 | 152 | for _, tt := range tests { 153 | t.Run(tt.name, func(t *testing.T) { 154 | ctrl := gomock.NewController(t) 155 | m := mock.NewMockStateGetter(ctrl) 156 | tt.contractResponse(m) 157 | 158 | resState, err := state.Resolve(context.Background(), m, tt.userID, tt.userState) 159 | require.Nil(t, resState) 160 | require.EqualError(t, err, tt.expectedError) 161 | 162 | ctrl.Finish() 163 | }) 164 | } 165 | } 166 | 167 | func TestResolveGlobalRoot_Success(t *testing.T) { 168 | tests := []struct { 169 | name string 170 | contractResponse func(m *mock.MockGISTGetter) 171 | userID *big.Int 172 | userState *big.Int 173 | expected *state.ResolvedState 174 | }{ 175 | { 176 | name: "Last state has not been replaced", 177 | contractResponse: func(m *mock.MockGISTGetter) { 178 | ri := abi.IStateGistRootInfo{ 179 | Root: userFirstState, 180 | CreatedAtTimestamp: big.NewInt(1), 181 | ReplacedByRoot: big.NewInt(0), 182 | } 183 | m.EXPECT().GetGISTRootInfo(gomock.Any(), gomock.Any()).Return(ri, nil) 184 | }, 185 | userState: userFirstState, 186 | expected: &state.ResolvedState{ 187 | State: userFirstState.String(), 188 | Latest: true, 189 | TransitionTimestamp: 0, 190 | }, 191 | }, 192 | { 193 | name: "Last state has been replaced", 194 | contractResponse: func(m *mock.MockGISTGetter) { 195 | ri := abi.IStateGistRootInfo{ 196 | Root: userFirstState, 197 | CreatedAtTimestamp: big.NewInt(3), 198 | ReplacedByRoot: big.NewInt(2), 199 | ReplacedAtTimestamp: big.NewInt(1), 200 | } 201 | m.EXPECT().GetGISTRootInfo(gomock.Any(), gomock.Any()).Return(ri, nil) 202 | }, 203 | userState: userFirstState, 204 | expected: &state.ResolvedState{ 205 | State: userFirstState.String(), 206 | Latest: false, 207 | TransitionTimestamp: 1, 208 | }, 209 | }, 210 | } 211 | 212 | for _, tt := range tests { 213 | t.Run(tt.name, func(t *testing.T) { 214 | ctrl := gomock.NewController(t) 215 | m := mock.NewMockGISTGetter(ctrl) 216 | tt.contractResponse(m) 217 | 218 | resState, err := state.ResolveGlobalRoot(context.Background(), m, tt.userState) 219 | require.NoError(t, err) 220 | require.Equal(t, tt.expected, resState) 221 | 222 | ctrl.Finish() 223 | }) 224 | } 225 | } 226 | 227 | func TestResolveGlobalRoot_Error(t *testing.T) { 228 | tests := []struct { 229 | name string 230 | contractResponse func(m *mock.MockGISTGetter) 231 | userID *big.Int 232 | userState *big.Int 233 | expectedError string 234 | }{ 235 | { 236 | name: "Contract call return an error", 237 | contractResponse: func(m *mock.MockGISTGetter) { 238 | err := errors.New("contract call error") 239 | m.EXPECT().GetGISTRootInfo(gomock.Any(), gomock.Any()).Return(abi.IStateGistRootInfo{}, err) 240 | }, 241 | userState: userFirstState, 242 | expectedError: "contract call error", 243 | }, 244 | { 245 | name: "Contract call with expected error", 246 | contractResponse: func(m *mock.MockGISTGetter) { 247 | err := errors.New("execution reverted: Root does not exist") 248 | m.EXPECT().GetGISTRootInfo(gomock.Any(), gomock.Any()).Return(abi.IStateGistRootInfo{}, err) 249 | }, 250 | userState: userFirstState, 251 | expectedError: "gist state doesn't exist on smart contract", 252 | }, 253 | { 254 | name: "State has been wrote for another users", 255 | contractResponse: func(m *mock.MockGISTGetter) { 256 | ri := abi.IStateGistRootInfo{ 257 | Root: userSecondState, 258 | CreatedAtTimestamp: big.NewInt(3), 259 | } 260 | m.EXPECT().GetGISTRootInfo(gomock.Any(), gomock.Any()).Return(ri, nil) 261 | }, 262 | userState: userFirstState, 263 | expectedError: "gist info contains invalid state", 264 | }, 265 | { 266 | name: "State was replaced, but replaced time is unknown", 267 | contractResponse: func(m *mock.MockGISTGetter) { 268 | ri := abi.IStateGistRootInfo{ 269 | Root: userFirstState, 270 | CreatedAtTimestamp: big.NewInt(3), 271 | ReplacedByRoot: userSecondState, 272 | ReplacedAtTimestamp: big.NewInt(0), 273 | } 274 | m.EXPECT().GetGISTRootInfo(gomock.Any(), gomock.Any()).Return(ri, nil) 275 | }, 276 | userState: userFirstState, 277 | expectedError: "state was replaced, but replaced time unknown", 278 | }, 279 | { 280 | name: "unknown error", 281 | contractResponse: func(m *mock.MockGISTGetter) { 282 | contractResponse := abi.IStateGistRootInfo{} 283 | err := errors.New("execution reverted: any reason") 284 | m.EXPECT().GetGISTRootInfo(gomock.Any(), gomock.Any()).Return(contractResponse, err) 285 | }, 286 | userState: userFirstState, 287 | expectedError: "execution reverted: any reason", 288 | }, 289 | } 290 | 291 | for _, tt := range tests { 292 | t.Run(tt.name, func(t *testing.T) { 293 | ctrl := gomock.NewController(t) 294 | m := mock.NewMockGISTGetter(ctrl) 295 | tt.contractResponse(m) 296 | 297 | resState, err := state.ResolveGlobalRoot(context.Background(), m, tt.userState) 298 | require.Nil(t, resState) 299 | require.EqualError(t, err, tt.expectedError) 300 | 301 | ctrl.Finish() 302 | }) 303 | } 304 | } 305 | 306 | func TestCheckGenesisStateID(t *testing.T) { 307 | userDID, err := w3c.ParseDID("did:iden3:polygon:mumbai:x6suHR8HkEYczV9yVeAKKiXCZAd25P8WS6QvNhszk") 308 | require.NoError(t, err) 309 | genesisID, ok := big.NewInt(0).SetString( 310 | "7521024223205616003431860562270429547098131848980857190502964780628723574810", 311 | 10) 312 | require.True(t, ok) 313 | 314 | uID, err := core.IDFromDID(*userDID) 315 | require.NoError(t, err) 316 | 317 | isGenesis, err := state.CheckGenesisStateID(uID.BigInt(), genesisID) 318 | require.NoError(t, err) 319 | require.True(t, isGenesis) 320 | 321 | notGenesisState, ok := big.NewInt(0).SetString( 322 | "6017654403209798611575982337826892532952335378376369712724079246845524041042", 323 | 10) 324 | require.True(t, ok) 325 | 326 | isGenesis, err = state.CheckGenesisStateID(uID.BigInt(), notGenesisState) 327 | require.NoError(t, err) 328 | require.False(t, isGenesis) 329 | } 330 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2023 0kims Association 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /loaders/verification_keys/credentialAtomicQueryMTPV2.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "groth16", 3 | "curve": "bn128", 4 | "nPublic": 77, 5 | "vk_alpha_1": [ 6 | "20491192805390485299153009773594534940189261866228447918068658471970481763042", 7 | "9383485363053290200918347156157836566562967994039712273449902621266178545958", 8 | "1" 9 | ], 10 | "vk_beta_2": [ 11 | [ 12 | "6375614351688725206403948262868962793625744043794305715222011528459656738731", 13 | "4252822878758300859123897981450591353533073413197771768651442665752259397132" 14 | ], 15 | [ 16 | "10505242626370262277552901082094356697409835680220590971873171140371331206856", 17 | "21847035105528745403288232691147584728191162732299865338377159692350059136679" 18 | ], 19 | [ 20 | "1", 21 | "0" 22 | ] 23 | ], 24 | "vk_gamma_2": [ 25 | [ 26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 28 | ], 29 | [ 30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 32 | ], 33 | [ 34 | "1", 35 | "0" 36 | ] 37 | ], 38 | "vk_delta_2": [ 39 | [ 40 | "1644379255755665639524620157273694289299700443812573873382829766089313318860", 41 | "7556188580549660317988384269627745620737293209908047921156248879248956624707" 42 | ], 43 | [ 44 | "4152535282542204467329585116559762832011400698522986966067931095980290970188", 45 | "16189055543084045005292506154593172627834306869372118812851261475395122300622" 46 | ], 47 | [ 48 | "1", 49 | "0" 50 | ] 51 | ], 52 | "vk_alphabeta_12": [ 53 | [ 54 | [ 55 | "2029413683389138792403550203267699914886160938906632433982220835551125967885", 56 | "21072700047562757817161031222997517981543347628379360635925549008442030252106" 57 | ], 58 | [ 59 | "5940354580057074848093997050200682056184807770593307860589430076672439820312", 60 | "12156638873931618554171829126792193045421052652279363021382169897324752428276" 61 | ], 62 | [ 63 | "7898200236362823042373859371574133993780991612861777490112507062703164551277", 64 | "7074218545237549455313236346927434013100842096812539264420499035217050630853" 65 | ] 66 | ], 67 | [ 68 | [ 69 | "7077479683546002997211712695946002074877511277312570035766170199895071832130", 70 | "10093483419865920389913245021038182291233451549023025229112148274109565435465" 71 | ], 72 | [ 73 | "4595479056700221319381530156280926371456704509942304414423590385166031118820", 74 | "19831328484489333784475432780421641293929726139240675179672856274388269393268" 75 | ], 76 | [ 77 | "11934129596455521040620786944827826205713621633706285934057045369193958244500", 78 | "8037395052364110730298837004334506829870972346962140206007064471173334027475" 79 | ] 80 | ] 81 | ], 82 | "IC": [ 83 | [ 84 | "18422857078372859553191448164294665542345065709653989973175579679294287359551", 85 | "19200412732094068217443600300610712526816543050849771388672029576371853469584", 86 | "1" 87 | ], 88 | [ 89 | "8966723725809147921162750050376358833176377832917899053889677861860829963550", 90 | "11341153581665210400343795342393322577490484170009235286254673614120878647101", 91 | "1" 92 | ], 93 | [ 94 | "9879865539447750277224788967575737948914682182107587045349147439108894751377", 95 | "21453364078164924208802775510032568576822274174182360910595757742538922255516", 96 | "1" 97 | ], 98 | [ 99 | "17271376920492004526143567349281665569798920608192890900207570109619938357965", 100 | "17658645521956741541229716428562791784745065800560561182268097024675562826941", 101 | "1" 102 | ], 103 | [ 104 | "19447905090608570348274226795081943117318789418973470654210086113107653241278", 105 | "3042974824199824823166471398866477356543673808199912551478342128204368365801", 106 | "1" 107 | ], 108 | [ 109 | "15156321942657123795505661861540145354490508397591060397451108946953030754823", 110 | "2174001979857398238020783370627974461537581724230646957383343539261668427900", 111 | "1" 112 | ], 113 | [ 114 | "2893784367520422410222380456081140868086719201082394136439924349009961441119", 115 | "6701132256860531139366218617785973102272561389281339326001731135503450776817", 116 | "1" 117 | ], 118 | [ 119 | "2682959541435350505256066121391007731952110231233962493700272969732411696733", 120 | "17209169979288623728661647278876944748718715772457044973402738622703306817989", 121 | "1" 122 | ], 123 | [ 124 | "499562621835133157087010512036306131395989534601985940081517169655947305794", 125 | "16171076175966316991086493265714063940602842446350652041818239810706021681879", 126 | "1" 127 | ], 128 | [ 129 | "5132244909724750316498584905084137056169137672686304456145214374629023392472", 130 | "6546991859900461714197094468917430881377836500486013407027474610681775159396", 131 | "1" 132 | ], 133 | [ 134 | "2668576684563152354350259868353189824258528180056497740408480383980454734066", 135 | "1535738486247883392173175472896261157323461087865457493262219315347601667500", 136 | "1" 137 | ], 138 | [ 139 | "10785473402637955729291841575016422918107164425021911175421942675184558968090", 140 | "11345810119385896301851632457198739313674262335948445894527389358734712913516", 141 | "1" 142 | ], 143 | [ 144 | "1412993008080518728455375349826306781032689703676503984254325722611846888434", 145 | "19781302125889607635883414978668480814071954491775541599692924120980145899599", 146 | "1" 147 | ], 148 | [ 149 | "2543531439810734534018065629410144813897832425457328128967847888580078363455", 150 | "8290575017821769892134912565219366777438869089694072485822723325342666816008", 151 | "1" 152 | ], 153 | [ 154 | "1002922190610148990099887492211004813681538196842215269979191666109888959814", 155 | "20619964733250977362581881412991948675311360234768187166450914392005451730358", 156 | "1" 157 | ], 158 | [ 159 | "15870912960135403856400514545374914694476998269086073865385158549754145963771", 160 | "20684949892083599847849427854173962987156046683062436388401257024101668208599", 161 | "1" 162 | ], 163 | [ 164 | "8831502501719650739624882314498213905138374744030524531789511798263213692297", 165 | "12841757675802823212324373320135070019627481835282469830860284467661624632496", 166 | "1" 167 | ], 168 | [ 169 | "11024979320888031984055829947181451956336570558598363948579563194733939622287", 170 | "18997905406534827287278617121302620290169563192770621622363184450430351660574", 171 | "1" 172 | ], 173 | [ 174 | "16869449048007600468318897118524861382044610982428636771901906750236031314195", 175 | "15438052670706503878189305795226519679700087347809533390683372366897495253782", 176 | "1" 177 | ], 178 | [ 179 | "15918279260795292593956401668763734193558830697313388423850914871334250125739", 180 | "8390709997430195886659648328077505730920457894542918693342626584476768467556", 181 | "1" 182 | ], 183 | [ 184 | "10798377190077256499154897763066112669971641940307492798780438616745102850691", 185 | "3612173055981570065938518906067521507588334568151689656355953453603129645964", 186 | "1" 187 | ], 188 | [ 189 | "10283501512088874941321977823410512484354301327524005689289271531565943800039", 190 | "3413727085936726278666795560940572030581500988023163312691493343929115927124", 191 | "1" 192 | ], 193 | [ 194 | "2296275912278297097224081815998877707798340371647976495099500783107062881957", 195 | "9398410071944512098160808850726511894933677864547346561538382995776881905238", 196 | "1" 197 | ], 198 | [ 199 | "16894600684081728341321342508855178930751254711101008689080082374710936127272", 200 | "12161453909477382567743014045075508805093784837270549401954931244139597225085", 201 | "1" 202 | ], 203 | [ 204 | "6268487288856125630650511644329678106052302875119583489182428159711946592368", 205 | "5841252196480850530373191299721977191681750934584486469365944205706179548638", 206 | "1" 207 | ], 208 | [ 209 | "6852882622300147668192439693377660004185303019132689479493632664567357096830", 210 | "10882891395088061300220569909151852301817335367848038253676795263334452296409", 211 | "1" 212 | ], 213 | [ 214 | "15198590029135566791939530181694358354001166637744293674348864120420627936109", 215 | "9367773651339063637980144228320691148645080564385341249114902167341421601663", 216 | "1" 217 | ], 218 | [ 219 | "11703644592499513786125973700632933001103077563618529422619953827430371965059", 220 | "15268256030107099411721655429931816597474879602558228384538893152110835355985", 221 | "1" 222 | ], 223 | [ 224 | "12524529491165694702027137268186075636174656025287741413565496343080631508399", 225 | "9372786123977825789042012545805363579046088706709621468746585656937388381431", 226 | "1" 227 | ], 228 | [ 229 | "273518393549043472687837864184789086758030869752905336300136035955706181307", 230 | "6816952832511221459658135400694225067096307534852277283270887023904178709525", 231 | "1" 232 | ], 233 | [ 234 | "1645523311170082397413986203809923280266656698291914513085993238167303820895", 235 | "13658793807208210506708310931635228156814129276176152104446631399468550574710", 236 | "1" 237 | ], 238 | [ 239 | "11390639911376397182713391277480364588913655592454794923096928705759144302325", 240 | "16055052215912926403164558682533278933518124603384506647616720186625870372867", 241 | "1" 242 | ], 243 | [ 244 | "10610808074017274236947952765930252005116639779114158879106786968725592243684", 245 | "7671742913687145209037761823969411792683583049858439139887877911509751057658", 246 | "1" 247 | ], 248 | [ 249 | "19573573343843071023372313695512762465067533761458715711343634116068133960793", 250 | "10804759726920349984061008954923558679191390728689650000941045331420650211581", 251 | "1" 252 | ], 253 | [ 254 | "5718892343875260885646810564014097593831900510564153360691631833735918621922", 255 | "19625601349877019059513350672441835825347413964694454283368396699203302112641", 256 | "1" 257 | ], 258 | [ 259 | "17307990529150693210709322957072714804583174025000604461211407702857003931209", 260 | "878943824392207542314091105918684915537006706374524180092127487257207923392", 261 | "1" 262 | ], 263 | [ 264 | "5300465178852377029624865156926876561044162413284703918440541317037871183286", 265 | "2915305225397411194819272200797185193292182665741238385087952771727267597912", 266 | "1" 267 | ], 268 | [ 269 | "9612880527467467068262006535491148962364353213124736729187536416888293209040", 270 | "3691954621663688303277327224518417341158474651376667361300715930069929949328", 271 | "1" 272 | ], 273 | [ 274 | "4659570938283906290187099509474824502769017396752042854687823331171116966970", 275 | "1982129089326682353432961132621675691495027987286282104478652337270349755786", 276 | "1" 277 | ], 278 | [ 279 | "9171669747307433455738879483524091533377393831008081692349023733885425842533", 280 | "14669324918730023540806349394380936953692102382177094137706966731531850185803", 281 | "1" 282 | ], 283 | [ 284 | "8483294380952291849397541046823929049822671375665974488330551974691931088249", 285 | "1118822438360952001976652032058766697856113279956390161343914269934471806948", 286 | "1" 287 | ], 288 | [ 289 | "16954932008548591797390692453664155464993616761337408187450399031436068691451", 290 | "6516092349871725883853494482885384994943299298314659902835087366050305733157", 291 | "1" 292 | ], 293 | [ 294 | "20430623878625162966436844654973340404250438949453265942184796279721889554820", 295 | "15872908111081564877987885319993945765058637105045568563559776178765096589967", 296 | "1" 297 | ], 298 | [ 299 | "175869145740468538971598041440955295445778770215511329335724056103936702436", 300 | "1330941033907902700992214800125843240733815089710216278151743962437271604780", 301 | "1" 302 | ], 303 | [ 304 | "12355335036350381959316132638698183510834366979584100346299938102486333409651", 305 | "4337197899687019529242916561241789784321321108925457005094595191731218061427", 306 | "1" 307 | ], 308 | [ 309 | "11278959974421454971056650663355901207164530384695376373432274315213283549762", 310 | "842554942909243186167969515896707366900091987841678552053050312967563820752", 311 | "1" 312 | ], 313 | [ 314 | "16572128460468464946178932017061778626056300216656975648812312257038874108983", 315 | "7496524676544202112869579855832101560057601523534017922081999640502666099689", 316 | "1" 317 | ], 318 | [ 319 | "19105814082294493715744150358143204382795031020497306458203104403838835752024", 320 | "19715005188048319300645177575714392862985133403160061825416709189094450469753", 321 | "1" 322 | ], 323 | [ 324 | "7636982228945323104243940147526887215043114989501502228623732711434331508800", 325 | "13982738495464494120120460721815986042347354712549997051203158421962713433676", 326 | "1" 327 | ], 328 | [ 329 | "7212703893248058395965164342811600518101083790353044441060046803166922457817", 330 | "15288762786599409245379182027975288580639251667570444798242660670608705209235", 331 | "1" 332 | ], 333 | [ 334 | "11337214755796827361301185036423160584799766990991395953495475417562574313330", 335 | "14282192223568265545782851423843119832895522296025493914034676871057884314807", 336 | "1" 337 | ], 338 | [ 339 | "20746519986905068147748204516567545274983109465248753666405436157746830920177", 340 | "5984414899536508968217223729861686103766469456226858624560779213690681060402", 341 | "1" 342 | ], 343 | [ 344 | "10835401963264758836309175755802257634401811007884975246749069652194030956375", 345 | "20233076666563354044232367680463639678769479105556538410861254285658708703420", 346 | "1" 347 | ], 348 | [ 349 | "243822971707479905147982175532573823409429573088000966949247818912169577321", 350 | "18374229255728581891524420253592041272334490428059631108193678882576242302072", 351 | "1" 352 | ], 353 | [ 354 | "16665621857935932261398090194052412477034502749265485109104610789248649096930", 355 | "4394568938787258691701414254311253333292906501134431595510892416905933008608", 356 | "1" 357 | ], 358 | [ 359 | "9950357876444140202359316333055625078754640885945343863436247592237465119463", 360 | "1138728549048290935207405656653273985530868679095638406347317405009163625829", 361 | "1" 362 | ], 363 | [ 364 | "19863557297411049209678228567424529354877434574079354325913524832101308332526", 365 | "8527626429667860262263355611120470385865138889073590553527605186068830407217", 366 | "1" 367 | ], 368 | [ 369 | "6454931913100737965253376358003045929798488773714456992517887361620467712565", 370 | "5326712240024551961475028927056696314978192616898138298267505948927925263882", 371 | "1" 372 | ], 373 | [ 374 | "15042250519748559882627540875078570819853921036848032840277256701118024280589", 375 | "5649902159571578160463121956645683130679194527097684396257161957099165347806", 376 | "1" 377 | ], 378 | [ 379 | "15096897533276062914425200316068732590699959101665592000874713484494800830431", 380 | "20313177966458554724734066811247575256604932796826056754597405446083708154473", 381 | "1" 382 | ], 383 | [ 384 | "17124672994386643376379203570239948164006585373341602602872802697337228865536", 385 | "1034249982625145986964431636683948940121344443741095836073135426238098732767", 386 | "1" 387 | ], 388 | [ 389 | "6786329514687183326195953834745659119650827869829843528091866552166007413531", 390 | "1993645881458801646027317410951338279337068483818691999503849794459167818711", 391 | "1" 392 | ], 393 | [ 394 | "5601166702091586493063206062643823571727623876835658007413482777129841428409", 395 | "5037705200482483083573800351985604926878171687751572424052471739482784122326", 396 | "1" 397 | ], 398 | [ 399 | "12517743032864053125136342570911419464259163379595553834414011868353108191599", 400 | "15318308882908411135628870052674621303091373949504950064687713217509534263616", 401 | "1" 402 | ], 403 | [ 404 | "2720076584159722030644911803109842442973174751015986695246040593821498987517", 405 | "6073106188050137778500476835712188492016074470565039712583218556941277893695", 406 | "1" 407 | ], 408 | [ 409 | "6072412759015559745976615160843960952517043392197448868050821137463119699799", 410 | "11697820246239769847517681526356370124485294496334591385652822729517455816263", 411 | "1" 412 | ], 413 | [ 414 | "14218939431514583760169339971126914781164242455722086424744905020963433287253", 415 | "1239871915323004456937785384528292474791919374060128150903363984409371850053", 416 | "1" 417 | ], 418 | [ 419 | "8387324433281274425414022898278760672945100111518697527852082193344751454886", 420 | "5589006578670031279992593208025532258965044721350145546467657955535328825951", 421 | "1" 422 | ], 423 | [ 424 | "21615450483089399676059755315641193001798326355023690261884634016377584537760", 425 | "10956155007380443561435691838052280090538388505191022308074967521520083662819", 426 | "1" 427 | ], 428 | [ 429 | "216446200713786284729733446575921700734085159824299226438396861091476902009", 430 | "13844554435458360555419931531505822549409871042801949625799040630213897945120", 431 | "1" 432 | ], 433 | [ 434 | "9845971582412603975624980875697041252601141575674463764818906420682062211318", 435 | "1541017164427640523004714101054634990123563920021310542692226961701567976926", 436 | "1" 437 | ], 438 | [ 439 | "1204229363117598338427021726830976171601871025347145772643221171662262684058", 440 | "3690138767954927564625982017409119462210512389179169664323854093643671574661", 441 | "1" 442 | ], 443 | [ 444 | "17447195784314061576734074992306359578375369517939049547706017414211939990948", 445 | "5224769475162921324539668905049572257714496627544607906446249174566771227829", 446 | "1" 447 | ], 448 | [ 449 | "13126571971650265371015826140101898742548802556718166762709215223240837280512", 450 | "4690349372257300850033015163519866378891105455880081651346259355150267250533", 451 | "1" 452 | ], 453 | [ 454 | "21063429119858892196984159725113911698991549202459080500178175790766238358869", 455 | "7912342920305948383152463874981556321577003229794067565185588863006975486779", 456 | "1" 457 | ], 458 | [ 459 | "1617209403466779091458035238367795741637095004483882576008873822959780975681", 460 | "11949429827523506994129552860898322068244208587609870060632189121669082060574", 461 | "1" 462 | ], 463 | [ 464 | "17419887907072158078351093176677693169251831632205134986750364946088731582087", 465 | "9178252111851939224017025851693510236346605583176672118134620364375005187172", 466 | "1" 467 | ], 468 | [ 469 | "15309663281578759488226592812361926542424721970055480411147967135175426869247", 470 | "13088871215177201383996211899405549173916825387544384325828612069408611872675", 471 | "1" 472 | ] 473 | ] 474 | } --------------------------------------------------------------------------------