@0xpolygonid/js-sdk 1.8.3 → 1.9.1
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 +420 -189
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.js +425 -189
- package/dist/browser/umd/index.js.map +1 -1
- package/dist/node/cjs/circuits/atomic-query-v3-on-chain.js +8 -25
- package/dist/node/cjs/circuits/atomic-query-v3.js +6 -5
- package/dist/node/cjs/circuits/common.js +1 -1
- package/dist/node/cjs/circuits/comparer.js +24 -3
- package/dist/node/cjs/circuits/linked-multi-query.js +6 -17
- package/dist/node/cjs/circuits/models.js +47 -3
- package/dist/node/cjs/iden3comm/handlers/auth.js +14 -55
- package/dist/node/cjs/iden3comm/handlers/common.js +85 -0
- package/dist/node/cjs/iden3comm/handlers/contract-request.js +6 -25
- package/dist/node/cjs/iden3comm/handlers/index.js +2 -0
- package/dist/node/cjs/iden3comm/handlers/revocation-status.js +119 -0
- package/dist/node/cjs/identity/identity-wallet.js +4 -0
- package/dist/node/cjs/proof/common.js +11 -5
- package/dist/node/cjs/proof/provers/inputs-generator.js +6 -10
- package/dist/node/cjs/proof/verifiers/index.js +1 -0
- package/dist/node/cjs/proof/verifiers/pub-signals-verifier.js +37 -22
- package/dist/node/cjs/proof/verifiers/query-hash.js +40 -0
- package/dist/node/cjs/proof/verifiers/query.js +24 -16
- package/dist/node/cjs/schema-processor/utils.js +2 -2
- package/dist/node/cjs/storage/filters/jsonQuery.js +28 -2
- package/dist/node/cjs/verifiable/core-utils.js +3 -3
- package/dist/node/cjs/verifiable/credential.js +1 -1
- package/dist/node/esm/circuits/atomic-query-v3-on-chain.js +9 -26
- package/dist/node/esm/circuits/atomic-query-v3.js +7 -6
- package/dist/node/esm/circuits/common.js +1 -1
- package/dist/node/esm/circuits/comparer.js +24 -3
- package/dist/node/esm/circuits/linked-multi-query.js +7 -18
- package/dist/node/esm/circuits/models.js +48 -4
- package/dist/node/esm/iden3comm/handlers/auth.js +15 -56
- package/dist/node/esm/iden3comm/handlers/common.js +81 -0
- package/dist/node/esm/iden3comm/handlers/contract-request.js +7 -26
- package/dist/node/esm/iden3comm/handlers/index.js +2 -0
- package/dist/node/esm/iden3comm/handlers/revocation-status.js +92 -0
- package/dist/node/esm/identity/identity-wallet.js +4 -0
- package/dist/node/esm/proof/common.js +12 -6
- package/dist/node/esm/proof/provers/inputs-generator.js +7 -11
- package/dist/node/esm/proof/verifiers/index.js +1 -0
- package/dist/node/esm/proof/verifiers/pub-signals-verifier.js +41 -26
- package/dist/node/esm/proof/verifiers/query-hash.js +35 -0
- package/dist/node/esm/proof/verifiers/query.js +23 -16
- package/dist/node/esm/schema-processor/utils.js +3 -3
- package/dist/node/esm/storage/filters/jsonQuery.js +28 -2
- package/dist/node/esm/verifiable/core-utils.js +1 -1
- package/dist/node/esm/verifiable/credential.js +2 -2
- package/dist/types/circuits/atomic-query-v3-on-chain.d.ts +4 -8
- package/dist/types/circuits/atomic-query-v3.d.ts +2 -2
- package/dist/types/circuits/common.d.ts +1 -1
- package/dist/types/circuits/comparer.d.ts +4 -0
- package/dist/types/circuits/linked-multi-query.d.ts +0 -1
- package/dist/types/circuits/models.d.ts +7 -4
- package/dist/types/iden3comm/handlers/auth.d.ts +1 -0
- package/dist/types/iden3comm/handlers/common.d.ts +23 -0
- package/dist/types/iden3comm/handlers/contract-request.d.ts +1 -1
- package/dist/types/iden3comm/handlers/index.d.ts +2 -0
- package/dist/types/iden3comm/handlers/revocation-status.d.ts +59 -0
- package/dist/types/iden3comm/types/protocol/contract-request.d.ts +1 -0
- package/dist/types/identity/identity-wallet.d.ts +13 -1
- package/dist/types/proof/verifiers/index.d.ts +1 -0
- package/dist/types/proof/verifiers/query-hash.d.ts +3 -0
- package/dist/types/proof/verifiers/query.d.ts +1 -0
- package/dist/types/schema-processor/utils.d.ts +1 -1
- package/dist/types/storage/filters/jsonQuery.d.ts +1 -1
- package/dist/types/verifiable/core-utils.d.ts +1 -1
- package/dist/types/verifiable/credential.d.ts +1 -1
- package/dist/types/verifiable/proof.d.ts +5 -1
- package/package.json +1 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { PROTOCOL_MESSAGE_TYPE } from '../constants';
|
|
2
|
+
import { MediaType } from '../constants';
|
|
3
|
+
import { DID } from '@iden3/js-iden3-core';
|
|
4
|
+
import * as uuid from 'uuid';
|
|
5
|
+
import { byteEncoder } from '../../utils';
|
|
6
|
+
import { proving } from '@iden3/js-jwz';
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* Allows to process RevocationStatusRequest protocol message
|
|
10
|
+
*
|
|
11
|
+
|
|
12
|
+
* @class RevocationStatusHandler
|
|
13
|
+
* @implements implements IRevocationStatusHandler interface
|
|
14
|
+
*/
|
|
15
|
+
export class RevocationStatusHandler {
|
|
16
|
+
/**
|
|
17
|
+
* Creates an instance of RevocationStatusHandler.
|
|
18
|
+
* @param {IPackageManager} _packerMgr - package manager to unpack message envelope
|
|
19
|
+
* @param {IIdentityWallet} _identityWallet - identity wallet
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
constructor(_packerMgr, _identityWallet) {
|
|
23
|
+
this._packerMgr = _packerMgr;
|
|
24
|
+
this._identityWallet = _identityWallet;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* @inheritdoc IRevocationStatusHandler#parseRevocationStatusRequest
|
|
28
|
+
*/
|
|
29
|
+
async parseRevocationStatusRequest(request) {
|
|
30
|
+
const { unpackedMessage: message } = await this._packerMgr.unpack(request);
|
|
31
|
+
const ciRequest = message;
|
|
32
|
+
if (message.type !== PROTOCOL_MESSAGE_TYPE.REVOCATION_STATUS_REQUEST_MESSAGE_TYPE) {
|
|
33
|
+
throw new Error('Invalid media type');
|
|
34
|
+
}
|
|
35
|
+
return ciRequest;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* @inheritdoc IRevocationStatusHandler#handleRevocationStatusRequest
|
|
39
|
+
*/
|
|
40
|
+
async handleRevocationStatusRequest(did, request, opts) {
|
|
41
|
+
if (!opts) {
|
|
42
|
+
opts = {
|
|
43
|
+
mediaType: MediaType.PlainMessage
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (opts.mediaType === MediaType.SignedMessage && !opts.packerOptions) {
|
|
47
|
+
throw new Error(`jws packer options are required for ${MediaType.SignedMessage}`);
|
|
48
|
+
}
|
|
49
|
+
const rsRequest = await this.parseRevocationStatusRequest(request);
|
|
50
|
+
if (!rsRequest.to) {
|
|
51
|
+
throw new Error(`failed request. empty 'to' field`);
|
|
52
|
+
}
|
|
53
|
+
if (!rsRequest.from) {
|
|
54
|
+
throw new Error(`failed request. empty 'from' field`);
|
|
55
|
+
}
|
|
56
|
+
if (!rsRequest.body?.revocation_nonce) {
|
|
57
|
+
throw new Error(`failed request. empty 'revocation_nonce' field`);
|
|
58
|
+
}
|
|
59
|
+
const issuerDID = DID.parse(rsRequest.to);
|
|
60
|
+
const mtpWithTreeState = await this._identityWallet.generateNonRevocationMtpWithNonce(issuerDID, BigInt(rsRequest.body.revocation_nonce), opts?.treeState);
|
|
61
|
+
const treeState = mtpWithTreeState.treeState;
|
|
62
|
+
const revStatus = {
|
|
63
|
+
issuer: {
|
|
64
|
+
state: treeState?.state.string(),
|
|
65
|
+
claimsTreeRoot: treeState.claimsRoot.string(),
|
|
66
|
+
revocationTreeRoot: treeState.revocationRoot.string(),
|
|
67
|
+
rootOfRoots: treeState.rootOfRoots.string()
|
|
68
|
+
},
|
|
69
|
+
mtp: mtpWithTreeState.proof
|
|
70
|
+
};
|
|
71
|
+
const packerOpts = opts.mediaType === MediaType.SignedMessage
|
|
72
|
+
? opts.packerOptions
|
|
73
|
+
: {
|
|
74
|
+
provingMethodAlg: proving.provingMethodGroth16AuthV2Instance.methodAlg
|
|
75
|
+
};
|
|
76
|
+
const senderDID = DID.parse(rsRequest.to);
|
|
77
|
+
const guid = uuid.v4();
|
|
78
|
+
const response = {
|
|
79
|
+
id: guid,
|
|
80
|
+
typ: MediaType.PlainMessage,
|
|
81
|
+
type: PROTOCOL_MESSAGE_TYPE.REVOCATION_STATUS_RESPONSE_MESSAGE_TYPE,
|
|
82
|
+
thid: rsRequest.thid ?? guid,
|
|
83
|
+
body: revStatus,
|
|
84
|
+
from: did.string(),
|
|
85
|
+
to: rsRequest.from
|
|
86
|
+
};
|
|
87
|
+
return this._packerMgr.pack(opts.mediaType, byteEncoder.encode(JSON.stringify(response)), {
|
|
88
|
+
senderDID,
|
|
89
|
+
...packerOpts
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -227,6 +227,10 @@ export class IdentityWallet {
|
|
|
227
227
|
async generateNonRevocationMtp(did, credential, treeState) {
|
|
228
228
|
const coreClaim = await this.getCoreClaimFromCredential(credential);
|
|
229
229
|
const revNonce = coreClaim.getRevocationNonce();
|
|
230
|
+
return this.generateNonRevocationMtpWithNonce(did, revNonce, treeState);
|
|
231
|
+
}
|
|
232
|
+
/** {@inheritDoc IIdentityWallet.generateNonRevocationMtpWithNonce} */
|
|
233
|
+
async generateNonRevocationMtpWithNonce(did, revNonce, treeState) {
|
|
230
234
|
const treesModel = await this.getDIDTreeModel(did);
|
|
231
235
|
const revocationTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(did.string(), MerkleTreeType.Revocations);
|
|
232
236
|
const claimsRoot = await treesModel.claimsTree.root();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hash, Proof, ZERO_HASH } from '@iden3/js-merkletree';
|
|
2
|
-
import { buildTreeState, isValidOperation, QueryOperators } from '../circuits';
|
|
2
|
+
import { buildTreeState, isValidOperation, Operators, QueryOperators, XSDNS } 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';
|
|
@@ -84,16 +84,21 @@ export const parseCredentialSubject = (credentialSubject) => {
|
|
|
84
84
|
return queries;
|
|
85
85
|
};
|
|
86
86
|
export const parseQueryMetadata = async (propertyQuery, ldContextJSON, credentialType, options) => {
|
|
87
|
-
const datatype = await Path.newTypeFromContext(ldContextJSON, `${credentialType}.${propertyQuery.fieldName}`, options);
|
|
88
87
|
const query = {
|
|
89
88
|
...propertyQuery,
|
|
90
89
|
slotIndex: 0,
|
|
91
90
|
merklizedSchema: false,
|
|
92
|
-
datatype:
|
|
91
|
+
datatype: '',
|
|
93
92
|
claimPathKey: BigInt(0),
|
|
94
93
|
values: [],
|
|
95
94
|
path: new Path()
|
|
96
95
|
};
|
|
96
|
+
if (!propertyQuery.fieldName && propertyQuery.operator !== Operators.NOOP) {
|
|
97
|
+
throw new Error('query must have a field name if operator is not $noop');
|
|
98
|
+
}
|
|
99
|
+
if (propertyQuery.fieldName) {
|
|
100
|
+
query.datatype = await Path.newTypeFromContext(ldContextJSON, `${credentialType}.${propertyQuery.fieldName}`, options);
|
|
101
|
+
}
|
|
97
102
|
const serAttr = await getSerializationAttrFromContext(JSON.parse(ldContextJSON), options, credentialType);
|
|
98
103
|
if (!serAttr) {
|
|
99
104
|
query.merklizedSchema = true;
|
|
@@ -115,9 +120,10 @@ export const parseQueryMetadata = async (propertyQuery, ldContextJSON, credentia
|
|
|
115
120
|
}
|
|
116
121
|
}
|
|
117
122
|
if (propertyQuery.operatorValue) {
|
|
118
|
-
if (!isValidOperation(datatype, propertyQuery.operator)) {
|
|
119
|
-
throw new Error(`operator ${propertyQuery.operator} is not supported for datatype ${datatype}`);
|
|
123
|
+
if (!isValidOperation(query.datatype, propertyQuery.operator)) {
|
|
124
|
+
throw new Error(`operator ${propertyQuery.operator} is not supported for datatype ${query.datatype}`);
|
|
120
125
|
}
|
|
126
|
+
const datatype = propertyQuery.operator === Operators.EXISTS ? XSDNS.Boolean : query.datatype;
|
|
121
127
|
query.values = await transformQueryValueToBigInts(propertyQuery.operatorValue, datatype);
|
|
122
128
|
}
|
|
123
129
|
return query;
|
|
@@ -127,7 +133,7 @@ export const parseQueriesMetadata = async (credentialType, ldContextJSON, creden
|
|
|
127
133
|
return Promise.all(queriesMetadata.map((m) => parseQueryMetadata(m, ldContextJSON, credentialType, options)));
|
|
128
134
|
};
|
|
129
135
|
export const transformQueryValueToBigInts = async (value, ldType) => {
|
|
130
|
-
const values =
|
|
136
|
+
const values = [];
|
|
131
137
|
if (Array.isArray(value)) {
|
|
132
138
|
for (let index = 0; index < value.length; index++) {
|
|
133
139
|
values[index] = await Merklizer.hashValue(ldType, value[index]);
|
|
@@ -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,
|
|
3
|
+
import { AtomicQueryMTPV2Inputs, AtomicQueryMTPV2OnChainInputs, AtomicQuerySigV2Inputs, AtomicQuerySigV2OnChainInputs, AtomicQueryV3Inputs, AtomicQueryV3OnChainInputs, CircuitClaim, CircuitId, LinkedMultiQueryInputs, Operators, QueryOperators, ValueProof } from '../../circuits';
|
|
4
4
|
import { toClaimNonRevStatus, toGISTProof } from '../common';
|
|
5
5
|
import { getUserDIDFromCredential } from '../../credentials';
|
|
6
6
|
const allOperations = Object.values(QueryOperators);
|
|
@@ -202,10 +202,8 @@ export class InputGenerator {
|
|
|
202
202
|
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
|
|
203
203
|
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
|
|
204
204
|
const query = circuitQueries[0];
|
|
205
|
-
query.values =
|
|
206
|
-
|
|
207
|
-
? new Array(defaultValueArraySize).fill(0)
|
|
208
|
-
: query.values;
|
|
205
|
+
query.values = [Operators.SD, Operators.NOOP].includes(query.operator) ? [] : query.values;
|
|
206
|
+
query.valueProof = query.operator === Operators.NOOP ? new ValueProof() : query.valueProof;
|
|
209
207
|
circuitInputs.query = query;
|
|
210
208
|
circuitInputs.currentTimeStamp = getUnixTimestamp(new Date());
|
|
211
209
|
circuitInputs.proofType = proofType;
|
|
@@ -253,10 +251,8 @@ export class InputGenerator {
|
|
|
253
251
|
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
|
|
254
252
|
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
|
|
255
253
|
const query = circuitQueries[0];
|
|
256
|
-
query.values =
|
|
257
|
-
|
|
258
|
-
? new Array(defaultValueArraySize).fill(0)
|
|
259
|
-
: query.values;
|
|
254
|
+
query.values = [Operators.SD, Operators.NOOP].includes(query.operator) ? [] : query.values;
|
|
255
|
+
query.valueProof = query.operator === Operators.NOOP ? new ValueProof() : query.valueProof;
|
|
260
256
|
circuitInputs.query = query;
|
|
261
257
|
circuitInputs.currentTimeStamp = getUnixTimestamp(new Date());
|
|
262
258
|
circuitInputs.proofType = proofType;
|
|
@@ -272,7 +268,7 @@ export class InputGenerator {
|
|
|
272
268
|
catch {
|
|
273
269
|
isEthIdentity = false;
|
|
274
270
|
}
|
|
275
|
-
circuitInputs.
|
|
271
|
+
circuitInputs.isBJJAuthEnabled = isEthIdentity ? 0 : 1;
|
|
276
272
|
circuitInputs.challenge = BigInt(params.challenge ?? 0);
|
|
277
273
|
const { nonce: authProfileNonce, genesisDID } = await this._identityWallet.getGenesisDIDMetadata(identifier);
|
|
278
274
|
const id = DID.idFromDID(genesisDID);
|
|
@@ -280,7 +276,7 @@ export class InputGenerator {
|
|
|
280
276
|
const gistProof = toGISTProof(stateProof);
|
|
281
277
|
circuitInputs.gistProof = gistProof;
|
|
282
278
|
// auth inputs
|
|
283
|
-
if (circuitInputs.
|
|
279
|
+
if (circuitInputs.isBJJAuthEnabled === 1) {
|
|
284
280
|
const authPrepared = await this.prepareAuthBJJCredential(genesisDID);
|
|
285
281
|
const authClaimData = await this.newCircuitClaimData({
|
|
286
282
|
credential: authPrepared.credential,
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { poseidon } from '@iden3/js-crypto';
|
|
2
1
|
import { DID, getDateFromUnixTimestamp } from '@iden3/js-iden3-core';
|
|
3
2
|
import { Path } from '@iden3/js-jsonld-merklization';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { byteEncoder, isGenesisState } from '../../utils';
|
|
4
|
+
import { calculateCoreSchemaHash, ProofType } from '../../verifiable';
|
|
6
5
|
import { AtomicQueryMTPV2PubSignals } from '../../circuits/atomic-query-mtp-v2';
|
|
7
6
|
import { AtomicQuerySigV2PubSignals } from '../../circuits/atomic-query-sig-v2';
|
|
8
7
|
import { AtomicQueryV3PubSignals } from '../../circuits/atomic-query-v3';
|
|
9
8
|
import { AuthV2PubSignals } from '../../circuits/auth-v2';
|
|
10
9
|
import { BaseConfig } from '../../circuits/common';
|
|
11
|
-
import { LinkedMultiQueryPubSignals } from '../../circuits/linked-multi-query';
|
|
10
|
+
import { LinkedMultiQueryPubSignals, LinkedMultiQueryInputs } from '../../circuits/linked-multi-query';
|
|
12
11
|
import { CircuitId } from '../../circuits/models';
|
|
13
|
-
import { checkQueryRequest } from './query';
|
|
12
|
+
import { checkQueryRequest, fieldValueFromVerifiablePresentation } from './query';
|
|
14
13
|
import { parseQueriesMetadata } from '../common';
|
|
14
|
+
import { Operators } from '../../circuits';
|
|
15
|
+
import { calculateQueryHashV3 } from './query-hash';
|
|
15
16
|
export const userStateError = new Error(`user state is not valid`);
|
|
16
17
|
const zeroInt = 0n;
|
|
17
18
|
const defaultProofVerifyOpts = 1 * 60 * 60 * 1000; // 1 hour
|
|
@@ -109,7 +110,6 @@ export class PubSignalsVerifier {
|
|
|
109
110
|
timestamp: v3PubSignals.timestamp,
|
|
110
111
|
merklized: v3PubSignals.merklized,
|
|
111
112
|
claimPathKey: v3PubSignals.claimPathKey,
|
|
112
|
-
claimPathNotExists: v3PubSignals.claimPathNotExists,
|
|
113
113
|
valueArraySize: v3PubSignals.getValueArrSize(),
|
|
114
114
|
isRevocationChecked: v3PubSignals.isRevocationChecked
|
|
115
115
|
};
|
|
@@ -186,7 +186,7 @@ export class PubSignalsVerifier {
|
|
|
186
186
|
this.verifyIdOwnership(sender, challenge);
|
|
187
187
|
return new BaseConfig();
|
|
188
188
|
};
|
|
189
|
-
this.linkedMultiQuery10Verify = async ({ query, pubSignals }) => {
|
|
189
|
+
this.linkedMultiQuery10Verify = async ({ query, verifiablePresentation, pubSignals }) => {
|
|
190
190
|
let multiQueryPubSignals = new LinkedMultiQueryPubSignals();
|
|
191
191
|
multiQueryPubSignals = multiQueryPubSignals.pubSignalsUnmarshal(byteEncoder.encode(JSON.stringify(pubSignals)));
|
|
192
192
|
// verify query
|
|
@@ -200,26 +200,41 @@ export class PubSignalsVerifier {
|
|
|
200
200
|
}
|
|
201
201
|
const ldContextJSON = JSON.stringify(schema);
|
|
202
202
|
const credentialSubject = query.credentialSubject;
|
|
203
|
-
const schemaId = await Path.getTypeIDFromContext(
|
|
204
|
-
const schemaHash =
|
|
203
|
+
const schemaId = await Path.getTypeIDFromContext(ldContextJSON, query.type || '', ldOpts);
|
|
204
|
+
const schemaHash = calculateCoreSchemaHash(byteEncoder.encode(schemaId));
|
|
205
205
|
const queriesMetadata = await parseQueriesMetadata(query.type || '', ldContextJSON, credentialSubject, ldOpts);
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
206
|
+
const request = [];
|
|
207
|
+
const merklized = queriesMetadata[0]?.merklizedSchema ? 1 : 0;
|
|
208
|
+
for (let i = 0; i < LinkedMultiQueryInputs.queryCount; i++) {
|
|
209
|
+
const queryMeta = queriesMetadata[i];
|
|
210
|
+
const values = queryMeta?.values ?? [];
|
|
211
|
+
const valArrSize = values.length;
|
|
212
|
+
const queryHash = calculateQueryHashV3(values, schemaHash, queryMeta?.slotIndex ?? 0, queryMeta?.operator ?? 0, queryMeta?.claimPathKey.toString() ?? 0, valArrSize, merklized, 0, 0, 0);
|
|
213
|
+
request.push({ queryHash, queryMeta });
|
|
214
|
+
}
|
|
215
|
+
const queryHashCompare = (a, b) => {
|
|
216
|
+
if (a.queryHash < b.queryHash)
|
|
217
|
+
return -1;
|
|
218
|
+
if (a.queryHash > b.queryHash)
|
|
219
|
+
return 1;
|
|
220
|
+
return 0;
|
|
221
|
+
};
|
|
222
|
+
const pubSignalsMeta = multiQueryPubSignals.circuitQueryHash.map((queryHash, index) => ({
|
|
223
|
+
queryHash,
|
|
224
|
+
operatorOutput: multiQueryPubSignals.operatorOutput[index]
|
|
225
|
+
}));
|
|
226
|
+
pubSignalsMeta.sort(queryHashCompare);
|
|
227
|
+
request.sort(queryHashCompare);
|
|
228
|
+
for (let i = 0; i < LinkedMultiQueryInputs.queryCount; i++) {
|
|
229
|
+
if (request[i].queryHash != pubSignalsMeta[i].queryHash) {
|
|
230
|
+
throw new Error('query hashes do not match');
|
|
231
|
+
}
|
|
232
|
+
if (request[i].queryMeta?.operator === Operators.SD) {
|
|
233
|
+
const disclosedValue = await fieldValueFromVerifiablePresentation(request[i].queryMeta.fieldName, verifiablePresentation, this._documentLoader);
|
|
234
|
+
if (disclosedValue != pubSignalsMeta[i].operatorOutput) {
|
|
235
|
+
throw new Error('disclosed value is not in the proof outputs');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
223
238
|
}
|
|
224
239
|
return multiQueryPubSignals;
|
|
225
240
|
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { poseidon } from '@iden3/js-crypto';
|
|
2
|
+
import { defaultValueArraySize, prepareCircuitArrayValues } from '../../circuits';
|
|
3
|
+
export function calculateQueryHashV2(values, schema, slotIndex, operator, claimPathKey, claimPathNotExists) {
|
|
4
|
+
const expValue = prepareCircuitArrayValues(values, 64);
|
|
5
|
+
const valueHash = poseidon.spongeHashX(expValue, 6);
|
|
6
|
+
return poseidon.hash([
|
|
7
|
+
schema.bigInt(),
|
|
8
|
+
BigInt(slotIndex),
|
|
9
|
+
BigInt(operator),
|
|
10
|
+
BigInt(claimPathKey),
|
|
11
|
+
BigInt(claimPathNotExists),
|
|
12
|
+
valueHash
|
|
13
|
+
]);
|
|
14
|
+
}
|
|
15
|
+
export function calculateQueryHashV3(values, schema, slotIndex, operator, claimPathKey, valueArraySize, merklized, isRevocationChecked, verifierID, nullifierSessionID) {
|
|
16
|
+
const expValue = prepareCircuitArrayValues(values, defaultValueArraySize);
|
|
17
|
+
const valueHash = poseidon.spongeHashX(expValue, 6);
|
|
18
|
+
const firstPartQueryHash = poseidon.hash([
|
|
19
|
+
schema.bigInt(),
|
|
20
|
+
BigInt(slotIndex),
|
|
21
|
+
BigInt(operator),
|
|
22
|
+
BigInt(claimPathKey),
|
|
23
|
+
BigInt(merklized),
|
|
24
|
+
valueHash
|
|
25
|
+
]);
|
|
26
|
+
const queryHash = poseidon.hash([
|
|
27
|
+
firstPartQueryHash,
|
|
28
|
+
BigInt(valueArraySize),
|
|
29
|
+
BigInt(isRevocationChecked),
|
|
30
|
+
BigInt(verifierID),
|
|
31
|
+
BigInt(nullifierSessionID),
|
|
32
|
+
0n
|
|
33
|
+
]);
|
|
34
|
+
return queryHash;
|
|
35
|
+
}
|
|
@@ -2,7 +2,7 @@ import { DID, getDateFromUnixTimestamp } from '@iden3/js-iden3-core';
|
|
|
2
2
|
import { getDocumentLoader, Merklizer, Path } from '@iden3/js-jsonld-merklization';
|
|
3
3
|
import { byteEncoder } from '../../utils';
|
|
4
4
|
import { Operators } from '../../circuits/comparer';
|
|
5
|
-
import {
|
|
5
|
+
import { calculateCoreSchemaHash, VerifiableConstants } from '../../verifiable';
|
|
6
6
|
import { parseQueriesMetadata } from '../common';
|
|
7
7
|
import { circuitValidator } from '../provers';
|
|
8
8
|
const defaultProofGenerationDelayOpts = 24 * 60 * 60 * 1000; // 24 hours
|
|
@@ -29,7 +29,7 @@ export async function checkQueryRequest(query, outputs, circuitId, schemaLoader,
|
|
|
29
29
|
const schemaId = await Path.getTypeIDFromContext(JSON.stringify(schema), query.type, {
|
|
30
30
|
documentLoader: schemaLoader
|
|
31
31
|
});
|
|
32
|
-
const schemaHash =
|
|
32
|
+
const schemaHash = calculateCoreSchemaHash(byteEncoder.encode(schemaId));
|
|
33
33
|
if (schemaHash.bigInt() !== outputs.schemaHash.bigInt()) {
|
|
34
34
|
throw new Error(`schema that was used is not equal to requested in query`);
|
|
35
35
|
}
|
|
@@ -47,7 +47,8 @@ export async function checkQueryRequest(query, outputs, circuitId, schemaLoader,
|
|
|
47
47
|
if (notSupportedOpIndx > -1) {
|
|
48
48
|
throw new Error(`circuit ${circuitId} not support ${queriesMetadata[notSupportedOpIndx].operator} operator`);
|
|
49
49
|
}
|
|
50
|
-
queriesMetadata.
|
|
50
|
+
for (let i = 0; i < queriesMetadata.length; i++) {
|
|
51
|
+
const metadata = queriesMetadata[i];
|
|
51
52
|
if (!query.type) {
|
|
52
53
|
throw new Error(`proof query type is undefined`);
|
|
53
54
|
}
|
|
@@ -100,7 +101,7 @@ export async function checkQueryRequest(query, outputs, circuitId, schemaLoader,
|
|
|
100
101
|
if (timeDiff > acceptedProofGenerationDelay) {
|
|
101
102
|
throw new Error('generated proof is outdated');
|
|
102
103
|
}
|
|
103
|
-
}
|
|
104
|
+
}
|
|
104
105
|
return;
|
|
105
106
|
}
|
|
106
107
|
async function validateEmptyCredentialSubject(cq, outputs) {
|
|
@@ -129,14 +130,14 @@ async function validateOperators(cq, outputs) {
|
|
|
129
130
|
}
|
|
130
131
|
for (let index = 0; index < outputs.value.length; index++) {
|
|
131
132
|
if (outputs.value[index] !== cq.values[index]) {
|
|
133
|
+
if (outputs.value[index] === 0n && cq.values[index] === undefined) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
132
136
|
throw new Error(`comparison value that was used is not equal to requested in query`);
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
}
|
|
136
140
|
async function validateDisclosure(cq, outputs, verifiablePresentation, ldLoader) {
|
|
137
|
-
if (!verifiablePresentation) {
|
|
138
|
-
throw new Error(`verifiablePresentation is required for selective disclosure request`);
|
|
139
|
-
}
|
|
140
141
|
if (outputs.operator !== Operators.EQ) {
|
|
141
142
|
throw new Error(`operator for selective disclosure must be $eq`);
|
|
142
143
|
}
|
|
@@ -145,6 +146,15 @@ async function validateDisclosure(cq, outputs, verifiablePresentation, ldLoader)
|
|
|
145
146
|
throw new Error(`selective disclosure not available for array of values`);
|
|
146
147
|
}
|
|
147
148
|
}
|
|
149
|
+
const bi = await fieldValueFromVerifiablePresentation(cq.fieldName, verifiablePresentation, ldLoader);
|
|
150
|
+
if (bi !== outputs.value[0]) {
|
|
151
|
+
throw new Error(`value that was used is not equal to requested in query`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export const fieldValueFromVerifiablePresentation = async (fieldName, verifiablePresentation, ldLoader) => {
|
|
155
|
+
if (!verifiablePresentation) {
|
|
156
|
+
throw new Error(`verifiablePresentation is required for selective disclosure request`);
|
|
157
|
+
}
|
|
148
158
|
let mz;
|
|
149
159
|
const strVerifiablePresentation = JSON.stringify(verifiablePresentation);
|
|
150
160
|
try {
|
|
@@ -157,13 +167,13 @@ async function validateDisclosure(cq, outputs, verifiablePresentation, ldLoader)
|
|
|
157
167
|
}
|
|
158
168
|
let merklizedPath;
|
|
159
169
|
try {
|
|
160
|
-
const p = `verifiableCredential.credentialSubject.${
|
|
170
|
+
const p = `verifiableCredential.credentialSubject.${fieldName}`;
|
|
161
171
|
merklizedPath = await Path.fromDocument(null, strVerifiablePresentation, p, {
|
|
162
172
|
documentLoader: ldLoader
|
|
163
173
|
});
|
|
164
174
|
}
|
|
165
175
|
catch (e) {
|
|
166
|
-
throw new Error(`can't build path to '${
|
|
176
|
+
throw new Error(`can't build path to '${fieldName}' key`);
|
|
167
177
|
}
|
|
168
178
|
let proof;
|
|
169
179
|
let value;
|
|
@@ -171,16 +181,13 @@ async function validateDisclosure(cq, outputs, verifiablePresentation, ldLoader)
|
|
|
171
181
|
({ proof, value } = await mz.proof(merklizedPath));
|
|
172
182
|
}
|
|
173
183
|
catch (e) {
|
|
174
|
-
throw new Error(`can't get value by path '${
|
|
184
|
+
throw new Error(`can't get value by path '${fieldName}'`);
|
|
175
185
|
}
|
|
176
186
|
if (!value) {
|
|
177
|
-
throw new Error(`can't get merkle value for field '${
|
|
187
|
+
throw new Error(`can't get merkle value for field '${fieldName}'`);
|
|
178
188
|
}
|
|
179
189
|
if (!proof.existence) {
|
|
180
190
|
throw new Error(`path [${merklizedPath.parts}] doesn't exist in verifiablePresentation document`);
|
|
181
191
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
throw new Error(`value that was used is not equal to requested in query`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
192
|
+
return await value.mtEntry();
|
|
193
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BytesHelper, checkBigIntInField } from '@iden3/js-iden3-core';
|
|
2
|
-
import {
|
|
2
|
+
import { calculateCoreSchemaHash, fillCoreClaimSlot } from '../verifiable';
|
|
3
3
|
/**
|
|
4
4
|
* SwapEndianness swaps the endianness of the value encoded in buf. If buf is
|
|
5
5
|
* Big-Endian, the result will be Little-Endian and vice-versa.
|
|
@@ -48,14 +48,14 @@ export function checkDataInField(data) {
|
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
*
|
|
51
|
-
* @deprecated The method should not be used. Use
|
|
51
|
+
* @deprecated The method should not be used. Use calculateCoreSchemaHash from verifiable.
|
|
52
52
|
* Calculates schema hash
|
|
53
53
|
*
|
|
54
54
|
* @param {Uint8Array} schemaId
|
|
55
55
|
* @returns {*} {SchemaHash}
|
|
56
56
|
*/
|
|
57
57
|
export const createSchemaHash = (schemaId) => {
|
|
58
|
-
return
|
|
58
|
+
return calculateCoreSchemaHash(schemaId);
|
|
59
59
|
};
|
|
60
60
|
/**
|
|
61
61
|
*
|
|
@@ -66,6 +66,19 @@ const lessThanOrEqual = (a, b) => {
|
|
|
66
66
|
}
|
|
67
67
|
return a <= b;
|
|
68
68
|
};
|
|
69
|
+
// a - field value
|
|
70
|
+
// b - true / false (exists operator values)
|
|
71
|
+
const existsComparator = (a, b) => {
|
|
72
|
+
if (truthyValues.includes(b) && typeof a !== 'undefined') {
|
|
73
|
+
// if exists val is true , a field val exists
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
// if exists val is false , a field val doesn't exist
|
|
77
|
+
if (falsyValues.includes(b) && (a === undefined || (Array.isArray(a) && !a.length))) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
};
|
|
69
82
|
const inOperator = (a, b) => {
|
|
70
83
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
71
84
|
return a.every((val) => b.includes(val));
|
|
@@ -78,9 +91,19 @@ const inOperator = (a, b) => {
|
|
|
78
91
|
}
|
|
79
92
|
return false;
|
|
80
93
|
};
|
|
94
|
+
const betweenOperator = (a, b) => {
|
|
95
|
+
if (!Array.isArray(b) || b.length !== 2) {
|
|
96
|
+
throw new Error('$between/$nonbetween operator value should be 2 elements array');
|
|
97
|
+
}
|
|
98
|
+
if (Array.isArray(a)) {
|
|
99
|
+
return a.every((val) => val >= b[0] && val <= b[1]);
|
|
100
|
+
}
|
|
101
|
+
return a >= b[0] && a <= b[1];
|
|
102
|
+
};
|
|
81
103
|
export const comparatorOptions = {
|
|
82
104
|
$noop: () => true,
|
|
83
105
|
$sd: () => true,
|
|
106
|
+
$exists: (a, b) => existsComparator(a, b),
|
|
84
107
|
$eq: (a, b) => equalsComparator(a, b),
|
|
85
108
|
$in: (a, b) => inOperator(a, b),
|
|
86
109
|
$nin: (a, b) => !inOperator(a, b),
|
|
@@ -88,7 +111,9 @@ export const comparatorOptions = {
|
|
|
88
111
|
$lt: (a, b) => !greaterThan(a, b),
|
|
89
112
|
$ne: (a, b) => !equalsComparator(a, b),
|
|
90
113
|
$gte: (a, b) => greaterThanOrEqual(a, b),
|
|
91
|
-
$lte: (a, b) => lessThanOrEqual(a, b)
|
|
114
|
+
$lte: (a, b) => lessThanOrEqual(a, b),
|
|
115
|
+
$between: (a, b) => betweenOperator(a, b),
|
|
116
|
+
$nonbetween: (a, b) => !betweenOperator(a, b)
|
|
92
117
|
};
|
|
93
118
|
/**
|
|
94
119
|
* credential search path resolver
|
|
@@ -136,7 +161,8 @@ export class FilterQuery {
|
|
|
136
161
|
throw new Error(SearchError.NotDefinedComparator);
|
|
137
162
|
}
|
|
138
163
|
const credentialPathValue = resolvePath(credential, this.path);
|
|
139
|
-
if (credentialPathValue === null || credentialPathValue === undefined)
|
|
164
|
+
if ((credentialPathValue === null || credentialPathValue === undefined) &&
|
|
165
|
+
this.operatorFunc !== existsComparator) {
|
|
140
166
|
return false;
|
|
141
167
|
}
|
|
142
168
|
if (this.isReverseParams) {
|
|
@@ -194,7 +194,7 @@ export const parseCoreClaimSlots = async (ldCtx, mz, credentialType) => {
|
|
|
194
194
|
* @param {Uint8Array} schemaId
|
|
195
195
|
* @returns {*} {SchemaHash}
|
|
196
196
|
*/
|
|
197
|
-
export const
|
|
197
|
+
export const calculateCoreSchemaHash = (schemaId) => {
|
|
198
198
|
const sHash = Hex.decodeString(keccak256(schemaId));
|
|
199
199
|
return new SchemaHash(sHash.slice(sHash.length - 16, sHash.length));
|
|
200
200
|
};
|
|
@@ -7,7 +7,7 @@ import { PublicKey, poseidon } from '@iden3/js-crypto';
|
|
|
7
7
|
import { getUserDIDFromCredential } from '../credentials/utils';
|
|
8
8
|
import { byteEncoder, validateDIDDocumentAuth } from '../utils';
|
|
9
9
|
import { MerklizedRootPosition, ProofType, SubjectPosition } from './constants';
|
|
10
|
-
import {
|
|
10
|
+
import { calculateCoreSchemaHash, findCredentialType, parseCoreClaimSlots } from './core-utils';
|
|
11
11
|
import * as jsonld from 'jsonld/lib';
|
|
12
12
|
import * as ldcontext from 'jsonld/lib/context';
|
|
13
13
|
/**
|
|
@@ -119,7 +119,7 @@ export class W3CCredential {
|
|
|
119
119
|
if (!nonMerklized && opts.merklizedRootPosition === MerklizedRootPosition.None) {
|
|
120
120
|
opts.merklizedRootPosition = MerklizedRootPosition.Index;
|
|
121
121
|
}
|
|
122
|
-
const schemaHash =
|
|
122
|
+
const schemaHash = calculateCoreSchemaHash(byteEncoder.encode(credentialType));
|
|
123
123
|
const claim = Claim.newClaim(schemaHash, ClaimOptions.withIndexDataBytes(slots.indexA, slots.indexB), ClaimOptions.withValueDataBytes(slots.valueA, slots.valueB), ClaimOptions.withRevocationNonce(BigInt(opts.revNonce)), ClaimOptions.withVersion(opts.version));
|
|
124
124
|
if (opts.updatable) {
|
|
125
125
|
claim.setFlagUpdatable(opts.updatable);
|
|
@@ -32,7 +32,7 @@ export declare class AtomicQueryV3OnChainInputs extends BaseConfig {
|
|
|
32
32
|
linkNonce: bigint;
|
|
33
33
|
verifierID?: Id;
|
|
34
34
|
nullifierSessionID: bigint;
|
|
35
|
-
|
|
35
|
+
isBJJAuthEnabled: number;
|
|
36
36
|
validate(): void;
|
|
37
37
|
fillMTPProofsWithZero(s: Partial<AtomicQueryV3OnChainCircuitInputs>): void;
|
|
38
38
|
fillSigProofWithZero(s: Partial<AtomicQueryV3OnChainCircuitInputs>): void;
|
|
@@ -73,7 +73,6 @@ interface AtomicQueryV3OnChainCircuitInputs {
|
|
|
73
73
|
issuerAuthRootsTreeRoot: string;
|
|
74
74
|
issuerAuthState: string;
|
|
75
75
|
isRevocationChecked: number;
|
|
76
|
-
claimPathNotExists: number;
|
|
77
76
|
claimPathMtp: string[];
|
|
78
77
|
claimPathMtpNoAux: string;
|
|
79
78
|
claimPathMtpAuxHi: string;
|
|
@@ -84,6 +83,7 @@ interface AtomicQueryV3OnChainCircuitInputs {
|
|
|
84
83
|
slotIndex: number;
|
|
85
84
|
timestamp: number;
|
|
86
85
|
value: string[];
|
|
86
|
+
valueArraySize: number;
|
|
87
87
|
issuerClaimMtp: string[];
|
|
88
88
|
issuerClaimClaimsTreeRoot: string;
|
|
89
89
|
issuerClaimRevTreeRoot: string;
|
|
@@ -112,7 +112,7 @@ interface AtomicQueryV3OnChainCircuitInputs {
|
|
|
112
112
|
linkNonce: string;
|
|
113
113
|
verifierID: string;
|
|
114
114
|
nullifierSessionID: string;
|
|
115
|
-
|
|
115
|
+
isBJJAuthEnabled: string;
|
|
116
116
|
}
|
|
117
117
|
/**
|
|
118
118
|
* @beta
|
|
@@ -125,8 +125,6 @@ export declare class AtomicQueryV3OnChainPubSignals extends BaseConfig {
|
|
|
125
125
|
issuerState: Hash;
|
|
126
126
|
issuerClaimNonRevState: Hash;
|
|
127
127
|
timestamp: number;
|
|
128
|
-
merklized: number;
|
|
129
|
-
isRevocationChecked: number;
|
|
130
128
|
circuitQueryHash: bigint;
|
|
131
129
|
challenge: bigint;
|
|
132
130
|
gistRoot: Hash;
|
|
@@ -134,9 +132,7 @@ export declare class AtomicQueryV3OnChainPubSignals extends BaseConfig {
|
|
|
134
132
|
linkID: bigint;
|
|
135
133
|
nullifier: bigint;
|
|
136
134
|
operatorOutput: bigint;
|
|
137
|
-
|
|
138
|
-
nullifierSessionID: bigint;
|
|
139
|
-
authEnabled: number;
|
|
135
|
+
isBJJAuthEnabled: number;
|
|
140
136
|
pubSignalsUnmarshal(data: Uint8Array): AtomicQueryV3OnChainPubSignals;
|
|
141
137
|
}
|
|
142
138
|
export {};
|
|
@@ -69,7 +69,6 @@ interface AtomicQueryV3CircuitInputs {
|
|
|
69
69
|
issuerAuthRootsTreeRoot: string;
|
|
70
70
|
issuerAuthState: string;
|
|
71
71
|
isRevocationChecked: number;
|
|
72
|
-
claimPathNotExists: number;
|
|
73
72
|
claimPathMtp: string[];
|
|
74
73
|
claimPathMtpNoAux: string;
|
|
75
74
|
claimPathMtpAuxHi: string;
|
|
@@ -80,6 +79,7 @@ interface AtomicQueryV3CircuitInputs {
|
|
|
80
79
|
slotIndex: number;
|
|
81
80
|
timestamp: number;
|
|
82
81
|
value: string[];
|
|
82
|
+
valueArraySize: number;
|
|
83
83
|
issuerClaimMtp: string[];
|
|
84
84
|
issuerClaimClaimsTreeRoot: string;
|
|
85
85
|
issuerClaimRevTreeRoot: string;
|
|
@@ -104,10 +104,10 @@ export declare class AtomicQueryV3PubSignals extends BaseConfig {
|
|
|
104
104
|
slotIndex: number;
|
|
105
105
|
operator: number;
|
|
106
106
|
value: bigint[];
|
|
107
|
+
valueArraySize: number;
|
|
107
108
|
timestamp: number;
|
|
108
109
|
merklized: number;
|
|
109
110
|
claimPathKey: bigint;
|
|
110
|
-
claimPathNotExists: number;
|
|
111
111
|
isRevocationChecked: number;
|
|
112
112
|
proofType: number;
|
|
113
113
|
linkID: bigint;
|