@beclab/olaresid 0.1.13 → 0.2.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.
Files changed (181) hide show
  1. package/CLI-TREE.md +107 -0
  2. package/CLI.md +122 -1340
  3. package/README.md +30 -12
  4. package/SDK-TREE.md +151 -0
  5. package/TAG.md +95 -41
  6. package/config.json +6 -4
  7. package/dist/abi/TerminusDIDQueryABI.d.ts +397 -0
  8. package/dist/abi/TerminusDIDQueryABI.d.ts.map +1 -0
  9. package/dist/abi/TerminusDIDQueryABI.js +519 -0
  10. package/dist/abi/TerminusDIDQueryABI.js.map +1 -0
  11. package/dist/business/index.d.ts.map +1 -1
  12. package/dist/business/index.js +9 -23
  13. package/dist/business/index.js.map +1 -1
  14. package/dist/business/tag-context.d.ts +1 -0
  15. package/dist/business/tag-context.d.ts.map +1 -1
  16. package/dist/business/tag-context.js +13 -7
  17. package/dist/business/tag-context.js.map +1 -1
  18. package/dist/cli.js +177 -76
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config/index.d.ts +16 -4
  21. package/dist/config/index.d.ts.map +1 -1
  22. package/dist/config/index.js +28 -14
  23. package/dist/config/index.js.map +1 -1
  24. package/dist/domain/core.d.ts +65 -0
  25. package/dist/domain/core.d.ts.map +1 -0
  26. package/dist/domain/core.js +317 -0
  27. package/dist/domain/core.js.map +1 -0
  28. package/dist/domain/index.d.ts +104 -57
  29. package/dist/domain/index.d.ts.map +1 -1
  30. package/dist/domain/index.js +188 -428
  31. package/dist/domain/index.js.map +1 -1
  32. package/dist/domain/types.d.ts +56 -0
  33. package/dist/domain/types.d.ts.map +1 -0
  34. package/dist/domain/types.js +3 -0
  35. package/dist/domain/types.js.map +1 -0
  36. package/dist/index.d.ts +80 -23
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +152 -143
  39. package/dist/index.js.map +1 -1
  40. package/dist/utils/crypto-utils.d.ts +110 -0
  41. package/dist/utils/crypto-utils.d.ts.map +1 -1
  42. package/dist/utils/crypto-utils.js +127 -8
  43. package/dist/utils/crypto-utils.js.map +1 -1
  44. package/dist/utils/error-parser.d.ts.map +1 -1
  45. package/dist/utils/error-parser.js +2 -1
  46. package/dist/utils/error-parser.js.map +1 -1
  47. package/dist/utils/event-parser.d.ts +161 -0
  48. package/dist/utils/event-parser.d.ts.map +1 -0
  49. package/dist/utils/event-parser.js +140 -0
  50. package/dist/utils/event-parser.js.map +1 -0
  51. package/dist/utils/tag-type-builder.d.ts +43 -0
  52. package/dist/utils/tag-type-builder.d.ts.map +1 -1
  53. package/dist/utils/tag-type-builder.js +122 -0
  54. package/dist/utils/tag-type-builder.js.map +1 -1
  55. package/dist/utils/tag-type-parser.d.ts +70 -0
  56. package/dist/utils/tag-type-parser.d.ts.map +1 -0
  57. package/dist/utils/tag-type-parser.js +190 -0
  58. package/dist/utils/tag-type-parser.js.map +1 -0
  59. package/examples/create-with-rpc-demo.ts +142 -0
  60. package/examples/fetch-all-flat-demo.ts +159 -0
  61. package/examples/fetch-by-indices-demo.ts +235 -0
  62. package/examples/fetch-domain-demo.ts +137 -0
  63. package/examples/fetch-domains-demo.ts +221 -0
  64. package/examples/frontend-demo/index.html +2 -2
  65. package/examples/frontend-demo/package-lock.json +4 -1
  66. package/examples/index.ts +3 -5
  67. package/jest.config.js +25 -0
  68. package/package.json +6 -2
  69. package/src/abi/TerminusDIDQueryABI.ts +516 -0
  70. package/src/business/index.ts +9 -33
  71. package/src/business/tag-context.ts +35 -7
  72. package/src/cli.ts +253 -90
  73. package/src/config/index.ts +34 -19
  74. package/src/domain/core.ts +382 -0
  75. package/src/domain/index.ts +271 -641
  76. package/src/domain/types.ts +59 -0
  77. package/src/index.ts +221 -207
  78. package/src/utils/crypto-utils.ts +205 -2
  79. package/src/utils/error-parser.ts +2 -1
  80. package/src/utils/event-parser.ts +353 -0
  81. package/src/utils/tag-type-builder.ts +138 -0
  82. package/src/utils/tag-type-parser.ts +246 -0
  83. package/tests/unit/crypto-utils.test.ts +338 -0
  84. package/tests/unit/ed25519-jwk.test.ts +201 -0
  85. package/tests/unit/event-parser.test.ts +690 -0
  86. package/tests/unit/generate-mnemonic.test.ts +268 -0
  87. package/tests/unit/olares-id-format.test.ts +321 -0
  88. package/tests/unit/tag-type-parser.test.ts +802 -0
  89. package/tests/unit/tag-types.test.ts +821 -0
  90. package/tsconfig.json +3 -2
  91. package/dist/abi/ABITypeABI.d.ts +0 -88
  92. package/dist/abi/ABITypeABI.d.ts.map +0 -1
  93. package/dist/abi/ABITypeABI.js +0 -382
  94. package/dist/abi/ABITypeABI.js.map +0 -1
  95. package/dist/abi/RegistryABI.d.ts +0 -77
  96. package/dist/abi/RegistryABI.d.ts.map +0 -1
  97. package/dist/abi/RegistryABI.js +0 -462
  98. package/dist/abi/RegistryABI.js.map +0 -1
  99. package/dist/tag/address.d.ts +0 -11
  100. package/dist/tag/address.d.ts.map +0 -1
  101. package/dist/tag/address.js +0 -44
  102. package/dist/tag/address.js.map +0 -1
  103. package/dist/tag/array.d.ts +0 -14
  104. package/dist/tag/array.d.ts.map +0 -1
  105. package/dist/tag/array.js +0 -72
  106. package/dist/tag/array.js.map +0 -1
  107. package/dist/tag/bool.d.ts +0 -11
  108. package/dist/tag/bool.d.ts.map +0 -1
  109. package/dist/tag/bool.js +0 -43
  110. package/dist/tag/bool.js.map +0 -1
  111. package/dist/tag/bytes.d.ts +0 -11
  112. package/dist/tag/bytes.d.ts.map +0 -1
  113. package/dist/tag/bytes.js +0 -37
  114. package/dist/tag/bytes.js.map +0 -1
  115. package/dist/tag/flarray.d.ts +0 -15
  116. package/dist/tag/flarray.d.ts.map +0 -1
  117. package/dist/tag/flarray.js +0 -81
  118. package/dist/tag/flarray.js.map +0 -1
  119. package/dist/tag/flbytes.d.ts +0 -11
  120. package/dist/tag/flbytes.d.ts.map +0 -1
  121. package/dist/tag/flbytes.js +0 -47
  122. package/dist/tag/flbytes.js.map +0 -1
  123. package/dist/tag/index.d.ts +0 -32
  124. package/dist/tag/index.d.ts.map +0 -1
  125. package/dist/tag/index.js +0 -121
  126. package/dist/tag/index.js.map +0 -1
  127. package/dist/tag/int.d.ts +0 -12
  128. package/dist/tag/int.d.ts.map +0 -1
  129. package/dist/tag/int.js +0 -49
  130. package/dist/tag/int.js.map +0 -1
  131. package/dist/tag/string.d.ts +0 -11
  132. package/dist/tag/string.d.ts.map +0 -1
  133. package/dist/tag/string.js +0 -37
  134. package/dist/tag/string.js.map +0 -1
  135. package/dist/tag/tag.d.ts +0 -67
  136. package/dist/tag/tag.d.ts.map +0 -1
  137. package/dist/tag/tag.js +0 -157
  138. package/dist/tag/tag.js.map +0 -1
  139. package/dist/tag/tuple.d.ts +0 -17
  140. package/dist/tag/tuple.d.ts.map +0 -1
  141. package/dist/tag/tuple.js +0 -162
  142. package/dist/tag/tuple.js.map +0 -1
  143. package/dist/tag/uint.d.ts +0 -12
  144. package/dist/tag/uint.d.ts.map +0 -1
  145. package/dist/tag/uint.js +0 -49
  146. package/dist/tag/uint.js.map +0 -1
  147. package/dist/test/did.d.ts +0 -2
  148. package/dist/test/did.d.ts.map +0 -1
  149. package/dist/test/did.js +0 -177
  150. package/dist/test/did.js.map +0 -1
  151. package/dist/utils/tag-abi-codec.d.ts +0 -69
  152. package/dist/utils/tag-abi-codec.d.ts.map +0 -1
  153. package/dist/utils/tag-abi-codec.js +0 -144
  154. package/dist/utils/tag-abi-codec.js.map +0 -1
  155. package/examples/crypto-utilities.ts +0 -140
  156. package/examples/ed25519-jwk.ts +0 -73
  157. package/examples/generate-mnemonic.ts +0 -149
  158. package/examples/legacy.ts +0 -33
  159. package/examples/olares-id-format.ts +0 -197
  160. package/examples/tag-builder.ts +0 -235
  161. package/examples/tag-nested-tuple.ts +0 -190
  162. package/examples/tag-simple.ts +0 -149
  163. package/examples/tag-tagger.ts +0 -217
  164. package/examples/test-nested-tuple-conversion.ts +0 -143
  165. package/examples/test-type-bytes-parser.ts +0 -70
  166. package/src/abi/ABITypeABI.ts +0 -379
  167. package/src/abi/RegistryABI.ts +0 -459
  168. package/src/tag/address.ts +0 -48
  169. package/src/tag/array.ts +0 -80
  170. package/src/tag/bool.ts +0 -43
  171. package/src/tag/bytes.ts +0 -38
  172. package/src/tag/flarray.ts +0 -99
  173. package/src/tag/flbytes.ts +0 -48
  174. package/src/tag/index.ts +0 -170
  175. package/src/tag/int.ts +0 -51
  176. package/src/tag/string.ts +0 -38
  177. package/src/tag/tag.ts +0 -229
  178. package/src/tag/tuple.ts +0 -193
  179. package/src/tag/uint.ts +0 -51
  180. package/src/test/did.ts +0 -346
  181. package/src/utils/tag-abi-codec.ts +0 -158
@@ -0,0 +1,338 @@
1
+ import {
2
+ generateMnemonic,
3
+ getEthereumAddressFromMnemonic,
4
+ getDIDFromMnemonic,
5
+ getEVMPrivateKeyFromMnemonic,
6
+ deriveDIDFromMnemonic,
7
+ generateDIDKeyData
8
+ } from '../../src/utils/crypto-utils';
9
+
10
+ /**
11
+ * Unit tests for crypto utility functions
12
+ * Tests mnemonic generation, address derivation, DID generation, etc.
13
+ */
14
+
15
+ describe('Crypto Utilities', () => {
16
+ // Test mnemonic for consistent testing
17
+ const testMnemonic =
18
+ 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
19
+
20
+ // ========================================
21
+ // Generate Mnemonic
22
+ // ========================================
23
+
24
+ describe('generateMnemonic', () => {
25
+ it('should generate 12-word mnemonic', () => {
26
+ const mnemonic = generateMnemonic(12);
27
+ expect(typeof mnemonic).toBe('string');
28
+ expect(mnemonic.split(' ').length).toBe(12);
29
+ });
30
+
31
+ it('should generate 24-word mnemonic', () => {
32
+ const mnemonic = generateMnemonic(24);
33
+ expect(typeof mnemonic).toBe('string');
34
+ expect(mnemonic.split(' ').length).toBe(24);
35
+ });
36
+
37
+ it('should generate different mnemonics each time', () => {
38
+ const mnemonic1 = generateMnemonic(12);
39
+ const mnemonic2 = generateMnemonic(12);
40
+ expect(mnemonic1).not.toBe(mnemonic2);
41
+ });
42
+
43
+ it('should generate valid BIP39 mnemonics', () => {
44
+ const mnemonic = generateMnemonic(12);
45
+ // Check that it's lowercase words separated by spaces
46
+ expect(mnemonic).toMatch(/^[a-z]+( [a-z]+){11}$/);
47
+ });
48
+ });
49
+
50
+ // ========================================
51
+ // Ethereum Address Derivation
52
+ // ========================================
53
+
54
+ describe('getEthereumAddressFromMnemonic', () => {
55
+ it('should derive Ethereum address from mnemonic', async () => {
56
+ const address = await getEthereumAddressFromMnemonic(testMnemonic);
57
+
58
+ expect(typeof address).toBe('string');
59
+ expect(address).toMatch(/^0x[a-fA-F0-9]{40}$/);
60
+ });
61
+
62
+ it('should derive consistent address from same mnemonic', async () => {
63
+ const address1 = await getEthereumAddressFromMnemonic(testMnemonic);
64
+ const address2 = await getEthereumAddressFromMnemonic(testMnemonic);
65
+
66
+ expect(address1).toBe(address2);
67
+ });
68
+
69
+ it('should derive different addresses from different mnemonics', async () => {
70
+ const mnemonic1 = generateMnemonic(12);
71
+ const mnemonic2 = generateMnemonic(12);
72
+
73
+ const address1 = await getEthereumAddressFromMnemonic(mnemonic1);
74
+ const address2 = await getEthereumAddressFromMnemonic(mnemonic2);
75
+
76
+ expect(address1).not.toBe(address2);
77
+ });
78
+
79
+ it('should derive expected address for test mnemonic', async () => {
80
+ const address = await getEthereumAddressFromMnemonic(testMnemonic);
81
+ // Known address for this test mnemonic
82
+ expect(address.toLowerCase()).toBe(
83
+ '0x9858effd232b4033e47d90003d41ec34ecaeda94'
84
+ );
85
+ });
86
+ });
87
+
88
+ // ========================================
89
+ // DID Derivation
90
+ // ========================================
91
+
92
+ describe('getDIDFromMnemonic', () => {
93
+ it('should derive DID from mnemonic', async () => {
94
+ const did = await getDIDFromMnemonic(testMnemonic);
95
+
96
+ expect(typeof did).toBe('string');
97
+ expect(did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
98
+ });
99
+
100
+ it('should derive consistent DID from same mnemonic', async () => {
101
+ const did1 = await getDIDFromMnemonic(testMnemonic);
102
+ const did2 = await getDIDFromMnemonic(testMnemonic);
103
+
104
+ expect(did1).toBe(did2);
105
+ });
106
+
107
+ it('should derive different DIDs from different mnemonics', async () => {
108
+ const mnemonic1 = generateMnemonic(12);
109
+ const mnemonic2 = generateMnemonic(12);
110
+
111
+ const did1 = await getDIDFromMnemonic(mnemonic1);
112
+ const did2 = await getDIDFromMnemonic(mnemonic2);
113
+
114
+ expect(did1).not.toBe(did2);
115
+ });
116
+ });
117
+
118
+ // ========================================
119
+ // EVM Private Key Derivation
120
+ // ========================================
121
+
122
+ describe('getEVMPrivateKeyFromMnemonic', () => {
123
+ it('should derive private key from mnemonic', async () => {
124
+ const privateKey = await getEVMPrivateKeyFromMnemonic(testMnemonic);
125
+
126
+ expect(typeof privateKey).toBe('string');
127
+ expect(privateKey).toMatch(/^0x[a-fA-F0-9]{64}$/);
128
+ });
129
+
130
+ it('should derive consistent private key from same mnemonic', async () => {
131
+ const privateKey1 = await getEVMPrivateKeyFromMnemonic(
132
+ testMnemonic
133
+ );
134
+ const privateKey2 = await getEVMPrivateKeyFromMnemonic(
135
+ testMnemonic
136
+ );
137
+
138
+ expect(privateKey1).toBe(privateKey2);
139
+ });
140
+
141
+ it('should derive different private keys from different mnemonics', async () => {
142
+ const mnemonic1 = generateMnemonic(12);
143
+ const mnemonic2 = generateMnemonic(12);
144
+
145
+ const privateKey1 = await getEVMPrivateKeyFromMnemonic(mnemonic1);
146
+ const privateKey2 = await getEVMPrivateKeyFromMnemonic(mnemonic2);
147
+
148
+ expect(privateKey1).not.toBe(privateKey2);
149
+ });
150
+ });
151
+
152
+ // ========================================
153
+ // Derive Owner and DID Together
154
+ // ========================================
155
+
156
+ describe('deriveDIDFromMnemonic', () => {
157
+ it('should derive both owner and DID from mnemonic', async () => {
158
+ const result = await deriveDIDFromMnemonic(testMnemonic);
159
+
160
+ expect(result).toHaveProperty('owner');
161
+ expect(result).toHaveProperty('did');
162
+ expect(result.owner).toMatch(/^0x[a-fA-F0-9]{40}$/);
163
+ expect(result.did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
164
+ });
165
+
166
+ it('should derive consistent results from same mnemonic', async () => {
167
+ const result1 = await deriveDIDFromMnemonic(testMnemonic);
168
+ const result2 = await deriveDIDFromMnemonic(testMnemonic);
169
+
170
+ expect(result1.owner).toBe(result2.owner);
171
+ expect(result1.did).toBe(result2.did);
172
+ });
173
+
174
+ it('should match individual derivation methods', async () => {
175
+ const combined = await deriveDIDFromMnemonic(testMnemonic);
176
+ const separateAddress = await getEthereumAddressFromMnemonic(
177
+ testMnemonic
178
+ );
179
+ const separateDid = await getDIDFromMnemonic(testMnemonic);
180
+
181
+ expect(combined.owner).toBe(separateAddress);
182
+ expect(combined.did).toBe(separateDid);
183
+ });
184
+ });
185
+
186
+ // ========================================
187
+ // Generate Complete Key Data
188
+ // ========================================
189
+
190
+ describe('generateDIDKeyData', () => {
191
+ it('should generate complete key data with 12 words', async () => {
192
+ const keyData = await generateDIDKeyData(12);
193
+
194
+ expect(keyData).toHaveProperty('mnemonic');
195
+ expect(keyData).toHaveProperty('owner');
196
+ expect(keyData).toHaveProperty('did');
197
+
198
+ expect(keyData.mnemonic.split(' ').length).toBe(12);
199
+ expect(keyData.owner).toMatch(/^0x[a-fA-F0-9]{40}$/);
200
+ expect(keyData.did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
201
+ });
202
+
203
+ it('should generate complete key data with 24 words', async () => {
204
+ const keyData = await generateDIDKeyData(24);
205
+
206
+ expect(keyData.mnemonic.split(' ').length).toBe(24);
207
+ expect(keyData.owner).toMatch(/^0x[a-fA-F0-9]{40}$/);
208
+ expect(keyData.did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
209
+ });
210
+
211
+ it('should generate unique key data each time', async () => {
212
+ const keyData1 = await generateDIDKeyData(12);
213
+ const keyData2 = await generateDIDKeyData(12);
214
+
215
+ expect(keyData1.mnemonic).not.toBe(keyData2.mnemonic);
216
+ expect(keyData1.owner).not.toBe(keyData2.owner);
217
+ expect(keyData1.did).not.toBe(keyData2.did);
218
+ });
219
+
220
+ it('should have consistent derivation within generated data', async () => {
221
+ const keyData = await generateDIDKeyData(12);
222
+
223
+ // Verify owner matches when derived separately
224
+ const separateOwner = await getEthereumAddressFromMnemonic(
225
+ keyData.mnemonic
226
+ );
227
+ expect(keyData.owner).toBe(separateOwner);
228
+
229
+ // Verify DID matches when derived separately
230
+ const separateDid = await getDIDFromMnemonic(keyData.mnemonic);
231
+ expect(keyData.did).toBe(separateDid);
232
+ });
233
+ });
234
+
235
+ // ========================================
236
+ // Cross-Validation Tests
237
+ // ========================================
238
+
239
+ describe('Cross-Validation', () => {
240
+ it('should have consistent address across all derivation methods', async () => {
241
+ const mnemonic = generateMnemonic(12);
242
+
243
+ const address1 = await getEthereumAddressFromMnemonic(mnemonic);
244
+ const { owner: address2 } = await deriveDIDFromMnemonic(mnemonic);
245
+ const { owner: address3 } = await generateDIDKeyData(12); // This uses different mnemonic
246
+
247
+ // Same mnemonic should produce same address
248
+ expect(address1).toBe(address2);
249
+
250
+ // Different mnemonics should produce different addresses
251
+ expect(address1).not.toBe(address3);
252
+ });
253
+
254
+ it('should have consistent DID across all derivation methods', async () => {
255
+ const mnemonic = generateMnemonic(12);
256
+
257
+ const did1 = await getDIDFromMnemonic(mnemonic);
258
+ const { did: did2 } = await deriveDIDFromMnemonic(mnemonic);
259
+
260
+ // Same mnemonic should produce same DID
261
+ expect(did1).toBe(did2);
262
+ });
263
+
264
+ it('should derive matching private key and address', async () => {
265
+ const { ethers } = await import('ethers');
266
+
267
+ const privateKey = await getEVMPrivateKeyFromMnemonic(testMnemonic);
268
+ const address = await getEthereumAddressFromMnemonic(testMnemonic);
269
+
270
+ // Create wallet from private key and verify address matches
271
+ const wallet = new ethers.Wallet(privateKey);
272
+ expect(wallet.address).toBe(address);
273
+ });
274
+ });
275
+
276
+ // ========================================
277
+ // Edge Cases
278
+ // ========================================
279
+
280
+ describe('Edge Cases', () => {
281
+ it('should handle 12-word and 24-word mnemonics equally', async () => {
282
+ const mnemonic12 = generateMnemonic(12);
283
+ const mnemonic24 = generateMnemonic(24);
284
+
285
+ const address12 = await getEthereumAddressFromMnemonic(mnemonic12);
286
+ const address24 = await getEthereumAddressFromMnemonic(mnemonic24);
287
+
288
+ // Both should be valid addresses
289
+ expect(address12).toMatch(/^0x[a-fA-F0-9]{40}$/);
290
+ expect(address24).toMatch(/^0x[a-fA-F0-9]{40}$/);
291
+
292
+ const did12 = await getDIDFromMnemonic(mnemonic12);
293
+ const did24 = await getDIDFromMnemonic(mnemonic24);
294
+
295
+ // Both should be valid DIDs
296
+ expect(did12).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
297
+ expect(did24).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
298
+ });
299
+
300
+ it('should handle mnemonic with extra whitespace', async () => {
301
+ // Note: Most implementations trim whitespace before validation
302
+ // So we test that trimmed mnemonics work correctly
303
+ const mnemonicWithSpaces = ' ' + testMnemonic + ' ';
304
+
305
+ // The crypto-utils functions should handle trimming internally
306
+ // For now, we verify that trimmed version works
307
+ const trimmedMnemonic = mnemonicWithSpaces.trim();
308
+ const address = await getEthereumAddressFromMnemonic(
309
+ trimmedMnemonic
310
+ );
311
+
312
+ expect(address).toMatch(/^0x[a-fA-F0-9]{40}$/);
313
+ });
314
+ });
315
+
316
+ // ========================================
317
+ // Known Test Vectors
318
+ // ========================================
319
+
320
+ describe('Known Test Vectors', () => {
321
+ it('should match expected values for standard test mnemonic', async () => {
322
+ const address = await getEthereumAddressFromMnemonic(testMnemonic);
323
+ const privateKey = await getEVMPrivateKeyFromMnemonic(testMnemonic);
324
+ const did = await getDIDFromMnemonic(testMnemonic);
325
+
326
+ // Known values for "abandon abandon..." mnemonic
327
+ expect(address.toLowerCase()).toBe(
328
+ '0x9858effd232b4033e47d90003d41ec34ecaeda94'
329
+ );
330
+ expect(privateKey.toLowerCase()).toBe(
331
+ '0x1ab42cc412b618bdea3a599e3c9bae199ebf030895b039e9db1e30dafb12b727'
332
+ );
333
+
334
+ // DID should be consistent (exact value depends on ed25519 derivation)
335
+ expect(did).toMatch(/^did:key:z6Mk/);
336
+ });
337
+ });
338
+ });
@@ -0,0 +1,201 @@
1
+ import { generateMnemonic, getEd25519JwkFromMnemonic } from '../../src/index';
2
+
3
+ /**
4
+ * Unit tests for Ed25519 JWK generation
5
+ * Tests Ed25519 key pair derivation from mnemonic and JWK format conversion
6
+ */
7
+
8
+ describe('Ed25519 JWK Generation', () => {
9
+ // Test mnemonic for consistent testing
10
+ const testMnemonic =
11
+ 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
12
+
13
+ // ========================================
14
+ // Basic JWK Generation
15
+ // ========================================
16
+
17
+ describe('getEd25519JwkFromMnemonic', () => {
18
+ it('should generate Ed25519 JWK from mnemonic', async () => {
19
+ const result = await getEd25519JwkFromMnemonic(testMnemonic);
20
+
21
+ expect(result).toHaveProperty('publicJwk');
22
+ expect(result).toHaveProperty('privateJwk');
23
+ });
24
+
25
+ it('should generate valid public JWK structure', async () => {
26
+ const { publicJwk } = await getEd25519JwkFromMnemonic(testMnemonic);
27
+
28
+ expect(publicJwk).toHaveProperty('kty', 'OKP');
29
+ expect(publicJwk).toHaveProperty('crv', 'Ed25519');
30
+ expect(publicJwk).toHaveProperty('x');
31
+ expect(typeof publicJwk.x).toBe('string');
32
+ expect(publicJwk.x.length).toBeGreaterThan(0);
33
+ });
34
+
35
+ it('should generate valid private JWK structure', async () => {
36
+ const { privateJwk } = await getEd25519JwkFromMnemonic(
37
+ testMnemonic
38
+ );
39
+
40
+ expect(privateJwk).toHaveProperty('kty', 'OKP');
41
+ expect(privateJwk).toHaveProperty('crv', 'Ed25519');
42
+ expect(privateJwk).toHaveProperty('x');
43
+ expect(privateJwk).toHaveProperty('d');
44
+ expect(typeof privateJwk.x).toBe('string');
45
+ expect(typeof privateJwk.d).toBe('string');
46
+ expect(privateJwk.x.length).toBeGreaterThan(0);
47
+ expect(privateJwk.d.length).toBeGreaterThan(0);
48
+ });
49
+
50
+ it('should have matching public key in both JWKs', async () => {
51
+ const { publicJwk, privateJwk } = await getEd25519JwkFromMnemonic(
52
+ testMnemonic
53
+ );
54
+
55
+ // The public key component (x) should match in both JWKs
56
+ expect(publicJwk.x).toBe(privateJwk.x);
57
+ });
58
+
59
+ it('should generate consistent JWKs from same mnemonic', async () => {
60
+ const result1 = await getEd25519JwkFromMnemonic(testMnemonic);
61
+ const result2 = await getEd25519JwkFromMnemonic(testMnemonic);
62
+
63
+ expect(result1.publicJwk.x).toBe(result2.publicJwk.x);
64
+ expect(result1.privateJwk.x).toBe(result2.privateJwk.x);
65
+ expect(result1.privateJwk.d).toBe(result2.privateJwk.d);
66
+ });
67
+
68
+ it('should generate different JWKs from different mnemonics', async () => {
69
+ const mnemonic1 = generateMnemonic(12);
70
+ const mnemonic2 = generateMnemonic(12);
71
+
72
+ const result1 = await getEd25519JwkFromMnemonic(mnemonic1);
73
+ const result2 = await getEd25519JwkFromMnemonic(mnemonic2);
74
+
75
+ expect(result1.publicJwk.x).not.toBe(result2.publicJwk.x);
76
+ expect(result1.privateJwk.d).not.toBe(result2.privateJwk.d);
77
+ });
78
+ });
79
+
80
+ // ========================================
81
+ // JWK Format Validation
82
+ // ========================================
83
+
84
+ describe('JWK Format Validation', () => {
85
+ it('should generate RFC 7517 compliant public JWK', async () => {
86
+ const { publicJwk } = await getEd25519JwkFromMnemonic(testMnemonic);
87
+
88
+ // RFC 7517: Public key must have kty, crv, x
89
+ expect(publicJwk.kty).toBe('OKP');
90
+ expect(publicJwk.crv).toBe('Ed25519');
91
+ expect(publicJwk.x).toBeDefined();
92
+
93
+ // Public JWK should NOT have private key component (d)
94
+ expect(publicJwk).not.toHaveProperty('d');
95
+ });
96
+
97
+ it('should generate RFC 7517 compliant private JWK', async () => {
98
+ const { privateJwk } = await getEd25519JwkFromMnemonic(
99
+ testMnemonic
100
+ );
101
+
102
+ // RFC 7517: Private key must have kty, crv, x, d
103
+ expect(privateJwk.kty).toBe('OKP');
104
+ expect(privateJwk.crv).toBe('Ed25519');
105
+ expect(privateJwk.x).toBeDefined();
106
+ expect(privateJwk.d).toBeDefined();
107
+ });
108
+
109
+ it('should use base64url encoding for key components', async () => {
110
+ const { publicJwk, privateJwk } = await getEd25519JwkFromMnemonic(
111
+ testMnemonic
112
+ );
113
+
114
+ // Base64url should not contain +, /, or =
115
+ expect(publicJwk.x).not.toMatch(/[+/=]/);
116
+ expect(privateJwk.x).not.toMatch(/[+/=]/);
117
+ expect(privateJwk.d).not.toMatch(/[+/=]/);
118
+ });
119
+ });
120
+
121
+ // ========================================
122
+ // Integration with Other Functions
123
+ // ========================================
124
+
125
+ describe('Integration Tests', () => {
126
+ it('should work with generated mnemonics', async () => {
127
+ const mnemonic = generateMnemonic(12);
128
+ const { publicJwk, privateJwk } = await getEd25519JwkFromMnemonic(
129
+ mnemonic
130
+ );
131
+
132
+ expect(publicJwk.x).toBeDefined();
133
+ expect(privateJwk.d).toBeDefined();
134
+ });
135
+
136
+ it('should work with 12-word and 24-word mnemonics', async () => {
137
+ const mnemonic12 = generateMnemonic(12);
138
+ const mnemonic24 = generateMnemonic(24);
139
+
140
+ const result12 = await getEd25519JwkFromMnemonic(mnemonic12);
141
+ const result24 = await getEd25519JwkFromMnemonic(mnemonic24);
142
+
143
+ // Both should generate valid JWKs
144
+ expect(result12.publicJwk.kty).toBe('OKP');
145
+ expect(result24.publicJwk.kty).toBe('OKP');
146
+
147
+ // Should be different keys
148
+ expect(result12.publicJwk.x).not.toBe(result24.publicJwk.x);
149
+ });
150
+ });
151
+
152
+ // ========================================
153
+ // Known Test Vectors
154
+ // ========================================
155
+
156
+ describe('Known Test Vectors', () => {
157
+ it('should generate expected JWK for standard test mnemonic', async () => {
158
+ const { publicJwk, privateJwk } = await getEd25519JwkFromMnemonic(
159
+ testMnemonic
160
+ );
161
+
162
+ // Verify structure
163
+ expect(publicJwk.kty).toBe('OKP');
164
+ expect(publicJwk.crv).toBe('Ed25519');
165
+ expect(privateJwk.kty).toBe('OKP');
166
+ expect(privateJwk.crv).toBe('Ed25519');
167
+
168
+ // Public and private JWK should have matching public key
169
+ expect(publicJwk.x).toBe(privateJwk.x);
170
+
171
+ // Keys should be valid base64url
172
+ expect(publicJwk.x).toMatch(/^[A-Za-z0-9_-]+$/);
173
+ expect(privateJwk.d).toMatch(/^[A-Za-z0-9_-]+$/);
174
+ });
175
+ });
176
+
177
+ // ========================================
178
+ // Security Tests
179
+ // ========================================
180
+
181
+ describe('Security Tests', () => {
182
+ it('should generate different keys for different mnemonics', async () => {
183
+ const result1 = await getEd25519JwkFromMnemonic(testMnemonic);
184
+ const result2 = await getEd25519JwkFromMnemonic(
185
+ generateMnemonic(12)
186
+ );
187
+
188
+ // Keys should be completely different
189
+ expect(result1.publicJwk.x).not.toBe(result2.publicJwk.x);
190
+ expect(result1.privateJwk.d).not.toBe(result2.privateJwk.d);
191
+ });
192
+
193
+ it('should not expose private key in public JWK', async () => {
194
+ const { publicJwk } = await getEd25519JwkFromMnemonic(testMnemonic);
195
+
196
+ // Ensure private key component is not present
197
+ expect(publicJwk.d).toBeUndefined();
198
+ expect(Object.keys(publicJwk)).not.toContain('d');
199
+ });
200
+ });
201
+ });