@0xpolygonid/js-sdk 1.9.1 → 1.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/esm/index.js +2991 -1225
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.js +2956 -1181
- package/dist/browser/umd/index.js.map +1 -1
- package/dist/node/cjs/circuits/comparer.js +6 -1
- package/dist/node/cjs/kms/key-providers/ed25519-provider.js +96 -0
- package/dist/node/cjs/kms/key-providers/index.js +1 -0
- package/dist/node/cjs/kms/store/types.js +1 -0
- package/dist/node/cjs/proof/common.js +11 -3
- package/dist/node/cjs/proof/proof-service.js +1 -4
- package/dist/node/cjs/proof/provers/inputs-generator.js +16 -1
- package/dist/node/cjs/proof/verifiers/pub-signals-verifier.js +93 -3
- package/dist/node/cjs/proof/verifiers/query.js +80 -72
- package/dist/node/cjs/storage/filters/jsonQuery.js +1 -1
- package/dist/node/esm/circuits/comparer.js +4 -0
- package/dist/node/esm/kms/key-providers/ed25519-provider.js +69 -0
- package/dist/node/esm/kms/key-providers/index.js +1 -0
- package/dist/node/esm/kms/store/types.js +1 -0
- package/dist/node/esm/proof/common.js +12 -4
- package/dist/node/esm/proof/proof-service.js +1 -4
- package/dist/node/esm/proof/provers/inputs-generator.js +17 -2
- package/dist/node/esm/proof/verifiers/pub-signals-verifier.js +95 -5
- package/dist/node/esm/proof/verifiers/query.js +74 -73
- package/dist/node/esm/storage/filters/jsonQuery.js +1 -1
- package/dist/types/circuits/comparer.d.ts +1 -0
- package/dist/types/kms/key-providers/ed25519-provider.d.ts +44 -0
- package/dist/types/kms/key-providers/index.d.ts +1 -0
- package/dist/types/kms/store/types.d.ts +2 -1
- package/dist/types/proof/provers/inputs-generator.d.ts +1 -0
- package/dist/types/proof/verifiers/pub-signals-verifier.d.ts +1 -0
- package/dist/types/proof/verifiers/query.d.ts +11 -1
- package/package.json +2 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as providerHelpers from '../provider-helpers';
|
|
2
|
+
import { ed25519 } from '@noble/curves/ed25519';
|
|
3
|
+
import { bytesToHex } from '../../utils';
|
|
4
|
+
/**
|
|
5
|
+
* Provider for Ed25519 keys
|
|
6
|
+
* @public
|
|
7
|
+
* @class Ed25519Provider
|
|
8
|
+
* @implements IKeyProvider interface
|
|
9
|
+
*/
|
|
10
|
+
export class Ed25519Provider {
|
|
11
|
+
/**
|
|
12
|
+
* Creates an instance of Ed25519Provider.
|
|
13
|
+
* @param {KmsKeyType} keyType - kms key type
|
|
14
|
+
* @param {AbstractPrivateKeyStore} keyStore - key store for kms
|
|
15
|
+
*/
|
|
16
|
+
constructor(keyType, _keyStore) {
|
|
17
|
+
this.keyType = keyType;
|
|
18
|
+
this._keyStore = _keyStore;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* generates a ed25519 key from a seed phrase
|
|
22
|
+
* @param {Uint8Array} seed - byte array seed
|
|
23
|
+
* @returns {Promise<KmsKeyId>} kms key identifier
|
|
24
|
+
*/
|
|
25
|
+
async newPrivateKeyFromSeed(seed) {
|
|
26
|
+
if (seed.length !== 32) {
|
|
27
|
+
throw new Error('Seed should be 32 bytes');
|
|
28
|
+
}
|
|
29
|
+
const publicKey = ed25519.getPublicKey(seed);
|
|
30
|
+
const kmsId = {
|
|
31
|
+
type: this.keyType,
|
|
32
|
+
id: providerHelpers.keyPath(this.keyType, bytesToHex(publicKey))
|
|
33
|
+
};
|
|
34
|
+
await this._keyStore.importKey({
|
|
35
|
+
alias: kmsId.id,
|
|
36
|
+
key: bytesToHex(seed)
|
|
37
|
+
});
|
|
38
|
+
return kmsId;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Gets public key by kmsKeyId
|
|
42
|
+
* @param {KmsKeyId} keyId - key identifier
|
|
43
|
+
* @returns {Promise<string>} Public key as a hex string
|
|
44
|
+
*/
|
|
45
|
+
async publicKey(keyId) {
|
|
46
|
+
const privateKeyHex = await this.privateKey(keyId);
|
|
47
|
+
const publicKey = ed25519.getPublicKey(privateKeyHex);
|
|
48
|
+
return bytesToHex(publicKey);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* signs prepared payload of size,
|
|
52
|
+
* with a key id
|
|
53
|
+
* @param {KmsKeyId} keyId - key identifier
|
|
54
|
+
* @param {Uint8Array} data - data to sign (32 bytes)
|
|
55
|
+
* @returns {Promise<Uint8Array>} signature
|
|
56
|
+
*/
|
|
57
|
+
async sign(keyId, data) {
|
|
58
|
+
const privateKeyHex = await this.privateKey(keyId);
|
|
59
|
+
return ed25519.sign(data, privateKeyHex);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Retrieves the private key for a given keyId from the key store.
|
|
63
|
+
* @param {KmsKeyId} keyId - The identifier of the key to retrieve.
|
|
64
|
+
* @returns {Promise<string>} The private key associated with the keyId.
|
|
65
|
+
*/
|
|
66
|
+
async privateKey(keyId) {
|
|
67
|
+
return this._keyStore.get({ alias: keyId.id });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hash, Proof, ZERO_HASH } from '@iden3/js-merkletree';
|
|
2
|
-
import { buildTreeState, isValidOperation, Operators, QueryOperators
|
|
2
|
+
import { buildTreeState, isValidOperation, Operators, QueryOperators } from '../circuits';
|
|
3
3
|
import { buildFieldPath, getSerializationAttrFromContext, getFieldSlotIndex } from '../verifiable';
|
|
4
4
|
import { Merklizer, Path } from '@iden3/js-jsonld-merklization';
|
|
5
5
|
import { byteEncoder } from '../utils';
|
|
@@ -119,12 +119,14 @@ export const parseQueryMetadata = async (propertyQuery, ldContextJSON, credentia
|
|
|
119
119
|
throw new Error(`field does not exist in the schema ${e.message}`);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
if (propertyQuery.operatorValue) {
|
|
122
|
+
if (propertyQuery.operatorValue !== undefined) {
|
|
123
123
|
if (!isValidOperation(query.datatype, propertyQuery.operator)) {
|
|
124
124
|
throw new Error(`operator ${propertyQuery.operator} is not supported for datatype ${query.datatype}`);
|
|
125
125
|
}
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
query.values =
|
|
127
|
+
propertyQuery.operator === Operators.EXISTS
|
|
128
|
+
? transformExistsValue(propertyQuery.operatorValue)
|
|
129
|
+
: await transformQueryValueToBigInts(propertyQuery.operatorValue, query.datatype);
|
|
128
130
|
}
|
|
129
131
|
return query;
|
|
130
132
|
};
|
|
@@ -144,3 +146,9 @@ export const transformQueryValueToBigInts = async (value, ldType) => {
|
|
|
144
146
|
}
|
|
145
147
|
return values;
|
|
146
148
|
};
|
|
149
|
+
const transformExistsValue = (value) => {
|
|
150
|
+
if (typeof value == 'boolean') {
|
|
151
|
+
return [BigInt(value)];
|
|
152
|
+
}
|
|
153
|
+
throw new Error('exists operator value must be true or false');
|
|
154
|
+
};
|
|
@@ -188,10 +188,7 @@ export class ProofService {
|
|
|
188
188
|
query.valueProof = new ValueProof();
|
|
189
189
|
query.valueProof.mtp = proof;
|
|
190
190
|
query.valueProof.path = queryMetadata.claimPathKey;
|
|
191
|
-
const mtEntry = await mtValue?.mtEntry();
|
|
192
|
-
if (!mtEntry) {
|
|
193
|
-
throw new Error(`can't merklize credential: no merkle tree entry found`);
|
|
194
|
-
}
|
|
191
|
+
const mtEntry = (await mtValue?.mtEntry()) ?? 0n;
|
|
195
192
|
query.valueProof.value = mtEntry;
|
|
196
193
|
if (!queryMetadata.fieldName) {
|
|
197
194
|
query.values = [mtEntry];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DID, Id, getUnixTimestamp } from '@iden3/js-iden3-core';
|
|
2
2
|
import { ProofType } from '../../verifiable';
|
|
3
|
-
import { AtomicQueryMTPV2Inputs, AtomicQueryMTPV2OnChainInputs, AtomicQuerySigV2Inputs, AtomicQuerySigV2OnChainInputs, AtomicQueryV3Inputs, AtomicQueryV3OnChainInputs, CircuitClaim, CircuitId, LinkedMultiQueryInputs, Operators, QueryOperators, ValueProof } from '../../circuits';
|
|
3
|
+
import { AtomicQueryMTPV2Inputs, AtomicQueryMTPV2OnChainInputs, AtomicQuerySigV2Inputs, AtomicQuerySigV2OnChainInputs, AtomicQueryV3Inputs, AtomicQueryV3OnChainInputs, CircuitClaim, CircuitId, LinkedMultiQueryInputs, Operators, QueryOperators, ValueProof, getOperatorNameByValue } from '../../circuits';
|
|
4
4
|
import { toClaimNonRevStatus, toGISTProof } from '../common';
|
|
5
5
|
import { getUserDIDFromCredential } from '../../credentials';
|
|
6
6
|
const allOperations = Object.values(QueryOperators);
|
|
@@ -48,6 +48,7 @@ export class InputGenerator {
|
|
|
48
48
|
circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
|
|
49
49
|
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
|
|
50
50
|
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
|
|
51
|
+
this.checkOperatorSupport(proofReq.circuitId, query.operator);
|
|
51
52
|
return circuitInputs.inputsMarshal();
|
|
52
53
|
};
|
|
53
54
|
this.credentialAtomicQueryMTPV2OnChainPrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
|
|
@@ -95,6 +96,7 @@ export class InputGenerator {
|
|
|
95
96
|
circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
|
|
96
97
|
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
|
|
97
98
|
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
|
|
99
|
+
this.checkOperatorSupport(proofReq.circuitId, query.operator);
|
|
98
100
|
return circuitInputs.inputsMarshal();
|
|
99
101
|
};
|
|
100
102
|
this.credentialAtomicQuerySigV2PrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
|
|
@@ -116,6 +118,7 @@ export class InputGenerator {
|
|
|
116
118
|
query.operator = this.transformV2QueryOperator(query.operator);
|
|
117
119
|
circuitInputs.query = query;
|
|
118
120
|
circuitInputs.currentTimeStamp = getUnixTimestamp(new Date());
|
|
121
|
+
this.checkOperatorSupport(proofReq.circuitId, query.operator);
|
|
119
122
|
return circuitInputs.inputsMarshal();
|
|
120
123
|
};
|
|
121
124
|
this.credentialAtomicQuerySigV2OnChainPrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
|
|
@@ -163,6 +166,7 @@ export class InputGenerator {
|
|
|
163
166
|
const signature = await this._identityWallet.signChallenge(params.challenge, authInfo.credential);
|
|
164
167
|
circuitInputs.signature = signature;
|
|
165
168
|
circuitInputs.challenge = params.challenge;
|
|
169
|
+
this.checkOperatorSupport(proofReq.circuitId, query.operator);
|
|
166
170
|
return circuitInputs.inputsMarshal();
|
|
167
171
|
};
|
|
168
172
|
this.credentialAtomicQueryV3PrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
|
|
@@ -212,6 +216,7 @@ export class InputGenerator {
|
|
|
212
216
|
circuitInputs.nullifierSessionID = proofReq.params?.nullifierSessionId
|
|
213
217
|
? BigInt(proofReq.params?.nullifierSessionId?.toString())
|
|
214
218
|
: BigInt(0);
|
|
219
|
+
this.checkOperatorSupport(proofReq.circuitId, query.operator);
|
|
215
220
|
return circuitInputs.inputsMarshal();
|
|
216
221
|
};
|
|
217
222
|
this.credentialAtomicQueryV3OnChainPrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
|
|
@@ -290,15 +295,19 @@ export class InputGenerator {
|
|
|
290
295
|
circuitInputs.treeState = authClaimData.treeState;
|
|
291
296
|
circuitInputs.signature = signature;
|
|
292
297
|
}
|
|
298
|
+
this.checkOperatorSupport(proofReq.circuitId, query.operator);
|
|
293
299
|
return circuitInputs.inputsMarshal();
|
|
294
300
|
};
|
|
295
|
-
this.linkedMultiQuery10PrepareInputs = async ({ preparedCredential, params, circuitQueries }) => {
|
|
301
|
+
this.linkedMultiQuery10PrepareInputs = async ({ preparedCredential, params, proofReq, circuitQueries }) => {
|
|
296
302
|
const circuitClaimData = await this.newCircuitClaimData(preparedCredential);
|
|
297
303
|
circuitClaimData.nonRevProof = toClaimNonRevStatus(preparedCredential.revStatus);
|
|
298
304
|
const circuitInputs = new LinkedMultiQueryInputs();
|
|
299
305
|
circuitInputs.linkNonce = params.linkNonce ?? BigInt(0);
|
|
300
306
|
circuitInputs.claim = circuitClaimData.claim;
|
|
301
307
|
circuitInputs.query = circuitQueries;
|
|
308
|
+
circuitQueries.forEach((query) => {
|
|
309
|
+
this.checkOperatorSupport(proofReq.circuitId, query.operator);
|
|
310
|
+
});
|
|
302
311
|
return circuitInputs.inputsMarshal();
|
|
303
312
|
};
|
|
304
313
|
}
|
|
@@ -383,4 +392,10 @@ export class InputGenerator {
|
|
|
383
392
|
transformV2QueryOperator(operator) {
|
|
384
393
|
return operator === Operators.SD || operator === Operators.NOOP ? Operators.EQ : operator;
|
|
385
394
|
}
|
|
395
|
+
checkOperatorSupport(circuitId, operator) {
|
|
396
|
+
const supportedOperators = circuitValidator[circuitId].supportedOperations;
|
|
397
|
+
if (!supportedOperators.includes(operator)) {
|
|
398
|
+
throw new Error(`operator ${getOperatorNameByValue(operator)} is not supported by ${circuitId}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
386
401
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DID, getDateFromUnixTimestamp } from '@iden3/js-iden3-core';
|
|
2
|
-
import { Path } from '@iden3/js-jsonld-merklization';
|
|
2
|
+
import { getDocumentLoader, Path } from '@iden3/js-jsonld-merklization';
|
|
3
3
|
import { byteEncoder, isGenesisState } from '../../utils';
|
|
4
4
|
import { calculateCoreSchemaHash, ProofType } from '../../verifiable';
|
|
5
5
|
import { AtomicQueryMTPV2PubSignals } from '../../circuits/atomic-query-mtp-v2';
|
|
@@ -9,7 +9,7 @@ import { AuthV2PubSignals } from '../../circuits/auth-v2';
|
|
|
9
9
|
import { BaseConfig } from '../../circuits/common';
|
|
10
10
|
import { LinkedMultiQueryPubSignals, LinkedMultiQueryInputs } from '../../circuits/linked-multi-query';
|
|
11
11
|
import { CircuitId } from '../../circuits/models';
|
|
12
|
-
import { checkQueryRequest, fieldValueFromVerifiablePresentation } from './query';
|
|
12
|
+
import { checkQueryRequest, fieldValueFromVerifiablePresentation, validateDisclosureV2Circuit, validateEmptyCredentialSubjectV2Circuit, validateOperators, verifyFieldValueInclusionV2, validateDisclosureNativeSDSupport, validateEmptyCredentialSubjectNoopNativeSupport, verifyFieldValueInclusionNativeExistsSupport } from './query';
|
|
13
13
|
import { parseQueriesMetadata } from '../common';
|
|
14
14
|
import { Operators } from '../../circuits';
|
|
15
15
|
import { calculateQueryHashV3 } from './query-hash';
|
|
@@ -56,7 +56,7 @@ export class PubSignalsVerifier {
|
|
|
56
56
|
valueArraySize: mtpv2PubSignals.getValueArrSize(),
|
|
57
57
|
isRevocationChecked: mtpv2PubSignals.isRevocationChecked
|
|
58
58
|
};
|
|
59
|
-
await
|
|
59
|
+
await this.checkQueryV2Circuits(CircuitId.AtomicQueryMTPV2, query, outs, opts, verifiablePresentation);
|
|
60
60
|
// verify state
|
|
61
61
|
await this.checkStateExistenceForId(mtpv2PubSignals.issuerID, mtpv2PubSignals.issuerClaimIdenState);
|
|
62
62
|
if (mtpv2PubSignals.isRevocationChecked !== 0) {
|
|
@@ -85,7 +85,7 @@ export class PubSignalsVerifier {
|
|
|
85
85
|
valueArraySize: sigV2PubSignals.getValueArrSize(),
|
|
86
86
|
isRevocationChecked: sigV2PubSignals.isRevocationChecked
|
|
87
87
|
};
|
|
88
|
-
await
|
|
88
|
+
await this.checkQueryV2Circuits(CircuitId.AtomicQuerySigV2, query, outs, opts, verifiablePresentation);
|
|
89
89
|
// verify state
|
|
90
90
|
await this.checkStateExistenceForId(sigV2PubSignals.issuerID, sigV2PubSignals.issuerAuthState);
|
|
91
91
|
if (sigV2PubSignals.isRevocationChecked !== 0) {
|
|
@@ -111,9 +111,53 @@ export class PubSignalsVerifier {
|
|
|
111
111
|
merklized: v3PubSignals.merklized,
|
|
112
112
|
claimPathKey: v3PubSignals.claimPathKey,
|
|
113
113
|
valueArraySize: v3PubSignals.getValueArrSize(),
|
|
114
|
+
operatorOutput: v3PubSignals.operatorOutput,
|
|
114
115
|
isRevocationChecked: v3PubSignals.isRevocationChecked
|
|
115
116
|
};
|
|
116
|
-
|
|
117
|
+
if (!query.type) {
|
|
118
|
+
throw new Error(`proof query type is undefined`);
|
|
119
|
+
}
|
|
120
|
+
const loader = this._documentLoader ?? getDocumentLoader();
|
|
121
|
+
// validate schema
|
|
122
|
+
let context;
|
|
123
|
+
try {
|
|
124
|
+
context = (await loader(query.context ?? '')).document;
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
throw new Error(`can't load schema for request query`);
|
|
128
|
+
}
|
|
129
|
+
const queriesMetadata = await parseQueriesMetadata(query.type, JSON.stringify(context), query.credentialSubject, {
|
|
130
|
+
documentLoader: loader
|
|
131
|
+
});
|
|
132
|
+
await checkQueryRequest(query, queriesMetadata, context, outs, CircuitId.AtomicQueryV3, this._documentLoader, opts);
|
|
133
|
+
const queryMetadata = queriesMetadata[0]; // only one query is supported
|
|
134
|
+
// validate selective disclosure
|
|
135
|
+
if (queryMetadata.operator === Operators.SD) {
|
|
136
|
+
try {
|
|
137
|
+
await validateDisclosureNativeSDSupport(queryMetadata, outs, verifiablePresentation, loader);
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
throw new Error(`failed to validate selective disclosure: ${e.message}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if (!queryMetadata.fieldName && queryMetadata.operator == Operators.NOOP) {
|
|
144
|
+
try {
|
|
145
|
+
await validateEmptyCredentialSubjectNoopNativeSupport(outs);
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
throw new Error(`failed to validate operators: ${e.message}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
try {
|
|
153
|
+
await validateOperators(queryMetadata, outs);
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
throw new Error(`failed to validate operators: ${e.message}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// verify field inclusion / non-inclusion
|
|
160
|
+
verifyFieldValueInclusionNativeExistsSupport(outs, queryMetadata);
|
|
117
161
|
const { proofType, verifierID, nullifier, nullifierSessionID, linkID } = v3PubSignals;
|
|
118
162
|
switch (query.proofType) {
|
|
119
163
|
case ProofType.BJJSignature:
|
|
@@ -288,6 +332,52 @@ export class PubSignalsVerifier {
|
|
|
288
332
|
}
|
|
289
333
|
return fn(ctx);
|
|
290
334
|
}
|
|
335
|
+
async checkQueryV2Circuits(circuitId, query, outs, opts, verifiablePresentation) {
|
|
336
|
+
if (!query.type) {
|
|
337
|
+
throw new Error(`proof query type is undefined`);
|
|
338
|
+
}
|
|
339
|
+
const loader = this._documentLoader ?? getDocumentLoader();
|
|
340
|
+
// validate schema
|
|
341
|
+
let context;
|
|
342
|
+
try {
|
|
343
|
+
context = (await loader(query.context ?? '')).document;
|
|
344
|
+
}
|
|
345
|
+
catch (e) {
|
|
346
|
+
throw new Error(`can't load schema for request query`);
|
|
347
|
+
}
|
|
348
|
+
const queriesMetadata = await parseQueriesMetadata(query.type, JSON.stringify(context), query.credentialSubject, {
|
|
349
|
+
documentLoader: loader
|
|
350
|
+
});
|
|
351
|
+
await checkQueryRequest(query, queriesMetadata, context, outs, circuitId, this._documentLoader, opts);
|
|
352
|
+
const queryMetadata = queriesMetadata[0]; // only one query is supported
|
|
353
|
+
// validate selective disclosure
|
|
354
|
+
if (queryMetadata.operator === Operators.SD) {
|
|
355
|
+
try {
|
|
356
|
+
await validateDisclosureV2Circuit(queryMetadata, outs, verifiablePresentation, loader);
|
|
357
|
+
}
|
|
358
|
+
catch (e) {
|
|
359
|
+
throw new Error(`failed to validate selective disclosure: ${e.message}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
else if (!queryMetadata.fieldName && queryMetadata.operator == Operators.NOOP) {
|
|
363
|
+
try {
|
|
364
|
+
await validateEmptyCredentialSubjectV2Circuit(queryMetadata, outs);
|
|
365
|
+
}
|
|
366
|
+
catch (e) {
|
|
367
|
+
throw new Error(`failed to validate operators: ${e.message}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
try {
|
|
372
|
+
await validateOperators(queryMetadata, outs);
|
|
373
|
+
}
|
|
374
|
+
catch (e) {
|
|
375
|
+
throw new Error(`failed to validate operators: ${e.message}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// verify field inclusion
|
|
379
|
+
verifyFieldValueInclusionV2(outs, queryMetadata);
|
|
380
|
+
}
|
|
291
381
|
async resolve(id, state) {
|
|
292
382
|
const idBigInt = id.bigInt();
|
|
293
383
|
const did = DID.parseFromId(id);
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { DID, getDateFromUnixTimestamp } from '@iden3/js-iden3-core';
|
|
2
|
-
import {
|
|
2
|
+
import { Merklizer, Path } from '@iden3/js-jsonld-merklization';
|
|
3
3
|
import { byteEncoder } from '../../utils';
|
|
4
|
-
import { Operators } from '../../circuits/comparer';
|
|
4
|
+
import { Operators, QueryOperators } from '../../circuits/comparer';
|
|
5
5
|
import { calculateCoreSchemaHash, VerifiableConstants } from '../../verifiable';
|
|
6
|
-
import { parseQueriesMetadata } from '../common';
|
|
7
6
|
import { circuitValidator } from '../provers';
|
|
8
7
|
const defaultProofGenerationDelayOpts = 24 * 60 * 60 * 1000; // 24 hours
|
|
9
|
-
export async function checkQueryRequest(query, outputs, circuitId, schemaLoader,
|
|
8
|
+
export async function checkQueryRequest(query, queriesMetadata, ldContext, outputs, circuitId, schemaLoader, opts) {
|
|
10
9
|
// validate issuer
|
|
11
10
|
const userDID = DID.parseFromId(outputs.issuerId);
|
|
12
11
|
const issuerAllowed = !query.allowedIssuers ||
|
|
@@ -14,19 +13,10 @@ export async function checkQueryRequest(query, outputs, circuitId, schemaLoader,
|
|
|
14
13
|
if (!issuerAllowed) {
|
|
15
14
|
throw new Error('issuer is not in allowed list');
|
|
16
15
|
}
|
|
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
16
|
if (!query.type) {
|
|
27
|
-
throw new Error(
|
|
17
|
+
throw new Error('query type is missing');
|
|
28
18
|
}
|
|
29
|
-
const schemaId = await Path.getTypeIDFromContext(JSON.stringify(
|
|
19
|
+
const schemaId = await Path.getTypeIDFromContext(JSON.stringify(ldContext), query.type, {
|
|
30
20
|
documentLoader: schemaLoader
|
|
31
21
|
});
|
|
32
22
|
const schemaHash = calculateCoreSchemaHash(byteEncoder.encode(schemaId));
|
|
@@ -36,9 +26,6 @@ export async function checkQueryRequest(query, outputs, circuitId, schemaLoader,
|
|
|
36
26
|
if (!query.skipClaimRevocationCheck && outputs.isRevocationChecked === 0) {
|
|
37
27
|
throw new Error(`check revocation is required`);
|
|
38
28
|
}
|
|
39
|
-
const queriesMetadata = await parseQueriesMetadata(query.type, JSON.stringify(schema), query.credentialSubject, {
|
|
40
|
-
documentLoader: schemaLoader
|
|
41
|
-
});
|
|
42
29
|
const circuitValidationData = circuitValidator[circuitId];
|
|
43
30
|
if (queriesMetadata.length > circuitValidationData.maxQueriesCount) {
|
|
44
31
|
throw new Error(`circuit ${circuitId} supports only ${circuitValidator[circuitId].maxQueriesCount} queries`);
|
|
@@ -47,64 +34,54 @@ export async function checkQueryRequest(query, outputs, circuitId, schemaLoader,
|
|
|
47
34
|
if (notSupportedOpIndx > -1) {
|
|
48
35
|
throw new Error(`circuit ${circuitId} not support ${queriesMetadata[notSupportedOpIndx].operator} operator`);
|
|
49
36
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
catch (e) {
|
|
70
|
-
throw new Error(`failed to validate operators: ${e.message}`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
try {
|
|
75
|
-
await validateOperators(metadata, outputs);
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
78
|
-
throw new Error(`failed to validate operators: ${e.message}`);
|
|
79
|
-
}
|
|
37
|
+
// verify timestamp
|
|
38
|
+
let acceptedProofGenerationDelay = defaultProofGenerationDelayOpts;
|
|
39
|
+
if (opts?.acceptedProofGenerationDelay) {
|
|
40
|
+
acceptedProofGenerationDelay = opts.acceptedProofGenerationDelay;
|
|
41
|
+
}
|
|
42
|
+
const timeDiff = Date.now() - getDateFromUnixTimestamp(Number(outputs.timestamp)).getTime();
|
|
43
|
+
if (timeDiff > acceptedProofGenerationDelay) {
|
|
44
|
+
throw new Error('generated proof is outdated');
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
export function verifyFieldValueInclusionV2(outputs, metadata) {
|
|
49
|
+
if (outputs.operator == QueryOperators.$noop) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (outputs.merklized === 1) {
|
|
53
|
+
if (outputs.claimPathNotExists === 1) {
|
|
54
|
+
throw new Error(`proof doesn't contains target query key`);
|
|
80
55
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (outputs.claimPathNotExists === 1) {
|
|
84
|
-
throw new Error(`proof doesn't contains target query key`);
|
|
85
|
-
}
|
|
86
|
-
if (outputs.claimPathKey !== metadata.claimPathKey) {
|
|
87
|
-
throw new Error(`proof was generated for another path`);
|
|
88
|
-
}
|
|
56
|
+
if (outputs.claimPathKey !== metadata.claimPathKey) {
|
|
57
|
+
throw new Error(`proof was generated for another path`);
|
|
89
58
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
if (outputs.slotIndex !== metadata.slotIndex) {
|
|
62
|
+
throw new Error(`wrong claim slot was used in claim`);
|
|
94
63
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function verifyFieldValueInclusionNativeExistsSupport(outputs, metadata) {
|
|
67
|
+
if (outputs.operator == Operators.NOOP) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (outputs.operator === Operators.EXISTS && !outputs.merklized) {
|
|
71
|
+
throw new Error('$exists operator is not supported for non-merklized credential');
|
|
72
|
+
}
|
|
73
|
+
if (outputs.merklized === 1) {
|
|
74
|
+
if (outputs.claimPathKey !== metadata.claimPathKey) {
|
|
75
|
+
throw new Error(`proof was generated for another path`);
|
|
99
76
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
if (outputs.slotIndex !== metadata.slotIndex) {
|
|
80
|
+
throw new Error(`wrong claim slot was used in claim`);
|
|
103
81
|
}
|
|
104
82
|
}
|
|
105
|
-
return;
|
|
106
83
|
}
|
|
107
|
-
async function
|
|
84
|
+
export async function validateEmptyCredentialSubjectV2Circuit(cq, outputs) {
|
|
108
85
|
if (outputs.operator !== Operators.EQ) {
|
|
109
86
|
throw new Error('empty credentialSubject request available only for equal operation');
|
|
110
87
|
}
|
|
@@ -120,7 +97,7 @@ async function validateEmptyCredentialSubject(cq, outputs) {
|
|
|
120
97
|
}
|
|
121
98
|
return;
|
|
122
99
|
}
|
|
123
|
-
async function validateOperators(cq, outputs) {
|
|
100
|
+
export async function validateOperators(cq, outputs) {
|
|
124
101
|
if (outputs.operator !== cq.operator) {
|
|
125
102
|
throw new Error(`operator that was used is not equal to request`);
|
|
126
103
|
}
|
|
@@ -137,7 +114,11 @@ async function validateOperators(cq, outputs) {
|
|
|
137
114
|
}
|
|
138
115
|
}
|
|
139
116
|
}
|
|
140
|
-
async function
|
|
117
|
+
export async function validateDisclosureV2Circuit(cq, outputs, verifiablePresentation, ldLoader) {
|
|
118
|
+
const bi = await fieldValueFromVerifiablePresentation(cq.fieldName, verifiablePresentation, ldLoader);
|
|
119
|
+
if (bi !== outputs.value[0]) {
|
|
120
|
+
throw new Error(`value that was used is not equal to requested in query`);
|
|
121
|
+
}
|
|
141
122
|
if (outputs.operator !== Operators.EQ) {
|
|
142
123
|
throw new Error(`operator for selective disclosure must be $eq`);
|
|
143
124
|
}
|
|
@@ -146,9 +127,29 @@ async function validateDisclosure(cq, outputs, verifiablePresentation, ldLoader)
|
|
|
146
127
|
throw new Error(`selective disclosure not available for array of values`);
|
|
147
128
|
}
|
|
148
129
|
}
|
|
130
|
+
}
|
|
131
|
+
export async function validateDisclosureNativeSDSupport(cq, outputs, verifiablePresentation, ldLoader) {
|
|
149
132
|
const bi = await fieldValueFromVerifiablePresentation(cq.fieldName, verifiablePresentation, ldLoader);
|
|
150
|
-
if (bi !== outputs.
|
|
151
|
-
throw new Error(`
|
|
133
|
+
if (bi !== outputs.operatorOutput) {
|
|
134
|
+
throw new Error(`operator output should be equal to disclosed value`);
|
|
135
|
+
}
|
|
136
|
+
if (outputs.operator !== Operators.SD) {
|
|
137
|
+
throw new Error(`operator for selective disclosure must be $sd`);
|
|
138
|
+
}
|
|
139
|
+
for (let index = 0; index < outputs.value.length; index++) {
|
|
140
|
+
if (outputs.value[index] !== 0n) {
|
|
141
|
+
throw new Error(`public signal values must be zero`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export async function validateEmptyCredentialSubjectNoopNativeSupport(outputs) {
|
|
146
|
+
if (outputs.operator !== Operators.NOOP) {
|
|
147
|
+
throw new Error('empty credentialSubject request available only for $noop operation');
|
|
148
|
+
}
|
|
149
|
+
for (let index = 1; index < outputs.value.length; index++) {
|
|
150
|
+
if (outputs.value[index] !== 0n) {
|
|
151
|
+
throw new Error(`empty credentialSubject request not available for array of values`);
|
|
152
|
+
}
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
export const fieldValueFromVerifiablePresentation = async (fieldName, verifiablePresentation, ldLoader) => {
|
|
@@ -162,7 +162,7 @@ export class FilterQuery {
|
|
|
162
162
|
}
|
|
163
163
|
const credentialPathValue = resolvePath(credential, this.path);
|
|
164
164
|
if ((credentialPathValue === null || credentialPathValue === undefined) &&
|
|
165
|
-
this.operatorFunc !==
|
|
165
|
+
this.operatorFunc !== comparatorOptions.$exists) {
|
|
166
166
|
return false;
|
|
167
167
|
}
|
|
168
168
|
if (this.isReverseParams) {
|
|
@@ -50,6 +50,7 @@ export declare const QueryOperators: {
|
|
|
50
50
|
$sd: Operators;
|
|
51
51
|
$nullify: Operators;
|
|
52
52
|
};
|
|
53
|
+
export declare const getOperatorNameByValue: (operator: number) => string;
|
|
53
54
|
export declare const availableTypesOperators: Map<string, Operators[]>;
|
|
54
55
|
/**
|
|
55
56
|
* Checks if the given operation is valid for the specified datatype.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { IKeyProvider } from '../kms';
|
|
2
|
+
import { AbstractPrivateKeyStore, KmsKeyId, KmsKeyType } from '../store';
|
|
3
|
+
/**
|
|
4
|
+
* Provider for Ed25519 keys
|
|
5
|
+
* @public
|
|
6
|
+
* @class Ed25519Provider
|
|
7
|
+
* @implements IKeyProvider interface
|
|
8
|
+
*/
|
|
9
|
+
export declare class Ed25519Provider implements IKeyProvider {
|
|
10
|
+
readonly keyType: KmsKeyType;
|
|
11
|
+
private readonly _keyStore;
|
|
12
|
+
/**
|
|
13
|
+
* Creates an instance of Ed25519Provider.
|
|
14
|
+
* @param {KmsKeyType} keyType - kms key type
|
|
15
|
+
* @param {AbstractPrivateKeyStore} keyStore - key store for kms
|
|
16
|
+
*/
|
|
17
|
+
constructor(keyType: KmsKeyType, _keyStore: AbstractPrivateKeyStore);
|
|
18
|
+
/**
|
|
19
|
+
* generates a ed25519 key from a seed phrase
|
|
20
|
+
* @param {Uint8Array} seed - byte array seed
|
|
21
|
+
* @returns {Promise<KmsKeyId>} kms key identifier
|
|
22
|
+
*/
|
|
23
|
+
newPrivateKeyFromSeed(seed: Uint8Array): Promise<KmsKeyId>;
|
|
24
|
+
/**
|
|
25
|
+
* Gets public key by kmsKeyId
|
|
26
|
+
* @param {KmsKeyId} keyId - key identifier
|
|
27
|
+
* @returns {Promise<string>} Public key as a hex string
|
|
28
|
+
*/
|
|
29
|
+
publicKey(keyId: KmsKeyId): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* signs prepared payload of size,
|
|
32
|
+
* with a key id
|
|
33
|
+
* @param {KmsKeyId} keyId - key identifier
|
|
34
|
+
* @param {Uint8Array} data - data to sign (32 bytes)
|
|
35
|
+
* @returns {Promise<Uint8Array>} signature
|
|
36
|
+
*/
|
|
37
|
+
sign(keyId: KmsKeyId, data: Uint8Array): Promise<Uint8Array>;
|
|
38
|
+
/**
|
|
39
|
+
* Retrieves the private key for a given keyId from the key store.
|
|
40
|
+
* @param {KmsKeyId} keyId - The identifier of the key to retrieve.
|
|
41
|
+
* @returns {Promise<string>} The private key associated with the keyId.
|
|
42
|
+
*/
|
|
43
|
+
private privateKey;
|
|
44
|
+
}
|