@0xpolygonid/js-sdk 1.5.1 → 1.6.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 (83) hide show
  1. package/dist/browser/esm/index.js +1685 -468
  2. package/dist/browser/esm/index.js.map +1 -1
  3. package/dist/browser/umd/index.js +1703 -470
  4. package/dist/browser/umd/index.js.map +1 -1
  5. package/dist/node/cjs/circuits/atomic-query-mtp-v2-on-chain.js +1 -1
  6. package/dist/node/cjs/circuits/atomic-query-mtp-v2.js +1 -1
  7. package/dist/node/cjs/circuits/atomic-query-sig-v2-on-chain.js +2 -2
  8. package/dist/node/cjs/circuits/atomic-query-sig-v2.js +11 -14
  9. package/dist/node/cjs/circuits/atomic-query-v3-on-chain.js +320 -0
  10. package/dist/node/cjs/circuits/atomic-query-v3.js +275 -0
  11. package/dist/node/cjs/circuits/common.js +5 -7
  12. package/dist/node/cjs/circuits/comparer.js +57 -2
  13. package/dist/node/cjs/circuits/index.js +4 -0
  14. package/dist/node/cjs/circuits/linked-multi-query.js +128 -0
  15. package/dist/node/cjs/circuits/linked-nullifier.js +57 -0
  16. package/dist/node/cjs/circuits/models.js +25 -1
  17. package/dist/node/cjs/credentials/credential-wallet.js +2 -10
  18. package/dist/node/cjs/credentials/index.js +1 -0
  19. package/dist/node/cjs/credentials/utils.js +23 -0
  20. package/dist/node/cjs/iden3comm/handlers/auth.js +49 -8
  21. package/dist/node/cjs/iden3comm/handlers/contract-request.js +20 -8
  22. package/dist/node/cjs/proof/common.js +104 -1
  23. package/dist/node/cjs/proof/inputs-generator.js +393 -0
  24. package/dist/node/cjs/proof/proof-service.js +105 -372
  25. package/dist/node/cjs/schema-processor/json/parser.js +7 -0
  26. package/dist/node/cjs/schema-processor/json/validator.js +1 -0
  27. package/dist/node/cjs/storage/filters/jsonQuery.js +73 -8
  28. package/dist/node/cjs/utils/did-helper.js +14 -0
  29. package/dist/node/cjs/utils/index.js +2 -0
  30. package/dist/node/cjs/utils/object.js +42 -0
  31. package/dist/node/cjs/verifiable/presentation.js +34 -33
  32. package/dist/node/cjs/verifiable/proof.js +2 -0
  33. package/dist/node/esm/circuits/atomic-query-mtp-v2-on-chain.js +1 -1
  34. package/dist/node/esm/circuits/atomic-query-mtp-v2.js +1 -1
  35. package/dist/node/esm/circuits/atomic-query-sig-v2-on-chain.js +2 -2
  36. package/dist/node/esm/circuits/atomic-query-sig-v2.js +11 -14
  37. package/dist/node/esm/circuits/atomic-query-v3-on-chain.js +315 -0
  38. package/dist/node/esm/circuits/atomic-query-v3.js +270 -0
  39. package/dist/node/esm/circuits/common.js +4 -6
  40. package/dist/node/esm/circuits/comparer.js +55 -1
  41. package/dist/node/esm/circuits/index.js +4 -0
  42. package/dist/node/esm/circuits/linked-multi-query.js +123 -0
  43. package/dist/node/esm/circuits/linked-nullifier.js +52 -0
  44. package/dist/node/esm/circuits/models.js +25 -1
  45. package/dist/node/esm/credentials/credential-wallet.js +2 -10
  46. package/dist/node/esm/credentials/index.js +1 -0
  47. package/dist/node/esm/credentials/utils.js +19 -0
  48. package/dist/node/esm/iden3comm/handlers/auth.js +50 -9
  49. package/dist/node/esm/iden3comm/handlers/contract-request.js +20 -8
  50. package/dist/node/esm/proof/common.js +101 -2
  51. package/dist/node/esm/proof/inputs-generator.js +389 -0
  52. package/dist/node/esm/proof/proof-service.js +111 -377
  53. package/dist/node/esm/schema-processor/json/parser.js +7 -0
  54. package/dist/node/esm/schema-processor/json/validator.js +1 -0
  55. package/dist/node/esm/storage/filters/jsonQuery.js +74 -9
  56. package/dist/node/esm/utils/did-helper.js +10 -0
  57. package/dist/node/esm/utils/index.js +2 -0
  58. package/dist/node/esm/utils/object.js +38 -0
  59. package/dist/node/esm/verifiable/presentation.js +30 -29
  60. package/dist/node/esm/verifiable/proof.js +2 -0
  61. package/dist/types/circuits/atomic-query-mtp-v2.d.ts +13 -13
  62. package/dist/types/circuits/atomic-query-v3-on-chain.d.ts +142 -0
  63. package/dist/types/circuits/atomic-query-v3.d.ts +120 -0
  64. package/dist/types/circuits/common.d.ts +4 -4
  65. package/dist/types/circuits/comparer.d.ts +33 -1
  66. package/dist/types/circuits/index.d.ts +4 -0
  67. package/dist/types/circuits/linked-multi-query.d.ts +38 -0
  68. package/dist/types/circuits/linked-nullifier.d.ts +37 -0
  69. package/dist/types/circuits/models.d.ts +20 -2
  70. package/dist/types/credentials/index.d.ts +1 -0
  71. package/dist/types/credentials/utils.d.ts +12 -0
  72. package/dist/types/iden3comm/types/packer.d.ts +1 -2
  73. package/dist/types/iden3comm/types/protocol/auth.d.ts +1 -0
  74. package/dist/types/proof/common.d.ts +34 -3
  75. package/dist/types/proof/inputs-generator.d.ts +46 -0
  76. package/dist/types/proof/proof-service.d.ts +14 -25
  77. package/dist/types/schema-processor/json/parser.d.ts +1 -0
  78. package/dist/types/storage/filters/jsonQuery.d.ts +1 -1
  79. package/dist/types/utils/did-helper.d.ts +6 -0
  80. package/dist/types/utils/index.d.ts +2 -0
  81. package/dist/types/utils/object.d.ts +12 -0
  82. package/dist/types/verifiable/presentation.d.ts +6 -10
  83. package/package.json +1 -1
@@ -1,13 +1,14 @@
1
- import { Hex, Poseidon, Signature } from '@iden3/js-crypto';
2
- import { BytesHelper, DID, getUnixTimestamp, MerklizedRootPosition } from '@iden3/js-iden3-core';
1
+ import { Poseidon } from '@iden3/js-crypto';
2
+ import { BytesHelper, DID, MerklizedRootPosition } from '@iden3/js-iden3-core';
3
3
  import { Hash } from '@iden3/js-merkletree';
4
- import { AtomicQueryMTPV2Inputs, AtomicQueryMTPV2OnChainInputs, AtomicQuerySigV2Inputs, AtomicQuerySigV2OnChainInputs, AuthV2Inputs, CircuitClaim, CircuitId, Query, QueryOperators, StateTransitionInputs, ValueProof } from '../circuits';
5
- import { createVerifiablePresentation, ProofType, verifiablePresentationFromCred } from '../verifiable';
6
- import { toClaimNonRevStatus, toGISTProof } from './common';
4
+ import { AuthV2Inputs, CircuitId, Operators, Query, StateTransitionInputs, ValueProof } from '../circuits';
5
+ import { createVerifiablePresentation } from '../verifiable';
6
+ import { parseCredentialSubject, parseQueryMetadata, toGISTProof, transformQueryValueToBigInts } from './common';
7
7
  import { NativeProver } from './prover';
8
- import { Merklizer, Path, getDocumentLoader } from '@iden3/js-jsonld-merklization';
9
- import { Parser, cacheLoader } from '../schema-processor';
8
+ import { getDocumentLoader } from '@iden3/js-jsonld-merklization';
9
+ import { cacheLoader } from '../schema-processor';
10
10
  import { byteDecoder, byteEncoder } from '../utils/encoding';
11
+ import { InputGenerator } from './inputs-generator';
11
12
  /**
12
13
  * Proof service is an implementation of IProofService
13
14
  * that works with a native groth16 prover
@@ -30,6 +31,7 @@ export class ProofService {
30
31
  this._stateStorage = _stateStorage;
31
32
  this._prover = opts?.prover ?? new NativeProver(_circuitStorage);
32
33
  this._ldOptions = { ...opts, documentLoader: opts?.documentLoader ?? cacheLoader(opts) };
34
+ this._inputsGenerator = new InputGenerator(_identityWallet, _credentialWallet, _stateStorage);
33
35
  }
34
36
  /** {@inheritdoc IProofService.verifyProof} */
35
37
  async verifyProof(zkp, circuitId) {
@@ -43,20 +45,61 @@ export class ProofService {
43
45
  challenge: 0n
44
46
  };
45
47
  }
46
- // find credential
47
- const credential = opts.credential ?? (await this.findCredential(identifier, proofReq.query));
48
+ let credentialWithRevStatus = { cred: opts.credential, revStatus: opts.credentialRevocationStatus };
49
+ if (!opts.credential) {
50
+ credentialWithRevStatus = await this.findCredentialByProofQuery(identifier, proofReq.query);
51
+ }
52
+ if (opts.credential && !opts.credentialRevocationStatus && !opts.skipRevocation) {
53
+ const revStatus = await this._credentialWallet.getRevocationStatusFromCredential(opts.credential);
54
+ credentialWithRevStatus = { cred: opts.credential, revStatus };
55
+ }
56
+ if (!credentialWithRevStatus.cred) {
57
+ throw new Error(`credential not found for query ${JSON.stringify(proofReq.query)}`);
58
+ }
59
+ const credentialCoreClaim = await this._identityWallet.getCoreClaimFromCredential(credentialWithRevStatus.cred);
48
60
  const { nonce: authProfileNonce, genesisDID } = await this._identityWallet.getGenesisDIDMetadata(identifier);
49
- const preparedCredential = await this.getPreparedCredential(credential);
61
+ const preparedCredential = {
62
+ credential: credentialWithRevStatus.cred,
63
+ credentialCoreClaim,
64
+ revStatus: credentialWithRevStatus.revStatus
65
+ };
50
66
  const subjectDID = DID.parse(preparedCredential.credential.credentialSubject['id']);
51
67
  const { nonce: credentialSubjectProfileNonce, genesisDID: subjectGenesisDID } = await this._identityWallet.getGenesisDIDMetadata(subjectDID);
52
68
  if (subjectGenesisDID.string() !== genesisDID.string()) {
53
69
  throw new Error('subject and auth profiles are not derived from the same did');
54
70
  }
55
- const { inputs, vp } = await this.generateInputs(preparedCredential, genesisDID, proofReq, {
71
+ const propertiesMetadata = parseCredentialSubject(proofReq.query.credentialSubject);
72
+ if (!propertiesMetadata.length) {
73
+ throw new Error('no queries in zkp request');
74
+ }
75
+ const mtPosition = preparedCredential.credentialCoreClaim.getMerklizedPosition();
76
+ let mk;
77
+ if (mtPosition !== MerklizedRootPosition.None) {
78
+ mk = await preparedCredential.credential.merklize(this._ldOptions);
79
+ }
80
+ const context = proofReq.query['context'];
81
+ const groupId = proofReq.query['groupId'];
82
+ const ldContext = await this.loadLdContext(context);
83
+ const credentialType = proofReq.query['type'];
84
+ const queriesMetadata = [];
85
+ const circuitQueries = [];
86
+ for (const propertyMetadata of propertiesMetadata) {
87
+ const queryMetadata = await parseQueryMetadata(propertyMetadata, byteDecoder.decode(ldContext), credentialType, this._ldOptions);
88
+ queriesMetadata.push(queryMetadata);
89
+ const circuitQuery = await this.toCircuitsQuery(preparedCredential.credential, queryMetadata, mk);
90
+ circuitQueries.push(circuitQuery);
91
+ }
92
+ const inputs = await this.generateInputs(preparedCredential, genesisDID, proofReq, {
56
93
  ...opts,
57
94
  authProfileNonce,
58
- credentialSubjectProfileNonce
59
- });
95
+ credentialSubjectProfileNonce,
96
+ linkNonce: groupId ? opts.linkNonce : 0n
97
+ }, circuitQueries);
98
+ const sdQueries = queriesMetadata.filter((q) => q.operator === Operators.SD);
99
+ let vp;
100
+ if (sdQueries.length) {
101
+ vp = createVerifiablePresentation(context, credentialType, preparedCredential.credential, sdQueries);
102
+ }
60
103
  const { proof, pub_signals } = await this._prover.generate(inputs, proofReq.circuitId);
61
104
  return {
62
105
  id: proofReq.id,
@@ -68,7 +111,7 @@ export class ProofService {
68
111
  }
69
112
  /** {@inheritdoc IProofService.transitState} */
70
113
  async transitState(did, oldTreeState, isOldStateGenesis, stateStorage, ethSigner) {
71
- const authInfo = await this.prepareAuthBJJCredential(did, oldTreeState);
114
+ const authInfo = await this._inputsGenerator.prepareAuthBJJCredential(did, oldTreeState);
72
115
  const newTreeModel = await this._identityWallet.getDIDTreeModel(did);
73
116
  const claimsRoot = await newTreeModel.claimsTree.root();
74
117
  const rootOfRoots = await newTreeModel.rootsTree.root();
@@ -80,17 +123,17 @@ export class ProofService {
80
123
  rootOfRoots
81
124
  };
82
125
  const challenge = Poseidon.hash([oldTreeState.state.bigInt(), newTreeState.state.bigInt()]);
83
- const signature = await this._identityWallet.signChallenge(challenge, authInfo.authCredential);
126
+ const signature = await this._identityWallet.signChallenge(challenge, authInfo.credential);
84
127
  const circuitInputs = new StateTransitionInputs();
85
128
  circuitInputs.id = DID.idFromDID(did);
86
129
  circuitInputs.signature = signature;
87
130
  circuitInputs.isOldStateGenesis = isOldStateGenesis;
88
- const authClaimIncProofNewState = await this._identityWallet.generateCredentialMtp(did, authInfo.authCredential, newTreeState);
131
+ const authClaimIncProofNewState = await this._identityWallet.generateCredentialMtp(did, authInfo.credential, newTreeState);
89
132
  circuitInputs.newTreeState = authClaimIncProofNewState.treeState;
90
133
  circuitInputs.authClaimNewStateIncProof = authClaimIncProofNewState.proof;
91
134
  circuitInputs.oldTreeState = oldTreeState;
92
135
  circuitInputs.authClaim = {
93
- claim: authInfo.authCoreClaim,
136
+ claim: authInfo.coreClaim,
94
137
  incProof: authInfo.incProof,
95
138
  nonRevProof: authInfo.nonRevProof
96
139
  };
@@ -100,370 +143,65 @@ export class ProofService {
100
143
  await this._identityWallet.updateIdentityState(did, true, newTreeState);
101
144
  return txId;
102
145
  }
103
- async getPreparedCredential(credential) {
104
- const revStatus = await this._credentialWallet.getRevocationStatusFromCredential(credential);
105
- const credCoreClaim = await this._identityWallet.getCoreClaimFromCredential(credential);
106
- return { credential, revStatus, credentialCoreClaim: credCoreClaim };
107
- }
108
- async prepareAuthBJJCredential(did, treeStateInfo) {
109
- const authCredential = await this._credentialWallet.getAuthBJJCredential(did);
110
- const incProof = await this._identityWallet.generateCredentialMtp(did, authCredential, treeStateInfo);
111
- const nonRevProof = await this._identityWallet.generateNonRevocationMtp(did, authCredential, treeStateInfo);
112
- const authCoreClaim = authCredential.getCoreClaimFromProof(ProofType.Iden3SparseMerkleTreeProof);
113
- if (!authCoreClaim) {
114
- throw new Error('auth core claim is not defined for auth bjj credential');
115
- }
116
- return { authCredential, incProof, nonRevProof, authCoreClaim };
117
- }
118
- async generateInputs(preparedCredential, identifier, proofReq, params) {
119
- let generateInputFn;
120
- switch (proofReq.circuitId) {
121
- case CircuitId.AtomicQueryMTPV2:
122
- generateInputFn = this.generateMTPV2Inputs.bind(this);
123
- break;
124
- case CircuitId.AtomicQueryMTPV2OnChain:
125
- generateInputFn = this.generateMTPV2OnChainInputs.bind(this);
126
- break;
127
- case CircuitId.AtomicQuerySigV2:
128
- generateInputFn = this.generateQuerySigV2Inputs.bind(this);
129
- break;
130
- case CircuitId.AtomicQuerySigV2OnChain:
131
- generateInputFn = this.generateQuerySigV2OnChainInputs.bind(this);
132
- break;
133
- default:
134
- throw new Error(`circuit with id ${proofReq.circuitId} is not supported by issuer`);
135
- }
136
- return generateInputFn(preparedCredential, identifier, proofReq, params);
137
- }
138
- async generateMTPV2Inputs(preparedCredential, identifier, proofReq, params) {
139
- const circuitClaimData = await this.newCircuitClaimData(preparedCredential.credential, preparedCredential.credentialCoreClaim);
140
- circuitClaimData.nonRevProof = toClaimNonRevStatus(preparedCredential.revStatus);
141
- const circuitInputs = new AtomicQueryMTPV2Inputs();
142
- circuitInputs.id = DID.idFromDID(identifier);
143
- circuitInputs.requestID = BigInt(proofReq.id);
144
- const { query, vp } = await this.toCircuitsQuery(proofReq.query, preparedCredential.credential, preparedCredential.credentialCoreClaim);
145
- circuitInputs.query = query;
146
- circuitInputs.claim = {
147
- issuerID: circuitClaimData.issuerId,
148
- claim: circuitClaimData.claim,
149
- incProof: { proof: circuitClaimData.proof, treeState: circuitClaimData.treeState },
150
- nonRevProof: circuitClaimData.nonRevProof
151
- };
152
- circuitInputs.currentTimeStamp = getUnixTimestamp(new Date());
153
- circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
154
- circuitInputs.profileNonce = BigInt(params.authProfileNonce);
155
- circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
156
- return { inputs: circuitInputs.inputsMarshal(), vp };
157
- }
158
- async generateMTPV2OnChainInputs(preparedCredential, identifier, proofReq, params) {
159
- const circuitClaimData = await this.newCircuitClaimData(preparedCredential.credential, preparedCredential.credentialCoreClaim);
160
- const authPrepared = await this.prepareAuthBJJCredential(identifier);
161
- const authClaimData = await this.newCircuitClaimData(authPrepared.authCredential, authPrepared.authCoreClaim);
162
- circuitClaimData.nonRevProof = toClaimNonRevStatus(preparedCredential.revStatus);
163
- const circuitInputs = new AtomicQueryMTPV2OnChainInputs();
164
- const id = DID.idFromDID(identifier);
165
- circuitInputs.id = DID.idFromDID(identifier);
166
- circuitInputs.requestID = BigInt(proofReq.id);
167
- const stateProof = await this._stateStorage.getGISTProof(id.bigInt());
168
- const gistProof = toGISTProof(stateProof);
169
- circuitInputs.gistProof = gistProof;
170
- if (authClaimData?.treeState) {
171
- circuitInputs.treeState = {
172
- state: authClaimData?.treeState?.state,
173
- claimsRoot: authClaimData?.treeState?.claimsRoot,
174
- revocationRoot: authClaimData?.treeState?.revocationRoot,
175
- rootOfRoots: authClaimData?.treeState?.rootOfRoots
176
- };
177
- }
178
- circuitInputs.authClaim = authClaimData.claim;
179
- circuitInputs.authClaimIncMtp = authClaimData.proof;
180
- circuitInputs.authClaimNonRevMtp = authPrepared.nonRevProof.proof;
181
- if (!params.challenge) {
182
- throw new Error('challenge must be provided for onchain circuits');
183
- }
184
- const signature = await this._identityWallet.signChallenge(params.challenge, authPrepared.authCredential);
185
- circuitInputs.signature = signature;
186
- circuitInputs.challenge = params.challenge;
187
- const { query, vp } = await this.toCircuitsQuery(proofReq.query, preparedCredential.credential, preparedCredential.credentialCoreClaim);
188
- circuitInputs.query = query;
189
- circuitInputs.claim = {
190
- issuerID: circuitClaimData.issuerId,
191
- claim: circuitClaimData.claim,
192
- incProof: { proof: circuitClaimData.proof, treeState: circuitClaimData.treeState },
193
- nonRevProof: circuitClaimData.nonRevProof
194
- };
195
- circuitInputs.currentTimeStamp = getUnixTimestamp(new Date());
196
- circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
197
- circuitInputs.profileNonce = BigInt(params.authProfileNonce);
198
- circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
199
- return { inputs: circuitInputs.inputsMarshal(), vp };
200
- }
201
- async generateQuerySigV2Inputs(preparedCredential, identifier, proofReq, params) {
202
- const circuitClaimData = await this.newCircuitClaimData(preparedCredential.credential, preparedCredential.credentialCoreClaim);
203
- circuitClaimData.nonRevProof = toClaimNonRevStatus(preparedCredential.revStatus);
204
- const circuitInputs = new AtomicQuerySigV2Inputs();
205
- circuitInputs.id = DID.idFromDID(identifier);
206
- circuitInputs.claim = {
207
- issuerID: circuitClaimData?.issuerId,
208
- signatureProof: circuitClaimData.signatureProof,
209
- claim: circuitClaimData.claim,
210
- nonRevProof: circuitClaimData.nonRevProof
211
- };
212
- circuitInputs.requestID = BigInt(proofReq.id);
213
- circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
214
- circuitInputs.profileNonce = BigInt(params.authProfileNonce);
215
- circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
216
- const { query, vp } = await this.toCircuitsQuery(proofReq.query, preparedCredential.credential, preparedCredential.credentialCoreClaim);
217
- circuitInputs.query = query;
218
- circuitInputs.currentTimeStamp = getUnixTimestamp(new Date());
219
- return { inputs: circuitInputs.inputsMarshal(), vp };
146
+ async generateInputs(preparedCredential, identifier, proofReq, params, circuitQueries) {
147
+ return this._inputsGenerator.generateInputs({
148
+ preparedCredential,
149
+ identifier,
150
+ proofReq,
151
+ params,
152
+ circuitQueries
153
+ });
220
154
  }
221
- async generateQuerySigV2OnChainInputs(preparedCredential, identifier, proofReq, params) {
222
- const circuitClaimData = await this.newCircuitClaimData(preparedCredential.credential, preparedCredential.credentialCoreClaim);
223
- const authPrepared = await this.prepareAuthBJJCredential(identifier);
224
- const authClaimData = await this.newCircuitClaimData(authPrepared.authCredential, authPrepared.authCoreClaim);
225
- circuitClaimData.nonRevProof = toClaimNonRevStatus(preparedCredential.revStatus);
226
- const circuitInputs = new AtomicQuerySigV2OnChainInputs();
227
- const id = DID.idFromDID(identifier);
228
- circuitInputs.id = id;
229
- circuitInputs.claim = {
230
- issuerID: circuitClaimData.issuerId,
231
- signatureProof: circuitClaimData.signatureProof,
232
- claim: circuitClaimData.claim,
233
- nonRevProof: circuitClaimData.nonRevProof
234
- };
235
- circuitInputs.requestID = BigInt(proofReq.id);
236
- circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
237
- circuitInputs.profileNonce = BigInt(params.authProfileNonce);
238
- circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
239
- const { query, vp } = await this.toCircuitsQuery(proofReq.query, preparedCredential.credential, preparedCredential.credentialCoreClaim);
240
- circuitInputs.query = query;
241
- circuitInputs.currentTimeStamp = getUnixTimestamp(new Date());
242
- if (authClaimData.treeState) {
243
- circuitInputs.treeState = {
244
- state: authClaimData.treeState?.state,
245
- claimsRoot: authClaimData.treeState?.claimsRoot,
246
- revocationRoot: authClaimData.treeState?.revocationRoot,
247
- rootOfRoots: authClaimData.treeState?.rootOfRoots
248
- };
155
+ async toCircuitsQuery(credential, queryMetadata, merklizedCredential) {
156
+ if (queryMetadata.merklizedSchema && !merklizedCredential) {
157
+ throw new Error('merklized root position is set to None for merklized schema');
249
158
  }
250
- const stateProof = await this._stateStorage.getGISTProof(id.bigInt());
251
- const gistProof = toGISTProof(stateProof);
252
- circuitInputs.gistProof = gistProof;
253
- circuitInputs.authClaim = authClaimData.claim;
254
- circuitInputs.authClaimIncMtp = authClaimData.proof;
255
- circuitInputs.authClaimNonRevMtp = authPrepared.nonRevProof.proof;
256
- if (!params.challenge) {
257
- throw new Error('challenge must be provided for onchain circuits');
258
- }
259
- const signature = await this._identityWallet.signChallenge(params.challenge, authPrepared.authCredential);
260
- circuitInputs.signature = signature;
261
- circuitInputs.challenge = params.challenge;
262
- return { inputs: circuitInputs.inputsMarshal(), vp };
263
- }
264
- // NewCircuitClaimData generates circuits claim structure
265
- async newCircuitClaimData(credential, coreClaim) {
266
- const smtProof = credential.getIden3SparseMerkleTreeProof();
267
- const circuitClaim = new CircuitClaim();
268
- circuitClaim.claim = coreClaim;
269
- circuitClaim.issuerId = DID.idFromDID(DID.parse(credential.issuer));
270
- if (smtProof) {
271
- circuitClaim.proof = smtProof.mtp;
272
- circuitClaim.treeState = {
273
- state: smtProof.issuerData.state.value,
274
- claimsRoot: smtProof.issuerData.state.claimsTreeRoot,
275
- revocationRoot: smtProof.issuerData.state.revocationTreeRoot,
276
- rootOfRoots: smtProof.issuerData.state.rootOfRoots
277
- };
159
+ if (!queryMetadata.merklizedSchema && merklizedCredential) {
160
+ throw new Error('merklized root position is not set to None for non-merklized schema');
278
161
  }
279
- const sigProof = credential.getBJJSignature2021Proof();
280
- if (sigProof) {
281
- const issuerDID = sigProof.issuerData.id;
282
- let userDID;
283
- if (!credential.credentialSubject.id) {
284
- userDID = issuerDID;
285
- }
286
- else {
287
- if (typeof credential.credentialSubject.id !== 'string') {
288
- throw new Error('credential status `id` is not a string');
289
- }
290
- userDID = DID.parse(credential.credentialSubject.id);
291
- }
292
- if (!sigProof.issuerData.credentialStatus) {
293
- throw new Error("can't check the validity of issuer auth claim: no credential status in proof");
162
+ const query = new Query();
163
+ query.slotIndex = queryMetadata.slotIndex;
164
+ query.operator = queryMetadata.operator;
165
+ query.values = queryMetadata.values;
166
+ if (queryMetadata.merklizedSchema && merklizedCredential) {
167
+ const { proof, value: mtValue } = await merklizedCredential.proof(queryMetadata.path);
168
+ query.valueProof = new ValueProof();
169
+ query.valueProof.mtp = proof;
170
+ query.valueProof.path = queryMetadata.claimPathKey;
171
+ const mtEntry = await mtValue?.mtEntry();
172
+ if (!mtEntry) {
173
+ throw new Error(`can't merklize credential: no merkle tree entry found`);
294
174
  }
295
- const opts = {
296
- issuerGenesisState: sigProof.issuerData.state,
297
- issuerDID,
298
- userDID
299
- };
300
- const rs = await this._credentialWallet.getRevocationStatus(sigProof.issuerData.credentialStatus, opts);
301
- if (!rs) {
302
- throw new Error("can't fetch the credential status of issuer auth claim");
175
+ query.valueProof.value = mtEntry;
176
+ if (!queryMetadata.fieldName) {
177
+ query.values = [mtEntry];
178
+ return query;
303
179
  }
304
- const issuerAuthNonRevProof = toClaimNonRevStatus(rs);
305
- if (!sigProof.issuerData.mtp) {
306
- throw new Error('issuer auth credential must have a mtp proof');
180
+ }
181
+ if (queryMetadata.operator === Operators.SD) {
182
+ const [first, ...rest] = queryMetadata.fieldName.split('.');
183
+ let v = credential.credentialSubject[first];
184
+ for (const part of rest) {
185
+ v = v[part];
307
186
  }
308
- if (!sigProof.issuerData.authCoreClaim) {
309
- throw new Error('issuer auth credential must have a core claim proof');
187
+ if (typeof v === 'undefined') {
188
+ throw new Error(`credential doesn't contain value for field ${queryMetadata.fieldName}`);
310
189
  }
311
- circuitClaim.signatureProof = {
312
- signature: sigProof.signature,
313
- issuerAuthIncProof: {
314
- proof: sigProof.issuerData.mtp,
315
- treeState: {
316
- state: sigProof.issuerData.state.value,
317
- claimsRoot: sigProof.issuerData.state.claimsTreeRoot,
318
- revocationRoot: sigProof.issuerData.state.revocationTreeRoot,
319
- rootOfRoots: sigProof.issuerData.state.rootOfRoots
320
- }
321
- },
322
- issuerAuthClaim: sigProof.issuerData.authCoreClaim,
323
- issuerAuthNonRevProof
324
- };
190
+ query.values = await transformQueryValueToBigInts(v, queryMetadata.datatype);
325
191
  }
326
- return circuitClaim;
327
- }
328
- async toCircuitsQuery(query, credential, coreClaim) {
329
- const mtPosition = coreClaim.getMerklizedPosition();
330
- return mtPosition === MerklizedRootPosition.None
331
- ? this.prepareNonMerklizedQuery(query, credential)
332
- : this.prepareMerklizedQuery(query, credential);
192
+ return query;
333
193
  }
334
- async prepareMerklizedQuery(query, credential) {
335
- const parsedQuery = await this.parseRequest(query.credentialSubject);
336
- const ldContext = await this.loadLdContextFromJSONSchema(credential.credentialSchema.id);
337
- let path = new Path();
338
- if (parsedQuery.fieldName) {
339
- path = await Path.getContextPathKey(byteDecoder.decode(ldContext), credential.type[1], parsedQuery.fieldName, this._ldOptions);
340
- }
341
- path.prepend(['https://www.w3.org/2018/credentials#credentialSubject']);
342
- const mk = await credential.merklize(this._ldOptions);
343
- const { proof, value: mtValue } = await mk.proof(path);
344
- const pathKey = await path.mtEntry();
345
- parsedQuery.query.valueProof = new ValueProof();
346
- parsedQuery.query.valueProof.mtp = proof;
347
- parsedQuery.query.valueProof.path = pathKey;
348
- parsedQuery.query.valueProof.mtp = proof;
349
- const mtEntry = await mtValue?.mtEntry();
350
- if (!mtEntry) {
351
- throw new Error(`can't merklize credential: no merkle tree entry found`);
352
- }
353
- parsedQuery.query.valueProof.value = mtEntry;
354
- // for merklized credentials slotIndex in query must be equal to zero
355
- // and not a position of merklization root.
356
- // it has no influence on check in the off-chain circuits, but it aligns with onchain verification standard
357
- parsedQuery.query.slotIndex = 0;
358
- if (!parsedQuery.fieldName) {
359
- const resultQuery = parsedQuery.query;
360
- resultQuery.operator = QueryOperators.$eq;
361
- resultQuery.values = [mtEntry];
362
- return { query: resultQuery };
363
- }
364
- if (parsedQuery.isSelectiveDisclosure) {
365
- const rawValue = mk.rawValue(path);
366
- const vp = createVerifiablePresentation(query.context ?? '', query.type ?? '', parsedQuery.fieldName, rawValue);
367
- const resultQuery = parsedQuery.query;
368
- resultQuery.operator = QueryOperators.$eq;
369
- resultQuery.values = [mtEntry];
370
- return { query: resultQuery, vp };
371
- }
372
- if (parsedQuery.rawValue === null || parsedQuery.rawValue === undefined) {
373
- throw new Error('value is not presented in the query');
374
- }
375
- const ldType = await mk.jsonLDType(path);
376
- parsedQuery.query.values = await this.transformQueryValueToBigInts(parsedQuery.rawValue, ldType);
377
- return { query: parsedQuery.query };
378
- }
379
- async prepareNonMerklizedQuery(query, credential) {
380
- const ldContext = await this.loadLdContextFromJSONSchema(credential.credentialSchema.id);
381
- if (query.credentialSubject && Object.keys(query.credentialSubject).length > 1) {
382
- throw new Error('multiple requests are not supported');
383
- }
384
- const parsedQuery = await this.parseRequest(query.credentialSubject);
385
- if (!query.type) {
386
- throw new Error('query type is not defined');
387
- }
388
- parsedQuery.query.slotIndex = await Parser.getFieldSlotIndex(parsedQuery.fieldName, query.type, ldContext);
389
- const { vp, mzValue, dataType } = await verifiablePresentationFromCred(credential, query, parsedQuery.fieldName, this._ldOptions);
390
- if (parsedQuery.isSelectiveDisclosure) {
391
- const resultQuery = parsedQuery.query;
392
- resultQuery.operator = QueryOperators.$eq;
393
- resultQuery.values = [await mzValue.mtEntry()];
394
- return { query: resultQuery, vp };
395
- }
396
- if (parsedQuery.rawValue === null || parsedQuery.rawValue === undefined) {
397
- throw new Error('value is not presented in the query');
398
- }
399
- parsedQuery.query.values = await this.transformQueryValueToBigInts(parsedQuery.rawValue, dataType);
400
- return { query: parsedQuery.query };
401
- }
402
- async loadLdContextFromJSONSchema(jsonSchemaURL) {
194
+ async loadLdContext(context) {
403
195
  const loader = getDocumentLoader(this._ldOptions);
404
- let schema;
405
- try {
406
- schema = (await loader(jsonSchemaURL)).document;
407
- }
408
- catch (e) {
409
- throw new Error(`can't load credential schema ${jsonSchemaURL}`);
410
- }
411
- const jsonSchema = schema;
412
196
  let ldSchema;
413
- let ldContextUrl = '';
414
197
  try {
415
- ldContextUrl = jsonSchema.$metadata.uris['jsonLdContext'];
416
- if (!ldContextUrl) {
417
- throw new Error('ldContext is not defined in json schema metadata');
418
- }
419
- ldSchema = (await loader(ldContextUrl)).document;
198
+ ldSchema = (await loader(context)).document;
420
199
  }
421
200
  catch (e) {
422
- throw new Error(`can't load ld context from url ${ldContextUrl}`);
201
+ throw new Error(`can't load ld context from url ${context}`);
423
202
  }
424
203
  return byteEncoder.encode(JSON.stringify(ldSchema));
425
204
  }
426
- async parseRequest(req) {
427
- if (!req) {
428
- const query = new Query();
429
- query.operator = QueryOperators.$eq;
430
- return { query, fieldName: '' };
431
- }
432
- const entries = Object.entries(req);
433
- if (entries.length > 1) {
434
- throw new Error(`multiple requests not supported`);
435
- }
436
- const [fieldName, fieldReq] = entries[0];
437
- const fieldReqEntries = Object.entries(fieldReq);
438
- if (fieldReqEntries.length > 1) {
439
- throw new Error(`multiple predicates for one field not supported`);
440
- }
441
- const isSelectiveDisclosure = fieldReqEntries.length === 0;
442
- const query = new Query();
443
- if (isSelectiveDisclosure) {
444
- return { query, fieldName, isSelectiveDisclosure };
445
- }
446
- let operator = 0;
447
- const [key, value] = fieldReqEntries[0];
448
- if (!QueryOperators[key]) {
449
- throw new Error(`operator is not supported by lib`);
450
- }
451
- operator = QueryOperators[key];
452
- query.operator = operator;
453
- return { query, fieldName, rawValue: value };
454
- }
455
- async transformQueryValueToBigInts(value, ldType) {
456
- const values = new Array(64).fill(BigInt(0));
457
- if (Array.isArray(value)) {
458
- for (let index = 0; index < value.length; index++) {
459
- values[index] = await Merklizer.hashValue(ldType, value[index]);
460
- }
461
- }
462
- else {
463
- values[0] = await Merklizer.hashValue(ldType, value);
464
- }
465
- return values;
466
- }
467
205
  /** {@inheritdoc IProofService.generateAuthV2Inputs} */
468
206
  async generateAuthV2Inputs(hash, did, circuitId) {
469
207
  if (circuitId !== CircuitId.AuthV2) {
@@ -471,9 +209,12 @@ export class ProofService {
471
209
  }
472
210
  const { nonce: authProfileNonce, genesisDID } = await this._identityWallet.getGenesisDIDMetadata(did);
473
211
  const challenge = BytesHelper.bytesToInt(hash.reverse());
474
- const authPrepared = await this.prepareAuthBJJCredential(genesisDID);
475
- const authClaimData = await this.newCircuitClaimData(authPrepared.authCredential, authPrepared.authCoreClaim);
476
- const signature = await this._identityWallet.signChallenge(challenge, authPrepared.authCredential);
212
+ const authPrepared = await this._inputsGenerator.prepareAuthBJJCredential(genesisDID);
213
+ const authClaimData = await this._inputsGenerator.newCircuitClaimData({
214
+ credential: authPrepared.credential,
215
+ credentialCoreClaim: authPrepared.coreClaim
216
+ });
217
+ const signature = await this._identityWallet.signChallenge(challenge, authPrepared.credential);
477
218
  const id = DID.idFromDID(genesisDID);
478
219
  const stateProof = await this._stateStorage.getGISTProof(id.bigInt());
479
220
  const gistProof = toGISTProof(stateProof);
@@ -509,7 +250,7 @@ export class ProofService {
509
250
  }
510
251
  return true;
511
252
  }
512
- async findCredential(did, query) {
253
+ async findCredentialByProofQuery(did, query) {
513
254
  const credentials = await this._identityWallet.findOwnedCredentialsByDID(did, query);
514
255
  if (!credentials.length) {
515
256
  throw new Error(`no credentials belong to did or its profiles`);
@@ -517,15 +258,8 @@ export class ProofService {
517
258
  // For EQ / IN / NIN / LT / GT operations selective if credential satisfies query - we can get any.
518
259
  // TODO: choose credential for selective credentials
519
260
  const credential = query.skipClaimRevocationCheck
520
- ? credentials[0]
521
- : (await this._credentialWallet.findNonRevokedCredential(credentials)).cred;
261
+ ? { cred: credentials[0], revStatus: undefined }
262
+ : await this._credentialWallet.findNonRevokedCredential(credentials);
522
263
  return credential;
523
264
  }
524
265
  }
525
- // BJJSignatureFromHexString converts hex to babyjub.Signature
526
- export const bJJSignatureFromHexString = async (sigHex) => {
527
- const signatureBytes = Hex.decodeString(sigHex);
528
- const compressedSig = Uint8Array.from(signatureBytes).slice(0, 64);
529
- const bjjSig = Signature.newFromCompressed(compressedSig);
530
- return bjjSig;
531
- };
@@ -126,6 +126,13 @@ export class Parser {
126
126
  const ldCtx = await jsonld.processContext(ldcontext.getInitialContext({}), credential['@context'], opts);
127
127
  return Parser.getSerializationAttrFromParsedContext(ldCtx, tp);
128
128
  }
129
+ // Get `iden3_serialization` attr definition from context document either using
130
+ // type name like DeliverAddressMultiTestForked or by type id like
131
+ // urn:uuid:ac2ede19-b3b9-454d-b1a9-a7b3d5763100.
132
+ static async getSerializationAttrFromContext(context, opts, tp) {
133
+ const ldCtx = await jsonld.processContext(ldcontext.getInitialContext({}), context, opts);
134
+ return Parser.getSerializationAttrFromParsedContext(ldCtx, tp);
135
+ }
129
136
  static async getSerializationAttrFromParsedContext(ldCtx, tp) {
130
137
  const termDef = ldCtx.mappings;
131
138
  if (!termDef) {
@@ -42,6 +42,7 @@ export class JsonSchemaValidator {
42
42
  const validate = (schema.$id ? validator.getSchema(schema.$id) : undefined) || validator.compile(schema);
43
43
  const valid = validate(data);
44
44
  if (!valid) {
45
+ // TODO: extract correct error messages
45
46
  throw new Error(validate.errors?.map((e) => e.message).join(', '));
46
47
  }
47
48
  return true;