@0xpolygonid/js-sdk 1.6.1 → 1.7.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.
Files changed (55) hide show
  1. package/README.md +3 -1
  2. package/dist/browser/esm/index.js +837 -494
  3. package/dist/browser/esm/index.js.map +1 -1
  4. package/dist/browser/umd/index.js +885 -536
  5. package/dist/browser/umd/index.js.map +1 -1
  6. package/dist/node/cjs/circuits/comparer.js +21 -3
  7. package/dist/node/cjs/circuits/linked-multi-query.js +1 -1
  8. package/dist/node/cjs/credentials/credential-wallet.js +20 -2
  9. package/dist/node/cjs/credentials/index.js +1 -0
  10. package/dist/node/cjs/credentials/rhs.js +28 -15
  11. package/dist/node/cjs/credentials/status/credential-status-publisher.js +84 -0
  12. package/dist/node/cjs/credentials/utils.js +14 -1
  13. package/dist/node/cjs/iden3comm/constants.js +2 -0
  14. package/dist/node/cjs/iden3comm/handlers/fetch.js +2 -2
  15. package/dist/node/cjs/iden3comm/handlers/index.js +1 -0
  16. package/dist/node/cjs/iden3comm/handlers/refresh.js +76 -0
  17. package/dist/node/cjs/identity/identity-wallet.js +57 -26
  18. package/dist/node/cjs/storage/blockchain/abi/CredentialStatusResolver.json +1 -1
  19. package/dist/node/cjs/storage/blockchain/index.js +1 -0
  20. package/dist/node/cjs/storage/blockchain/onchain-revocation.js +45 -5
  21. package/dist/node/cjs/verifiable/constants.js +10 -1
  22. package/dist/node/esm/circuits/comparer.js +21 -3
  23. package/dist/node/esm/circuits/linked-multi-query.js +1 -1
  24. package/dist/node/esm/credentials/credential-wallet.js +21 -3
  25. package/dist/node/esm/credentials/index.js +1 -0
  26. package/dist/node/esm/credentials/rhs.js +26 -14
  27. package/dist/node/esm/credentials/status/credential-status-publisher.js +78 -0
  28. package/dist/node/esm/credentials/utils.js +12 -0
  29. package/dist/node/esm/iden3comm/constants.js +2 -0
  30. package/dist/node/esm/iden3comm/handlers/fetch.js +2 -2
  31. package/dist/node/esm/iden3comm/handlers/index.js +1 -0
  32. package/dist/node/esm/iden3comm/handlers/refresh.js +72 -0
  33. package/dist/node/esm/identity/identity-wallet.js +52 -21
  34. package/dist/node/esm/storage/blockchain/abi/CredentialStatusResolver.json +1 -1
  35. package/dist/node/esm/storage/blockchain/index.js +1 -0
  36. package/dist/node/esm/storage/blockchain/onchain-revocation.js +45 -5
  37. package/dist/node/esm/verifiable/constants.js +9 -0
  38. package/dist/types/credentials/credential-wallet.d.ts +5 -1
  39. package/dist/types/credentials/index.d.ts +1 -0
  40. package/dist/types/credentials/rhs.d.ts +11 -0
  41. package/dist/types/credentials/status/credential-status-publisher.d.ts +70 -0
  42. package/dist/types/credentials/utils.d.ts +2 -0
  43. package/dist/types/iden3comm/constants.d.ts +1 -0
  44. package/dist/types/iden3comm/handlers/fetch.d.ts +2 -2
  45. package/dist/types/iden3comm/handlers/index.d.ts +1 -0
  46. package/dist/types/iden3comm/handlers/refresh.d.ts +56 -0
  47. package/dist/types/iden3comm/types/packer.d.ts +2 -1
  48. package/dist/types/iden3comm/types/protocol/credentials.d.ts +15 -0
  49. package/dist/types/identity/identity-wallet.d.ts +42 -13
  50. package/dist/types/storage/blockchain/index.d.ts +1 -0
  51. package/dist/types/storage/blockchain/onchain-revocation.d.ts +7 -3
  52. package/dist/types/verifiable/constants.d.ts +8 -0
  53. package/dist/types/verifiable/credential.d.ts +2 -1
  54. package/dist/types/verifiable/proof.d.ts +10 -1
  55. package/package.json +1 -1
@@ -22,9 +22,16 @@ class OnChainRevocationStorage {
22
22
  * @param {string} - onhcain contract address
23
23
  * @param {string} - rpc url to connect to the blockchain
24
24
  */
25
- constructor(config, contractAddress) {
26
- this.provider = new ethers_1.JsonRpcProvider(config.url);
27
- this.onchainContract = new ethers_1.Contract(contractAddress, CredentialStatusResolver_json_1.default, this.provider);
25
+ constructor(_config, contractAddress, _signer) {
26
+ this._config = _config;
27
+ this._signer = _signer;
28
+ this._provider = new ethers_1.JsonRpcProvider(_config.url);
29
+ let contract = new ethers_1.Contract(contractAddress, CredentialStatusResolver_json_1.default, this._provider);
30
+ if (this._signer) {
31
+ this._signer = this._signer.connect(this._provider);
32
+ contract = contract.connect(this._signer);
33
+ }
34
+ this._contract = contract;
28
35
  }
29
36
  /**
30
37
  * Get revocation status by issuerId, issuerState and nonce from the onchain.
@@ -32,7 +39,7 @@ class OnChainRevocationStorage {
32
39
  * @returns Promise<RevocationStatus>
33
40
  */
34
41
  async getRevocationStatusByIdAndState(issuerID, state, nonce) {
35
- const response = await this.onchainContract.getRevocationStatusByIdAndState(issuerID, state, nonce);
42
+ const response = await this._contract.getRevocationStatusByIdAndState(issuerID, state, nonce);
36
43
  const issuer = OnChainRevocationStorage.convertIssuerInfo(response.issuer);
37
44
  const mtp = OnChainRevocationStorage.convertSmtProofToProof(response.mtp);
38
45
  return {
@@ -46,7 +53,7 @@ class OnChainRevocationStorage {
46
53
  * @returns Promise<RevocationStatus>
47
54
  */
48
55
  async getRevocationStatus(issuerID, nonce) {
49
- const response = await this.onchainContract.getRevocationStatus(issuerID, nonce);
56
+ const response = await this._contract.getRevocationStatus(issuerID, nonce);
50
57
  const issuer = OnChainRevocationStorage.convertIssuerInfo(response.issuer);
51
58
  const mtp = OnChainRevocationStorage.convertSmtProofToProof(response.mtp);
52
59
  return {
@@ -54,6 +61,39 @@ class OnChainRevocationStorage {
54
61
  mtp
55
62
  };
56
63
  }
64
+ async saveNodes(payload) {
65
+ if (!this._signer) {
66
+ throw new Error('No signer provided');
67
+ }
68
+ const feeData = await this._provider.getFeeData();
69
+ const maxFeePerGas = this._config.maxFeePerGas
70
+ ? BigInt(this._config.maxFeePerGas)
71
+ : feeData.maxFeePerGas;
72
+ const maxPriorityFeePerGas = this._config.maxPriorityFeePerGas
73
+ ? BigInt(this._config.maxPriorityFeePerGas)
74
+ : feeData.maxPriorityFeePerGas;
75
+ const gasLimit = await this._contract.saveNodes.estimateGas(payload);
76
+ const txData = await this._contract.saveNodes.populateTransaction(payload);
77
+ const request = {
78
+ to: txData.to,
79
+ data: txData.data,
80
+ gasLimit,
81
+ maxFeePerGas,
82
+ maxPriorityFeePerGas
83
+ };
84
+ const tx = await this._signer.sendTransaction(request);
85
+ return tx.wait().then((txReceipt) => {
86
+ if (!txReceipt) {
87
+ throw new Error(`transaction: ${tx.hash} failed to mine`);
88
+ }
89
+ const status = txReceipt.status;
90
+ const txnHash = txReceipt.hash;
91
+ if (!status) {
92
+ throw new Error(`transaction: ${txnHash} failed to mine`);
93
+ }
94
+ return txReceipt;
95
+ });
96
+ }
57
97
  static convertIssuerInfo(issuer) {
58
98
  const [state, claimsTreeRoot, revocationTreeRoot, rootOfRoots] = issuer.map((i) => js_merkletree_1.Hash.fromBigInt(i).hex());
59
99
  return {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SubjectPosition = exports.MerklizedRootPosition = exports.ProofPurpose = exports.CredentialStatusType = exports.ProofType = exports.VerifiableConstants = void 0;
3
+ exports.RefreshServiceType = exports.SubjectPosition = exports.MerklizedRootPosition = exports.ProofPurpose = exports.CredentialStatusType = exports.ProofType = exports.VerifiableConstants = void 0;
4
4
  /** Verifiable constants */
5
5
  exports.VerifiableConstants = Object.freeze({
6
6
  ERRORS: {
@@ -103,3 +103,12 @@ var SubjectPosition;
103
103
  // Value save subject in value part of claim.
104
104
  SubjectPosition["Value"] = "value";
105
105
  })(SubjectPosition = exports.SubjectPosition || (exports.SubjectPosition = {}));
106
+ /**
107
+ * RefreshServiceType type for refreshService
108
+ *
109
+ * @enum {string}
110
+ */
111
+ var RefreshServiceType;
112
+ (function (RefreshServiceType) {
113
+ RefreshServiceType["Iden3RefreshService2023"] = "Iden3RefreshService2023";
114
+ })(RefreshServiceType = exports.RefreshServiceType || (exports.RefreshServiceType = {}));
@@ -50,12 +50,30 @@ export const QueryOperators = {
50
50
  };
51
51
  const allOperations = Object.values(QueryOperators);
52
52
  export const availableTypesOperators = new Map([
53
- [XSDNS.Boolean, [QueryOperators.$eq, QueryOperators.$ne]],
53
+ [XSDNS.Boolean, [QueryOperators.$eq, QueryOperators.$ne, QueryOperators.$sd]],
54
54
  [XSDNS.Integer, allOperations],
55
55
  [XSDNS.NonNegativeInteger, allOperations],
56
56
  [XSDNS.PositiveInteger, allOperations],
57
- [XSDNS.Double, [QueryOperators.$eq, QueryOperators.$ne, QueryOperators.$in, QueryOperators.$nin]],
58
- [XSDNS.String, [QueryOperators.$eq, QueryOperators.$ne, QueryOperators.$in, QueryOperators.$nin]],
57
+ [
58
+ XSDNS.Double,
59
+ [
60
+ QueryOperators.$eq,
61
+ QueryOperators.$ne,
62
+ QueryOperators.$in,
63
+ QueryOperators.$nin,
64
+ QueryOperators.$sd
65
+ ]
66
+ ],
67
+ [
68
+ XSDNS.String,
69
+ [
70
+ QueryOperators.$eq,
71
+ QueryOperators.$ne,
72
+ QueryOperators.$in,
73
+ QueryOperators.$nin,
74
+ QueryOperators.$sd
75
+ ]
76
+ ],
59
77
  [XSDNS.DateTime, allOperations]
60
78
  ]);
61
79
  /**
@@ -25,7 +25,7 @@ export class LinkedMultiQueryInputs extends BaseConfig {
25
25
  if (!this.query[i]) {
26
26
  enabled.push(0);
27
27
  claimPathNotExists.push(0);
28
- claimPathMtp.push([]);
28
+ claimPathMtp.push(new Array(this.getMTLevelsClaim()).fill('0'));
29
29
  claimPathMtpNoAux.push('0');
30
30
  claimPathMtpAuxHi.push('0');
31
31
  claimPathMtpAuxHv.push('0');
@@ -1,4 +1,4 @@
1
- import { DID } from '@iden3/js-iden3-core';
1
+ import { DID, getChainId } from '@iden3/js-iden3-core';
2
2
  import { W3CCredential, VerifiableConstants, CredentialStatusType } from './../verifiable';
3
3
  import * as uuid from 'uuid';
4
4
  import { CredentialStatusResolverRegistry } from './status/resolver';
@@ -50,6 +50,7 @@ export class CredentialWallet {
50
50
  cr['@context'] = context;
51
51
  cr.type = credentialType;
52
52
  cr.expirationDate = expirationDate ? new Date(expirationDate * 1000).toISOString() : undefined;
53
+ cr.refreshService = request.refreshService;
53
54
  cr.issuanceDate = new Date().toISOString();
54
55
  cr.credentialSubject = credentialSubject;
55
56
  cr.issuer = issuer.string();
@@ -57,7 +58,7 @@ export class CredentialWallet {
57
58
  id: request.credentialSchema,
58
59
  type: VerifiableConstants.JSON_SCHEMA_VALIDATOR
59
60
  };
60
- cr.credentialStatus = this.buildCredentialStatus(request);
61
+ cr.credentialStatus = this.buildCredentialStatus(request, issuer);
61
62
  return cr;
62
63
  };
63
64
  // if no credential status resolvers are provided
@@ -123,7 +124,7 @@ export class CredentialWallet {
123
124
  * @param {CredentialRequest} request
124
125
  * @returns `CredentialStatus`
125
126
  */
126
- buildCredentialStatus(request) {
127
+ buildCredentialStatus(request, issuer) {
127
128
  const credentialStatus = {
128
129
  id: request.revocationOpts.id,
129
130
  type: request.revocationOpts.type,
@@ -142,6 +143,23 @@ export class CredentialWallet {
142
143
  ? `${credentialStatus.id.replace(/\/$/, '')}/node?state=${request.revocationOpts.issuerState}`
143
144
  : `${credentialStatus.id.replace(/\/$/, '')}`
144
145
  };
146
+ case CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023: {
147
+ const issuerId = DID.idFromDID(issuer);
148
+ const chainId = getChainId(DID.blockchainFromId(issuerId), DID.networkIdFromId(issuerId));
149
+ const searchParams = [
150
+ ['revocationNonce', request.revocationOpts.nonce?.toString() || ''],
151
+ ['contractAddress', `${chainId}:${request.revocationOpts.id}`],
152
+ ['state', request.revocationOpts.issuerState || '']
153
+ ]
154
+ .filter(([, value]) => Boolean(value))
155
+ .map(([key, value]) => `${key}=${value}`)
156
+ .join('&');
157
+ return {
158
+ ...credentialStatus,
159
+ // `[did]:[methodid]:[chain]:[network]:[id]/credentialStatus?(revocationNonce=value)&[contractAddress=[chainID]:[contractAddress]]&(state=issuerState)`
160
+ id: `${issuer.string()}/credentialStatus?${searchParams}`
161
+ };
162
+ }
145
163
  default:
146
164
  return credentialStatus;
147
165
  }
@@ -3,6 +3,7 @@ export * from './status/reverse-sparse-merkle-tree';
3
3
  export * from './status/sparse-merkle-tree';
4
4
  export * from './status/resolver';
5
5
  export * from './status/agent-revocation';
6
+ export * from './status/credential-status-publisher';
6
7
  export * from './status/utils';
7
8
  export * from './credential-wallet';
8
9
  export * from './rhs';
@@ -1,13 +1,16 @@
1
- import { newHashFromBigInt, testBit, NodeLeaf } from '@iden3/js-merkletree';
1
+ import { Hash, testBit, NodeLeaf } from '@iden3/js-merkletree';
2
2
  import { NODE_TYPE_LEAF } from '@iden3/js-merkletree';
3
3
  import { hashElems } from '@iden3/js-merkletree';
4
4
  import { ProofNode } from './status/reverse-sparse-merkle-tree';
5
+ import { Iden3SmtRhsCredentialStatusPublisher } from './status/credential-status-publisher';
6
+ import { CredentialStatusType } from '../verifiable';
5
7
  /**
6
8
  * Pushes identity state information to a reverse hash service.
7
9
  *
8
10
  * A reverse hash service (RHS) is a centralized or decentralized service for storing publicly available data about identity.
9
11
  * Such data are identity state and state of revocation tree and roots tree root tree.
10
12
  *
13
+ * @deprecated Use `pushHashesToReverseHashService` instead.
11
14
  * @param {Hash} state - current state of identity
12
15
  * @param {TreesModel} trees - current trees of identity (claims, revocation, rootOfRoots )
13
16
  * @param {string} rhsUrl - URL of service
@@ -15,6 +18,23 @@ import { ProofNode } from './status/reverse-sparse-merkle-tree';
15
18
  * @returns void
16
19
  */
17
20
  export async function pushHashesToRHS(state, trees, rhsUrl, revokedNonces) {
21
+ const nodes = await getNodesRepresentation(revokedNonces, trees, state);
22
+ const publisher = new Iden3SmtRhsCredentialStatusPublisher();
23
+ await publisher.publish({
24
+ nodes,
25
+ credentialStatusType: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
26
+ rhsUrl: rhsUrl
27
+ });
28
+ }
29
+ /**
30
+ * Retrieves the representation of nodes for generating a proof.
31
+ *
32
+ * @param revokedNonces - An array of revoked nonces.
33
+ * @param trees - The TreesModel object containing the necessary trees.
34
+ * @param state - The hash of the state.
35
+ * @returns A Promise that resolves to an array of ProofNode objects.
36
+ */
37
+ export async function getNodesRepresentation(revokedNonces, trees, state) {
18
38
  const nb = new NodesBuilder();
19
39
  if (revokedNonces) {
20
40
  await addRevocationNode(nb, trees, revokedNonces);
@@ -28,15 +48,7 @@ export async function pushHashesToRHS(state, trees, rhsUrl, revokedNonces) {
28
48
  await trees.rootsTree.root()
29
49
  ]));
30
50
  }
31
- if (nb.nodes.length > 0) {
32
- await saveNodes(nb.nodes, rhsUrl);
33
- }
34
- }
35
- async function saveNodes(nodes, nodeUrl) {
36
- const nodesJSON = nodes.map((n) => n.toJSON());
37
- const resp = await fetch(nodeUrl + '/node', { method: 'post', body: JSON.stringify(nodesJSON) });
38
- const status = resp.status;
39
- return status === 200;
51
+ return nb.nodes;
40
52
  }
41
53
  async function addRoRNode(nb, trees) {
42
54
  const currentRootsTree = trees.rootsTree;
@@ -62,8 +74,8 @@ class NodesBuilder {
62
74
  }
63
75
  async addKey(tree, nodeKey) {
64
76
  const { value: nodeValue, siblings } = await tree.get(nodeKey);
65
- const nodeKeyHash = newHashFromBigInt(nodeKey);
66
- const nodeValueHash = newHashFromBigInt(nodeValue);
77
+ const nodeKeyHash = Hash.fromBigInt(nodeKey);
78
+ const nodeValueHash = Hash.fromBigInt(nodeValue);
67
79
  const node = new NodeLeaf(nodeKeyHash, nodeValueHash);
68
80
  const newNodes = await buildNodesUp(siblings, node);
69
81
  for (const n of newNodes) {
@@ -93,7 +105,7 @@ async function buildNodesUp(siblings, node) {
93
105
  nodes[index] = new ProofNode();
94
106
  }
95
107
  nodes[sl].hash = prevHash;
96
- const hashOfOne = newHashFromBigInt(BigInt(1));
108
+ const hashOfOne = Hash.fromBigInt(BigInt(1));
97
109
  nodes[sl].children = [node.entry[0], node.entry[1], hashOfOne];
98
110
  const pathKey = node.entry[0];
99
111
  for (let i = sl - 1; i >= 0; i--) {
@@ -107,7 +119,7 @@ async function buildNodesUp(siblings, node) {
107
119
  nodes[i].children[0] = prevHash;
108
120
  nodes[i].children[1] = siblings[i];
109
121
  }
110
- nodes[i].hash = await hashElems([nodes[i].children[0].bigInt(), nodes[i].children[1].bigInt()]);
122
+ nodes[i].hash = hashElems([nodes[i].children[0].bigInt(), nodes[i].children[1].bigInt()]);
111
123
  prevHash = nodes[i].hash;
112
124
  }
113
125
  return nodes;
@@ -0,0 +1,78 @@
1
+ import { CredentialStatusType } from '../../verifiable';
2
+ /**
3
+ * Registry for managing credential status publishers.
4
+ */
5
+ export class CredentialStatusPublisherRegistry {
6
+ constructor() {
7
+ this._publishers = new Map();
8
+ }
9
+ /**
10
+ * Registers one or more credential status publishers for a given type.
11
+ * @param type - The credential status type.
12
+ * @param publisher - One or more credential status publishers.
13
+ */
14
+ register(type, ...publisher) {
15
+ const publishers = this._publishers.get(type) ?? [];
16
+ publishers.push(...publisher);
17
+ this._publishers.set(type, publishers);
18
+ }
19
+ /**
20
+ * Retrieves the credential status publishers for a given type.
21
+ * @param type - The credential status type.
22
+ * @returns An array of credential status publishers or undefined if none are registered for the given type.
23
+ */
24
+ get(type) {
25
+ return this._publishers.get(type);
26
+ }
27
+ }
28
+ /**
29
+ * Implementation of the ICredentialStatusPublisher interface for publishing on-chain credential status.
30
+ */
31
+ export class Iden3OnchainSmtCredentialStatusPublisher {
32
+ constructor(_storage) {
33
+ this._storage = _storage;
34
+ }
35
+ /**
36
+ * Publishes the credential status to the blockchain.
37
+ * @param params - The parameters for publishing the credential status.
38
+ */
39
+ async publish(params) {
40
+ if (![CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023].includes(params.credentialStatusType)) {
41
+ throw new Error(`On-chain publishing is not supported for credential status type ${params.credentialStatusType}`);
42
+ }
43
+ const nodesBigInts = params.nodes.map((n) => n.children.map((c) => c.bigInt()));
44
+ const txPromise = this._storage.saveNodes(nodesBigInts);
45
+ if (params.onChain?.txCallback) {
46
+ const cb = params.onChain?.txCallback;
47
+ txPromise.then((receipt) => cb(receipt));
48
+ return;
49
+ }
50
+ await txPromise;
51
+ }
52
+ }
53
+ /**
54
+ * Implementation of the ICredentialStatusPublisher interface for publishing off-chain credential status.
55
+ */
56
+ export class Iden3SmtRhsCredentialStatusPublisher {
57
+ /**
58
+ * Publishes the credential status to a specified node URL.
59
+ * @param params - The parameters for publishing the credential status.
60
+ * @param params.nodes - The proof nodes to be published.
61
+ * @param params.rhsUrl - The URL of the node to publish the credential status to.
62
+ * @returns A promise that resolves when the credential status is successfully published.
63
+ * @throws An error if the publishing fails.
64
+ */
65
+ async publish(params) {
66
+ if (![CredentialStatusType.Iden3ReverseSparseMerkleTreeProof].includes(params.credentialStatusType)) {
67
+ throw new Error(`On-chain publishing is not supported for credential status type ${params.credentialStatusType}`);
68
+ }
69
+ const nodesJSON = params.nodes.map((n) => n.toJSON());
70
+ const resp = await fetch(params.rhsUrl + '/node', {
71
+ method: 'post',
72
+ body: JSON.stringify(nodesJSON)
73
+ });
74
+ if (resp.status !== 200) {
75
+ throw new Error(`Failed to publish credential status. Status: ${resp.status}`);
76
+ }
77
+ }
78
+ }
@@ -1,4 +1,6 @@
1
1
  import { DID } from '@iden3/js-iden3-core';
2
+ import { PublicKey } from '@iden3/js-crypto';
3
+ import { KmsKeyType, keyPath } from '../kms';
2
4
  /**
3
5
  * Retrieves the user DID from a given credential.
4
6
  * If the credential does not have a credentialSubject.id property, the issuer DID is returned.
@@ -17,3 +19,13 @@ export const getUserDIDFromCredential = (issuerDID, credential) => {
17
19
  }
18
20
  return DID.parse(credential.credentialSubject.id);
19
21
  };
22
+ export const getKMSIdByAuthCredential = (credential) => {
23
+ if (!credential.type.includes('AuthBJJCredential')) {
24
+ throw new Error("can't sign with not AuthBJJCredential credential");
25
+ }
26
+ const x = credential.credentialSubject['x'];
27
+ const y = credential.credentialSubject['y'];
28
+ const pb = new PublicKey([BigInt(x), BigInt(y)]);
29
+ const kp = keyPath(KmsKeyType.BabyJubJub, pb.hex());
30
+ return { type: KmsKeyType.BabyJubJub, id: kp };
31
+ };
@@ -15,6 +15,8 @@ export const PROTOCOL_MESSAGE_TYPE = Object.freeze({
15
15
  CREDENTIAL_OFFER_MESSAGE_TYPE: IDEN3_PROTOCOL + 'credentials/1.0/offer',
16
16
  // CredentialIssuanceResponseMessageType is type for message with a credential issuance
17
17
  CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE: IDEN3_PROTOCOL + 'credentials/1.0/issuance-response',
18
+ // CredentialRefreshMessageType is type for message with a credential issuance
19
+ CREDENTIAL_REFRESH_MESSAGE_TYPE: IDEN3_PROTOCOL + 'credentials/1.0/refresh',
18
20
  // DeviceRegistrationRequestMessageType defines device registration request type of the communication protocol
19
21
  DEVICE_REGISTRATION_REQUEST_MESSAGE_TYPE: IDEN3_PROTOCOL + 'devices/1.0/registration',
20
22
  // MessageFetMessageFetchRequestMessageType defines message fetch request type of the communication protocol.
@@ -16,7 +16,7 @@ import { DID } from '@iden3/js-iden3-core';
16
16
  */
17
17
  export class FetchHandler {
18
18
  /**
19
- * Creates an instance of AuthHandler.
19
+ * Creates an instance of FetchHandler.
20
20
  * @param {IPackageManager} _packerMgr - package manager to unpack message envelope
21
21
  */
22
22
  constructor(_packerMgr) {
@@ -29,7 +29,7 @@ export class FetchHandler {
29
29
  * offer: Uint8Array; offer - raw offer message
30
30
  * opts
31
31
  * }) options how to fetch credential
32
- * @returns `Promise<W3CCredential>`
32
+ * @returns `Promise<W3CCredential[]>`
33
33
  */
34
34
  async handleCredentialOffer(offer, opts) {
35
35
  if (!opts) {
@@ -1,3 +1,4 @@
1
1
  export * from './auth';
2
2
  export * from './fetch';
3
3
  export * from './contract-request';
4
+ export * from './refresh';
@@ -0,0 +1,72 @@
1
+ import { MediaType } from '../constants';
2
+ import { PROTOCOL_MESSAGE_TYPE } from '../constants';
3
+ import { RefreshServiceType, W3CCredential } from '../../verifiable';
4
+ import { byteEncoder } from '../../utils';
5
+ import { proving, ProvingMethodAlg } from '@iden3/js-jwz';
6
+ import { DID } from '@iden3/js-iden3-core';
7
+ import { CircuitId } from '../../circuits';
8
+ import { randomUUID } from 'crypto';
9
+ /**
10
+ *
11
+ * Allows to refresh credential from refresh service and return refreshed credential
12
+ *
13
+ * @public
14
+
15
+ * @class RefreshHandler
16
+ * @implements implements RefreshHandler interface
17
+ */
18
+ export class RefreshHandler {
19
+ /**
20
+ * Creates an instance of RefreshHandler.
21
+ * @param {RefreshHandlerOptions} _options - refresh handler options
22
+ */
23
+ constructor(_options) {
24
+ this._options = _options;
25
+ }
26
+ async refreshCredential(credential, opts) {
27
+ if (!credential.refreshService) {
28
+ throw new Error('refreshService not specified for W3CCredential');
29
+ }
30
+ if (credential.refreshService.type !== RefreshServiceType.Iden3RefreshService2023) {
31
+ throw new Error(`refresh service type ${credential.refreshService.type} is not supported`);
32
+ }
33
+ const otherIdentifier = credential.credentialSubject.id;
34
+ if (!otherIdentifier) {
35
+ throw new Error('self credentials do not support refresh');
36
+ }
37
+ const senderDID = DID.parse(otherIdentifier);
38
+ const zkpParams = {
39
+ senderDID,
40
+ provingMethodAlg: new ProvingMethodAlg(proving.provingMethodGroth16AuthV2Instance.methodAlg.alg, CircuitId.AuthV2)
41
+ };
42
+ const refreshMsg = {
43
+ id: randomUUID(),
44
+ typ: MediaType.ZKPMessage,
45
+ type: PROTOCOL_MESSAGE_TYPE.CREDENTIAL_REFRESH_MESSAGE_TYPE,
46
+ thid: randomUUID(),
47
+ body: {
48
+ id: otherIdentifier,
49
+ reason: opts?.reason ?? 'credential is expired'
50
+ },
51
+ from: otherIdentifier,
52
+ to: credential.issuer
53
+ };
54
+ const msgBytes = byteEncoder.encode(JSON.stringify(refreshMsg));
55
+ const jwzToken = await this._options.packageManager.pack(MediaType.ZKPMessage, msgBytes, zkpParams);
56
+ const resp = await fetch(credential.refreshService.id, {
57
+ method: 'post',
58
+ headers: {
59
+ 'Content-Type': 'application/json'
60
+ },
61
+ body: jwzToken
62
+ });
63
+ if (resp.status !== 200) {
64
+ throw new Error(`could not refresh W3C credential, return status ${resp.status}`);
65
+ }
66
+ const respBody = await resp.json();
67
+ if (!respBody.body?.credential) {
68
+ throw new Error('no credential in CredentialIssuanceMessage response');
69
+ }
70
+ return W3CCredential.fromJSON(respBody.body.credential);
71
+ }
72
+ }
@@ -5,11 +5,11 @@ import { hashElems, ZERO_HASH } from '@iden3/js-merkletree';
5
5
  import { generateProfileDID, subjectPositionIndex } from './common';
6
6
  import * as uuid from 'uuid';
7
7
  import { Parser, JsonSchemaValidator, cacheLoader } from '../schema-processor';
8
- import { MerkleTreeType } from '../storage/entities/mt';
9
- import { keyPath } from '../kms/provider-helpers';
8
+ import { MerkleTreeType } from '../storage';
10
9
  import { VerifiableConstants, BJJSignatureProof2021, MerklizedRootPosition, SubjectPosition, W3CCredential, Iden3SparseMerkleTreeProof, ProofType, CredentialStatusType } from '../verifiable';
11
- import { pushHashesToRHS } from '../credentials';
10
+ import { getKMSIdByAuthCredential, getNodesRepresentation, pushHashesToRHS } from '../credentials';
12
11
  import { byteEncoder } from '../utils';
12
+ import { CredentialStatusPublisherRegistry, Iden3SmtRhsCredentialStatusPublisher } from '../credentials/status/credential-status-publisher';
13
13
  /**
14
14
  * @public
15
15
  * Wallet instance to manage the digital identity based on iden3 protocol
@@ -30,10 +30,19 @@ export class IdentityWallet {
30
30
  * @param {ICredentialWallet} _credentialWallet - credential wallet instance to quickly access credential CRUD functionality
31
31
  * @public
32
32
  */
33
- constructor(_kms, _storage, _credentialWallet) {
33
+ constructor(_kms, _storage, _credentialWallet, _opts) {
34
34
  this._kms = _kms;
35
35
  this._storage = _storage;
36
36
  this._credentialWallet = _credentialWallet;
37
+ this._opts = _opts;
38
+ if (!_opts?.credentialStatusPublisherRegistry) {
39
+ this._credentialStatusPublisherRegistry = new CredentialStatusPublisherRegistry();
40
+ this._credentialStatusPublisherRegistry.register(CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, new Iden3SmtRhsCredentialStatusPublisher());
41
+ }
42
+ else {
43
+ this._credentialStatusPublisherRegistry = this._opts
44
+ ?.credentialStatusPublisherRegistry;
45
+ }
37
46
  }
38
47
  /**
39
48
  * {@inheritDoc IIdentityWallet.createIdentity}
@@ -107,9 +116,10 @@ export class IdentityWallet {
107
116
  coreClaim: authClaim
108
117
  });
109
118
  credential.proof = [mtpProof];
110
- if (opts.revocationOpts.type === CredentialStatusType.Iden3ReverseSparseMerkleTreeProof) {
111
- await this.publishStateToRHS(did, opts.revocationOpts.id);
112
- }
119
+ await this.publishRevocationInfoByCredentialStatusType(did, opts.revocationOpts.type, {
120
+ rhsUrl: opts.revocationOpts.id,
121
+ onChain: opts.revocationOpts.onChain
122
+ });
113
123
  await this._storage.identity.saveIdentity({
114
124
  did: did.string(),
115
125
  state: currentState,
@@ -171,10 +181,11 @@ export class IdentityWallet {
171
181
  }
172
182
  /** {@inheritDoc IIdentityWallet.getDIDTreeModel} */
173
183
  async getDIDTreeModel(did) {
174
- const claimsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(did.string(), MerkleTreeType.Claims);
175
- const revocationTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(did.string(), MerkleTreeType.Revocations);
176
- const rootsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(did.string(), MerkleTreeType.Roots);
177
- const state = await hashElems([
184
+ const didStr = did.string();
185
+ const claimsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(didStr, MerkleTreeType.Claims);
186
+ const revocationTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(didStr, MerkleTreeType.Revocations);
187
+ const rootsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(didStr, MerkleTreeType.Roots);
188
+ const state = hashElems([
178
189
  (await claimsTree.root()).bigInt(),
179
190
  (await revocationTree.root()).bigInt(),
180
191
  (await rootsTree.root()).bigInt()
@@ -228,14 +239,14 @@ export class IdentityWallet {
228
239
  }
229
240
  /** {@inheritDoc IIdentityWallet.sign} */
230
241
  async sign(message, credential) {
231
- const keyKMSId = this.getKMSIdByAuthCredential(credential);
242
+ const keyKMSId = getKMSIdByAuthCredential(credential);
232
243
  const payload = poseidon.hashBytes(message);
233
244
  const signature = await this._kms.sign(keyKMSId, BytesHelper.intToBytes(payload));
234
245
  return Signature.newFromCompressed(signature);
235
246
  }
236
247
  /** {@inheritDoc IIdentityWallet.signChallenge} */
237
248
  async signChallenge(challenge, credential) {
238
- const keyKMSId = this.getKMSIdByAuthCredential(credential);
249
+ const keyKMSId = getKMSIdByAuthCredential(credential);
239
250
  const signature = await this._kms.sign(keyKMSId, BytesHelper.intToBytes(challenge));
240
251
  return Signature.newFromCompressed(signature);
241
252
  }
@@ -403,15 +414,35 @@ export class IdentityWallet {
403
414
  rootsTree: treeState.rootsTree
404
415
  }, rhsURL, revokedNonces);
405
416
  }
406
- getKMSIdByAuthCredential(credential) {
407
- if (credential.type.indexOf('AuthBJJCredential') === -1) {
408
- throw new Error("can't sign with not AuthBJJCredential credential");
417
+ /** {@inheritDoc IIdentityWallet.publishRevocationInfoByCredentialStatusType} */
418
+ async publishRevocationInfoByCredentialStatusType(issuerDID, credentialStatusType, opts) {
419
+ const rhsPublishers = this._credentialStatusPublisherRegistry.get(credentialStatusType);
420
+ if (!rhsPublishers) {
421
+ throw new Error(`there is no registered publisher to save hash is not registered for ${credentialStatusType} is not registered`);
422
+ }
423
+ let nodes = [];
424
+ if (opts?.treeModel) {
425
+ nodes = await getNodesRepresentation(opts.revokedNonces, {
426
+ revocationTree: opts.treeModel.revocationTree,
427
+ claimsTree: opts.treeModel.claimsTree,
428
+ state: opts.treeModel.state,
429
+ rootsTree: opts.treeModel.rootsTree
430
+ }, opts.treeModel.state);
431
+ }
432
+ else {
433
+ const treeState = await this.getDIDTreeModel(issuerDID);
434
+ nodes = await getNodesRepresentation(opts?.revokedNonces, {
435
+ revocationTree: treeState.revocationTree,
436
+ claimsTree: treeState.claimsTree,
437
+ state: treeState.state,
438
+ rootsTree: treeState.rootsTree
439
+ }, treeState.state);
440
+ }
441
+ if (!nodes.length) {
442
+ return;
409
443
  }
410
- const x = credential.credentialSubject['x'];
411
- const y = credential.credentialSubject['y'];
412
- const pb = new PublicKey([BigInt(x), BigInt(y)]);
413
- const kp = keyPath(KmsKeyType.BabyJubJub, pb.hex());
414
- return { type: KmsKeyType.BabyJubJub, id: kp };
444
+ const rhsPublishersTask = rhsPublishers.map((publisher) => publisher.publish({ nodes, ...opts, credentialStatusType, issuerDID }));
445
+ await Promise.all(rhsPublishersTask);
415
446
  }
416
447
  async getCoreClaimFromCredential(credential) {
417
448
  const coreClaimFromSigProof = credential.getCoreClaimFromProof(ProofType.BJJSignature);
@@ -1 +1 @@
1
- [{ "inputs": [{ "internalType": "uint256", "name": "id", "type": "uint256" }, { "internalType": "uint64", "name": "nonce", "type": "uint64" }], "name": "getRevocationStatus", "outputs": [{ "components": [{ "components": [{ "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint256", "name": "claimsTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "revocationTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "rootOfRoots", "type": "uint256" }], "internalType": "structIOnchainCredentialStatusResolver.IdentityStateRoots", "name": "issuer", "type": "tuple" }, { "components": [{ "internalType": "uint256", "name": "root", "type": "uint256" }, { "internalType": "bool", "name": "existence", "type": "bool" }, { "internalType": "uint256[]", "name": "siblings", "type": "uint256[]" }, { "internalType": "uint256", "name": "index", "type": "uint256" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bool", "name": "auxExistence", "type": "bool" }, { "internalType": "uint256", "name": "auxIndex", "type": "uint256" }, { "internalType": "uint256", "name": "auxValue", "type": "uint256" }], "internalType": "structIOnchainCredentialStatusResolver.Proof", "name": "mtp", "type": "tuple" }], "internalType": "structIOnchainCredentialStatusResolver.CredentialStatus", "name": "", "type": "tuple" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "id", "type": "uint256" }, { "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint64", "name": "nonce", "type": "uint64" }], "name": "getRevocationStatusByIdAndState", "outputs": [{ "components": [{ "components": [{ "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint256", "name": "claimsTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "revocationTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "rootOfRoots", "type": "uint256" }], "internalType": "structIOnchainCredentialStatusResolver.IdentityStateRoots", "name": "issuer", "type": "tuple" }, { "components": [{ "internalType": "uint256", "name": "root", "type": "uint256" }, { "internalType": "bool", "name": "existence", "type": "bool" }, { "internalType": "uint256[]", "name": "siblings", "type": "uint256[]" }, { "internalType": "uint256", "name": "index", "type": "uint256" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bool", "name": "auxExistence", "type": "bool" }, { "internalType": "uint256", "name": "auxIndex", "type": "uint256" }, { "internalType": "uint256", "name": "auxValue", "type": "uint256" }], "internalType": "structIOnchainCredentialStatusResolver.Proof", "name": "mtp", "type": "tuple" }], "internalType": "structIOnchainCredentialStatusResolver.CredentialStatus", "name": "", "type": "tuple" }], "stateMutability": "view", "type": "function" }]
1
+ [{ "inputs": [], "name": "MAX_SMT_DEPTH", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "key", "type": "uint256" }], "name": "getNode", "outputs": [{ "internalType": "uint256[]", "name": "", "type": "uint256[]" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "id", "type": "uint256" }, { "internalType": "uint64", "name": "nonce", "type": "uint64" }], "name": "getRevocationStatus", "outputs": [{ "components": [{ "components": [{ "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint256", "name": "claimsTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "revocationTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "rootOfRoots", "type": "uint256" }], "internalType": "struct IOnchainCredentialStatusResolver.IdentityStateRoots", "name": "issuer", "type": "tuple" }, { "components": [{ "internalType": "uint256", "name": "root", "type": "uint256" }, { "internalType": "bool", "name": "existence", "type": "bool" }, { "internalType": "uint256[]", "name": "siblings", "type": "uint256[]" }, { "internalType": "uint256", "name": "index", "type": "uint256" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bool", "name": "auxExistence", "type": "bool" }, { "internalType": "uint256", "name": "auxIndex", "type": "uint256" }, { "internalType": "uint256", "name": "auxValue", "type": "uint256" }], "internalType": "struct IOnchainCredentialStatusResolver.Proof", "name": "mtp", "type": "tuple" }], "internalType": "struct IOnchainCredentialStatusResolver.CredentialStatus", "name": "", "type": "tuple" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "id", "type": "uint256" }, { "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint64", "name": "nonce", "type": "uint64" }], "name": "getRevocationStatusByIdAndState", "outputs": [{ "components": [{ "components": [{ "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint256", "name": "claimsTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "revocationTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "rootOfRoots", "type": "uint256" }], "internalType": "struct IOnchainCredentialStatusResolver.IdentityStateRoots", "name": "issuer", "type": "tuple" }, { "components": [{ "internalType": "uint256", "name": "root", "type": "uint256" }, { "internalType": "bool", "name": "existence", "type": "bool" }, { "internalType": "uint256[]", "name": "siblings", "type": "uint256[]" }, { "internalType": "uint256", "name": "index", "type": "uint256" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bool", "name": "auxExistence", "type": "bool" }, { "internalType": "uint256", "name": "auxIndex", "type": "uint256" }, { "internalType": "uint256", "name": "auxValue", "type": "uint256" }], "internalType": "struct IOnchainCredentialStatusResolver.Proof", "name": "mtp", "type": "tuple" }], "internalType": "struct IOnchainCredentialStatusResolver.CredentialStatus", "name": "", "type": "tuple" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256[][]", "name": "nodes", "type": "uint256[][]" }], "name": "saveNodes", "outputs": [], "stateMutability": "nonpayable", "type": "function" }]