@enbox/dids 0.0.4 → 0.0.5

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 (48) hide show
  1. package/dist/browser.mjs +1 -1
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/methods/did-dht-dns.js +455 -0
  4. package/dist/esm/methods/did-dht-dns.js.map +1 -0
  5. package/dist/esm/methods/did-dht-pkarr.js +168 -0
  6. package/dist/esm/methods/did-dht-pkarr.js.map +1 -0
  7. package/dist/esm/methods/did-dht-types.js +116 -0
  8. package/dist/esm/methods/did-dht-types.js.map +1 -0
  9. package/dist/esm/methods/did-dht-utils.js +143 -0
  10. package/dist/esm/methods/did-dht-utils.js.map +1 -0
  11. package/dist/esm/methods/did-dht.js +65 -842
  12. package/dist/esm/methods/did-dht.js.map +1 -1
  13. package/dist/esm/methods/did-ion-utils.js +161 -0
  14. package/dist/esm/methods/did-ion-utils.js.map +1 -0
  15. package/dist/esm/methods/did-ion.js +4 -151
  16. package/dist/esm/methods/did-ion.js.map +1 -1
  17. package/dist/esm/methods/did-key-utils.js +235 -0
  18. package/dist/esm/methods/did-key-utils.js.map +1 -0
  19. package/dist/esm/methods/did-key.js +6 -222
  20. package/dist/esm/methods/did-key.js.map +1 -1
  21. package/dist/types/methods/did-dht-dns.d.ts +114 -0
  22. package/dist/types/methods/did-dht-dns.d.ts.map +1 -0
  23. package/dist/types/methods/did-dht-pkarr.d.ts +56 -0
  24. package/dist/types/methods/did-dht-pkarr.d.ts.map +1 -0
  25. package/dist/types/methods/did-dht-types.d.ts +286 -0
  26. package/dist/types/methods/did-dht-types.d.ts.map +1 -0
  27. package/dist/types/methods/did-dht-utils.d.ts +54 -0
  28. package/dist/types/methods/did-dht-utils.d.ts.map +1 -0
  29. package/dist/types/methods/did-dht.d.ts +42 -457
  30. package/dist/types/methods/did-dht.d.ts.map +1 -1
  31. package/dist/types/methods/did-ion-utils.d.ts +86 -0
  32. package/dist/types/methods/did-ion-utils.d.ts.map +1 -0
  33. package/dist/types/methods/did-ion.d.ts +2 -82
  34. package/dist/types/methods/did-ion.d.ts.map +1 -1
  35. package/dist/types/methods/did-key-utils.d.ts +138 -0
  36. package/dist/types/methods/did-key-utils.d.ts.map +1 -0
  37. package/dist/types/methods/did-key.d.ts +3 -124
  38. package/dist/types/methods/did-key.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/methods/did-dht-dns.ts +516 -0
  41. package/src/methods/did-dht-pkarr.ts +192 -0
  42. package/src/methods/did-dht-types.ts +316 -0
  43. package/src/methods/did-dht-utils.ts +157 -0
  44. package/src/methods/did-dht.ts +122 -1128
  45. package/src/methods/did-ion-utils.ts +186 -0
  46. package/src/methods/did-ion.ts +14 -190
  47. package/src/methods/did-key-utils.ts +258 -0
  48. package/src/methods/did-key.ts +14 -266
@@ -0,0 +1,186 @@
1
+ import type { Jwk } from '@enbox/crypto';
2
+ import type {
3
+ IonDocumentModel,
4
+ IonPublicKeyModel,
5
+ IonPublicKeyPurpose,
6
+ JwkEs256k,
7
+ } from '@decentralized-identity/ion-sdk';
8
+
9
+ import type { DidService } from '../types/did-core.js';
10
+ import type { DidIonCreateRequest, DidIonVerificationMethod } from './did-ion.js';
11
+
12
+ import { computeJwkThumbprint } from '@enbox/crypto';
13
+ import { IonDid, IonRequest } from '@decentralized-identity/ion-sdk';
14
+
15
+ /**
16
+ * The `DidIonUtils` class provides utility functions to support operations in the DID ION method.
17
+ */
18
+ export class DidIonUtils {
19
+ /**
20
+ * Appends a specified path to a base URL, ensuring proper formatting of the resulting URL.
21
+ *
22
+ * This method is useful for constructing URLs for accessing various endpoints, such as Sidetree
23
+ * nodes in the ION network. It handles the nuances of URL path concatenation, including the
24
+ * addition or removal of leading/trailing slashes, to create a well-formed URL.
25
+ *
26
+ * @param params - The parameters for URL construction.
27
+ * @param params.baseUrl - The base URL to which the path will be appended.
28
+ * @param params.path - The path to append to the base URL.
29
+ * @returns The fully constructed URL string with the path appended to the base URL.
30
+ */
31
+ public static appendPathToUrl({ baseUrl, path }: {
32
+ baseUrl: string;
33
+ path: string;
34
+ }): string {
35
+ const url = new URL(baseUrl);
36
+ url.pathname = url.pathname.endsWith('/') ? url.pathname : url.pathname + '/';
37
+ url.pathname += path.startsWith('/') ? path.substring(1) : path;
38
+
39
+ return url.toString();
40
+ }
41
+
42
+ /**
43
+ * Computes the Long Form DID URI given an ION DID's recovery key, update key, services, and
44
+ * verification methods.
45
+ *
46
+ * @param params - The parameters for computing the Long Form DID URI.
47
+ * @param params.recoveryKey - The ION Recovery Key.
48
+ * @param params.updateKey - The ION Update Key.
49
+ * @param params.services - An array of services associated with the DID.
50
+ * @param params.verificationMethods - An array of verification methods associated with the DID.
51
+ * @returns A Promise resolving to the Long Form DID URI.
52
+ */
53
+ public static async computeLongFormDidUri({ recoveryKey, updateKey, services, verificationMethods }: {
54
+ recoveryKey: Jwk;
55
+ updateKey: Jwk;
56
+ services: DidService[];
57
+ verificationMethods: DidIonVerificationMethod[];
58
+ }): Promise<string> {
59
+ // Create the ION document.
60
+ const ionDocument = await DidIonUtils.createIonDocument({ services, verificationMethods });
61
+
62
+ // Normalize JWK to onnly include specific members and in lexicographic order.
63
+ const normalizedRecoveryKey = DidIonUtils.normalizeJwk(recoveryKey);
64
+ const normalizedUpdateKey = DidIonUtils.normalizeJwk(updateKey);
65
+
66
+ // Compute the Long Form DID URI.
67
+ const longFormDidUri = await IonDid.createLongFormDid({
68
+ document : ionDocument,
69
+ recoveryKey : normalizedRecoveryKey as JwkEs256k,
70
+ updateKey : normalizedUpdateKey as JwkEs256k
71
+ });
72
+
73
+ return longFormDidUri;
74
+ }
75
+
76
+ /**
77
+ * Constructs a Sidetree Create Operation request for a DID document within the ION network.
78
+ *
79
+ * This method prepares the necessary payload for submitting a Create Operation to a Sidetree
80
+ * node, encapsulating the details of the DID document, recovery key, and update key.
81
+ *
82
+ * @param params - Parameters required to construct the Create Operation request.
83
+ * @param params.ionDocument - The DID document model containing public keys and service endpoints.
84
+ * @param params.recoveryKey - The recovery public key in JWK format.
85
+ * @param params.updateKey - The update public key in JWK format.
86
+ * @returns A promise resolving to the ION Create Operation request model, ready for submission to a Sidetree node.
87
+ */
88
+ public static async constructCreateRequest({ ionDocument, recoveryKey, updateKey }: {
89
+ ionDocument: IonDocumentModel,
90
+ recoveryKey: Jwk,
91
+ updateKey: Jwk
92
+ }): Promise<DidIonCreateRequest> {
93
+ // Create an ION DID create request operation.
94
+ const createRequest = await IonRequest.createCreateRequest({
95
+ document : ionDocument,
96
+ recoveryKey : DidIonUtils.normalizeJwk(recoveryKey) as JwkEs256k,
97
+ updateKey : DidIonUtils.normalizeJwk(updateKey) as JwkEs256k
98
+ }) as DidIonCreateRequest;
99
+
100
+ return createRequest;
101
+ }
102
+
103
+ /**
104
+ * Assembles an ION document model from provided services and verification methods
105
+ *
106
+ * This model serves as the foundation for a DID document in the ION network, facilitating the
107
+ * creation and management of decentralized identities. It translates service endpoints and
108
+ * public keys into a format compatible with the Sidetree protocol, ensuring the resulting DID
109
+ * document adheres to the required specifications for ION DIDs. This method is essential for
110
+ * constructing the payload needed to register or update DIDs within the ION network.
111
+ *
112
+ * @param params - The parameters containing the services and verification methods to include in the ION document.
113
+ * @param params.services - A list of service endpoints to be included in the DID document, specifying ways to interact with the DID subject.
114
+ * @param params.verificationMethods - A list of verification methods to be included, detailing the
115
+ * cryptographic keys and their intended uses within the DID document.
116
+ * @returns A Promise resolving to an `IonDocumentModel`, ready for use in Sidetree operations like DID creation and updates.
117
+ */
118
+ public static async createIonDocument({ services, verificationMethods }: {
119
+ services: DidService[];
120
+ verificationMethods: DidIonVerificationMethod[]
121
+ }): Promise<IonDocumentModel> {
122
+ /**
123
+ * STEP 1: Convert verification methods to ION SDK format.
124
+ */
125
+ const ionPublicKeys: IonPublicKeyModel[] = [];
126
+
127
+ for (const vm of verificationMethods) {
128
+ // Use the given ID, the key's ID, or the key's thumbprint as the verification method ID.
129
+ let methodId = vm.id ?? vm.publicKeyJwk.kid ?? await computeJwkThumbprint({ jwk: vm.publicKeyJwk });
130
+ methodId = `${methodId.split('#').pop()}`; // Remove fragment prefix, if any.
131
+
132
+ // Convert public key JWK to ION format.
133
+ const publicKey: IonPublicKeyModel = {
134
+ id : methodId,
135
+ publicKeyJwk : DidIonUtils.normalizeJwk(vm.publicKeyJwk),
136
+ purposes : vm.purposes as IonPublicKeyPurpose[],
137
+ type : 'JsonWebKey2020'
138
+ };
139
+
140
+ ionPublicKeys.push(publicKey);
141
+ }
142
+
143
+ /**
144
+ * STEP 2: Convert service entries, if any, to ION SDK format.
145
+ */
146
+ const ionServices = services.map(service => ({
147
+ ...service,
148
+ id: `${service.id.split('#').pop()}` // Remove fragment prefix, if any.
149
+ }));
150
+
151
+ /**
152
+ * STEP 3: Format as ION document.
153
+ */
154
+ const ionDocumentModel: IonDocumentModel = {
155
+ publicKeys : ionPublicKeys,
156
+ services : ionServices
157
+ };
158
+
159
+ return ionDocumentModel;
160
+ }
161
+
162
+ /**
163
+ * Normalize the given JWK to include only specific members and in lexicographic order.
164
+ *
165
+ * @param jwk - The JWK to normalize.
166
+ * @returns The normalized JWK.
167
+ */
168
+ private static normalizeJwk(jwk: Jwk): Jwk {
169
+ const keyType = jwk.kty;
170
+ let normalizedJwk: Jwk;
171
+
172
+ if (keyType === 'EC') {
173
+ normalizedJwk = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
174
+ } else if (keyType === 'oct') {
175
+ normalizedJwk = { k: jwk.k, kty: jwk.kty };
176
+ } else if (keyType === 'OKP') {
177
+ normalizedJwk = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
178
+ } else if (keyType === 'RSA') {
179
+ normalizedJwk = { e: jwk.e, kty: jwk.kty, n: jwk.n };
180
+ } else {
181
+ throw new Error(`Unsupported key type: ${keyType}`);
182
+ }
183
+
184
+ return normalizedJwk;
185
+ }
186
+ }
@@ -1,21 +1,4 @@
1
- import type {
2
- IonDocumentModel,
3
- IonPublicKeyModel,
4
- IonPublicKeyPurpose,
5
- JwkEs256k,
6
- } from '@decentralized-identity/ion-sdk';
7
- import type {
8
- Jwk,
9
- KeyIdentifier,
10
- KeyImporterExporter,
11
- KeyManager,
12
- KmsExportKeyParams,
13
- KmsImportKeyParams,
14
- } from '@enbox/crypto';
15
-
16
- import { computeJwkThumbprint, LocalKeyManager } from '@enbox/crypto';
17
- import { IonDid, IonRequest } from '@decentralized-identity/ion-sdk';
18
-
1
+ import type { IonDocumentModel } from '@decentralized-identity/ion-sdk';
19
2
  import type { PortableDid } from '../types/portable-did.js';
20
3
  import type { DidCreateOptions, DidCreateVerificationMethod, DidRegistrationResult } from '../methods/did-method.js';
21
4
  import type {
@@ -26,9 +9,20 @@ import type {
26
9
  DidVerificationMethod,
27
10
  DidVerificationRelationship,
28
11
  } from '../types/did-core.js';
12
+ import type {
13
+ Jwk,
14
+ KeyIdentifier,
15
+ KeyImporterExporter,
16
+ KeyManager,
17
+ KmsExportKeyParams,
18
+ KmsImportKeyParams,
19
+ } from '@enbox/crypto';
20
+
21
+ import { LocalKeyManager } from '@enbox/crypto';
29
22
 
30
23
  import { BearerDid } from '../bearer-did.js';
31
24
  import { Did } from '../did.js';
25
+ import { DidIonUtils } from './did-ion-utils.js';
32
26
  import { DidMethod } from '../methods/did-method.js';
33
27
  import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js';
34
28
  import { getVerificationRelationshipsById } from '../utils.js';
@@ -721,175 +715,5 @@ export class DidIon extends DidMethod {
721
715
  }
722
716
  }
723
717
 
724
- /**
725
- * The `DidIonUtils` class provides utility functions to support operations in the DID ION method.
726
- */
727
- export class DidIonUtils {
728
- /**
729
- * Appends a specified path to a base URL, ensuring proper formatting of the resulting URL.
730
- *
731
- * This method is useful for constructing URLs for accessing various endpoints, such as Sidetree
732
- * nodes in the ION network. It handles the nuances of URL path concatenation, including the
733
- * addition or removal of leading/trailing slashes, to create a well-formed URL.
734
- *
735
- * @param params - The parameters for URL construction.
736
- * @param params.baseUrl - The base URL to which the path will be appended.
737
- * @param params.path - The path to append to the base URL.
738
- * @returns The fully constructed URL string with the path appended to the base URL.
739
- */
740
- public static appendPathToUrl({ baseUrl, path }: {
741
- baseUrl: string;
742
- path: string;
743
- }): string {
744
- const url = new URL(baseUrl);
745
- url.pathname = url.pathname.endsWith('/') ? url.pathname : url.pathname + '/';
746
- url.pathname += path.startsWith('/') ? path.substring(1) : path;
747
-
748
- return url.toString();
749
- }
750
-
751
- /**
752
- * Computes the Long Form DID URI given an ION DID's recovery key, update key, services, and
753
- * verification methods.
754
- *
755
- * @param params - The parameters for computing the Long Form DID URI.
756
- * @param params.recoveryKey - The ION Recovery Key.
757
- * @param params.updateKey - The ION Update Key.
758
- * @param params.services - An array of services associated with the DID.
759
- * @param params.verificationMethods - An array of verification methods associated with the DID.
760
- * @returns A Promise resolving to the Long Form DID URI.
761
- */
762
- public static async computeLongFormDidUri({ recoveryKey, updateKey, services, verificationMethods }: {
763
- recoveryKey: Jwk;
764
- updateKey: Jwk;
765
- services: DidService[];
766
- verificationMethods: DidIonVerificationMethod[];
767
- }): Promise<string> {
768
- // Create the ION document.
769
- const ionDocument = await DidIonUtils.createIonDocument({ services, verificationMethods });
770
-
771
- // Normalize JWK to onnly include specific members and in lexicographic order.
772
- const normalizedRecoveryKey = DidIonUtils.normalizeJwk(recoveryKey);
773
- const normalizedUpdateKey = DidIonUtils.normalizeJwk(updateKey);
774
-
775
- // Compute the Long Form DID URI.
776
- const longFormDidUri = await IonDid.createLongFormDid({
777
- document : ionDocument,
778
- recoveryKey : normalizedRecoveryKey as JwkEs256k,
779
- updateKey : normalizedUpdateKey as JwkEs256k
780
- });
781
-
782
- return longFormDidUri;
783
- }
784
-
785
- /**
786
- * Constructs a Sidetree Create Operation request for a DID document within the ION network.
787
- *
788
- * This method prepares the necessary payload for submitting a Create Operation to a Sidetree
789
- * node, encapsulating the details of the DID document, recovery key, and update key.
790
- *
791
- * @param params - Parameters required to construct the Create Operation request.
792
- * @param params.ionDocument - The DID document model containing public keys and service endpoints.
793
- * @param params.recoveryKey - The recovery public key in JWK format.
794
- * @param params.updateKey - The update public key in JWK format.
795
- * @returns A promise resolving to the ION Create Operation request model, ready for submission to a Sidetree node.
796
- */
797
- public static async constructCreateRequest({ ionDocument, recoveryKey, updateKey }: {
798
- ionDocument: IonDocumentModel,
799
- recoveryKey: Jwk,
800
- updateKey: Jwk
801
- }): Promise<DidIonCreateRequest> {
802
- // Create an ION DID create request operation.
803
- const createRequest = await IonRequest.createCreateRequest({
804
- document : ionDocument,
805
- recoveryKey : DidIonUtils.normalizeJwk(recoveryKey) as JwkEs256k,
806
- updateKey : DidIonUtils.normalizeJwk(updateKey) as JwkEs256k
807
- }) as DidIonCreateRequest;
808
-
809
- return createRequest;
810
- }
811
-
812
- /**
813
- * Assembles an ION document model from provided services and verification methods
814
- *
815
- * This model serves as the foundation for a DID document in the ION network, facilitating the
816
- * creation and management of decentralized identities. It translates service endpoints and
817
- * public keys into a format compatible with the Sidetree protocol, ensuring the resulting DID
818
- * document adheres to the required specifications for ION DIDs. This method is essential for
819
- * constructing the payload needed to register or update DIDs within the ION network.
820
- *
821
- * @param params - The parameters containing the services and verification methods to include in the ION document.
822
- * @param params.services - A list of service endpoints to be included in the DID document, specifying ways to interact with the DID subject.
823
- * @param params.verificationMethods - A list of verification methods to be included, detailing the
824
- * cryptographic keys and their intended uses within the DID document.
825
- * @returns A Promise resolving to an `IonDocumentModel`, ready for use in Sidetree operations like DID creation and updates.
826
- */
827
- public static async createIonDocument({ services, verificationMethods }: {
828
- services: DidService[];
829
- verificationMethods: DidIonVerificationMethod[]
830
- }): Promise<IonDocumentModel> {
831
- /**
832
- * STEP 1: Convert verification methods to ION SDK format.
833
- */
834
- const ionPublicKeys: IonPublicKeyModel[] = [];
835
-
836
- for (const vm of verificationMethods) {
837
- // Use the given ID, the key's ID, or the key's thumbprint as the verification method ID.
838
- let methodId = vm.id ?? vm.publicKeyJwk.kid ?? await computeJwkThumbprint({ jwk: vm.publicKeyJwk });
839
- methodId = `${methodId.split('#').pop()}`; // Remove fragment prefix, if any.
840
-
841
- // Convert public key JWK to ION format.
842
- const publicKey: IonPublicKeyModel = {
843
- id : methodId,
844
- publicKeyJwk : DidIonUtils.normalizeJwk(vm.publicKeyJwk),
845
- purposes : vm.purposes as IonPublicKeyPurpose[],
846
- type : 'JsonWebKey2020'
847
- };
848
-
849
- ionPublicKeys.push(publicKey);
850
- }
851
-
852
- /**
853
- * STEP 2: Convert service entries, if any, to ION SDK format.
854
- */
855
- const ionServices = services.map(service => ({
856
- ...service,
857
- id: `${service.id.split('#').pop()}` // Remove fragment prefix, if any.
858
- }));
859
-
860
- /**
861
- * STEP 3: Format as ION document.
862
- */
863
- const ionDocumentModel: IonDocumentModel = {
864
- publicKeys : ionPublicKeys,
865
- services : ionServices
866
- };
867
-
868
- return ionDocumentModel;
869
- }
870
-
871
- /**
872
- * Normalize the given JWK to include only specific members and in lexicographic order.
873
- *
874
- * @param jwk - The JWK to normalize.
875
- * @returns The normalized JWK.
876
- */
877
- private static normalizeJwk(jwk: Jwk): Jwk {
878
- const keyType = jwk.kty;
879
- let normalizedJwk: Jwk;
880
-
881
- if (keyType === 'EC') {
882
- normalizedJwk = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
883
- } else if (keyType === 'oct') {
884
- normalizedJwk = { k: jwk.k, kty: jwk.kty };
885
- } else if (keyType === 'OKP') {
886
- normalizedJwk = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
887
- } else if (keyType === 'RSA') {
888
- normalizedJwk = { e: jwk.e, kty: jwk.kty, n: jwk.n };
889
- } else {
890
- throw new Error(`Unsupported key type: ${keyType}`);
891
- }
892
-
893
- return normalizedJwk;
894
- }
895
- }
718
+ // Re-export DidIonUtils from its dedicated module for backward compatibility.
719
+ export { DidIonUtils } from './did-ion-utils.js';
@@ -0,0 +1,258 @@
1
+ import type { AsymmetricKeyConverter, Jwk, KeyCompressor } from '@enbox/crypto';
2
+ import type { MulticodecCode, MulticodecDefinition } from '@enbox/common';
3
+
4
+ import { Multicodec } from '@enbox/common';
5
+ import { Ed25519, Secp256k1, Secp256r1 } from '@enbox/crypto';
6
+
7
+ import { keyBytesToMultibaseId } from '../utils.js';
8
+ import { DidError, DidErrorCode } from '../did-error.js';
9
+
10
+ /**
11
+ * Private helper that maps algorithm identifiers to their corresponding DID Key
12
+ * {@link DidKeyRegisteredKeyType | registered key type}.
13
+ *
14
+ * Note: This is also used by `DidKeyUtils.publicKeyToMultibaseId()` to validate key types.
15
+ */
16
+ export const AlgorithmToKeyTypeMap = {
17
+ Ed25519 : 'Ed25519',
18
+ ES256K : 'secp256k1',
19
+ ES256 : 'secp256r1',
20
+ 'P-256' : 'secp256r1',
21
+ secp256k1 : 'secp256k1',
22
+ secp256r1 : 'secp256r1',
23
+ } as const;
24
+
25
+ /**
26
+ * The `DidKeyUtils` class provides utility functions to support operations in the DID Key method.
27
+ */
28
+ export class DidKeyUtils {
29
+ /**
30
+ * A mapping from JSON Web Key (JWK) property descriptors to multicodec names.
31
+ *
32
+ * This mapping is used to convert keys in JWK (JSON Web Key) format to multicodec format.
33
+ *
34
+ * @remarks
35
+ * The keys of this object are strings that describe the JOSE key type and usage,
36
+ * such as 'Ed25519:public', 'Ed25519:private', etc. The values are the corresponding multicodec
37
+ * names used to represent these key types.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const multicodecName = JWK_TO_MULTICODEC['Ed25519:public'];
42
+ * // Returns 'ed25519-pub', the multicodec name for an Ed25519 public key
43
+ * ```
44
+ */
45
+ private static JWK_TO_MULTICODEC: { [key: string]: string } = {
46
+ 'Ed25519:public' : 'ed25519-pub',
47
+ 'Ed25519:private' : 'ed25519-priv',
48
+ 'secp256k1:public' : 'secp256k1-pub',
49
+ 'secp256k1:private' : 'secp256k1-priv',
50
+ };
51
+
52
+ /**
53
+ * Defines the expected byte lengths for public keys associated with different cryptographic
54
+ * algorithms, indexed by their multicodec code values.
55
+ */
56
+ public static MULTICODEC_PUBLIC_KEY_LENGTH: Record<number, number> = {
57
+ // secp256k1-pub - Secp256k1 public key (compressed) - 33 bytes
58
+ 0xe7: 33,
59
+
60
+ // ed25519-pub - Ed25519 public key - 32 bytes
61
+ 0xed: 32
62
+ };
63
+
64
+ /**
65
+ * A mapping from multicodec names to their corresponding JOSE (JSON Object Signing and Encryption)
66
+ * representations. This mapping facilitates the conversion of multicodec key formats to
67
+ * JWK (JSON Web Key) formats.
68
+ *
69
+ * @remarks
70
+ * The keys of this object are multicodec names, such as 'ed25519-pub', 'ed25519-priv', etc.
71
+ * The values are objects representing the corresponding JWK properties for that key type.
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * const joseKey = MULTICODEC_TO_JWK['ed25519-pub'];
76
+ * // Returns a partial JWK for an Ed25519 public key
77
+ * ```
78
+ */
79
+ private static MULTICODEC_TO_JWK: { [key: string]: Jwk } = {
80
+ 'ed25519-pub' : { crv: 'Ed25519', kty: 'OKP', x: '' },
81
+ 'ed25519-priv' : { crv: 'Ed25519', kty: 'OKP', x: '', d: '' },
82
+ 'secp256k1-pub' : { crv: 'secp256k1', kty: 'EC', x: '', y: '' },
83
+ 'secp256k1-priv' : { crv: 'secp256k1', kty: 'EC', x: '', y: '', d: '' },
84
+ };
85
+
86
+ /**
87
+ * Converts a JWK (JSON Web Key) to a Multicodec code and name.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * const jwk: Jwk = { crv: 'Ed25519', kty: 'OKP', x: '...' };
92
+ * const { code, name } = await DidKeyUtils.jwkToMulticodec({ jwk });
93
+ * ```
94
+ *
95
+ * @param params - The parameters for the conversion.
96
+ * @param params.jwk - The JSON Web Key to be converted.
97
+ * @returns A promise that resolves to a Multicodec definition.
98
+ */
99
+ public static async jwkToMulticodec({ jwk }: {
100
+ jwk: Jwk
101
+ }): Promise<MulticodecDefinition<MulticodecCode>> {
102
+ const params: string[] = [];
103
+
104
+ if (jwk.crv) {
105
+ params.push(jwk.crv);
106
+ if (jwk.d) {
107
+ params.push('private');
108
+ } else {
109
+ params.push('public');
110
+ }
111
+ }
112
+
113
+ const lookupKey = params.join(':');
114
+ const name = DidKeyUtils.JWK_TO_MULTICODEC[lookupKey];
115
+
116
+ if (name === undefined) {
117
+ throw new Error(`Unsupported JWK to Multicodec conversion: '${lookupKey}'`);
118
+ }
119
+
120
+ const code = Multicodec.getCodeFromName({ name });
121
+
122
+ return { code, name };
123
+ }
124
+
125
+ /**
126
+ * Returns the appropriate public key compressor for the specified cryptographic curve.
127
+ *
128
+ * @param curve - The cryptographic curve to use for the key conversion.
129
+ * @returns A public key compressor for the specified curve.
130
+ */
131
+ public static keyCompressor(
132
+ curve: string
133
+ ): KeyCompressor['compressPublicKey'] {
134
+ // ): ({ publicKeyBytes }: { publicKeyBytes: Uint8Array }) => Promise<Uint8Array> {
135
+ const compressors = {
136
+ 'P-256' : Secp256r1.compressPublicKey,
137
+ 'secp256k1' : Secp256k1.compressPublicKey
138
+ } as Record<string, KeyCompressor['compressPublicKey']>;
139
+
140
+ const compressor = compressors[curve];
141
+
142
+ if (!compressor) {throw new DidError(DidErrorCode.InvalidPublicKeyType, `Unsupported curve: ${curve}`);}
143
+
144
+ return compressor;
145
+ }
146
+
147
+ /**
148
+ * Returns the appropriate key converter for the specified cryptographic curve.
149
+ *
150
+ * @param curve - The cryptographic curve to use for the key conversion.
151
+ * @returns An `AsymmetricKeyConverter` for the specified curve.
152
+ */
153
+ public static keyConverter(curve: string): AsymmetricKeyConverter {
154
+ const converters: Record<string, AsymmetricKeyConverter> = {
155
+ 'Ed25519' : Ed25519,
156
+ 'P-256' : Secp256r1,
157
+ 'secp256k1' : Secp256k1,
158
+ };
159
+
160
+ const converter = converters[curve];
161
+
162
+ if (!converter) {throw new DidError(DidErrorCode.InvalidPublicKeyType, `Unsupported curve: ${curve}`);}
163
+
164
+ return converter;
165
+ }
166
+
167
+ /**
168
+ * Converts a Multicodec code or name to parial JWK (JSON Web Key).
169
+ *
170
+ * @example
171
+ * ```ts
172
+ * const partialJwk = await DidKeyUtils.multicodecToJwk({ name: 'ed25519-pub' });
173
+ * ```
174
+ *
175
+ * @param params - The parameters for the conversion.
176
+ * @param params.code - Optional Multicodec code to convert.
177
+ * @param params.name - Optional Multicodec name to convert.
178
+ * @returns A promise that resolves to a JOSE format key.
179
+ */
180
+ public static async multicodecToJwk({ code, name }: {
181
+ code?: MulticodecCode,
182
+ name?: string
183
+ }): Promise<Jwk> {
184
+ // Either code or name must be specified, but not both.
185
+ if (!(name ? !code : code)) {
186
+ throw new Error(`Either 'name' or 'code' must be defined, but not both.`);
187
+ }
188
+
189
+ // If name is undefined, lookup by code.
190
+ name = (name === undefined ) ? Multicodec.getNameFromCode({ code: code! }) : name;
191
+
192
+ const lookupKey = name;
193
+ const jose = DidKeyUtils.MULTICODEC_TO_JWK[lookupKey];
194
+
195
+ if (jose === undefined) {
196
+ throw new Error(`Unsupported Multicodec to JWK conversion`);
197
+ }
198
+
199
+ return { ...jose };
200
+ }
201
+
202
+ /**
203
+ * Converts a public key in JWK (JSON Web Key) format to a multibase identifier.
204
+ *
205
+ * @remarks
206
+ * Note: All secp public keys are converted to compressed point encoding
207
+ * before the multibase identifier is computed.
208
+ *
209
+ * Per {@link https://github.com/multiformats/multicodec/blob/master/table.csv | Multicodec table}:
210
+ * Public keys for Elliptic Curve cryptography algorithms (e.g., secp256k1,
211
+ * secp256k1r1, secp384r1, etc.) are always represented with compressed point
212
+ * encoding (e.g., secp256k1-pub, p256-pub, p384-pub, etc.).
213
+ *
214
+ * Per {@link https://datatracker.ietf.org/doc/html/rfc8812#name-jose-and-cose-secp256k1-cur | RFC 8812}:
215
+ * "As a compressed point encoding representation is not defined for JWK
216
+ * elliptic curve points, the uncompressed point encoding defined there
217
+ * MUST be used. The x and y values represented MUST both be exactly
218
+ * 256 bits, with any leading zeros preserved."
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * const publicKey = { crv: 'Ed25519', kty: 'OKP', x: '...' };
223
+ * const multibaseId = await DidKeyUtils.publicKeyToMultibaseId({ publicKey });
224
+ * ```
225
+ *
226
+ * @param params - The parameters for the conversion.
227
+ * @param params.publicKey - The public key in JWK format.
228
+ * @returns A promise that resolves to the multibase identifier.
229
+ */
230
+ public static async publicKeyToMultibaseId({ publicKey }: {
231
+ publicKey: Jwk
232
+ }): Promise<string> {
233
+ if (!(publicKey?.crv && publicKey.crv in AlgorithmToKeyTypeMap)) {
234
+ throw new DidError(DidErrorCode.InvalidPublicKeyType, `Public key contains an unsupported key type: ${publicKey?.crv ?? 'undefined'}`);
235
+ }
236
+
237
+ // Convert the public key from JWK format to a byte array.
238
+ let publicKeyBytes = await DidKeyUtils.keyConverter(publicKey.crv).publicKeyToBytes({ publicKey });
239
+
240
+ // Compress the public key if it is an elliptic curve key.
241
+ if (/^(secp256k1|P-256|P-384|P-521)$/.test(publicKey.crv)) {
242
+ publicKeyBytes = await DidKeyUtils.keyCompressor(publicKey.crv)({ publicKeyBytes });
243
+ }
244
+
245
+ // Convert the JSON Web Key (JWK) parameters to a Multicodec name.
246
+ const { name: multicodecName } = await DidKeyUtils.jwkToMulticodec({ jwk: publicKey });
247
+
248
+ // Compute the multibase identifier based on the provided key.
249
+ const multibaseId = keyBytesToMultibaseId({
250
+ keyBytes: publicKeyBytes,
251
+ multicodecName
252
+ });
253
+
254
+ return multibaseId;
255
+ }
256
+ }
257
+
258
+