@0xpolygonid/js-sdk 1.5.0 → 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.
- package/dist/browser/esm/index.js +1685 -468
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.js +1706 -473
- package/dist/browser/umd/index.js.map +1 -1
- package/dist/node/cjs/circuits/atomic-query-mtp-v2-on-chain.js +1 -1
- package/dist/node/cjs/circuits/atomic-query-mtp-v2.js +1 -1
- package/dist/node/cjs/circuits/atomic-query-sig-v2-on-chain.js +2 -2
- package/dist/node/cjs/circuits/atomic-query-sig-v2.js +11 -14
- package/dist/node/cjs/circuits/atomic-query-v3-on-chain.js +320 -0
- package/dist/node/cjs/circuits/atomic-query-v3.js +275 -0
- package/dist/node/cjs/circuits/common.js +5 -7
- package/dist/node/cjs/circuits/comparer.js +57 -2
- package/dist/node/cjs/circuits/index.js +4 -0
- package/dist/node/cjs/circuits/linked-multi-query.js +128 -0
- package/dist/node/cjs/circuits/linked-nullifier.js +57 -0
- package/dist/node/cjs/circuits/models.js +25 -1
- package/dist/node/cjs/credentials/credential-wallet.js +2 -10
- package/dist/node/cjs/credentials/index.js +1 -0
- package/dist/node/cjs/credentials/utils.js +23 -0
- package/dist/node/cjs/iden3comm/handlers/auth.js +49 -8
- package/dist/node/cjs/iden3comm/handlers/contract-request.js +20 -8
- package/dist/node/cjs/proof/common.js +104 -1
- package/dist/node/cjs/proof/inputs-generator.js +393 -0
- package/dist/node/cjs/proof/proof-service.js +105 -372
- package/dist/node/cjs/schema-processor/json/parser.js +7 -0
- package/dist/node/cjs/schema-processor/json/validator.js +1 -0
- package/dist/node/cjs/storage/filters/jsonQuery.js +73 -8
- package/dist/node/cjs/utils/did-helper.js +14 -0
- package/dist/node/cjs/utils/index.js +2 -0
- package/dist/node/cjs/utils/object.js +42 -0
- package/dist/node/cjs/verifiable/presentation.js +34 -33
- package/dist/node/cjs/verifiable/proof.js +2 -0
- package/dist/node/esm/circuits/atomic-query-mtp-v2-on-chain.js +1 -1
- package/dist/node/esm/circuits/atomic-query-mtp-v2.js +1 -1
- package/dist/node/esm/circuits/atomic-query-sig-v2-on-chain.js +2 -2
- package/dist/node/esm/circuits/atomic-query-sig-v2.js +11 -14
- package/dist/node/esm/circuits/atomic-query-v3-on-chain.js +315 -0
- package/dist/node/esm/circuits/atomic-query-v3.js +270 -0
- package/dist/node/esm/circuits/common.js +4 -6
- package/dist/node/esm/circuits/comparer.js +55 -1
- package/dist/node/esm/circuits/index.js +4 -0
- package/dist/node/esm/circuits/linked-multi-query.js +123 -0
- package/dist/node/esm/circuits/linked-nullifier.js +52 -0
- package/dist/node/esm/circuits/models.js +25 -1
- package/dist/node/esm/credentials/credential-wallet.js +2 -10
- package/dist/node/esm/credentials/index.js +1 -0
- package/dist/node/esm/credentials/utils.js +19 -0
- package/dist/node/esm/iden3comm/handlers/auth.js +50 -9
- package/dist/node/esm/iden3comm/handlers/contract-request.js +20 -8
- package/dist/node/esm/proof/common.js +101 -2
- package/dist/node/esm/proof/inputs-generator.js +389 -0
- package/dist/node/esm/proof/proof-service.js +111 -377
- package/dist/node/esm/schema-processor/json/parser.js +7 -0
- package/dist/node/esm/schema-processor/json/validator.js +1 -0
- package/dist/node/esm/storage/filters/jsonQuery.js +74 -9
- package/dist/node/esm/utils/did-helper.js +10 -0
- package/dist/node/esm/utils/index.js +2 -0
- package/dist/node/esm/utils/object.js +38 -0
- package/dist/node/esm/verifiable/presentation.js +30 -29
- package/dist/node/esm/verifiable/proof.js +2 -0
- package/dist/types/circuits/atomic-query-mtp-v2.d.ts +13 -13
- package/dist/types/circuits/atomic-query-v3-on-chain.d.ts +142 -0
- package/dist/types/circuits/atomic-query-v3.d.ts +120 -0
- package/dist/types/circuits/common.d.ts +4 -4
- package/dist/types/circuits/comparer.d.ts +33 -1
- package/dist/types/circuits/index.d.ts +4 -0
- package/dist/types/circuits/linked-multi-query.d.ts +38 -0
- package/dist/types/circuits/linked-nullifier.d.ts +37 -0
- package/dist/types/circuits/models.d.ts +20 -2
- package/dist/types/credentials/index.d.ts +1 -0
- package/dist/types/credentials/utils.d.ts +12 -0
- package/dist/types/iden3comm/types/packer.d.ts +1 -2
- package/dist/types/iden3comm/types/protocol/auth.d.ts +1 -0
- package/dist/types/proof/common.d.ts +34 -3
- package/dist/types/proof/inputs-generator.d.ts +46 -0
- package/dist/types/proof/proof-service.d.ts +14 -25
- package/dist/types/schema-processor/json/parser.d.ts +1 -0
- package/dist/types/storage/filters/jsonQuery.d.ts +1 -1
- package/dist/types/utils/did-helper.d.ts +6 -0
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/object.d.ts +12 -0
- package/dist/types/verifiable/presentation.d.ts +6 -10
- package/package.json +3 -3
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BytesHelper, DID,
|
|
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 {
|
|
5
|
-
import { createVerifiablePresentation
|
|
6
|
-
import {
|
|
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 {
|
|
9
|
-
import {
|
|
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
|
-
|
|
47
|
-
|
|
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 =
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
251
|
-
|
|
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
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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 (
|
|
309
|
-
throw new Error(
|
|
187
|
+
if (typeof v === 'undefined') {
|
|
188
|
+
throw new Error(`credential doesn't contain value for field ${queryMetadata.fieldName}`);
|
|
310
189
|
}
|
|
311
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 ${
|
|
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(
|
|
476
|
-
|
|
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
|
|
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
|
-
:
|
|
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;
|