@0xpolygonid/js-sdk 1.30.0 → 1.31.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/browser/esm/index.js +972 -367
  2. package/dist/browser/esm/index.js.map +1 -1
  3. package/dist/browser/umd/index.js +975 -365
  4. package/dist/browser/umd/index.js.map +1 -1
  5. package/dist/node/cjs/credentials/credential-wallet.js +1 -1
  6. package/dist/node/cjs/credentials/status/on-chain-revocation.js +3 -10
  7. package/dist/node/cjs/iden3comm/handlers/common.js +51 -24
  8. package/dist/node/cjs/identity/identity-wallet.js +29 -16
  9. package/dist/node/cjs/proof/proof-service.js +5 -4
  10. package/dist/node/cjs/proof/verifiers/query.js +25 -1
  11. package/dist/node/cjs/schema-processor/json/validator.js +11 -0
  12. package/dist/node/cjs/storage/blockchain/onchain-zkp-verifier.js +0 -1
  13. package/dist/node/cjs/storage/blockchain/state.js +120 -3
  14. package/dist/node/cjs/storage/memory/cache-lru.js +25 -0
  15. package/dist/node/cjs/storage/memory/index.js +1 -0
  16. package/dist/node/cjs/storage/shared/identity-storage.js +7 -0
  17. package/dist/node/cjs/verifiable/constants.js +26 -2
  18. package/dist/node/cjs/verifiable/presentation.js +3 -3
  19. package/dist/node/esm/credentials/credential-wallet.js +1 -1
  20. package/dist/node/esm/credentials/status/on-chain-revocation.js +4 -11
  21. package/dist/node/esm/iden3comm/handlers/common.js +51 -24
  22. package/dist/node/esm/identity/identity-wallet.js +29 -16
  23. package/dist/node/esm/proof/proof-service.js +6 -5
  24. package/dist/node/esm/proof/verifiers/query.js +21 -0
  25. package/dist/node/esm/schema-processor/json/validator.js +11 -0
  26. package/dist/node/esm/storage/blockchain/onchain-zkp-verifier.js +0 -1
  27. package/dist/node/esm/storage/blockchain/state.js +120 -3
  28. package/dist/node/esm/storage/memory/cache-lru.js +18 -0
  29. package/dist/node/esm/storage/memory/index.js +1 -0
  30. package/dist/node/esm/storage/shared/identity-storage.js +7 -0
  31. package/dist/node/esm/verifiable/constants.js +25 -1
  32. package/dist/node/esm/verifiable/presentation.js +3 -3
  33. package/dist/types/credentials/status/on-chain-revocation.d.ts +6 -2
  34. package/dist/types/iden3comm/types/protocol/auth.d.ts +2 -2
  35. package/dist/types/identity/identity-wallet.d.ts +18 -3
  36. package/dist/types/proof/verifiers/query.d.ts +3 -0
  37. package/dist/types/storage/blockchain/state.d.ts +65 -1
  38. package/dist/types/storage/entities/identity.d.ts +1 -0
  39. package/dist/types/storage/interfaces/identity.d.ts +8 -1
  40. package/dist/types/storage/memory/cache-lru.d.ts +10 -0
  41. package/dist/types/storage/memory/index.d.ts +1 -0
  42. package/dist/types/storage/shared/identity-storage.d.ts +5 -0
  43. package/dist/types/verifiable/constants.d.ts +21 -0
  44. package/package.json +3 -2
@@ -196,7 +196,7 @@ class CredentialWallet {
196
196
  }
197
197
  return { cred, revStatus };
198
198
  }
199
- throw new Error('all claims are revoked');
199
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.CREDENTIAL_WALLET_ALL_CREDENTIALS_ARE_REVOKED);
200
200
  }
201
201
  }
202
202
  exports.CredentialWallet = CredentialWallet;
@@ -21,8 +21,9 @@ class OnChainResolver {
21
21
  * @public
22
22
  * @param {Array<EthConnectionConfig>} _configs - list of ethereum network connections
23
23
  */
24
- constructor(_configs) {
24
+ constructor(_configs, _opts) {
25
25
  this._configs = _configs;
26
+ this._stateStorage = new state_1.EthStateStorage(_configs, _opts?.stateStorageOptions);
26
27
  }
27
28
  /**
28
29
  * resolve is a method to resolve a credential status from the blockchain.
@@ -53,8 +54,7 @@ class OnChainResolver {
53
54
  const issuerId = js_iden3_core_1.DID.idFromDID(issuer);
54
55
  let latestIssuerState;
55
56
  try {
56
- const ethStorage = this._getStateStorageForIssuer(issuerId);
57
- const latestStateInfo = await ethStorage.getLatestStateById(issuerId.bigInt());
57
+ const latestStateInfo = await this._stateStorage.getLatestStateById(issuerId.bigInt());
58
58
  if (!latestStateInfo.state) {
59
59
  throw new Error('state contract returned empty state');
60
60
  }
@@ -120,13 +120,6 @@ class OnChainResolver {
120
120
  }
121
121
  return network;
122
122
  }
123
- // TODO: is dirty hack for mock in tests.
124
- // need to pass to constructor list of state stores not list of network configs
125
- _getStateStorageForIssuer(issuerId) {
126
- const issuerChainId = (0, js_iden3_core_1.getChainId)(js_iden3_core_1.DID.blockchainFromId(issuerId), js_iden3_core_1.DID.networkIdFromId(issuerId));
127
- const ethStorage = new state_1.EthStateStorage(this.networkByChainId(issuerChainId));
128
- return ethStorage;
129
- }
130
123
  _getOnChainRevocationStorageForIssuer(chainId, contractAddress) {
131
124
  const networkConfig = this.networkByChainId(chainId);
132
125
  const onChainCaller = new onchain_revocation_1.OnChainRevocationStorage(networkConfig, contractAddress);
@@ -4,6 +4,7 @@ exports.verifyExpiresTime = exports.packMetadatas = exports.calcChallengeAuthV2
4
4
  const js_crypto_1 = require("@iden3/js-crypto");
5
5
  const types_1 = require("../types");
6
6
  const utils_1 = require("../../utils");
7
+ const verifiable_1 = require("../../verifiable");
7
8
  const js_iden3_core_1 = require("@iden3/js-iden3-core");
8
9
  const constants_1 = require("../constants");
9
10
  const ethers_1 = require("ethers");
@@ -55,34 +56,60 @@ const processZeroKnowledgeProofRequests = async (to, requests, from, proofServic
55
56
  const groupedCredentialsCache = new Map();
56
57
  const zkpResponses = [];
57
58
  for (const proofReq of requestScope) {
58
- if (!opts.supportedCircuits.includes(proofReq.circuitId)) {
59
- throw new Error(`Circuit ${proofReq.circuitId} is not allowed`);
60
- }
61
- const query = proofReq.query;
62
- const groupId = query.groupId;
63
- const combinedQueryData = combinedQueries.get(groupId);
64
- if (groupId) {
65
- if (!combinedQueryData) {
66
- throw new Error(`Invalid group id ${query.groupId}`);
59
+ let zkpRes;
60
+ try {
61
+ const isCircuitSupported = opts.supportedCircuits.includes(proofReq.circuitId);
62
+ if (!isCircuitSupported) {
63
+ if (proofReq.optional) {
64
+ continue;
65
+ }
66
+ throw new Error(`Circuit ${proofReq.circuitId} is not allowed`);
67
67
  }
68
- const combinedQuery = combinedQueryData.query;
69
- if (!groupedCredentialsCache.has(groupId)) {
70
- const credWithRevStatus = await proofService.findCredentialByProofQuery(to, combinedQueryData.query);
71
- if (!credWithRevStatus.cred) {
72
- throw new Error(`Credential not found for query ${JSON.stringify(combinedQuery)}`);
68
+ const query = proofReq.query;
69
+ const groupId = query.groupId;
70
+ const combinedQueryData = combinedQueries.get(groupId);
71
+ if (groupId) {
72
+ if (!combinedQueryData) {
73
+ throw new Error(`Invalid group id ${query.groupId}`);
74
+ }
75
+ const combinedQuery = combinedQueryData.query;
76
+ if (!groupedCredentialsCache.has(groupId)) {
77
+ const credWithRevStatus = await proofService.findCredentialByProofQuery(to, combinedQueryData.query);
78
+ if (!credWithRevStatus.cred) {
79
+ if (proofReq.optional) {
80
+ continue;
81
+ }
82
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.PROOF_SERVICE_NO_CREDENTIAL_FOR_QUERY +
83
+ `${JSON.stringify(combinedQuery)}`);
84
+ }
85
+ groupedCredentialsCache.set(groupId, credWithRevStatus);
73
86
  }
74
- groupedCredentialsCache.set(groupId, credWithRevStatus);
75
87
  }
88
+ const credWithRevStatus = groupedCredentialsCache.get(groupId);
89
+ zkpRes = await proofService.generateProof(proofReq, to, {
90
+ verifierDid: from,
91
+ challenge: opts.challenge,
92
+ skipRevocation: Boolean(query.skipClaimRevocationCheck),
93
+ credential: credWithRevStatus?.cred,
94
+ credentialRevocationStatus: credWithRevStatus?.revStatus,
95
+ linkNonce: combinedQueryData?.linkNonce ? BigInt(combinedQueryData.linkNonce) : undefined
96
+ });
97
+ }
98
+ catch (error) {
99
+ const expectedErrors = [
100
+ verifiable_1.VerifiableConstants.ERRORS.PROOF_SERVICE_NO_CREDENTIAL_FOR_IDENTITY_OR_PROFILE,
101
+ verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_NO_CREDENTIAL_SATISFIED_QUERY,
102
+ verifiable_1.VerifiableConstants.ERRORS.CREDENTIAL_WALLET_ALL_CREDENTIALS_ARE_REVOKED
103
+ ];
104
+ // handle only errors in case credential is not found and it is optional proof request - otherwise throw
105
+ if (error instanceof Error &&
106
+ (expectedErrors.includes(error.message) ||
107
+ error.message.includes(verifiable_1.VerifiableConstants.ERRORS.PROOF_SERVICE_NO_CREDENTIAL_FOR_QUERY)) &&
108
+ proofReq.optional) {
109
+ continue;
110
+ }
111
+ throw error;
76
112
  }
77
- const credWithRevStatus = groupedCredentialsCache.get(groupId);
78
- const zkpRes = await proofService.generateProof(proofReq, to, {
79
- verifierDid: from,
80
- challenge: opts.challenge,
81
- skipRevocation: Boolean(query.skipClaimRevocationCheck),
82
- credential: credWithRevStatus?.cred,
83
- credentialRevocationStatus: credWithRevStatus?.revStatus,
84
- linkNonce: combinedQueryData?.linkNonce ? BigInt(combinedQueryData.linkNonce) : undefined
85
- });
86
113
  zkpResponses.push(zkpRes);
87
114
  }
88
115
  return zkpResponses;
@@ -229,7 +229,7 @@ class IdentityWallet {
229
229
  let credential;
230
230
  const ethSigner = opts.ethSigner;
231
231
  if (opts.createBjjCredential && !ethSigner) {
232
- throw new Error('Ethereum signer is required to create Ethereum identities in order to transit state');
232
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_SIGNER_IS_REQUIRED);
233
233
  }
234
234
  const currentState = js_merkletree_1.ZERO_HASH; // In Ethereum identities we don't have an initial state with the auth credential
235
235
  const didType = (0, js_iden3_core_1.buildDIDType)(opts.method || js_iden3_core_1.DidMethod.Iden3, opts.blockchain || js_iden3_core_1.Blockchain.Polygon, opts.networkId || js_iden3_core_1.NetworkId.Amoy);
@@ -267,23 +267,28 @@ class IdentityWallet {
267
267
  }
268
268
  const profile = await this._storage.identity.getProfileById(did.string());
269
269
  if (!profile) {
270
- throw new Error('profile or identity not found');
270
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_PROFILE_OR_IDENTITY_NOT_FOUND);
271
271
  }
272
272
  return { nonce: profile.nonce, genesisDID: js_iden3_core_1.DID.parse(profile.genesisIdentifier) };
273
273
  }
274
274
  /** {@inheritDoc IIdentityWallet.createProfile} */
275
- async createProfile(did, nonce, verifier) {
275
+ async createProfile(did, nonce, verifier, tags) {
276
276
  const profileDID = (0, common_1.generateProfileDID)(did, nonce);
277
277
  const identityProfiles = await this._storage.identity.getProfilesByGenesisIdentifier(did.string());
278
- const existingProfile = identityProfiles.find((p) => p.nonce == nonce || p.verifier == verifier);
279
- if (existingProfile) {
280
- throw new Error('profile with given nonce or verifier already exists');
278
+ const profilesForTagAndVerifier = await this._storage.identity.getProfilesByVerifier(verifier, tags);
279
+ if (profilesForTagAndVerifier.length) {
280
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_PROFILE_ALREADY_EXISTS_VERIFIER_TAGS);
281
+ }
282
+ const existingProfileWithNonce = identityProfiles.find((p) => p.nonce == nonce);
283
+ if (existingProfileWithNonce) {
284
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_PROFILE_ALREADY_EXISTS);
281
285
  }
282
286
  await this._storage.identity.saveProfile({
283
287
  id: profileDID.string(),
284
288
  nonce,
285
289
  genesisIdentifier: did.string(),
286
- verifier
290
+ verifier,
291
+ tags
287
292
  });
288
293
  return profileDID;
289
294
  }
@@ -302,9 +307,17 @@ class IdentityWallet {
302
307
  const key = await this._kms.createKeyFromSeed(keyType, (0, js_crypto_1.getRandomBytes)(32));
303
308
  return key;
304
309
  }
310
+ /**
311
+ * @deprecated The method should not be used. It returns only one profile per verifier, which can potentially restrict business use cases
312
+ * {@inheritDoc IIdentityWallet.getProfileByVerifier}
313
+ */
305
314
  async getProfileByVerifier(verifier) {
306
315
  return this._storage.identity.getProfileByVerifier(verifier);
307
316
  }
317
+ /** {@inheritDoc IIdentityWallet.getProfilesByVerifier} */
318
+ async getProfilesByVerifier(verifier, tags) {
319
+ return this._storage.identity.getProfilesByVerifier(verifier, tags);
320
+ }
308
321
  /** {@inheritDoc IIdentityWallet.getDIDTreeModel} */
309
322
  async getDIDTreeModel(did) {
310
323
  const didStr = did.string();
@@ -426,11 +439,11 @@ class IdentityWallet {
426
439
  const coreClaimHash = js_crypto_1.poseidon.hash([hi, hv]);
427
440
  const signature = await this.signChallenge(coreClaimHash, issuerAuthBJJCredential);
428
441
  if (!issuerAuthBJJCredential.proof) {
429
- throw new Error('issuer auth credential must have proof');
442
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_ISSUER_AUTH_BJJ_CRED_MUST_HAVE_ANY_PROOF);
430
443
  }
431
444
  const mtpAuthBJJProof = issuerAuthBJJCredential.getIden3SparseMerkleTreeProof();
432
445
  if (!mtpAuthBJJProof) {
433
- throw new Error('mtp is required for auth bjj key to issue new credentials');
446
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_ISSUER_AUTH_BJJ_CRED_MUST_HAVE_MTP_PROOF);
434
447
  }
435
448
  const sigProof = new verifiable_1.BJJSignatureProof2021({
436
449
  issuerData: {
@@ -470,7 +483,7 @@ class IdentityWallet {
470
483
  const issuerTree = await this.getDIDTreeModel(issuerDID);
471
484
  const coreClaim = await this.getCoreClaimFromCredential(credential);
472
485
  if (!coreClaim) {
473
- throw new Error('credential must have coreClaim representation in proofs');
486
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_CORE_CLAIM_REQUIRED_IN_ANY_PROOF);
474
487
  }
475
488
  const nonce = coreClaim.getRevocationNonce();
476
489
  await issuerTree.revocationTree.add(nonce, BigInt(0));
@@ -493,7 +506,7 @@ class IdentityWallet {
493
506
  // credential must have a bjj signature proof
494
507
  const coreClaim = credential.getCoreClaimFromProof(verifiable_1.ProofType.BJJSignature);
495
508
  if (!coreClaim) {
496
- throw new Error('credential must have coreClaim representation in the signature proof');
509
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_CORE_CLAIM_REQUIRED_IN_SIG_PROOF);
497
510
  }
498
511
  await this._storage.mt.addToMerkleTree(issuerDID.string(), storage_1.MerkleTreeType.Claims, coreClaim.hIndex(), coreClaim.hValue());
499
512
  }
@@ -525,7 +538,7 @@ class IdentityWallet {
525
538
  const coreClaim = credential.getCoreClaimFromProof(verifiable_1.ProofType.BJJSignature) ||
526
539
  (await credential.toCoreClaim(opts));
527
540
  if (!coreClaim) {
528
- throw new Error('credential must have coreClaim representation in the signature proof');
541
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_CORE_CLAIM_REQUIRED_IN_SIG_PROOF);
529
542
  }
530
543
  const mtpWithProof = await this.generateCoreClaimMtp(issuerDID, coreClaim, treeState);
531
544
  const mtpProof = new verifiable_1.Iden3SparseMerkleTreeProof({
@@ -595,10 +608,10 @@ class IdentityWallet {
595
608
  if (coreClaimFromMtpProof &&
596
609
  coreClaimFromSigProof &&
597
610
  coreClaimFromMtpProof.hex() !== coreClaimFromSigProof.hex()) {
598
- throw new Error('core claim representations is set in both proofs but they are not equal');
611
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_CORE_CLAIM_MISMATCH);
599
612
  }
600
613
  if (!coreClaimFromMtpProof && !coreClaimFromSigProof) {
601
- throw new Error('core claim is not set in credential proofs');
614
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_CORE_CLAIM_IS_NOT_SET);
602
615
  }
603
616
  //eslint-disable-next-line @typescript-eslint/no-non-null-assertion
604
617
  const coreClaim = coreClaimFromMtpProof ?? coreClaimFromSigProof;
@@ -607,7 +620,7 @@ class IdentityWallet {
607
620
  async findOwnedCredentialsByDID(did, query) {
608
621
  const credentials = await this._credentialWallet.findByQuery(query);
609
622
  if (!credentials.length) {
610
- throw new Error(`no credential satisfied query`);
623
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_NO_CREDENTIAL_SATISFIED_QUERY);
611
624
  }
612
625
  const { genesisDID } = await this.getGenesisDIDMetadata(did);
613
626
  const profiles = await this.getProfilesByDID(genesisDID);
@@ -647,7 +660,7 @@ class IdentityWallet {
647
660
  let txId;
648
661
  if (!isEthIdentity) {
649
662
  if (!prover) {
650
- throw new Error('prover is required to generate proofs for non ethereum identities');
663
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_PROVER_IS_REQUIRED);
651
664
  }
652
665
  // generate the proof
653
666
  const authInfo = await this._inputsGenerator.prepareAuthBJJCredential(did, oldTreeState);
@@ -76,7 +76,8 @@ class ProofService {
76
76
  credentialWithRevStatus = { cred: opts.credential, revStatus };
77
77
  }
78
78
  if (!credentialWithRevStatus.cred) {
79
- throw new Error(`credential not found for query ${JSON.stringify(proofReq.query)}`);
79
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.PROOF_SERVICE_NO_CREDENTIAL_FOR_QUERY +
80
+ ` ${JSON.stringify(proofReq.query)}`);
80
81
  }
81
82
  const credentialCoreClaim = await this._identityWallet.getCoreClaimFromCredential(credentialWithRevStatus.cred);
82
83
  const { nonce: authProfileNonce, genesisDID } = await this._identityWallet.getGenesisDIDMetadata(identifier);
@@ -88,11 +89,11 @@ class ProofService {
88
89
  const subjectDID = js_iden3_core_1.DID.parse(preparedCredential.credential.credentialSubject['id']);
89
90
  const { nonce: credentialSubjectProfileNonce, genesisDID: subjectGenesisDID } = await this._identityWallet.getGenesisDIDMetadata(subjectDID);
90
91
  if (subjectGenesisDID.string() !== genesisDID.string()) {
91
- throw new Error('subject and auth profiles are not derived from the same did');
92
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.PROOF_SERVICE_PROFILE_GENESIS_DID_MISMATCH);
92
93
  }
93
94
  const propertiesMetadata = (0, common_1.parseCredentialSubject)(proofReq.query.credentialSubject);
94
95
  if (!propertiesMetadata.length) {
95
- throw new Error('no queries in zkp request');
96
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.PROOF_SERVICE_NO_QUERIES_IN_ZKP_REQUEST);
96
97
  }
97
98
  const mtPosition = preparedCredential.credentialCoreClaim.getMerklizedPosition();
98
99
  let mk;
@@ -276,7 +277,7 @@ class ProofService {
276
277
  async findCredentialByProofQuery(did, query) {
277
278
  const credentials = await this._identityWallet.findOwnedCredentialsByDID(did, query);
278
279
  if (!credentials.length) {
279
- throw new Error(`no credentials belong to did or its profiles`);
280
+ throw new Error(verifiable_1.VerifiableConstants.ERRORS.PROOF_SERVICE_NO_CREDENTIAL_FOR_IDENTITY_OR_PROFILE);
280
281
  }
281
282
  // For EQ / IN / NIN / LT / GT operations selective if credential satisfies query - we can get any.
282
283
  // TODO: choose credential for selective credentials
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fieldValueFromVerifiablePresentation = exports.validateEmptyCredentialSubjectNoopNativeSupport = exports.validateDisclosureNativeSDSupport = exports.validateDisclosureV2Circuit = exports.validateOperators = exports.validateEmptyCredentialSubjectV2Circuit = exports.verifyFieldValueInclusionNativeExistsSupport = exports.verifyFieldValueInclusionV2 = exports.checkCircuitOperator = exports.checkCircuitQueriesLength = exports.checkQueryRequest = void 0;
3
+ exports.calculateMultiRequestId = exports.calculateRequestId = exports.calculateGroupId = exports.fieldValueFromVerifiablePresentation = exports.validateEmptyCredentialSubjectNoopNativeSupport = exports.validateDisclosureNativeSDSupport = exports.validateDisclosureV2Circuit = exports.validateOperators = exports.validateEmptyCredentialSubjectV2Circuit = exports.verifyFieldValueInclusionNativeExistsSupport = exports.verifyFieldValueInclusionV2 = exports.checkCircuitOperator = exports.checkCircuitQueriesLength = exports.checkQueryRequest = void 0;
4
4
  const js_iden3_core_1 = require("@iden3/js-iden3-core");
5
5
  const js_jsonld_merklization_1 = require("@iden3/js-jsonld-merklization");
6
6
  const utils_1 = require("../../utils");
7
7
  const comparer_1 = require("../../circuits/comparer");
8
8
  const verifiable_1 = require("../../verifiable");
9
9
  const provers_1 = require("../provers");
10
+ const ethers_1 = require("ethers");
10
11
  const defaultProofGenerationDelayOpts = 24 * 60 * 60 * 1000; // 24 hours
11
12
  async function checkQueryRequest(query, queriesMetadata, ldContext, outputs, circuitId, schemaLoader, opts) {
12
13
  // validate issuer
@@ -211,3 +212,26 @@ const fieldValueFromVerifiablePresentation = async (fieldName, verifiablePresent
211
212
  return await value.mtEntry();
212
213
  };
213
214
  exports.fieldValueFromVerifiablePresentation = fieldValueFromVerifiablePresentation;
215
+ function calculateGroupId(requestIds) {
216
+ const types = Array(requestIds.length).fill('uint256');
217
+ const groupID = BigInt(ethers_1.ethers.keccak256(ethers_1.ethers.solidityPacked(types, requestIds))) &
218
+ // It should fit in a field number in the circuit (max 253 bits). With this we truncate to 252 bits for the group ID
219
+ BigInt('0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF');
220
+ return groupID;
221
+ }
222
+ exports.calculateGroupId = calculateGroupId;
223
+ function calculateRequestId(requestParams, creatorAddress) {
224
+ // 0x0000000000000000FFFF...FF. Reserved first 8 bytes for the request Id type and future use
225
+ // 0x00010000000000000000...00. First 2 bytes for the request Id type
226
+ // - 0x0000... for old request Ids with uint64
227
+ // - 0x0001... for new request Ids with uint256
228
+ const requestId = (BigInt(ethers_1.ethers.keccak256(ethers_1.ethers.solidityPacked(['bytes', 'address'], [requestParams, creatorAddress]))) &
229
+ BigInt('0x0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')) +
230
+ BigInt('0x0001000000000000000000000000000000000000000000000000000000000000');
231
+ return requestId;
232
+ }
233
+ exports.calculateRequestId = calculateRequestId;
234
+ function calculateMultiRequestId(requestIds, groupIds, creatorAddress) {
235
+ return BigInt(ethers_1.ethers.keccak256(ethers_1.ethers.solidityPacked(['uint256[]', 'uint256[]', 'address'], [requestIds, groupIds, creatorAddress])));
236
+ }
237
+ exports.calculateMultiRequestId = calculateMultiRequestId;
@@ -44,6 +44,7 @@ class JsonSchemaValidator {
44
44
  validator = ajv ?? defaultJSONSchemaValidator;
45
45
  if (validator.formats && !Object.keys(validator.formats).length) {
46
46
  (0, ajv_formats_1.default)(validator);
47
+ addCustomFormats(validator);
47
48
  }
48
49
  const validate = (schema.$id ? validator.getSchema(schema.$id) : undefined) || validator.compile(schema);
49
50
  const valid = validate(data);
@@ -55,3 +56,13 @@ class JsonSchemaValidator {
55
56
  }
56
57
  }
57
58
  exports.JsonSchemaValidator = JsonSchemaValidator;
59
+ function addCustomFormats(validator) {
60
+ validator.addFormat('positive-integer', {
61
+ type: 'string',
62
+ validate: (positiveIntegerStr) => /^[1-9]\d*$/.test(positiveIntegerStr)
63
+ });
64
+ validator.addFormat('non-negative-integer', {
65
+ type: 'string',
66
+ validate: (nonNegativeIntegerStr) => /^(0|[1-9]\d*)$/.test(nonNegativeIntegerStr)
67
+ });
68
+ }
@@ -7,7 +7,6 @@ exports.packEthIdentityProof = exports.OnChainZKPVerifier = exports.toTxDataArgs
7
7
  const ethers_1 = require("ethers");
8
8
  const iden3comm_1 = require("../../iden3comm");
9
9
  const ZkpVerifier_json_1 = __importDefault(require("./abi/ZkpVerifier.json"));
10
- //import { UniversalVerifier } from '@iden3/universal-verifier-v2-abi';
11
10
  const universal_verifier_v2_abi_1 = require("@iden3/universal-verifier-v2-abi");
12
11
  const blockchain_1 = require("../../blockchain");
13
12
  const js_iden3_core_1 = require("@iden3/js-iden3-core");
@@ -11,6 +11,9 @@ const State_json_1 = __importDefault(require("./abi/State.json"));
11
11
  const js_iden3_core_1 = require("@iden3/js-iden3-core");
12
12
  const blockchain_1 = require("../../blockchain");
13
13
  const common_1 = require("./common");
14
+ const memory_1 = require("../memory");
15
+ const iden3comm_1 = require("../../iden3comm");
16
+ const verifiable_1 = require("../../verifiable");
14
17
  exports.defaultEthConnectionConfig = {
15
18
  url: 'http://localhost:8545',
16
19
  defaultGasLimit: 600000,
@@ -36,15 +39,71 @@ class EthStateStorage {
36
39
  * Creates an instance of EthStateStorage.
37
40
  * @param {EthConnectionConfig} [ethConfig=defaultEthConnectionConfig]
38
41
  */
39
- constructor(ethConfig) {
42
+ constructor(ethConfig, options) {
40
43
  this.ethConfig = ethConfig;
44
+ this._disableCache = false;
41
45
  const config = Array.isArray(ethConfig) ? ethConfig[0] : ethConfig;
42
46
  this.provider = new ethers_1.JsonRpcProvider(config.url);
43
47
  this.stateContract = new ethers_1.Contract(config.contractAddress, State_json_1.default, this.provider);
44
48
  this._transactionService = new blockchain_1.TransactionService(this.getRpcProvider());
49
+ // Store cache options for later use
50
+ this._latestStateCacheOptions = {
51
+ ttl: options?.latestStateCacheOptions?.ttl ?? iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_PROOF_VERIFY_DELAY / 2,
52
+ maxSize: options?.latestStateCacheOptions?.maxSize ?? verifiable_1.DEFAULT_CACHE_MAX_SIZE
53
+ };
54
+ this._stateCacheOptions = {
55
+ notReplacedTtl: options?.stateCacheOptions?.notReplacedTtl ??
56
+ iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_PROOF_VERIFY_DELAY / 2,
57
+ replacedTtl: options?.stateCacheOptions?.replacedTtl ?? iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_PROOF_VERIFY_DELAY,
58
+ maxSize: options?.stateCacheOptions?.maxSize ?? verifiable_1.DEFAULT_CACHE_MAX_SIZE
59
+ };
60
+ this._rootCacheOptions = {
61
+ replacedTtl: options?.rootCacheOptions?.replacedTtl ?? iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY,
62
+ notReplacedTtl: options?.rootCacheOptions?.notReplacedTtl ??
63
+ iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY / 2,
64
+ maxSize: options?.rootCacheOptions?.maxSize ?? verifiable_1.DEFAULT_CACHE_MAX_SIZE
65
+ };
66
+ this._gistProofCacheOptions = {
67
+ ttl: iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY / 2,
68
+ maxSize: options?.gistProofCacheOptions?.maxSize ?? verifiable_1.DEFAULT_CACHE_MAX_SIZE
69
+ };
70
+ // Initialize cache instances
71
+ this._latestStateResolveCache =
72
+ options?.latestStateCacheOptions?.cache ??
73
+ (0, memory_1.createInMemoryCache)({
74
+ maxSize: this._latestStateCacheOptions.maxSize,
75
+ ttl: this._latestStateCacheOptions.ttl
76
+ });
77
+ this._stateResolveCache =
78
+ options?.stateCacheOptions?.cache ??
79
+ (0, memory_1.createInMemoryCache)({
80
+ maxSize: this._stateCacheOptions.maxSize,
81
+ ttl: this._stateCacheOptions.replacedTtl
82
+ });
83
+ this._rootResolveCache =
84
+ options?.rootCacheOptions?.cache ??
85
+ (0, memory_1.createInMemoryCache)({
86
+ maxSize: this._rootCacheOptions.maxSize,
87
+ ttl: this._rootCacheOptions.replacedTtl
88
+ });
89
+ this._gistProofResolveCache =
90
+ options?.gistProofCacheOptions?.cache ??
91
+ (0, memory_1.createInMemoryCache)({
92
+ maxSize: this._gistProofCacheOptions.maxSize,
93
+ ttl: this._gistProofCacheOptions.ttl
94
+ });
95
+ this._disableCache = options?.disableCache ?? false;
45
96
  }
46
97
  /** {@inheritdoc IStateStorage.getLatestStateById} */
47
98
  async getLatestStateById(id) {
99
+ const cacheKey = this.getLatestStateCacheKey(id);
100
+ if (!this._disableCache) {
101
+ // Check cache first
102
+ const cachedResult = await this._latestStateResolveCache?.get(cacheKey);
103
+ if (cachedResult) {
104
+ return cachedResult;
105
+ }
106
+ }
48
107
  const { stateContract } = this.getStateContractAndProviderForId(id);
49
108
  const rawData = await stateContract.getStateInfoById(id);
50
109
  const stateInfo = {
@@ -56,10 +115,20 @@ class EthStateStorage {
56
115
  createdAtBlock: BigInt(rawData[5]),
57
116
  replacedAtBlock: BigInt(rawData[6])
58
117
  };
118
+ !this._disableCache &&
119
+ (await this._latestStateResolveCache?.set(cacheKey, stateInfo, this._latestStateCacheOptions.ttl));
59
120
  return stateInfo;
60
121
  }
61
122
  /** {@inheritdoc IStateStorage.getStateInfoByIdAndState} */
62
123
  async getStateInfoByIdAndState(id, state) {
124
+ const cacheKey = this.getStateCacheKey(id, state);
125
+ if (!this._disableCache) {
126
+ // Check cache first
127
+ const cachedResult = await this._stateResolveCache?.get(cacheKey);
128
+ if (cachedResult) {
129
+ return cachedResult;
130
+ }
131
+ }
63
132
  const { stateContract } = this.getStateContractAndProviderForId(id);
64
133
  const rawData = await stateContract.getStateInfoByIdAndState(id, state);
65
134
  const stateInfo = {
@@ -71,6 +140,10 @@ class EthStateStorage {
71
140
  createdAtBlock: BigInt(rawData[5]),
72
141
  replacedAtBlock: BigInt(rawData[6])
73
142
  };
143
+ const ttl = stateInfo.replacedAtTimestamp === 0n
144
+ ? this._stateCacheOptions.notReplacedTtl
145
+ : this._stateCacheOptions.replacedTtl;
146
+ !this._disableCache && (await this._stateResolveCache?.set(cacheKey, stateInfo, ttl));
74
147
  return stateInfo;
75
148
  }
76
149
  /** {@inheritdoc IStateStorage.publishState} */
@@ -143,9 +216,17 @@ class EthStateStorage {
143
216
  }
144
217
  /** {@inheritdoc IStateStorage.getGISTProof} */
145
218
  async getGISTProof(id) {
219
+ const cacheKey = this.getGistProofCacheKey(id);
220
+ if (!this._disableCache) {
221
+ // Check cache first
222
+ const cachedResult = await this._gistProofResolveCache?.get(cacheKey);
223
+ if (cachedResult) {
224
+ return cachedResult;
225
+ }
226
+ }
146
227
  const { stateContract } = this.getStateContractAndProviderForId(id);
147
228
  const data = await stateContract.getGISTProof(id);
148
- return {
229
+ const stateProof = {
149
230
  root: BigInt(data.root.toString()),
150
231
  existence: data.existence,
151
232
  siblings: data.siblings?.map((sibling) => BigInt(sibling.toString())),
@@ -155,12 +236,23 @@ class EthStateStorage {
155
236
  auxIndex: BigInt(data.auxIndex.toString()),
156
237
  auxValue: BigInt(data.auxValue.toString())
157
238
  };
239
+ !this._disableCache &&
240
+ (await this._gistProofResolveCache?.set(cacheKey, stateProof, this._gistProofCacheOptions.ttl));
241
+ return stateProof;
158
242
  }
159
243
  /** {@inheritdoc IStateStorage.getGISTRootInfo} */
160
244
  async getGISTRootInfo(root, id) {
245
+ const cacheKey = this.getRootCacheKey(root);
246
+ if (!this._disableCache) {
247
+ // Check cache first
248
+ const cachedResult = await this._rootResolveCache?.get(cacheKey);
249
+ if (cachedResult) {
250
+ return cachedResult;
251
+ }
252
+ }
161
253
  const { stateContract } = this.getStateContractAndProviderForId(id);
162
254
  const data = await stateContract.getGISTRootInfo(root);
163
- return {
255
+ const rootInfo = {
164
256
  root: BigInt(data.root.toString()),
165
257
  replacedByRoot: BigInt(data.replacedByRoot.toString()),
166
258
  createdAtTimestamp: BigInt(data.createdAtTimestamp.toString()),
@@ -168,11 +260,24 @@ class EthStateStorage {
168
260
  createdAtBlock: BigInt(data.createdAtBlock.toString()),
169
261
  replacedAtBlock: BigInt(data.replacedAtBlock.toString())
170
262
  };
263
+ const ttl = rootInfo.replacedAtTimestamp == 0n
264
+ ? this._rootCacheOptions.notReplacedTtl
265
+ : this._rootCacheOptions.replacedTtl;
266
+ !this._disableCache && (await this._rootResolveCache?.set(cacheKey, rootInfo, ttl));
267
+ return rootInfo;
171
268
  }
172
269
  /** {@inheritdoc IStateStorage.getRpcProvider} */
173
270
  getRpcProvider() {
174
271
  return this.provider;
175
272
  }
273
+ /** enable caching */
274
+ enableCache() {
275
+ this._disableCache = false;
276
+ }
277
+ /** disable caching */
278
+ disableCache() {
279
+ this._disableCache = true;
280
+ }
176
281
  getStateContractAndProviderForId(id) {
177
282
  const idTyped = js_iden3_core_1.Id.fromBigInt(id);
178
283
  const chainId = (0, js_iden3_core_1.getChainId)(js_iden3_core_1.DID.blockchainFromId(idTyped), js_iden3_core_1.DID.networkIdFromId(idTyped));
@@ -189,5 +294,17 @@ class EthStateStorage {
189
294
  }
190
295
  return network;
191
296
  }
297
+ getGistProofCacheKey(id) {
298
+ return `gist-${id.toString()}`;
299
+ }
300
+ getLatestStateCacheKey(id) {
301
+ return `latest-${id.toString()}`;
302
+ }
303
+ getStateCacheKey(id, state) {
304
+ return `${id.toString()}-${state.toString()}`;
305
+ }
306
+ getRootCacheKey(root) {
307
+ return root.toString();
308
+ }
192
309
  }
193
310
  exports.EthStateStorage = EthStateStorage;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createInMemoryCache = void 0;
7
+ const quick_lru_1 = __importDefault(require("quick-lru"));
8
+ function createInMemoryCache(params) {
9
+ const cache = new quick_lru_1.default({ maxSize: params.maxSize, maxAge: params.ttl });
10
+ return {
11
+ get: async (key) => {
12
+ return cache.get(key);
13
+ },
14
+ set: async (key, value, ttl) => {
15
+ cache.set(key, value, { maxAge: ttl ?? params.ttl });
16
+ },
17
+ clear: async () => {
18
+ cache.clear();
19
+ },
20
+ delete: async (key) => {
21
+ cache.delete(key);
22
+ }
23
+ };
24
+ }
25
+ exports.createInMemoryCache = createInMemoryCache;
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./merkletree"), exports);
18
18
  __exportStar(require("./data-source"), exports);
19
+ __exportStar(require("./cache-lru"), exports);
@@ -27,9 +27,16 @@ class IdentityStorage {
27
27
  await this._profileDataSource.save(element.id, element);
28
28
  }
29
29
  }
30
+ /**
31
+ * @deprecated The method should not be used. It returns only one profile per verifier, which can potentially restrict business use cases
32
+ * Use getProfilesByVerifier instead.
33
+ */
30
34
  async getProfileByVerifier(verifier) {
31
35
  return this._profileDataSource.get(verifier, 'verifier');
32
36
  }
37
+ async getProfilesByVerifier(verifier, tags) {
38
+ return (await this._profileDataSource.load()).filter((p) => p.verifier === verifier && (!tags || tags.every((tag) => p.tags?.includes(tag))));
39
+ }
33
40
  async getProfileById(profileId) {
34
41
  return this._profileDataSource.get(profileId);
35
42
  }