@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.
- package/dist/browser/esm/index.js +972 -367
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.js +975 -365
- package/dist/browser/umd/index.js.map +1 -1
- package/dist/node/cjs/credentials/credential-wallet.js +1 -1
- package/dist/node/cjs/credentials/status/on-chain-revocation.js +3 -10
- package/dist/node/cjs/iden3comm/handlers/common.js +51 -24
- package/dist/node/cjs/identity/identity-wallet.js +29 -16
- package/dist/node/cjs/proof/proof-service.js +5 -4
- package/dist/node/cjs/proof/verifiers/query.js +25 -1
- package/dist/node/cjs/schema-processor/json/validator.js +11 -0
- package/dist/node/cjs/storage/blockchain/onchain-zkp-verifier.js +0 -1
- package/dist/node/cjs/storage/blockchain/state.js +120 -3
- package/dist/node/cjs/storage/memory/cache-lru.js +25 -0
- package/dist/node/cjs/storage/memory/index.js +1 -0
- package/dist/node/cjs/storage/shared/identity-storage.js +7 -0
- package/dist/node/cjs/verifiable/constants.js +26 -2
- package/dist/node/cjs/verifiable/presentation.js +3 -3
- package/dist/node/esm/credentials/credential-wallet.js +1 -1
- package/dist/node/esm/credentials/status/on-chain-revocation.js +4 -11
- package/dist/node/esm/iden3comm/handlers/common.js +51 -24
- package/dist/node/esm/identity/identity-wallet.js +29 -16
- package/dist/node/esm/proof/proof-service.js +6 -5
- package/dist/node/esm/proof/verifiers/query.js +21 -0
- package/dist/node/esm/schema-processor/json/validator.js +11 -0
- package/dist/node/esm/storage/blockchain/onchain-zkp-verifier.js +0 -1
- package/dist/node/esm/storage/blockchain/state.js +120 -3
- package/dist/node/esm/storage/memory/cache-lru.js +18 -0
- package/dist/node/esm/storage/memory/index.js +1 -0
- package/dist/node/esm/storage/shared/identity-storage.js +7 -0
- package/dist/node/esm/verifiable/constants.js +25 -1
- package/dist/node/esm/verifiable/presentation.js +3 -3
- package/dist/types/credentials/status/on-chain-revocation.d.ts +6 -2
- package/dist/types/iden3comm/types/protocol/auth.d.ts +2 -2
- package/dist/types/identity/identity-wallet.d.ts +18 -3
- package/dist/types/proof/verifiers/query.d.ts +3 -0
- package/dist/types/storage/blockchain/state.d.ts +65 -1
- package/dist/types/storage/entities/identity.d.ts +1 -0
- package/dist/types/storage/interfaces/identity.d.ts +8 -1
- package/dist/types/storage/memory/cache-lru.d.ts +10 -0
- package/dist/types/storage/memory/index.d.ts +1 -0
- package/dist/types/storage/shared/identity-storage.d.ts +5 -0
- package/dist/types/verifiable/constants.d.ts +21 -0
- package/package.json +3 -2
|
@@ -196,7 +196,7 @@ class CredentialWallet {
|
|
|
196
196
|
}
|
|
197
197
|
return { cred, revStatus };
|
|
198
198
|
}
|
|
199
|
-
throw new Error(
|
|
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
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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(
|
|
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(
|
|
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
|
|
279
|
-
if (
|
|
280
|
-
throw new Error(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
611
|
+
throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_CORE_CLAIM_MISMATCH);
|
|
599
612
|
}
|
|
600
613
|
if (!coreClaimFromMtpProof && !coreClaimFromSigProof) {
|
|
601
|
-
throw new Error(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|