@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
|
@@ -4,6 +4,10 @@ export * from './comparer';
|
|
|
4
4
|
export * from './atomic-query-mtp-v2';
|
|
5
5
|
export * from './atomic-query-mtp-v2-on-chain';
|
|
6
6
|
export * from './atomic-query-sig-v2';
|
|
7
|
+
export * from './atomic-query-v3';
|
|
8
|
+
export * from './atomic-query-v3-on-chain';
|
|
7
9
|
export * from './atomic-query-sig-v2-on-chain';
|
|
8
10
|
export * from './auth-v2';
|
|
9
11
|
export * from './state-transition';
|
|
12
|
+
export * from './linked-nullifier';
|
|
13
|
+
export * from './linked-multi-query';
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { byteDecoder, byteEncoder } from '../utils';
|
|
2
|
+
import { BaseConfig, bigIntArrayToStringArray, existenceToInt, getNodeAuxValue, prepareCircuitArrayValues, prepareSiblingsStr } from './common';
|
|
3
|
+
/**
|
|
4
|
+
* LinkedMultiQuery circuit representation
|
|
5
|
+
* Inputs and public signals declaration, marshalling and parsing
|
|
6
|
+
*
|
|
7
|
+
* @beta
|
|
8
|
+
* @class LinkedMultiQueryInputs
|
|
9
|
+
*/
|
|
10
|
+
export class LinkedMultiQueryInputs extends BaseConfig {
|
|
11
|
+
// InputsMarshal returns Circom private inputs for linkedMultiQueryInputs.circom
|
|
12
|
+
inputsMarshal() {
|
|
13
|
+
const enabled = [];
|
|
14
|
+
const claimPathNotExists = [];
|
|
15
|
+
const claimPathMtp = [];
|
|
16
|
+
const claimPathMtpNoAux = [];
|
|
17
|
+
const claimPathMtpAuxHi = [];
|
|
18
|
+
const claimPathMtpAuxHv = [];
|
|
19
|
+
const claimPathKey = [];
|
|
20
|
+
const claimPathValue = [];
|
|
21
|
+
const slotIndex = [];
|
|
22
|
+
const operator = [];
|
|
23
|
+
const value = [];
|
|
24
|
+
for (let i = 0; i < this.queryLength; i++) {
|
|
25
|
+
if (!this.query) {
|
|
26
|
+
enabled.push(0);
|
|
27
|
+
claimPathNotExists.push(0);
|
|
28
|
+
claimPathMtp.push([]);
|
|
29
|
+
claimPathMtpNoAux.push('0');
|
|
30
|
+
claimPathMtpAuxHi.push('0');
|
|
31
|
+
claimPathMtpAuxHv.push('0');
|
|
32
|
+
claimPathKey.push('0');
|
|
33
|
+
claimPathValue.push('0');
|
|
34
|
+
slotIndex.push(0);
|
|
35
|
+
operator.push(0);
|
|
36
|
+
const valuesArr = prepareCircuitArrayValues([], this.getValueArrSize());
|
|
37
|
+
value.push(bigIntArrayToStringArray(valuesArr));
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
enabled.push(1);
|
|
41
|
+
const valueProof = this.query[i].valueProof;
|
|
42
|
+
claimPathNotExists.push(existenceToInt(valueProof.mtp.existence));
|
|
43
|
+
claimPathMtp.push(prepareSiblingsStr(valueProof.mtp, this.getMTLevelsClaim()));
|
|
44
|
+
const nodAuxJSONLD = getNodeAuxValue(valueProof.mtp);
|
|
45
|
+
claimPathMtpNoAux.push(nodAuxJSONLD.noAux);
|
|
46
|
+
claimPathMtpAuxHi.push(nodAuxJSONLD.key.bigInt().toString());
|
|
47
|
+
claimPathMtpAuxHv.push(nodAuxJSONLD.value.bigInt().toString());
|
|
48
|
+
claimPathKey.push(valueProof.path.toString());
|
|
49
|
+
claimPathValue.push(valueProof.value.toString());
|
|
50
|
+
slotIndex.push(this.query[i].slotIndex);
|
|
51
|
+
operator.push(this.query[i].operator);
|
|
52
|
+
const valuesArr = prepareCircuitArrayValues(this.query[i].values, this.getValueArrSize());
|
|
53
|
+
value.push(bigIntArrayToStringArray(valuesArr));
|
|
54
|
+
}
|
|
55
|
+
const s = {
|
|
56
|
+
linkNonce: this.linkNonce.toString(),
|
|
57
|
+
issuerClaim: this.claim.marshalJson(),
|
|
58
|
+
enabled,
|
|
59
|
+
claimSchema: this.claim.getSchemaHash().bigInt().toString(),
|
|
60
|
+
claimPathNotExists,
|
|
61
|
+
claimPathMtp,
|
|
62
|
+
claimPathMtpNoAux,
|
|
63
|
+
claimPathMtpAuxHi,
|
|
64
|
+
claimPathMtpAuxHv,
|
|
65
|
+
claimPathKey,
|
|
66
|
+
claimPathValue,
|
|
67
|
+
slotIndex,
|
|
68
|
+
operator,
|
|
69
|
+
value
|
|
70
|
+
};
|
|
71
|
+
return byteEncoder.encode(JSON.stringify(s));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// LinkedMultiQueryPubSignals linkedMultiQuery.circom public signals
|
|
75
|
+
/**
|
|
76
|
+
* public signals
|
|
77
|
+
*
|
|
78
|
+
* @beta
|
|
79
|
+
* @class LinkedMultiQueryPubSignals
|
|
80
|
+
*/
|
|
81
|
+
export class LinkedMultiQueryPubSignals {
|
|
82
|
+
/**
|
|
83
|
+
* PubSignalsUnmarshal unmarshal linkedMultiQuery.circom public inputs to LinkedMultiQueryPubSignals
|
|
84
|
+
*
|
|
85
|
+
* @beta
|
|
86
|
+
* @param {Uint8Array} data
|
|
87
|
+
* @returns LinkedMultiQueryPubSignals
|
|
88
|
+
*/
|
|
89
|
+
pubSignalsUnmarshal(data, queryLength) {
|
|
90
|
+
const len = queryLength * 3 + 2;
|
|
91
|
+
const sVals = JSON.parse(byteDecoder.decode(data));
|
|
92
|
+
if (sVals.length !== len) {
|
|
93
|
+
throw new Error(`invalid number of Output values expected ${len} got ${sVals.length}`);
|
|
94
|
+
}
|
|
95
|
+
let fieldIdx = 0;
|
|
96
|
+
// -- linkID
|
|
97
|
+
this.linkID = BigInt(sVals[fieldIdx]);
|
|
98
|
+
fieldIdx++;
|
|
99
|
+
// -- merklized
|
|
100
|
+
this.merklized = parseInt(sVals[fieldIdx]);
|
|
101
|
+
fieldIdx++;
|
|
102
|
+
// - operatorOutput
|
|
103
|
+
this.operatorOutput = [];
|
|
104
|
+
for (let i = 0; i < queryLength; i++) {
|
|
105
|
+
this.operatorOutput.push(BigInt(sVals[fieldIdx]));
|
|
106
|
+
fieldIdx++;
|
|
107
|
+
}
|
|
108
|
+
// - circuitQueryHash
|
|
109
|
+
this.circuitQueryHash = [];
|
|
110
|
+
for (let i = 0; i < queryLength; i++) {
|
|
111
|
+
this.circuitQueryHash.push(BigInt(sVals[fieldIdx]));
|
|
112
|
+
fieldIdx++;
|
|
113
|
+
}
|
|
114
|
+
// - enabled
|
|
115
|
+
this.enabled = [];
|
|
116
|
+
for (let i = 0; i < queryLength; i++) {
|
|
117
|
+
const enabledNum = parseInt(sVals[fieldIdx]);
|
|
118
|
+
this.enabled.push(enabledNum === 1);
|
|
119
|
+
fieldIdx++;
|
|
120
|
+
}
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Id } from '@iden3/js-iden3-core';
|
|
2
|
+
import { byteDecoder, byteEncoder } from '../utils';
|
|
3
|
+
/**
|
|
4
|
+
* LinkedNullifier circuit representation
|
|
5
|
+
* Inputs and public signals declaration, marshalling and parsing
|
|
6
|
+
*
|
|
7
|
+
* @beta
|
|
8
|
+
* @class LinkedNullifierInputs
|
|
9
|
+
*/
|
|
10
|
+
export class LinkedNullifierInputs {
|
|
11
|
+
// InputsMarshal returns Circom private inputs for nullifier.circom
|
|
12
|
+
inputsMarshal() {
|
|
13
|
+
const s = {
|
|
14
|
+
linkNonce: this.linkNonce.toString(),
|
|
15
|
+
issuerClaim: this.issuerClaim.marshalJson(),
|
|
16
|
+
userGenesisID: this.id.bigInt().toString(),
|
|
17
|
+
claimSubjectProfileNonce: this.claimSubjectProfileNonce.toString(),
|
|
18
|
+
claimSchema: this.issuerClaim.getSchemaHash().bigInt().toString(),
|
|
19
|
+
verifierID: this.verifierID?.bigInt().toString() ?? '0',
|
|
20
|
+
nullifierSessionID: this.nullifierSessionID.toString()
|
|
21
|
+
};
|
|
22
|
+
return byteEncoder.encode(JSON.stringify(s));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// LinkedNullifierPubSignals nullifier.circom public signals
|
|
26
|
+
/**
|
|
27
|
+
* public signals
|
|
28
|
+
*
|
|
29
|
+
* @beta
|
|
30
|
+
* @class LinkedNullifierPubSignals
|
|
31
|
+
*/
|
|
32
|
+
export class LinkedNullifierPubSignals {
|
|
33
|
+
/**
|
|
34
|
+
* PubSignalsUnmarshal unmarshal nullifier.circom public inputs to LinkedNullifierPubSignals
|
|
35
|
+
*
|
|
36
|
+
* @beta
|
|
37
|
+
* @param {Uint8Array} data
|
|
38
|
+
* @returns LinkedNullifierPubSignals
|
|
39
|
+
*/
|
|
40
|
+
pubSignalsUnmarshal(data) {
|
|
41
|
+
const len = 4;
|
|
42
|
+
const sVals = JSON.parse(byteDecoder.decode(data));
|
|
43
|
+
if (sVals.length !== len) {
|
|
44
|
+
throw new Error(`invalid number of Output values expected ${len} got ${sVals.length}`);
|
|
45
|
+
}
|
|
46
|
+
this.nullifier = BigInt(sVals[0]);
|
|
47
|
+
this.linkID = BigInt(sVals[1]);
|
|
48
|
+
this.verifierID = Id.fromBigInt(BigInt(sVals[2]));
|
|
49
|
+
this.nullifierSessionID = BigInt(sVals[3]);
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -12,7 +12,9 @@ export class Query {
|
|
|
12
12
|
*
|
|
13
13
|
*/
|
|
14
14
|
validate() {
|
|
15
|
-
if (this.operator !== QueryOperators.$noop &&
|
|
15
|
+
if (this.operator !== QueryOperators.$noop &&
|
|
16
|
+
this.operator !== QueryOperators.$sd &&
|
|
17
|
+
this.values?.some((v) => typeof v !== 'bigint'))
|
|
16
18
|
throw new Error(CircuitError.EmptyQueryValue);
|
|
17
19
|
}
|
|
18
20
|
}
|
|
@@ -35,6 +37,26 @@ export var CircuitId;
|
|
|
35
37
|
CircuitId["AtomicQuerySigV2"] = "credentialAtomicQuerySigV2";
|
|
36
38
|
// AtomicQuerySigOnChain is a type for credentialAtomicQuerySigOnChain.circom
|
|
37
39
|
CircuitId["AtomicQuerySigV2OnChain"] = "credentialAtomicQuerySigV2OnChain";
|
|
40
|
+
/**
|
|
41
|
+
* @beta
|
|
42
|
+
*/
|
|
43
|
+
// AtomicQueryV3CircuitID is a type for credentialAtomicQueryV3.circom
|
|
44
|
+
CircuitId["AtomicQueryV3"] = "credentialAtomicQueryV3-beta.0";
|
|
45
|
+
/**
|
|
46
|
+
* @beta
|
|
47
|
+
*/
|
|
48
|
+
// AtomicQueryV3OnChainCircuitID is a type for credentialAtomicQueryV3OnChain.circom
|
|
49
|
+
CircuitId["AtomicQueryV3OnChain"] = "credentialAtomicQueryV3OnChain-beta.0";
|
|
50
|
+
/**
|
|
51
|
+
* @beta
|
|
52
|
+
*/
|
|
53
|
+
// LinkedNullifier is a type for linkedNullifier.circom
|
|
54
|
+
CircuitId["LinkedNullifier"] = "linkedNullifier-beta.0";
|
|
55
|
+
/**
|
|
56
|
+
* @beta
|
|
57
|
+
*/
|
|
58
|
+
// LinkedMultiQuery is a type for linkedMultiQuery.circom
|
|
59
|
+
CircuitId["LinkedMultiQuery10"] = "linkedMultiQuery10-beta.0";
|
|
38
60
|
})(CircuitId || (CircuitId = {}));
|
|
39
61
|
/**
|
|
40
62
|
* Claim structure for circuit inputs
|
|
@@ -68,7 +90,9 @@ export var CircuitError;
|
|
|
68
90
|
CircuitError["EmptyId"] = "empty Id";
|
|
69
91
|
CircuitError["EmptyChallenge"] = "empty challenge";
|
|
70
92
|
CircuitError["EmptyGISTProof"] = "empty GIST merkle tree proof";
|
|
93
|
+
CircuitError["EmptyTreeState"] = "empty tree state";
|
|
71
94
|
CircuitError["EmptyRequestID"] = "empty request ID";
|
|
95
|
+
CircuitError["InvalidProofType"] = "invalid proof type";
|
|
72
96
|
})(CircuitError || (CircuitError = {}));
|
|
73
97
|
/**
|
|
74
98
|
* ValueProof represents a Merkle Proof for a value stored as MT
|
|
@@ -4,6 +4,7 @@ import * as uuid from 'uuid';
|
|
|
4
4
|
import { CredentialStatusResolverRegistry } from './status/resolver';
|
|
5
5
|
import { IssuerResolver } from './status/sparse-merkle-tree';
|
|
6
6
|
import { AgentResolver } from './status/agent-revocation';
|
|
7
|
+
import { getUserDIDFromCredential } from './utils';
|
|
7
8
|
// ErrAllClaimsRevoked all claims are revoked.
|
|
8
9
|
const ErrAllClaimsRevoked = 'all claims are revoked';
|
|
9
10
|
/**
|
|
@@ -99,16 +100,7 @@ export class CredentialWallet {
|
|
|
99
100
|
? mtpProof.issuerData.state
|
|
100
101
|
: sigProof?.issuerData.state;
|
|
101
102
|
const issuerDID = DID.parse(cred.issuer);
|
|
102
|
-
|
|
103
|
-
if (!cred.credentialSubject.id) {
|
|
104
|
-
userDID = issuerDID;
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
if (typeof cred.credentialSubject.id !== 'string') {
|
|
108
|
-
throw new Error('credential status `id` is not a string');
|
|
109
|
-
}
|
|
110
|
-
userDID = DID.parse(cred.credentialSubject.id);
|
|
111
|
-
}
|
|
103
|
+
const userDID = getUserDIDFromCredential(issuerDID, cred);
|
|
112
104
|
const opts = {
|
|
113
105
|
issuerGenesisState: stateInfo,
|
|
114
106
|
issuerDID,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DID } from '@iden3/js-iden3-core';
|
|
2
|
+
/**
|
|
3
|
+
* Retrieves the user DID from a given credential.
|
|
4
|
+
* If the credential does not have a credentialSubject.id property, the issuer DID is returned.
|
|
5
|
+
* If the credentialSubject.id is not a string, an error is thrown.
|
|
6
|
+
* @param issuerDID The DID of the issuer.
|
|
7
|
+
* @param credential The credential object.
|
|
8
|
+
* @returns The user DID parsed from the credential.
|
|
9
|
+
* @throws Error if the credentialSubject.id is not a string.
|
|
10
|
+
*/
|
|
11
|
+
export const getUserDIDFromCredential = (issuerDID, credential) => {
|
|
12
|
+
if (!credential.credentialSubject.id) {
|
|
13
|
+
return issuerDID;
|
|
14
|
+
}
|
|
15
|
+
if (typeof credential.credentialSubject.id !== 'string') {
|
|
16
|
+
throw new Error('credential subject `id` is not a string');
|
|
17
|
+
}
|
|
18
|
+
return DID.parse(credential.credentialSubject.id);
|
|
19
|
+
};
|
|
@@ -3,7 +3,8 @@ import { PROTOCOL_MESSAGE_TYPE } from '../constants';
|
|
|
3
3
|
import { DID } from '@iden3/js-iden3-core';
|
|
4
4
|
import { proving } from '@iden3/js-jwz';
|
|
5
5
|
import * as uuid from 'uuid';
|
|
6
|
-
import { byteDecoder, byteEncoder } from '../../utils';
|
|
6
|
+
import { byteDecoder, byteEncoder, mergeObjects } from '../../utils';
|
|
7
|
+
import { getRandomBytes } from '@iden3/js-crypto';
|
|
7
8
|
/**
|
|
8
9
|
*
|
|
9
10
|
* Allows to process AuthorizationRequest protocol message and produce JWZ response.
|
|
@@ -79,15 +80,55 @@ export class AuthHandler {
|
|
|
79
80
|
from: did.string(),
|
|
80
81
|
to: authRequest.from
|
|
81
82
|
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
83
|
+
const requestScope = authRequest.body.scope;
|
|
84
|
+
const combinedQueries = requestScope.reduce((acc, proofReq) => {
|
|
85
|
+
const groupId = proofReq.query.groupId;
|
|
86
|
+
if (!groupId) {
|
|
87
|
+
return acc;
|
|
88
|
+
}
|
|
89
|
+
const existedData = acc.get(groupId);
|
|
90
|
+
if (!existedData) {
|
|
91
|
+
const seed = getRandomBytes(12);
|
|
92
|
+
const dataView = new DataView(seed.buffer);
|
|
93
|
+
const linkNonce = dataView.getUint32(0);
|
|
94
|
+
acc.set(groupId, { query: proofReq.query, linkNonce });
|
|
95
|
+
return acc;
|
|
96
|
+
}
|
|
97
|
+
const credentialSubject = mergeObjects(existedData.query.credentialSubject, proofReq.query.credentialSubject);
|
|
98
|
+
acc.set(groupId, {
|
|
99
|
+
...existedData,
|
|
100
|
+
query: {
|
|
101
|
+
skipClaimRevocationCheck: existedData.query.skipClaimRevocationCheck || proofReq.query.skipClaimRevocationCheck,
|
|
102
|
+
...existedData.query,
|
|
103
|
+
credentialSubject
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
return acc;
|
|
107
|
+
}, new Map());
|
|
108
|
+
const groupedCredentialsCache = new Map();
|
|
109
|
+
for (const proofReq of requestScope) {
|
|
88
110
|
const query = proofReq.query;
|
|
89
|
-
const
|
|
90
|
-
|
|
111
|
+
const groupId = query.groupId;
|
|
112
|
+
const combinedQueryData = combinedQueries.get(groupId);
|
|
113
|
+
if (groupId) {
|
|
114
|
+
if (!combinedQueryData) {
|
|
115
|
+
throw new Error(`Invalid group id ${query.groupId}`);
|
|
116
|
+
}
|
|
117
|
+
const combinedQuery = combinedQueryData.query;
|
|
118
|
+
if (!groupedCredentialsCache.has(groupId)) {
|
|
119
|
+
const credWithRevStatus = await this._proofService.findCredentialByProofQuery(did, combinedQueryData.query);
|
|
120
|
+
if (!credWithRevStatus.cred) {
|
|
121
|
+
throw new Error(`Credential not found for query ${JSON.stringify(combinedQuery)}`);
|
|
122
|
+
}
|
|
123
|
+
groupedCredentialsCache.set(groupId, credWithRevStatus);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const credWithRevStatus = groupedCredentialsCache.get(groupId);
|
|
127
|
+
const zkpRes = await this._proofService.generateProof(proofReq, did, {
|
|
128
|
+
skipRevocation: Boolean(query.skipClaimRevocationCheck),
|
|
129
|
+
credential: credWithRevStatus?.cred,
|
|
130
|
+
credentialRevocationStatus: credWithRevStatus?.revStatus,
|
|
131
|
+
linkNonce: combinedQueryData?.linkNonce ? BigInt(combinedQueryData.linkNonce) : undefined
|
|
91
132
|
});
|
|
92
133
|
authResponse.body.scope.push(zkpRes);
|
|
93
134
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { CircuitId } from '../../circuits/models';
|
|
2
2
|
import { PROTOCOL_MESSAGE_TYPE } from '../constants';
|
|
3
|
+
import { DID, ChainIds, DidMethod } from '@iden3/js-iden3-core';
|
|
4
|
+
import { buildVerifierId } from '../../utils';
|
|
3
5
|
/**
|
|
4
6
|
*
|
|
5
7
|
* Allows to process ContractInvokeRequest protocol message
|
|
@@ -23,7 +25,8 @@ export class ContractRequestHandler {
|
|
|
23
25
|
this._zkpVerifier = _zkpVerifier;
|
|
24
26
|
this._allowedCircuits = [
|
|
25
27
|
CircuitId.AtomicQueryMTPV2OnChain,
|
|
26
|
-
CircuitId.AtomicQuerySigV2OnChain
|
|
28
|
+
CircuitId.AtomicQuerySigV2OnChain,
|
|
29
|
+
CircuitId.AtomicQueryV3OnChain
|
|
27
30
|
];
|
|
28
31
|
}
|
|
29
32
|
/**
|
|
@@ -57,19 +60,28 @@ export class ContractRequestHandler {
|
|
|
57
60
|
throw new Error("Can't sign transaction. Provide Signer in options.");
|
|
58
61
|
}
|
|
59
62
|
const zkRequests = [];
|
|
63
|
+
const { contract_address, chain_id } = ciRequest.body.transaction_data;
|
|
64
|
+
const networkFlag = Object.keys(ChainIds).find((key) => ChainIds[key] === chain_id);
|
|
65
|
+
if (!networkFlag) {
|
|
66
|
+
throw new Error(`Invalid chain id ${chain_id}`);
|
|
67
|
+
}
|
|
68
|
+
const [blockchain, networkId] = networkFlag.split(':');
|
|
69
|
+
const verifierId = buildVerifierId(contract_address, {
|
|
70
|
+
blockchain,
|
|
71
|
+
networkId,
|
|
72
|
+
// DidMethod.Iden3 is used based on discussions: all onchain issuers have iden3 did method by default. This can be changed in the release of v3 circuit.
|
|
73
|
+
method: DidMethod.Iden3
|
|
74
|
+
});
|
|
75
|
+
const verifierDid = DID.parseFromId(verifierId);
|
|
60
76
|
for (const proofReq of ciRequest.body.scope) {
|
|
61
77
|
if (!this._allowedCircuits.includes(proofReq.circuitId)) {
|
|
62
78
|
throw new Error(`Can't handle circuit ${proofReq.circuitId}. Only onchain circuits are allowed.`);
|
|
63
79
|
}
|
|
64
|
-
const zkpReq = {
|
|
65
|
-
id: proofReq.id,
|
|
66
|
-
circuitId: proofReq.circuitId,
|
|
67
|
-
query: proofReq.query
|
|
68
|
-
};
|
|
69
80
|
const query = proofReq.query;
|
|
70
|
-
const zkpRes = await this._proofService.generateProof(
|
|
81
|
+
const zkpRes = await this._proofService.generateProof(proofReq, did, {
|
|
71
82
|
skipRevocation: query.skipClaimRevocationCheck ?? false,
|
|
72
|
-
challenge: opts.challenge
|
|
83
|
+
challenge: opts.challenge,
|
|
84
|
+
verifierDid
|
|
73
85
|
});
|
|
74
86
|
zkRequests.push(zkpRes);
|
|
75
87
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import { Hash, Proof } from '@iden3/js-merkletree';
|
|
2
|
-
import { buildTreeState } from '../circuits';
|
|
1
|
+
import { Hash, Proof, ZERO_HASH } from '@iden3/js-merkletree';
|
|
2
|
+
import { buildTreeState, isValidOperation, QueryOperators } from '../circuits';
|
|
3
|
+
import { buildFieldPath } from '../verifiable';
|
|
4
|
+
import { Merklizer, Path } from '@iden3/js-jsonld-merklization';
|
|
5
|
+
import { Parser } from '../schema-processor/json';
|
|
6
|
+
import { byteEncoder } from '../utils';
|
|
7
|
+
import { poseidon } from '@iden3/js-crypto';
|
|
3
8
|
/**
|
|
4
9
|
* converts verifiable RevocationStatus model to circuits structure
|
|
5
10
|
*
|
|
@@ -7,6 +12,18 @@ import { buildTreeState } from '../circuits';
|
|
|
7
12
|
* @returns {ClaimNonRevStatus}
|
|
8
13
|
*/
|
|
9
14
|
export const toClaimNonRevStatus = (s) => {
|
|
15
|
+
if (!s) {
|
|
16
|
+
const hash = poseidon.hash(new Array(3).fill(0n));
|
|
17
|
+
return {
|
|
18
|
+
proof: new Proof(),
|
|
19
|
+
treeState: {
|
|
20
|
+
state: Hash.fromBigInt(hash),
|
|
21
|
+
claimsRoot: ZERO_HASH,
|
|
22
|
+
revocationRoot: ZERO_HASH,
|
|
23
|
+
rootOfRoots: ZERO_HASH
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
10
27
|
return {
|
|
11
28
|
proof: s.mtp,
|
|
12
29
|
treeState: buildTreeState(s.issuer.state, s.issuer.claimsTreeRoot, s.issuer.revocationTreeRoot, s.issuer.rootOfRoots)
|
|
@@ -40,3 +57,85 @@ export const toGISTProof = (smtProof) => {
|
|
|
40
57
|
proof
|
|
41
58
|
};
|
|
42
59
|
};
|
|
60
|
+
export const parseCredentialSubject = (credentialSubject) => {
|
|
61
|
+
// credentialSubject is empty
|
|
62
|
+
if (!credentialSubject) {
|
|
63
|
+
return [{ operator: QueryOperators.$eq, fieldName: '' }];
|
|
64
|
+
}
|
|
65
|
+
const queries = [];
|
|
66
|
+
const entries = Object.entries(credentialSubject);
|
|
67
|
+
if (!entries.length) {
|
|
68
|
+
throw new Error(`query must have at least 1 predicate`);
|
|
69
|
+
}
|
|
70
|
+
for (const [fieldName, fieldReq] of entries) {
|
|
71
|
+
const fieldReqEntries = Object.entries(fieldReq);
|
|
72
|
+
const isSelectiveDisclosure = fieldReqEntries.length === 0;
|
|
73
|
+
if (isSelectiveDisclosure) {
|
|
74
|
+
queries.push({ operator: QueryOperators.$sd, fieldName: fieldName });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
for (const [operatorName, operatorValue] of fieldReqEntries) {
|
|
78
|
+
if (!QueryOperators[operatorName]) {
|
|
79
|
+
throw new Error(`operator is not supported by lib`);
|
|
80
|
+
}
|
|
81
|
+
const operator = QueryOperators[operatorName];
|
|
82
|
+
queries.push({ operator, fieldName, operatorValue });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return queries;
|
|
86
|
+
};
|
|
87
|
+
export const parseQueryMetadata = async (propertyQuery, ldContextJSON, credentialType, options) => {
|
|
88
|
+
const datatype = await Path.newTypeFromContext(ldContextJSON, `${credentialType}.${propertyQuery.fieldName}`, options);
|
|
89
|
+
const query = {
|
|
90
|
+
...propertyQuery,
|
|
91
|
+
slotIndex: 0,
|
|
92
|
+
merklizedSchema: false,
|
|
93
|
+
datatype: datatype,
|
|
94
|
+
claimPathKey: BigInt(0),
|
|
95
|
+
values: [],
|
|
96
|
+
path: new Path()
|
|
97
|
+
};
|
|
98
|
+
const serAttr = await Parser.getSerializationAttrFromContext(JSON.parse(ldContextJSON), options, credentialType);
|
|
99
|
+
if (!serAttr) {
|
|
100
|
+
query.merklizedSchema = true;
|
|
101
|
+
}
|
|
102
|
+
// for merklized credentials slotIndex in query must be equal to zero
|
|
103
|
+
// and not a position of merklization root.
|
|
104
|
+
// it has no influence on check in the off-chain circuits, but it aligns with onchain verification standard
|
|
105
|
+
if (!query.merklizedSchema) {
|
|
106
|
+
query.slotIndex = await Parser.getFieldSlotIndex(propertyQuery.fieldName, credentialType, byteEncoder.encode(ldContextJSON));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
try {
|
|
110
|
+
const path = await buildFieldPath(ldContextJSON, credentialType, propertyQuery.fieldName, options);
|
|
111
|
+
query.claimPathKey = await path.mtEntry();
|
|
112
|
+
query.path = path;
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
throw new Error(`field does not exist in the schema ${e.message}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (propertyQuery.operatorValue) {
|
|
119
|
+
if (!isValidOperation(datatype, propertyQuery.operator)) {
|
|
120
|
+
throw new Error(`operator ${propertyQuery.operator} is not supported for datatype ${datatype}`);
|
|
121
|
+
}
|
|
122
|
+
query.values = await transformQueryValueToBigInts(propertyQuery.operatorValue, datatype);
|
|
123
|
+
}
|
|
124
|
+
return query;
|
|
125
|
+
};
|
|
126
|
+
export const parseQueriesMetadata = async (credentialType, ldContextJSON, credentialSubject, options) => {
|
|
127
|
+
const queriesMetadata = parseCredentialSubject(credentialSubject);
|
|
128
|
+
return Promise.all(queriesMetadata.map((m) => parseQueryMetadata(m, ldContextJSON, credentialType, options)));
|
|
129
|
+
};
|
|
130
|
+
export const transformQueryValueToBigInts = async (value, ldType) => {
|
|
131
|
+
const values = new Array(64).fill(BigInt(0));
|
|
132
|
+
if (Array.isArray(value)) {
|
|
133
|
+
for (let index = 0; index < value.length; index++) {
|
|
134
|
+
values[index] = await Merklizer.hashValue(ldType, value[index]);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
values[0] = await Merklizer.hashValue(ldType, value);
|
|
139
|
+
}
|
|
140
|
+
return values;
|
|
141
|
+
};
|