@0xpolygonid/js-sdk 1.7.5 → 1.8.0

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 (92) hide show
  1. package/dist/browser/esm/index.js +13041 -11748
  2. package/dist/browser/esm/index.js.map +1 -1
  3. package/dist/browser/umd/index.js +13070 -11755
  4. package/dist/browser/umd/index.js.map +1 -1
  5. package/dist/node/cjs/circuits/atomic-query-mtp-v2.js +3 -3
  6. package/dist/node/cjs/circuits/atomic-query-sig-v2.js +3 -3
  7. package/dist/node/cjs/circuits/auth-v2.js +1 -1
  8. package/dist/node/cjs/credentials/credential-wallet.js +1 -3
  9. package/dist/node/cjs/credentials/index.js +1 -0
  10. package/dist/node/cjs/credentials/models.js +2 -0
  11. package/dist/node/cjs/credentials/status/credential-status-publisher.js +23 -4
  12. package/dist/node/cjs/iden3comm/constants.js +3 -1
  13. package/dist/node/cjs/iden3comm/handlers/auth.js +119 -14
  14. package/dist/node/cjs/kms/key-providers/sec256k1-provider.js +5 -2
  15. package/dist/node/cjs/proof/common.js +3 -4
  16. package/dist/node/cjs/proof/index.js +2 -1
  17. package/dist/node/cjs/proof/proof-service.js +22 -2
  18. package/dist/node/cjs/proof/provers/index.js +19 -0
  19. package/dist/node/cjs/proof/{inputs-generator.js → provers/inputs-generator.js} +42 -23
  20. package/dist/node/cjs/proof/{prover.js → provers/prover.js} +1 -1
  21. package/dist/node/cjs/proof/verifiers/index.js +18 -0
  22. package/dist/node/cjs/proof/verifiers/pub-signals-verifier.js +344 -0
  23. package/dist/node/cjs/proof/verifiers/query.js +190 -0
  24. package/dist/node/cjs/schema-processor/json/parser.js +39 -198
  25. package/dist/node/cjs/schema-processor/utils.js +13 -26
  26. package/dist/node/cjs/storage/blockchain/state.js +53 -8
  27. package/dist/node/cjs/utils/compare-func.js +11 -0
  28. package/dist/node/cjs/utils/index.js +2 -0
  29. package/dist/node/cjs/utils/message-bus.js +73 -0
  30. package/dist/node/cjs/verifiable/core-utils.js +234 -0
  31. package/dist/node/cjs/verifiable/credential.js +139 -1
  32. package/dist/node/cjs/verifiable/index.js +1 -0
  33. package/dist/node/esm/circuits/atomic-query-mtp-v2.js +3 -3
  34. package/dist/node/esm/circuits/atomic-query-sig-v2.js +3 -3
  35. package/dist/node/esm/circuits/auth-v2.js +2 -2
  36. package/dist/node/esm/credentials/credential-wallet.js +1 -3
  37. package/dist/node/esm/credentials/index.js +1 -0
  38. package/dist/node/esm/credentials/models.js +1 -0
  39. package/dist/node/esm/credentials/status/credential-status-publisher.js +23 -4
  40. package/dist/node/esm/iden3comm/constants.js +3 -1
  41. package/dist/node/esm/iden3comm/handlers/auth.js +116 -13
  42. package/dist/node/esm/kms/key-providers/sec256k1-provider.js +5 -2
  43. package/dist/node/esm/proof/common.js +4 -5
  44. package/dist/node/esm/proof/index.js +2 -1
  45. package/dist/node/esm/proof/proof-service.js +22 -2
  46. package/dist/node/esm/proof/provers/index.js +3 -0
  47. package/dist/node/esm/proof/{inputs-generator.js → provers/inputs-generator.js} +39 -20
  48. package/dist/node/esm/proof/{prover.js → provers/prover.js} +1 -1
  49. package/dist/node/esm/proof/verifiers/index.js +2 -0
  50. package/dist/node/esm/proof/verifiers/pub-signals-verifier.js +340 -0
  51. package/dist/node/esm/proof/verifiers/query.js +186 -0
  52. package/dist/node/esm/schema-processor/json/parser.js +40 -199
  53. package/dist/node/esm/schema-processor/utils.js +13 -26
  54. package/dist/node/esm/storage/blockchain/state.js +53 -8
  55. package/dist/node/esm/utils/compare-func.js +7 -0
  56. package/dist/node/esm/utils/index.js +2 -0
  57. package/dist/node/esm/utils/message-bus.js +66 -0
  58. package/dist/node/esm/verifiable/core-utils.js +200 -0
  59. package/dist/node/esm/verifiable/credential.js +118 -3
  60. package/dist/node/esm/verifiable/index.js +1 -0
  61. package/dist/types/credentials/credential-wallet.d.ts +2 -60
  62. package/dist/types/credentials/index.d.ts +1 -0
  63. package/dist/types/credentials/models.d.ts +68 -0
  64. package/dist/types/credentials/status/credential-status-publisher.d.ts +2 -0
  65. package/dist/types/iden3comm/constants.d.ts +1 -0
  66. package/dist/types/iden3comm/handlers/auth.d.ts +53 -13
  67. package/dist/types/iden3comm/types/protocol/credentials.d.ts +16 -0
  68. package/dist/types/identity/identity-wallet.d.ts +3 -1
  69. package/dist/types/kms/key-providers/sec256k1-provider.d.ts +1 -1
  70. package/dist/types/proof/index.d.ts +2 -1
  71. package/dist/types/proof/proof-service.d.ts +28 -3
  72. package/dist/types/proof/provers/index.d.ts +3 -0
  73. package/dist/types/proof/{inputs-generator.d.ts → provers/inputs-generator.d.ts} +14 -7
  74. package/dist/types/proof/{prover.d.ts → provers/prover.d.ts} +2 -2
  75. package/dist/types/proof/verifiers/index.d.ts +2 -0
  76. package/dist/types/proof/verifiers/pub-signals-verifier.d.ts +58 -0
  77. package/dist/types/proof/verifiers/query.d.ts +25 -0
  78. package/dist/types/schema-processor/json/parser.d.ts +47 -28
  79. package/dist/types/schema-processor/utils.d.ts +9 -4
  80. package/dist/types/storage/blockchain/state.d.ts +5 -1
  81. package/dist/types/storage/interfaces/state.d.ts +8 -0
  82. package/dist/types/utils/compare-func.d.ts +1 -0
  83. package/dist/types/utils/index.d.ts +2 -0
  84. package/dist/types/utils/message-bus.d.ts +62 -0
  85. package/dist/types/verifiable/core-utils.d.ts +84 -0
  86. package/dist/types/verifiable/credential.d.ts +11 -1
  87. package/dist/types/verifiable/index.d.ts +1 -0
  88. package/dist/types/verifiable/proof.d.ts +4 -0
  89. package/package.json +10 -10
  90. /package/dist/node/cjs/proof/{witness_calculator.js → provers/witness_calculator.js} +0 -0
  91. /package/dist/node/esm/proof/{witness_calculator.js → provers/witness_calculator.js} +0 -0
  92. /package/dist/types/proof/{witness_calculator.d.ts → provers/witness_calculator.d.ts} +0 -0
@@ -0,0 +1,340 @@
1
+ import { poseidon } from '@iden3/js-crypto';
2
+ import { DID, getDateFromUnixTimestamp } from '@iden3/js-iden3-core';
3
+ import { Path } from '@iden3/js-jsonld-merklization';
4
+ import { bigIntCompare, byteEncoder, isGenesisState } from '../../utils';
5
+ import { caclulateCoreSchemaHash, ProofType } from '../../verifiable';
6
+ import { AtomicQueryMTPV2PubSignals } from '../../circuits/atomic-query-mtp-v2';
7
+ import { AtomicQuerySigV2PubSignals } from '../../circuits/atomic-query-sig-v2';
8
+ import { AtomicQueryV3PubSignals } from '../../circuits/atomic-query-v3';
9
+ import { AuthV2PubSignals } from '../../circuits/auth-v2';
10
+ import { BaseConfig } from '../../circuits/common';
11
+ import { LinkedMultiQueryPubSignals } from '../../circuits/linked-multi-query';
12
+ import { CircuitId } from '../../circuits/models';
13
+ import { checkQueryRequest } from './query';
14
+ import { parseQueriesMetadata } from '../common';
15
+ export const userStateError = new Error(`user state is not valid`);
16
+ const zeroInt = 0n;
17
+ const defaultProofVerifyOpts = 1 * 60 * 60 * 1000; // 1 hour
18
+ const defaultAuthVerifyOpts = 5 * 60 * 1000; // 5 minutes
19
+ /**
20
+ * PubSignalsVerifier provides verify method
21
+ * @public
22
+ * @class PubSignalsVerifier
23
+ */
24
+ export class PubSignalsVerifier {
25
+ /**
26
+ * Creates an instance of PubSignalsVerifier.
27
+ * @param {DocumentLoader} _documentLoader document loader
28
+ * @param {IStateStorage} _stateStorage state storage
29
+ */
30
+ constructor(_documentLoader, _stateStorage) {
31
+ this._documentLoader = _documentLoader;
32
+ this._stateStorage = _stateStorage;
33
+ this.credentialAtomicQueryMTPV2Verify = async ({ query, verifiablePresentation, sender, challenge, pubSignals, opts }) => {
34
+ let mtpv2PubSignals = new AtomicQueryMTPV2PubSignals();
35
+ mtpv2PubSignals = mtpv2PubSignals.pubSignalsUnmarshal(byteEncoder.encode(JSON.stringify(pubSignals)));
36
+ if (!mtpv2PubSignals.userID) {
37
+ throw new Error('user id is not presented in proof public signals');
38
+ }
39
+ if (!mtpv2PubSignals.requestID) {
40
+ throw new Error('requestId is not presented in proof public signals');
41
+ }
42
+ this.userId = mtpv2PubSignals.userID;
43
+ this.challenge = mtpv2PubSignals.requestID;
44
+ // verify query
45
+ const outs = {
46
+ issuerId: mtpv2PubSignals.issuerID,
47
+ schemaHash: mtpv2PubSignals.claimSchema,
48
+ slotIndex: mtpv2PubSignals.slotIndex,
49
+ operator: mtpv2PubSignals.operator,
50
+ value: mtpv2PubSignals.value,
51
+ timestamp: mtpv2PubSignals.timestamp,
52
+ merklized: mtpv2PubSignals.merklized,
53
+ claimPathKey: mtpv2PubSignals.claimPathKey,
54
+ claimPathNotExists: mtpv2PubSignals.claimPathNotExists,
55
+ valueArraySize: mtpv2PubSignals.getValueArrSize(),
56
+ isRevocationChecked: mtpv2PubSignals.isRevocationChecked
57
+ };
58
+ await checkQueryRequest(query, outs, CircuitId.AtomicQueryMTPV2, this._documentLoader, verifiablePresentation, opts);
59
+ // verify state
60
+ await this.checkStateExistenceForId(mtpv2PubSignals.issuerID, mtpv2PubSignals.issuerClaimIdenState);
61
+ if (mtpv2PubSignals.isRevocationChecked !== 0) {
62
+ await this.checkRevocationState(mtpv2PubSignals.issuerID, mtpv2PubSignals.issuerClaimNonRevState, opts);
63
+ }
64
+ // verify ID ownership
65
+ this.verifyIdOwnership(sender, challenge);
66
+ return mtpv2PubSignals;
67
+ };
68
+ this.credentialAtomicQuerySigV2Verify = async ({ query, verifiablePresentation, sender, challenge, pubSignals, opts }) => {
69
+ let sigV2PubSignals = new AtomicQuerySigV2PubSignals();
70
+ sigV2PubSignals = sigV2PubSignals.pubSignalsUnmarshal(byteEncoder.encode(JSON.stringify(pubSignals)));
71
+ this.userId = sigV2PubSignals.userID;
72
+ this.challenge = sigV2PubSignals.requestID;
73
+ // verify query
74
+ const outs = {
75
+ issuerId: sigV2PubSignals.issuerID,
76
+ schemaHash: sigV2PubSignals.claimSchema,
77
+ slotIndex: sigV2PubSignals.slotIndex,
78
+ operator: sigV2PubSignals.operator,
79
+ value: sigV2PubSignals.value,
80
+ timestamp: sigV2PubSignals.timestamp,
81
+ merklized: sigV2PubSignals.merklized,
82
+ claimPathKey: sigV2PubSignals.claimPathKey,
83
+ claimPathNotExists: sigV2PubSignals.claimPathNotExists,
84
+ valueArraySize: sigV2PubSignals.getValueArrSize(),
85
+ isRevocationChecked: sigV2PubSignals.isRevocationChecked
86
+ };
87
+ await checkQueryRequest(query, outs, CircuitId.AtomicQuerySigV2, this._documentLoader, verifiablePresentation, opts);
88
+ // verify state
89
+ await this.checkStateExistenceForId(sigV2PubSignals.issuerID, sigV2PubSignals.issuerAuthState);
90
+ if (sigV2PubSignals.isRevocationChecked !== 0) {
91
+ await this.checkRevocationState(sigV2PubSignals.issuerID, sigV2PubSignals.issuerClaimNonRevState, opts);
92
+ }
93
+ // verify Id ownership
94
+ this.verifyIdOwnership(sender, challenge);
95
+ return sigV2PubSignals;
96
+ };
97
+ this.credentialAtomicQueryV3Verify = async ({ query, verifiablePresentation, sender, challenge, pubSignals, opts, params }) => {
98
+ let v3PubSignals = new AtomicQueryV3PubSignals();
99
+ v3PubSignals = v3PubSignals.pubSignalsUnmarshal(byteEncoder.encode(JSON.stringify(pubSignals)));
100
+ this.userId = v3PubSignals.userID;
101
+ this.challenge = v3PubSignals.requestID;
102
+ // verify query
103
+ const outs = {
104
+ issuerId: v3PubSignals.issuerID,
105
+ schemaHash: v3PubSignals.claimSchema,
106
+ slotIndex: v3PubSignals.slotIndex,
107
+ operator: v3PubSignals.operator,
108
+ value: v3PubSignals.value,
109
+ timestamp: v3PubSignals.timestamp,
110
+ merklized: v3PubSignals.merklized,
111
+ claimPathKey: v3PubSignals.claimPathKey,
112
+ claimPathNotExists: v3PubSignals.claimPathNotExists,
113
+ valueArraySize: v3PubSignals.getValueArrSize(),
114
+ isRevocationChecked: v3PubSignals.isRevocationChecked
115
+ };
116
+ await checkQueryRequest(query, outs, CircuitId.AtomicQueryV3, this._documentLoader, verifiablePresentation, opts);
117
+ const { proofType, verifierID, nullifier, nullifierSessionID, linkID } = v3PubSignals;
118
+ switch (query.proofType) {
119
+ case ProofType.BJJSignature:
120
+ if (proofType !== 1) {
121
+ throw new Error('wrong proof type for BJJSignature');
122
+ }
123
+ break;
124
+ case ProofType.Iden3SparseMerkleTreeProof:
125
+ if (proofType !== 2) {
126
+ throw new Error('wrong proof type for Iden3SparseMerkleTreeProof');
127
+ }
128
+ break;
129
+ default:
130
+ throw new Error('invalid proof type');
131
+ }
132
+ const nSessionId = BigInt(params?.nullifierSessionId ?? 0);
133
+ if (nSessionId !== 0n) {
134
+ if (BigInt(nullifier ?? 0) === 0n) {
135
+ throw new Error('nullifier should be provided for nullification and should not be 0');
136
+ }
137
+ // verify nullifier information
138
+ const verifierDIDParam = params?.verifierDid;
139
+ if (!verifierDIDParam) {
140
+ throw new Error('verifierDid is required');
141
+ }
142
+ const id = DID.idFromDID(verifierDIDParam);
143
+ if (verifierID.bigInt() != id.bigInt()) {
144
+ throw new Error('wrong verifier is used for nullification');
145
+ }
146
+ if (nullifierSessionID !== nSessionId) {
147
+ throw new Error(`wrong verifier session id is used for nullification, expected ${nSessionId}, got ${nullifierSessionID}`);
148
+ }
149
+ }
150
+ else if (nullifierSessionID !== 0n) {
151
+ throw new Error(`Nullifier id is generated but wasn't requested`);
152
+ }
153
+ if (!query.groupId && linkID !== 0n) {
154
+ throw new Error(`proof contains link id, but group id is not provided`);
155
+ }
156
+ if (query.groupId && linkID === 0n) {
157
+ throw new Error("proof doesn't contain link id, but group id is provided");
158
+ }
159
+ // verify state
160
+ await this.checkStateExistenceForId(v3PubSignals.issuerID, v3PubSignals.issuerState);
161
+ if (v3PubSignals.isRevocationChecked !== 0) {
162
+ await this.checkRevocationState(v3PubSignals.issuerID, v3PubSignals.issuerClaimNonRevState, opts);
163
+ }
164
+ this.verifyIdOwnership(sender, challenge);
165
+ return v3PubSignals;
166
+ };
167
+ this.authV2Verify = async ({ sender, challenge, pubSignals, opts }) => {
168
+ let authV2PubSignals = new AuthV2PubSignals();
169
+ authV2PubSignals = authV2PubSignals.pubSignalsUnmarshal(byteEncoder.encode(JSON.stringify(pubSignals)));
170
+ this.userId = authV2PubSignals.userID;
171
+ this.challenge = authV2PubSignals.challenge;
172
+ // no query verification
173
+ // verify state
174
+ const gist = await this.checkGlobalState(authV2PubSignals.GISTRoot);
175
+ let acceptedStateTransitionDelay = defaultAuthVerifyOpts;
176
+ if (opts?.acceptedStateTransitionDelay) {
177
+ acceptedStateTransitionDelay = opts.acceptedStateTransitionDelay;
178
+ }
179
+ if (!gist.latest) {
180
+ const timeDiff = Date.now() - getDateFromUnixTimestamp(Number(gist.transitionTimestamp)).getTime();
181
+ if (timeDiff > acceptedStateTransitionDelay) {
182
+ throw new Error('global state is outdated');
183
+ }
184
+ }
185
+ // verify Id ownership
186
+ this.verifyIdOwnership(sender, challenge);
187
+ return new BaseConfig();
188
+ };
189
+ this.linkedMultiQuery10Verify = async ({ query, pubSignals }) => {
190
+ let multiQueryPubSignals = new LinkedMultiQueryPubSignals();
191
+ multiQueryPubSignals = multiQueryPubSignals.pubSignalsUnmarshal(byteEncoder.encode(JSON.stringify(pubSignals)));
192
+ // verify query
193
+ let schema;
194
+ const ldOpts = { documentLoader: this._documentLoader };
195
+ try {
196
+ schema = (await ldOpts.documentLoader(query.context || '')).document;
197
+ }
198
+ catch (e) {
199
+ throw new Error(`can't load schema for request query`);
200
+ }
201
+ const ldContextJSON = JSON.stringify(schema);
202
+ const credentialSubject = query.credentialSubject;
203
+ const schemaId = await Path.getTypeIDFromContext(JSON.stringify(schema), query.type || '', ldOpts);
204
+ const schemaHash = caclulateCoreSchemaHash(byteEncoder.encode(schemaId));
205
+ const queriesMetadata = await parseQueriesMetadata(query.type || '', ldContextJSON, credentialSubject, ldOpts);
206
+ const queryHashes = queriesMetadata.map((queryMeta) => {
207
+ const valueHash = poseidon.spongeHashX(queryMeta.values, 6);
208
+ return poseidon.hash([
209
+ schemaHash.bigInt(),
210
+ BigInt(queryMeta.slotIndex),
211
+ BigInt(queryMeta.operator),
212
+ BigInt(queryMeta.claimPathKey),
213
+ queryMeta.merklizedSchema ? 0n : 1n,
214
+ valueHash
215
+ ]);
216
+ });
217
+ const circuitQueryHashes = multiQueryPubSignals.circuitQueryHash
218
+ .filter((i) => i !== 0n)
219
+ .sort(bigIntCompare);
220
+ queryHashes.sort(bigIntCompare);
221
+ if (!queryHashes.every((queryHash, i) => queryHash === circuitQueryHashes[i])) {
222
+ throw new Error('query hashes do not match');
223
+ }
224
+ return multiQueryPubSignals;
225
+ };
226
+ this.verifyIdOwnership = (sender, challenge) => {
227
+ const senderId = DID.idFromDID(DID.parse(sender));
228
+ if (senderId.string() !== this.userId.string()) {
229
+ throw new Error(`sender id is not used for proof creation, expected ${sender}, user from public signals: ${this.userId.string()}`);
230
+ }
231
+ if (challenge !== this.challenge) {
232
+ throw new Error(`challenge is not used for proof creation, expected ${challenge}, challenge from public signals: ${this.challenge} `);
233
+ }
234
+ };
235
+ this.checkStateExistenceForId = async (userId, userState) => {
236
+ const { latest } = await this.resolve(userId, userState.bigInt());
237
+ if (!latest) {
238
+ throw userStateError;
239
+ }
240
+ };
241
+ this.checkGlobalState = async (state) => {
242
+ const gistStateResolved = await this.rootResolve(state.bigInt());
243
+ return gistStateResolved;
244
+ };
245
+ this.checkRevocationStateForId = async (issuerId, issuerClaimNonRevState) => {
246
+ const issuerNonRevStateResolved = await this.resolve(issuerId, issuerClaimNonRevState.bigInt());
247
+ return issuerNonRevStateResolved;
248
+ };
249
+ this.checkRevocationState = async (issuerID, issuerClaimNonRevState, opts) => {
250
+ const issuerNonRevStateResolved = await this.checkRevocationStateForId(issuerID, issuerClaimNonRevState);
251
+ const acceptedStateTransitionDelay = opts?.acceptedStateTransitionDelay ?? defaultProofVerifyOpts;
252
+ if (!issuerNonRevStateResolved.latest) {
253
+ const timeDiff = Date.now() -
254
+ getDateFromUnixTimestamp(Number(issuerNonRevStateResolved.transitionTimestamp)).getTime();
255
+ if (timeDiff > acceptedStateTransitionDelay) {
256
+ throw new Error('issuer state is outdated');
257
+ }
258
+ }
259
+ };
260
+ }
261
+ /**
262
+ * verify public signals
263
+ *
264
+ * @param {string} circuitId circuit id
265
+ * @param {VerifyContext} ctx verification parameters
266
+ * @returns `Promise<BaseConfig>`
267
+ */
268
+ async verify(circuitId, ctx) {
269
+ const fnName = `${circuitId.split('-')[0]}Verify`;
270
+ const fn = this[fnName];
271
+ if (!fn) {
272
+ throw new Error(`public signals verifier for ${circuitId} not found`);
273
+ }
274
+ return fn(ctx);
275
+ }
276
+ async resolve(id, state) {
277
+ const idBigInt = id.bigInt();
278
+ const did = DID.parseFromId(id);
279
+ // check if id is genesis
280
+ const isGenesis = isGenesisState(did, state);
281
+ let contractState;
282
+ try {
283
+ contractState = await this._stateStorage.getStateInfoByIdAndState(idBigInt, state);
284
+ }
285
+ catch (e) {
286
+ if (e.errorArgs[0] === 'State does not exist') {
287
+ if (isGenesis) {
288
+ return {
289
+ latest: true,
290
+ transitionTimestamp: 0
291
+ };
292
+ }
293
+ throw new Error('State is not genesis and not registered in the smart contract');
294
+ }
295
+ throw e;
296
+ }
297
+ if (!contractState.id || contractState.id.toString() !== idBigInt.toString()) {
298
+ throw new Error(`state was recorded for another identity`);
299
+ }
300
+ if (!contractState.state || contractState.state.toString() !== state.toString()) {
301
+ if (!contractState.replacedAtTimestamp ||
302
+ contractState.replacedAtTimestamp.toString() === zeroInt.toString()) {
303
+ throw new Error(`no information about state transition`);
304
+ }
305
+ return {
306
+ latest: false,
307
+ transitionTimestamp: contractState.replacedAtTimestamp.toString()
308
+ };
309
+ }
310
+ return { latest: true, transitionTimestamp: 0 };
311
+ }
312
+ async rootResolve(state) {
313
+ let globalStateInfo;
314
+ try {
315
+ globalStateInfo = await this._stateStorage.getGISTRootInfo(state);
316
+ }
317
+ catch (e) {
318
+ if (e.errorArgs[0] === 'Root does not exist') {
319
+ throw new Error('GIST root does not exist in the smart contract');
320
+ }
321
+ throw e;
322
+ }
323
+ if (globalStateInfo.root.toString() !== state.toString()) {
324
+ throw new Error(`gist info contains invalid state`);
325
+ }
326
+ if (globalStateInfo.replacedByRoot.toString() !== zeroInt.toString()) {
327
+ if (globalStateInfo.replacedAtTimestamp.toString() === zeroInt.toString()) {
328
+ throw new Error(`state was replaced, but replaced time unknown`);
329
+ }
330
+ return {
331
+ latest: false,
332
+ transitionTimestamp: globalStateInfo.replacedAtTimestamp.toString()
333
+ };
334
+ }
335
+ return {
336
+ latest: true,
337
+ transitionTimestamp: 0
338
+ };
339
+ }
340
+ }
@@ -0,0 +1,186 @@
1
+ import { DID, getDateFromUnixTimestamp } from '@iden3/js-iden3-core';
2
+ import { getDocumentLoader, Merklizer, Path } from '@iden3/js-jsonld-merklization';
3
+ import { byteEncoder } from '../../utils';
4
+ import { Operators } from '../../circuits/comparer';
5
+ import { caclulateCoreSchemaHash, VerifiableConstants } from '../../verifiable';
6
+ import { parseQueriesMetadata } from '../common';
7
+ import { circuitValidator } from '../provers';
8
+ const defaultProofGenerationDelayOpts = 24 * 60 * 60 * 1000; // 24 hours
9
+ export async function checkQueryRequest(query, outputs, circuitId, schemaLoader, verifiablePresentation, opts) {
10
+ // validate issuer
11
+ const userDID = DID.parseFromId(outputs.issuerId);
12
+ const issuerAllowed = !query.allowedIssuers ||
13
+ query.allowedIssuers?.some((issuer) => issuer === '*' || issuer === userDID.string());
14
+ if (!issuerAllowed) {
15
+ throw new Error('issuer is not in allowed list');
16
+ }
17
+ // validate schema
18
+ let schema;
19
+ try {
20
+ const loader = schemaLoader ?? getDocumentLoader();
21
+ schema = (await loader(query.context ?? '')).document;
22
+ }
23
+ catch (e) {
24
+ throw new Error(`can't load schema for request query`);
25
+ }
26
+ if (!query.type) {
27
+ throw new Error(`proof query type is undefined`);
28
+ }
29
+ const schemaId = await Path.getTypeIDFromContext(JSON.stringify(schema), query.type, {
30
+ documentLoader: schemaLoader
31
+ });
32
+ const schemaHash = caclulateCoreSchemaHash(byteEncoder.encode(schemaId));
33
+ if (schemaHash.bigInt() !== outputs.schemaHash.bigInt()) {
34
+ throw new Error(`schema that was used is not equal to requested in query`);
35
+ }
36
+ if (!query.skipClaimRevocationCheck && outputs.isRevocationChecked === 0) {
37
+ throw new Error(`check revocation is required`);
38
+ }
39
+ const queriesMetadata = await parseQueriesMetadata(query.type, JSON.stringify(schema), query.credentialSubject, {
40
+ documentLoader: schemaLoader
41
+ });
42
+ const circuitValidationData = circuitValidator[circuitId];
43
+ if (queriesMetadata.length > circuitValidationData.maxQueriesCount) {
44
+ throw new Error(`circuit ${circuitId} supports only ${circuitValidator[circuitId].maxQueriesCount} queries`);
45
+ }
46
+ const notSupportedOpIndx = queriesMetadata.findIndex((i) => !circuitValidationData.supportedOperations.includes(i.operator));
47
+ if (notSupportedOpIndx > -1) {
48
+ throw new Error(`circuit ${circuitId} not support ${queriesMetadata[notSupportedOpIndx].operator} operator`);
49
+ }
50
+ queriesMetadata.forEach(async (metadata) => {
51
+ if (!query.type) {
52
+ throw new Error(`proof query type is undefined`);
53
+ }
54
+ // validate selective disclosure
55
+ if (metadata.operator === Operators.SD) {
56
+ try {
57
+ await validateDisclosure(metadata, outputs, verifiablePresentation, schemaLoader);
58
+ }
59
+ catch (e) {
60
+ throw new Error(`failed to validate selective disclosure: ${e.message}`);
61
+ }
62
+ }
63
+ else if (!metadata.fieldName && metadata.operator == Operators.NOOP) {
64
+ try {
65
+ await validateEmptyCredentialSubject(metadata, outputs);
66
+ return;
67
+ }
68
+ catch (e) {
69
+ throw new Error(`failed to validate operators: ${e.message}`);
70
+ }
71
+ }
72
+ else {
73
+ try {
74
+ await validateOperators(metadata, outputs);
75
+ }
76
+ catch (e) {
77
+ throw new Error(`failed to validate operators: ${e.message}`);
78
+ }
79
+ }
80
+ // verify claim
81
+ if (outputs.merklized === 1) {
82
+ if (outputs.claimPathNotExists === 1) {
83
+ throw new Error(`proof doesn't contains target query key`);
84
+ }
85
+ if (outputs.claimPathKey !== metadata.claimPathKey) {
86
+ throw new Error(`proof was generated for another path`);
87
+ }
88
+ }
89
+ else {
90
+ if (outputs.slotIndex !== metadata.slotIndex) {
91
+ throw new Error(`wrong claim slot was used in claim`);
92
+ }
93
+ }
94
+ // verify timestamp
95
+ let acceptedProofGenerationDelay = defaultProofGenerationDelayOpts;
96
+ if (opts?.acceptedProofGenerationDelay) {
97
+ acceptedProofGenerationDelay = opts.acceptedProofGenerationDelay;
98
+ }
99
+ const timeDiff = Date.now() - getDateFromUnixTimestamp(Number(outputs.timestamp)).getTime();
100
+ if (timeDiff > acceptedProofGenerationDelay) {
101
+ throw new Error('generated proof is outdated');
102
+ }
103
+ });
104
+ return;
105
+ }
106
+ async function validateEmptyCredentialSubject(cq, outputs) {
107
+ if (outputs.operator !== Operators.EQ) {
108
+ throw new Error('empty credentialSubject request available only for equal operation');
109
+ }
110
+ for (let index = 1; index < outputs.value.length; index++) {
111
+ if (outputs.value[index] !== 0n) {
112
+ throw new Error(`empty credentialSubject request not available for array of values`);
113
+ }
114
+ }
115
+ const path = Path.newPath([VerifiableConstants.CREDENTIAL_SUBJECT_PATH]);
116
+ const subjectEntry = await path.mtEntry();
117
+ if (outputs.claimPathKey !== subjectEntry) {
118
+ throw new Error(`proof doesn't contain credentialSubject in claimPathKey`);
119
+ }
120
+ return;
121
+ }
122
+ async function validateOperators(cq, outputs) {
123
+ if (outputs.operator !== cq.operator) {
124
+ throw new Error(`operator that was used is not equal to request`);
125
+ }
126
+ if (outputs.operator === Operators.NOOP) {
127
+ // for noop operator slot and value are not used in this case
128
+ return;
129
+ }
130
+ for (let index = 0; index < outputs.value.length; index++) {
131
+ if (outputs.value[index] !== cq.values[index]) {
132
+ throw new Error(`comparison value that was used is not equal to requested in query`);
133
+ }
134
+ }
135
+ }
136
+ async function validateDisclosure(cq, outputs, verifiablePresentation, ldLoader) {
137
+ if (!verifiablePresentation) {
138
+ throw new Error(`verifiablePresentation is required for selective disclosure request`);
139
+ }
140
+ if (outputs.operator !== Operators.EQ) {
141
+ throw new Error(`operator for selective disclosure must be $eq`);
142
+ }
143
+ for (let index = 1; index < outputs.value.length; index++) {
144
+ if (outputs.value[index] !== 0n) {
145
+ throw new Error(`selective disclosure not available for array of values`);
146
+ }
147
+ }
148
+ let mz;
149
+ const strVerifiablePresentation = JSON.stringify(verifiablePresentation);
150
+ try {
151
+ mz = await Merklizer.merklizeJSONLD(strVerifiablePresentation, {
152
+ documentLoader: ldLoader
153
+ });
154
+ }
155
+ catch (e) {
156
+ throw new Error(`can't merklize verifiablePresentation`);
157
+ }
158
+ let merklizedPath;
159
+ try {
160
+ const p = `verifiableCredential.credentialSubject.${cq.fieldName}`;
161
+ merklizedPath = await Path.fromDocument(null, strVerifiablePresentation, p, {
162
+ documentLoader: ldLoader
163
+ });
164
+ }
165
+ catch (e) {
166
+ throw new Error(`can't build path to '${cq.fieldName}' key`);
167
+ }
168
+ let proof;
169
+ let value;
170
+ try {
171
+ ({ proof, value } = await mz.proof(merklizedPath));
172
+ }
173
+ catch (e) {
174
+ throw new Error(`can't get value by path '${cq.fieldName}'`);
175
+ }
176
+ if (!value) {
177
+ throw new Error(`can't get merkle value for field '${cq.fieldName}'`);
178
+ }
179
+ if (!proof.existence) {
180
+ throw new Error(`path [${merklizedPath.parts}] doesn't exist in verifiablePresentation document`);
181
+ }
182
+ const bi = await value.mtEntry();
183
+ if (bi !== outputs.value[0]) {
184
+ throw new Error(`value that was used is not equal to requested in query`);
185
+ }
186
+ }