@enbox/agent 0.1.2 → 0.1.4

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 (224) hide show
  1. package/dist/browser.mjs +45 -52
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/crypto-api.js +6 -13
  4. package/dist/esm/crypto-api.js.map +1 -1
  5. package/dist/esm/dwn-api.js +80 -78
  6. package/dist/esm/dwn-api.js.map +1 -1
  7. package/dist/esm/hd-identity-vault.js +4 -5
  8. package/dist/esm/hd-identity-vault.js.map +1 -1
  9. package/dist/esm/identity-api.js +1 -1
  10. package/dist/esm/identity-api.js.map +1 -1
  11. package/dist/esm/index.js +0 -2
  12. package/dist/esm/index.js.map +1 -1
  13. package/dist/esm/local-key-manager.js +31 -32
  14. package/dist/esm/local-key-manager.js.map +1 -1
  15. package/dist/esm/prototyping/crypto/jose/jwe-compact.js +1 -2
  16. package/dist/esm/prototyping/crypto/jose/jwe-compact.js.map +1 -1
  17. package/dist/esm/prototyping/crypto/jose/jwe-flattened.js +15 -4
  18. package/dist/esm/prototyping/crypto/jose/jwe-flattened.js.map +1 -1
  19. package/dist/esm/prototyping/crypto/jose/jwe.js +1 -1
  20. package/dist/esm/prototyping/crypto/jose/jwe.js.map +1 -1
  21. package/dist/esm/store-data.js +3 -3
  22. package/dist/esm/store-data.js.map +1 -1
  23. package/dist/esm/store-did.js +1 -1
  24. package/dist/esm/store-did.js.map +1 -1
  25. package/dist/esm/sync-engine-level.js +49 -11
  26. package/dist/esm/sync-engine-level.js.map +1 -1
  27. package/dist/esm/test-harness.js +24 -8
  28. package/dist/esm/test-harness.js.map +1 -1
  29. package/dist/esm/types/dwn.js +1 -1
  30. package/dist/esm/types/dwn.js.map +1 -1
  31. package/dist/esm/web5-user-agent.js +1 -1
  32. package/dist/esm/web5-user-agent.js.map +1 -1
  33. package/dist/types/crypto-api.d.ts +8 -12
  34. package/dist/types/crypto-api.d.ts.map +1 -1
  35. package/dist/types/dwn-api.d.ts +10 -10
  36. package/dist/types/dwn-api.d.ts.map +1 -1
  37. package/dist/types/hd-identity-vault.d.ts.map +1 -1
  38. package/dist/types/identity-api.d.ts.map +1 -1
  39. package/dist/types/index.d.ts +0 -2
  40. package/dist/types/index.d.ts.map +1 -1
  41. package/dist/types/local-key-manager.d.ts +15 -18
  42. package/dist/types/local-key-manager.d.ts.map +1 -1
  43. package/dist/types/prototyping/crypto/jose/jwe-compact.d.ts +1 -3
  44. package/dist/types/prototyping/crypto/jose/jwe-compact.d.ts.map +1 -1
  45. package/dist/types/prototyping/crypto/jose/jwe-flattened.d.ts +1 -3
  46. package/dist/types/prototyping/crypto/jose/jwe-flattened.d.ts.map +1 -1
  47. package/dist/types/prototyping/crypto/jose/jwe.d.ts +1 -3
  48. package/dist/types/prototyping/crypto/jose/jwe.d.ts.map +1 -1
  49. package/dist/types/store-data.d.ts +2 -2
  50. package/dist/types/store-did.d.ts.map +1 -1
  51. package/dist/types/sync-engine-level.d.ts +18 -6
  52. package/dist/types/sync-engine-level.d.ts.map +1 -1
  53. package/dist/types/test-harness.d.ts.map +1 -1
  54. package/dist/types/types/agent.d.ts +1 -1
  55. package/dist/types/types/agent.d.ts.map +1 -1
  56. package/dist/types/types/dwn.d.ts +2 -2
  57. package/dist/types/types/dwn.d.ts.map +1 -1
  58. package/dist/types/types/key-manager.d.ts +15 -22
  59. package/dist/types/types/key-manager.d.ts.map +1 -1
  60. package/dist/types/utils-internal.d.ts +1 -1
  61. package/dist/types/utils-internal.d.ts.map +1 -1
  62. package/dist/types/web5-user-agent.d.ts +1 -1
  63. package/dist/types/web5-user-agent.d.ts.map +1 -1
  64. package/package.json +13 -15
  65. package/src/crypto-api.ts +24 -20
  66. package/src/dwn-api.ts +109 -102
  67. package/src/hd-identity-vault.ts +4 -5
  68. package/src/identity-api.ts +2 -1
  69. package/src/index.ts +0 -2
  70. package/src/local-key-manager.ts +43 -44
  71. package/src/prototyping/crypto/jose/jwe-compact.ts +3 -7
  72. package/src/prototyping/crypto/jose/jwe-flattened.ts +20 -9
  73. package/src/prototyping/crypto/jose/jwe.ts +2 -6
  74. package/src/store-data.ts +3 -3
  75. package/src/store-did.ts +1 -1
  76. package/src/sync-engine-level.ts +59 -16
  77. package/src/test-harness.ts +23 -8
  78. package/src/types/agent.ts +1 -1
  79. package/src/types/dwn.ts +2 -2
  80. package/src/types/key-manager.ts +31 -22
  81. package/src/utils-internal.ts +1 -1
  82. package/src/web5-user-agent.ts +2 -2
  83. package/dist/browser.js +0 -2213
  84. package/dist/browser.js.map +0 -7
  85. package/dist/esm/dwn-registrar.js +0 -120
  86. package/dist/esm/dwn-registrar.js.map +0 -1
  87. package/dist/esm/prototyping/clients/dwn-rpc-types.js +0 -2
  88. package/dist/esm/prototyping/clients/dwn-rpc-types.js.map +0 -1
  89. package/dist/esm/prototyping/clients/dwn-server-info-cache-memory.js +0 -74
  90. package/dist/esm/prototyping/clients/dwn-server-info-cache-memory.js.map +0 -1
  91. package/dist/esm/prototyping/clients/http-dwn-rpc-client.js +0 -112
  92. package/dist/esm/prototyping/clients/http-dwn-rpc-client.js.map +0 -1
  93. package/dist/esm/prototyping/clients/json-rpc-socket.js +0 -167
  94. package/dist/esm/prototyping/clients/json-rpc-socket.js.map +0 -1
  95. package/dist/esm/prototyping/clients/json-rpc.js +0 -58
  96. package/dist/esm/prototyping/clients/json-rpc.js.map +0 -1
  97. package/dist/esm/prototyping/clients/server-info-types.js +0 -2
  98. package/dist/esm/prototyping/clients/server-info-types.js.map +0 -1
  99. package/dist/esm/prototyping/clients/web-socket-clients.js +0 -90
  100. package/dist/esm/prototyping/clients/web-socket-clients.js.map +0 -1
  101. package/dist/esm/prototyping/common/object.js +0 -14
  102. package/dist/esm/prototyping/common/object.js.map +0 -1
  103. package/dist/esm/prototyping/common/type-utils.js +0 -2
  104. package/dist/esm/prototyping/common/type-utils.js.map +0 -1
  105. package/dist/esm/prototyping/crypto/algorithms/aes-gcm.js +0 -147
  106. package/dist/esm/prototyping/crypto/algorithms/aes-gcm.js.map +0 -1
  107. package/dist/esm/prototyping/crypto/algorithms/aes-kw.js +0 -136
  108. package/dist/esm/prototyping/crypto/algorithms/aes-kw.js.map +0 -1
  109. package/dist/esm/prototyping/crypto/algorithms/ecdsa.js +0 -311
  110. package/dist/esm/prototyping/crypto/algorithms/ecdsa.js.map +0 -1
  111. package/dist/esm/prototyping/crypto/algorithms/eddsa.js +0 -268
  112. package/dist/esm/prototyping/crypto/algorithms/eddsa.js.map +0 -1
  113. package/dist/esm/prototyping/crypto/algorithms/hkdf.js +0 -38
  114. package/dist/esm/prototyping/crypto/algorithms/hkdf.js.map +0 -1
  115. package/dist/esm/prototyping/crypto/algorithms/pbkdf2.js +0 -40
  116. package/dist/esm/prototyping/crypto/algorithms/pbkdf2.js.map +0 -1
  117. package/dist/esm/prototyping/crypto/crypto-error.js +0 -41
  118. package/dist/esm/prototyping/crypto/crypto-error.js.map +0 -1
  119. package/dist/esm/prototyping/crypto/types/crypto-api.js +0 -2
  120. package/dist/esm/prototyping/crypto/types/crypto-api.js.map +0 -1
  121. package/dist/esm/prototyping/crypto/types/key-converter.js +0 -2
  122. package/dist/esm/prototyping/crypto/types/key-converter.js.map +0 -1
  123. package/dist/esm/prototyping/crypto/types/key-deriver.js +0 -2
  124. package/dist/esm/prototyping/crypto/types/key-deriver.js.map +0 -1
  125. package/dist/esm/prototyping/crypto/types/key-io.js +0 -2
  126. package/dist/esm/prototyping/crypto/types/key-io.js.map +0 -1
  127. package/dist/esm/prototyping/crypto/types/key-manager.js +0 -2
  128. package/dist/esm/prototyping/crypto/types/key-manager.js.map +0 -1
  129. package/dist/esm/prototyping/crypto/types/params-direct.js +0 -2
  130. package/dist/esm/prototyping/crypto/types/params-direct.js.map +0 -1
  131. package/dist/esm/prototyping/crypto/types/params-kms.js +0 -2
  132. package/dist/esm/prototyping/crypto/types/params-kms.js.map +0 -1
  133. package/dist/esm/prototyping/crypto/utils.js +0 -19
  134. package/dist/esm/prototyping/crypto/utils.js.map +0 -1
  135. package/dist/esm/prototyping/dids/resolver-cache-memory.js +0 -77
  136. package/dist/esm/prototyping/dids/resolver-cache-memory.js.map +0 -1
  137. package/dist/esm/prototyping/dids/utils.js +0 -9
  138. package/dist/esm/prototyping/dids/utils.js.map +0 -1
  139. package/dist/esm/rpc-client.js +0 -123
  140. package/dist/esm/rpc-client.js.map +0 -1
  141. package/dist/types/dwn-registrar.d.ts +0 -29
  142. package/dist/types/dwn-registrar.d.ts.map +0 -1
  143. package/dist/types/prototyping/clients/dwn-rpc-types.d.ts +0 -45
  144. package/dist/types/prototyping/clients/dwn-rpc-types.d.ts.map +0 -1
  145. package/dist/types/prototyping/clients/dwn-server-info-cache-memory.d.ts +0 -57
  146. package/dist/types/prototyping/clients/dwn-server-info-cache-memory.d.ts.map +0 -1
  147. package/dist/types/prototyping/clients/http-dwn-rpc-client.d.ts +0 -13
  148. package/dist/types/prototyping/clients/http-dwn-rpc-client.d.ts.map +0 -1
  149. package/dist/types/prototyping/clients/json-rpc-socket.d.ts +0 -43
  150. package/dist/types/prototyping/clients/json-rpc-socket.d.ts.map +0 -1
  151. package/dist/types/prototyping/clients/json-rpc.d.ts +0 -49
  152. package/dist/types/prototyping/clients/json-rpc.d.ts.map +0 -1
  153. package/dist/types/prototyping/clients/server-info-types.d.ts +0 -20
  154. package/dist/types/prototyping/clients/server-info-types.d.ts.map +0 -1
  155. package/dist/types/prototyping/clients/web-socket-clients.d.ts +0 -10
  156. package/dist/types/prototyping/clients/web-socket-clients.d.ts.map +0 -1
  157. package/dist/types/prototyping/common/object.d.ts +0 -2
  158. package/dist/types/prototyping/common/object.d.ts.map +0 -1
  159. package/dist/types/prototyping/common/type-utils.d.ts +0 -7
  160. package/dist/types/prototyping/common/type-utils.d.ts.map +0 -1
  161. package/dist/types/prototyping/crypto/algorithms/aes-gcm.d.ts +0 -151
  162. package/dist/types/prototyping/crypto/algorithms/aes-gcm.d.ts.map +0 -1
  163. package/dist/types/prototyping/crypto/algorithms/aes-kw.d.ts +0 -108
  164. package/dist/types/prototyping/crypto/algorithms/aes-kw.d.ts.map +0 -1
  165. package/dist/types/prototyping/crypto/algorithms/ecdsa.d.ts +0 -160
  166. package/dist/types/prototyping/crypto/algorithms/ecdsa.d.ts.map +0 -1
  167. package/dist/types/prototyping/crypto/algorithms/eddsa.d.ts +0 -157
  168. package/dist/types/prototyping/crypto/algorithms/eddsa.d.ts.map +0 -1
  169. package/dist/types/prototyping/crypto/algorithms/hkdf.d.ts +0 -20
  170. package/dist/types/prototyping/crypto/algorithms/hkdf.d.ts.map +0 -1
  171. package/dist/types/prototyping/crypto/algorithms/pbkdf2.d.ts +0 -20
  172. package/dist/types/prototyping/crypto/algorithms/pbkdf2.d.ts.map +0 -1
  173. package/dist/types/prototyping/crypto/crypto-error.d.ts +0 -29
  174. package/dist/types/prototyping/crypto/crypto-error.d.ts.map +0 -1
  175. package/dist/types/prototyping/crypto/types/crypto-api.d.ts +0 -34
  176. package/dist/types/prototyping/crypto/types/crypto-api.d.ts.map +0 -1
  177. package/dist/types/prototyping/crypto/types/key-converter.d.ts +0 -49
  178. package/dist/types/prototyping/crypto/types/key-converter.d.ts.map +0 -1
  179. package/dist/types/prototyping/crypto/types/key-deriver.d.ts +0 -50
  180. package/dist/types/prototyping/crypto/types/key-deriver.d.ts.map +0 -1
  181. package/dist/types/prototyping/crypto/types/key-io.d.ts +0 -49
  182. package/dist/types/prototyping/crypto/types/key-io.d.ts.map +0 -1
  183. package/dist/types/prototyping/crypto/types/key-manager.d.ts +0 -69
  184. package/dist/types/prototyping/crypto/types/key-manager.d.ts.map +0 -1
  185. package/dist/types/prototyping/crypto/types/params-direct.d.ts +0 -75
  186. package/dist/types/prototyping/crypto/types/params-direct.d.ts.map +0 -1
  187. package/dist/types/prototyping/crypto/types/params-kms.d.ts +0 -63
  188. package/dist/types/prototyping/crypto/types/params-kms.d.ts.map +0 -1
  189. package/dist/types/prototyping/crypto/utils.d.ts +0 -7
  190. package/dist/types/prototyping/crypto/utils.d.ts.map +0 -1
  191. package/dist/types/prototyping/dids/resolver-cache-memory.d.ts +0 -57
  192. package/dist/types/prototyping/dids/resolver-cache-memory.d.ts.map +0 -1
  193. package/dist/types/prototyping/dids/utils.d.ts +0 -3
  194. package/dist/types/prototyping/dids/utils.d.ts.map +0 -1
  195. package/dist/types/rpc-client.d.ts +0 -51
  196. package/dist/types/rpc-client.d.ts.map +0 -1
  197. package/src/dwn-registrar.ts +0 -127
  198. package/src/prototyping/clients/dwn-rpc-types.ts +0 -55
  199. package/src/prototyping/clients/dwn-server-info-cache-memory.ts +0 -79
  200. package/src/prototyping/clients/http-dwn-rpc-client.ts +0 -119
  201. package/src/prototyping/clients/json-rpc-socket.ts +0 -189
  202. package/src/prototyping/clients/json-rpc.ts +0 -113
  203. package/src/prototyping/clients/server-info-types.ts +0 -21
  204. package/src/prototyping/clients/web-socket-clients.ts +0 -103
  205. package/src/prototyping/common/object.ts +0 -15
  206. package/src/prototyping/common/type-utils.ts +0 -6
  207. package/src/prototyping/crypto/algorithms/aes-gcm.ts +0 -211
  208. package/src/prototyping/crypto/algorithms/aes-kw.ts +0 -160
  209. package/src/prototyping/crypto/algorithms/ecdsa.ts +0 -366
  210. package/src/prototyping/crypto/algorithms/eddsa.ts +0 -311
  211. package/src/prototyping/crypto/algorithms/hkdf.ts +0 -38
  212. package/src/prototyping/crypto/algorithms/pbkdf2.ts +0 -41
  213. package/src/prototyping/crypto/crypto-error.ts +0 -45
  214. package/src/prototyping/crypto/types/crypto-api.ts +0 -77
  215. package/src/prototyping/crypto/types/key-converter.ts +0 -53
  216. package/src/prototyping/crypto/types/key-deriver.ts +0 -56
  217. package/src/prototyping/crypto/types/key-io.ts +0 -51
  218. package/src/prototyping/crypto/types/key-manager.ts +0 -83
  219. package/src/prototyping/crypto/types/params-direct.ts +0 -95
  220. package/src/prototyping/crypto/types/params-kms.ts +0 -76
  221. package/src/prototyping/crypto/utils.ts +0 -41
  222. package/src/prototyping/dids/resolver-cache-memory.ts +0 -83
  223. package/src/prototyping/dids/utils.ts +0 -10
  224. package/src/rpc-client.ts +0 -160
@@ -9,6 +9,7 @@ import type {
9
9
  KeyGenerator,
10
10
  KeyIdentifier,
11
11
  KeyWrapper,
12
+ KmsCipherParams,
12
13
  KmsDigestParams,
13
14
  KmsExportKeyParams,
14
15
  KmsGenerateKeyParams,
@@ -16,6 +17,8 @@ import type {
16
17
  KmsGetPublicKeyParams,
17
18
  KmsImportKeyParams,
18
19
  KmsSignParams,
20
+ KmsUriUnwrapKeyParams,
21
+ KmsUriWrapKeyParams,
19
22
  KmsVerifyParams,
20
23
  PublicKeyJwk,
21
24
  Signer,
@@ -26,6 +29,7 @@ import type {
26
29
 
27
30
  import {
28
31
  AesGcmAlgorithm,
32
+ AesKwAlgorithm,
29
33
  computeJwkThumbprint,
30
34
  CryptoError,
31
35
  CryptoErrorCode,
@@ -34,19 +38,18 @@ import {
34
38
  isPrivateJwk,
35
39
  KEY_URI_PREFIX_JWK,
36
40
  Sha2Algorithm,
41
+ X25519Algorithm,
37
42
  } from '@enbox/crypto';
38
43
 
39
44
  import type { PrivateKeyJwk } from '@enbox/dwn-sdk-js';
40
45
 
41
- import { Encryption, HdKey, Secp256k1 } from '@enbox/dwn-sdk-js';
46
+ import { X25519 } from '@enbox/crypto';
47
+ import { Encryption, HdKey } from '@enbox/dwn-sdk-js';
42
48
 
43
49
  import type { AgentDataStore } from './store-data.js';
44
50
  import type { AgentKeyManager } from './types/key-manager.js';
45
- import type { InferType } from './prototyping/common/type-utils.js';
46
51
  import type { Web5PlatformAgent } from './types/agent.js';
47
- import type { KmsCipherParams, KmsUnwrapKeyParams, KmsWrapKeyParams } from './prototyping/crypto/types/params-kms.js';
48
52
 
49
- import { AesKwAlgorithm } from './prototyping/crypto/algorithms/aes-kw.js';
50
53
  import { InMemoryKeyStore } from './store-key.js';
51
54
 
52
55
  /**
@@ -80,7 +83,11 @@ const supportedAlgorithms = {
80
83
  },
81
84
  'SHA-256': {
82
85
  implementation : Sha2Algorithm,
83
- names : ['SHA-256'] as const
86
+ names : ['SHA-256']
87
+ },
88
+ 'X25519': {
89
+ implementation : X25519Algorithm,
90
+ names : ['X25519']
84
91
  }
85
92
  } satisfies {
86
93
  [key: string]: {
@@ -102,6 +109,7 @@ type AlgorithmConstructor = typeof supportedAlgorithms[SupportedAlgorithm]['impl
102
109
  type SupportedKeyGeneratorAlgorithm =
103
110
  | 'Ed25519' // Edwards Curve Digital Signature Algorithm (EdDSA)
104
111
  | 'secp256k1' | 'ES256K' | 'secp256r1' | 'ES256' // Elliptic Curve Digital Signature Algorithm (ECDSA)
112
+ | 'X25519' // Elliptic Curve Diffie-Hellman key agreement (ECDH)
105
113
  | 'A128GCM' | 'A192GCM' | 'A256GCM' // AES GCM with a 128-bit, 192-bit, or 256-bit key
106
114
  | 'A128KW' | 'A192KW' | 'A256KW'; // AES Key Wrap with a 128-bit, 192-bit, or 256-bit key
107
115
 
@@ -133,7 +141,7 @@ export interface LocalKmsGenerateKeyParams extends KmsGenerateKeyParams {
133
141
  /**
134
142
  * A string defining the type of key to generate.
135
143
  */
136
- algorithm: InferType<SupportedKeyGeneratorAlgorithm>
144
+ algorithm: SupportedKeyGeneratorAlgorithm
137
145
  }
138
146
 
139
147
  /**
@@ -141,7 +149,7 @@ export interface LocalKmsGenerateKeyParams extends KmsGenerateKeyParams {
141
149
  * should be passed into the {@link LocalKeyManager.wrapKey} method when wrapping a key using a
142
150
  * key stored in the local KMS to encrypt the key material.
143
151
  */
144
- export interface LocalKmsUnwrapKeyParams extends KmsUnwrapKeyParams {
152
+ export interface LocalKmsUnwrapKeyParams extends KmsUriUnwrapKeyParams {
145
153
  /**
146
154
  * A string defining the type of wrapped key. The value must be one of the following:
147
155
  * - `"A128GCM"`: AES GCM using a 128-bit key.
@@ -400,8 +408,8 @@ export class LocalKeyManager implements AgentKeyManager {
400
408
  keyUri: KeyIdentifier;
401
409
  derivationPath: string[];
402
410
  }): Promise<PublicKeyJwk> {
403
- // Get stored secp256k1 private key as bytes
404
- const privateKeyBytes = await this.getSecp256k1PrivateKeyBytes({ keyUri });
411
+ // Get stored X25519 private key as bytes
412
+ const privateKeyBytes = await this.getX25519PrivateKeyBytes({ keyUri });
405
413
 
406
414
  // Run HKDF derivation through each path segment
407
415
  const derivedPrivateKeyBytes = await HdKey.derivePrivateKeyBytes(
@@ -409,35 +417,29 @@ export class LocalKeyManager implements AgentKeyManager {
409
417
  derivationPath
410
418
  );
411
419
 
412
- // Compute public key from derived private key
413
- const derivedPublicKeyBytes = await Secp256k1.getPublicKey(derivedPrivateKeyBytes);
414
-
415
- // Convert to JWK format — cast is safe because secp256k1 public keys
416
- // always produce JwkParamsEcPublic (kty: 'EC', crv: 'secp256k1', x, y)
417
- return await Secp256k1.publicKeyToJwk(derivedPublicKeyBytes) as PublicKeyJwk;
420
+ // Convert derived bytes to X25519 JWK and compute public key
421
+ const derivedPrivateKeyJwk = await X25519.bytesToPrivateKey({ privateKeyBytes: derivedPrivateKeyBytes });
422
+ return await X25519.getPublicKey({ key: derivedPrivateKeyJwk }) as PublicKeyJwk;
418
423
  }
419
424
 
420
425
  /**
421
- * Decrypts an ECIES-SECP256K1 encrypted payload using a derived private key.
422
- * The derived private key is used internally and discarded after decryption.
426
+ * Unwraps a JWE-encrypted Content Encryption Key (CEK) using a derived X25519 private key.
427
+ * Performs ECDH-ES key agreement with the ephemeral public key, derives the KEK via
428
+ * Concat KDF, and unwraps the CEK with AES-256 Key Unwrap.
423
429
  */
424
- public async eciesSecp256k1Decrypt({
430
+ public async jweKeyUnwrap({
425
431
  keyUri,
426
432
  derivationPath,
427
- ciphertext,
433
+ encryptedKey,
428
434
  ephemeralPublicKey,
429
- initializationVector,
430
- messageAuthenticationCode
431
435
  }: {
432
436
  keyUri: KeyIdentifier;
433
437
  derivationPath: string[];
434
- ciphertext: Uint8Array;
435
- ephemeralPublicKey: Uint8Array;
436
- initializationVector: Uint8Array;
437
- messageAuthenticationCode: Uint8Array;
438
+ encryptedKey: Uint8Array;
439
+ ephemeralPublicKey: PublicKeyJwk;
438
440
  }): Promise<Uint8Array> {
439
- // Get stored secp256k1 private key as bytes
440
- const privateKeyBytes = await this.getSecp256k1PrivateKeyBytes({ keyUri });
441
+ // Get stored X25519 private key as bytes
442
+ const privateKeyBytes = await this.getX25519PrivateKeyBytes({ keyUri });
441
443
 
442
444
  // Run HKDF derivation through each path segment to get leaf private key
443
445
  const leafPrivateKeyBytes = await HdKey.derivePrivateKeyBytes(
@@ -445,14 +447,11 @@ export class LocalKeyManager implements AgentKeyManager {
445
447
  derivationPath
446
448
  );
447
449
 
448
- // Perform ECIES decryption leaf key bytes consumed and discarded after
449
- return Encryption.eciesSecp256k1Decrypt({
450
- privateKey: leafPrivateKeyBytes,
451
- ciphertext,
452
- ephemeralPublicKey,
453
- initializationVector,
454
- messageAuthenticationCode,
455
- });
450
+ // Convert leaf bytes to X25519 JWK for ECDH-ES unwrap
451
+ const leafPrivateKeyJwk = await X25519.bytesToPrivateKey({ privateKeyBytes: leafPrivateKeyBytes });
452
+
453
+ // Perform ECDH-ES key agreement and AES-256 Key Unwrap
454
+ return Encryption.ecdhEsUnwrapKey(leafPrivateKeyJwk, ephemeralPublicKey, encryptedKey);
456
455
  }
457
456
 
458
457
  /**
@@ -464,8 +463,8 @@ export class LocalKeyManager implements AgentKeyManager {
464
463
  keyUri: KeyIdentifier;
465
464
  derivationPath: string[];
466
465
  }): Promise<Uint8Array> {
467
- // Get stored secp256k1 private key as bytes
468
- const privateKeyBytes = await this.getSecp256k1PrivateKeyBytes({ keyUri });
466
+ // Get stored X25519 private key as bytes
467
+ const privateKeyBytes = await this.getX25519PrivateKeyBytes({ keyUri });
469
468
 
470
469
  // Run HKDF derivation through each path segment, return raw bytes
471
470
  return HdKey.derivePrivateKeyBytes(
@@ -624,7 +623,7 @@ export class LocalKeyManager implements AgentKeyManager {
624
623
  }
625
624
 
626
625
  public async wrapKey({ unwrappedKey, encryptionKeyUri }:
627
- KmsWrapKeyParams
626
+ KmsUriWrapKeyParams
628
627
  ): Promise<Uint8Array> {
629
628
  // Get the private key from the key store.
630
629
  const encryptionKey = await this.getPrivateKey({ keyUri: encryptionKeyUri });
@@ -732,18 +731,18 @@ export class LocalKeyManager implements AgentKeyManager {
732
731
  }
733
732
 
734
733
  /**
735
- * Helper method to retrieve a secp256k1 private key and convert it to bytes.
734
+ * Helper method to retrieve an X25519 private key and convert it to bytes.
736
735
  * Used by HD key derivation methods to avoid code duplication.
737
736
  *
738
- * @param keyUri - The key URI identifying the secp256k1 private key
737
+ * @param keyUri - The key URI identifying the X25519 private key
739
738
  * @returns The private key as raw bytes
740
- * @throws Error if the key is not found or is not a secp256k1 key
739
+ * @throws Error if the key is not found or is not an X25519 key
741
740
  */
742
- private async getSecp256k1PrivateKeyBytes({ keyUri }: {
741
+ private async getX25519PrivateKeyBytes({ keyUri }: {
743
742
  keyUri: KeyIdentifier;
744
743
  }): Promise<Uint8Array> {
745
744
  const privateKeyJwk = await this.getPrivateKey({ keyUri }) as PrivateKeyJwk;
746
- return Secp256k1.privateJwkToBytes(privateKeyJwk);
745
+ return X25519.privateKeyToBytes({ privateKey: privateKeyJwk });
747
746
  }
748
747
 
749
748
  /**
@@ -768,7 +767,7 @@ export class LocalKeyManager implements AgentKeyManager {
768
767
  // (from the vault) are held in-memory by BearerDid.keyManager and are NOT
769
768
  // stored in the DwnKeyStore. Checking here FIRST is critical when the
770
769
  // DwnKeyStore is encrypted: the encryption/decryption key is derived from the
771
- // agent DID's secp256k1 key, so looking up that key via the DwnKeyStore would
770
+ // agent DID's X25519 key, so looking up that key via the DwnKeyStore would
772
771
  // cause infinite recursion (decrypt → getPrivateKey → DwnKeyStore.get → decrypt…).
773
772
  try {
774
773
  const agentKeyManager = this.agent?.agentDid?.keyManager;
@@ -1,15 +1,11 @@
1
- import type { Jwk, KeyIdentifier } from '@enbox/crypto';
2
-
3
- import { LocalKeyManager } from '@enbox/crypto';
4
-
5
- import type { CryptoApi } from '../types/crypto-api.js';
6
- import type { KeyManager } from '../types/key-manager.js';
1
+ import type { CryptoApi, Jwk, KeyIdentifier, KeyManager } from '@enbox/crypto';
7
2
  import type { JweDecryptOptions, JweEncryptOptions, JweHeaderParams } from './jwe.js';
8
3
 
4
+ import { CryptoError, CryptoErrorCode, LocalKeyManager } from '@enbox/crypto';
5
+
9
6
  import { AgentCryptoApi } from '../../../crypto-api.js';
10
7
  import { FlattenedJwe } from './jwe-flattened.js';
11
8
  import { isValidJweHeader } from './jwe.js';
12
- import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
13
9
 
14
10
  /**
15
11
  * Parameters required for decrypting a JWE in Compact Serialization format.
@@ -1,16 +1,10 @@
1
- import type { Jwk, KeyIdentifier } from '@enbox/crypto';
1
+ import type { CryptoApi, Jwk, KeyIdentifier, KeyManager } from '@enbox/crypto';
2
+ import type { JweDecryptOptions, JweEncryptOptions, JweHeaderParams } from './jwe.js';
2
3
 
3
4
  import { Convert } from '@enbox/common';
4
- import { CryptoUtils, LocalKeyManager } from '@enbox/crypto';
5
-
6
- import type { CryptoApi } from '../types/crypto-api.js';
7
- import type { KeyManager } from '../types/key-manager.js';
8
- import type { JweDecryptOptions, JweEncryptOptions, JweHeaderParams } from './jwe.js';
5
+ import { CryptoError, CryptoErrorCode, CryptoUtils, isCipher, LocalKeyManager } from '@enbox/crypto';
9
6
 
10
7
  import { AgentCryptoApi } from '../../../crypto-api.js';
11
- import { hasDuplicateProperties } from '../../common/object.js';
12
- import { isCipher } from '../utils.js';
13
- import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
14
8
  import { isValidJweHeader, JweKeyManagement } from './jwe.js';
15
9
 
16
10
  /**
@@ -456,4 +450,21 @@ export class FlattenedJwe {
456
450
 
457
451
  return jwe;
458
452
  }
453
+ }
454
+
455
+ /** Check whether any two of the given objects share the same property name. */
456
+ function hasDuplicateProperties(...objects: Array<Record<string, any> | undefined>): boolean {
457
+ const propertySet = new Set<string>();
458
+ const objectsWithoutUndefined = objects.filter(Boolean);
459
+
460
+ for (const obj of objectsWithoutUndefined) {
461
+ for (const key in obj) {
462
+ if (propertySet.has(key)) {
463
+ return true;
464
+ }
465
+ propertySet.add(key);
466
+ }
467
+ }
468
+
469
+ return false;
459
470
  }
@@ -1,11 +1,7 @@
1
- import type { JoseHeaderParams, Jwk, KeyIdentifier } from '@enbox/crypto';
1
+ import type { CryptoApi, JoseHeaderParams, Jwk, KeyIdentifier, KeyManager } from '@enbox/crypto';
2
2
 
3
3
  import { Convert } from '@enbox/common';
4
-
5
- import type { CryptoApi } from '../types/crypto-api.js';
6
- import type { KeyManager } from '../types/key-manager.js';
7
-
8
- import { CryptoError, CryptoErrorCode } from '../crypto-error.js';
4
+ import { CryptoError, CryptoErrorCode } from '@enbox/crypto';
9
5
 
10
6
  /**
11
7
  * Specifies options for decrypting a JWE, allowing the caller to define constraints on the JWE
package/src/store-data.ts CHANGED
@@ -80,7 +80,7 @@ export class DwnDataStore<TStoreObject extends Record<string, any> = Jwk> implem
80
80
 
81
81
  /**
82
82
  * Per-tenant encryption resolution cache. Populated during `initialize()`:
83
- * `true` if the tenant supports encryption (has secp256k1 keyAgreement).
83
+ * `true` if the tenant supports encryption (has X25519 keyAgreement).
84
84
  * When any type in `_recordProtocolDefinition` has `encryptionRequired: true`,
85
85
  * this will always be `true` after successful initialization (since
86
86
  * installation fails if encryption is not possible).
@@ -316,7 +316,7 @@ export class DwnDataStore<TStoreObject extends Record<string, any> = Jwk> implem
316
316
  * Install the protocol for the given tenant using a `ProtocolsConfigure` message.
317
317
  * When any type in the protocol definition has `encryptionRequired: true`,
318
318
  * `$encryption` keys are derived and injected into the protocol definition.
319
- * If the tenant DID lacks a secp256k1 keyAgreement key, the error propagates
319
+ * If the tenant DID lacks an X25519 keyAgreement key, the error propagates
320
320
  * — plaintext fallback is not allowed.
321
321
  */
322
322
  private async installProtocol(tenant: string, agent: Web5PlatformAgent): Promise<void> {
@@ -324,7 +324,7 @@ export class DwnDataStore<TStoreObject extends Record<string, any> = Jwk> implem
324
324
  let encryptionActive = false;
325
325
 
326
326
  if (this.encryptionRequired) {
327
- // Derive encryption keys — requires the tenant DID to have a secp256k1
327
+ // Derive encryption keys — requires the tenant DID to have an X25519
328
328
  // keyAgreement key. If it does not, the error propagates to the caller.
329
329
  const keyDeriver = await agent.dwn.getEncryptionKeyDeriver(tenant);
330
330
  definition = await Protocols.deriveAndInjectPublicEncryptionKeys(
package/src/store-did.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import type { PortableDid } from '@enbox/dids';
2
2
 
3
3
  import { Convert } from '@enbox/common';
4
+ import { isPortableDid } from '@enbox/dids';
4
5
 
5
6
  import type { Web5PlatformAgent } from './types/agent.js';
6
7
  import type { AgentDataStore, DataStoreDeleteParams, DataStoreGetParams, DataStoreListParams, DataStoreSetParams } from './store-data.js';
7
8
 
8
9
  import { DwnInterface } from './types/dwn.js';
9
10
  import { IdentityProtocolDefinition } from './store-data-protocols.js';
10
- import { isPortableDid } from './prototyping/dids/utils.js';
11
11
  import { TENANT_SEPARATOR } from './utils-internal.js';
12
12
  import { DwnDataStore, InMemoryDataStore } from './store-data.js';
13
13
 
@@ -15,6 +15,7 @@ import {
15
15
  Message,
16
16
  PermissionsProtocol,
17
17
  } from '@enbox/dwn-sdk-js';
18
+ import { hashToHex, initDefaultHashes } from '@enbox/dwn-sdk-js';
18
19
 
19
20
  import type { PermissionsApi } from './types/permissions.js';
20
21
  import type { SyncEngine, SyncIdentityOptions } from './types/sync.js';
@@ -55,6 +56,13 @@ export class SyncEngineLevel implements SyncEngine {
55
56
  private _syncIntervalId?: ReturnType<typeof setInterval>;
56
57
  private _syncLock = false;
57
58
 
59
+ /**
60
+ * Hex-encoded default hashes for empty subtrees at each depth, keyed by depth.
61
+ * Lazily initialized on first use. Used by `walkTreeDiff` to detect empty subtrees
62
+ * and short-circuit the recursive walk instead of descending all the way to MAX_DIFF_DEPTH.
63
+ */
64
+ private _defaultHashHex?: Map<number, string>;
65
+
58
66
  constructor({ agent, dataPath, db }: SyncEngineLevelParams) {
59
67
  this._agent = agent;
60
68
  this._permissionsApi = new AgentPermissionsApi({ agent: agent as Web5Agent });
@@ -255,6 +263,27 @@ export class SyncEngineLevel implements SyncEngine {
255
263
  }
256
264
  }
257
265
 
266
+ // ---------------------------------------------------------------------------
267
+ // Default Hash Cache
268
+ // ---------------------------------------------------------------------------
269
+
270
+ /**
271
+ * Returns the hex-encoded default (empty-subtree) hash for a given depth.
272
+ * Lazily initializes the cache on first call.
273
+ */
274
+ private async getDefaultHashHex(depth: number): Promise<string> {
275
+ if (this._defaultHashHex === undefined) {
276
+ const defaults = await initDefaultHashes();
277
+ const map = new Map<number, string>();
278
+ // Pre-compute hex strings for depths 0 through MAX_DIFF_DEPTH (inclusive).
279
+ for (let d = 0; d <= MAX_DIFF_DEPTH; d++) {
280
+ map.set(d, hashToHex(defaults[d]));
281
+ }
282
+ this._defaultHashHex = map;
283
+ }
284
+ return this._defaultHashHex.get(depth) ?? '';
285
+ }
286
+
258
287
  // ---------------------------------------------------------------------------
259
288
  // SMT Root Comparison
260
289
  // ---------------------------------------------------------------------------
@@ -345,16 +374,17 @@ export class SyncEngineLevel implements SyncEngine {
345
374
  return;
346
375
  }
347
376
 
348
- // Short-circuit: if one side is entirely empty, all entries on the other
349
- // side are unique. Enumerate leaves directly instead of recursing further
350
- // into the tree — this avoids the exponential walk when the remote DWN
351
- // returns empty responses (e.g. auth failure or truly empty tree).
352
- if (!remoteHash && localHash) {
377
+ // Short-circuit: if one side is the default (empty-subtree) hash, all entries
378
+ // on the other side are unique. Enumerate leaves directly instead of recursing
379
+ // further into the tree — this avoids an exponential walk when one DWN has
380
+ // entries that the other lacks entirely in this subtree.
381
+ const emptyHash = await this.getDefaultHashHex(prefix.length);
382
+ if (remoteHash === emptyHash && localHash !== emptyHash) {
353
383
  const localLeaves = await this.getLocalLeaves(did, prefix, delegateDid, protocol, permissionGrantId);
354
384
  onlyLocal.push(...localLeaves);
355
385
  return;
356
386
  }
357
- if (!localHash && remoteHash) {
387
+ if (localHash === emptyHash && remoteHash !== emptyHash) {
358
388
  const remoteLeaves = await this.getRemoteLeaves(did, dwnUrl, prefix, delegateDid, protocol, permissionGrantId);
359
389
  onlyRemote.push(...remoteLeaves);
360
390
  return;
@@ -493,6 +523,11 @@ export class SyncEngineLevel implements SyncEngine {
493
523
  /**
494
524
  * Fetches missing messages from the remote DWN and processes them on the local DWN
495
525
  * in dependency order (topological sort).
526
+ *
527
+ * Messages that fail processing are re-fetched from the remote before each retry
528
+ * pass rather than buffered in memory. ReadableStream is single-use, so a failed
529
+ * message's data stream is consumed on the first attempt. Re-fetching provides a
530
+ * fresh stream without holding all record data in memory simultaneously.
496
531
  */
497
532
  private async pullMessages({ did, dwnUrl, delegateDid, protocol, messageCids }: {
498
533
  did: string;
@@ -509,22 +544,30 @@ export class SyncEngineLevel implements SyncEngine {
509
544
 
510
545
  // Step 3: Process messages in dependency order with multi-pass retry.
511
546
  // Retry up to MAX_RETRY_PASSES times for messages that fail due to
512
- // dependency ordering issues (e.g., a dependency was already local
513
- // but not yet committed when the dependent was first processed).
547
+ // dependency ordering issues (e.g., a RecordsWrite whose ProtocolsConfigure
548
+ // hasn't committed yet). Failed messages are re-fetched from the remote
549
+ // to obtain a fresh data stream, since ReadableStream is single-use.
514
550
  const MAX_RETRY_PASSES = 3;
515
551
  let pending = sorted;
516
552
 
517
553
  for (let pass = 0; pass <= MAX_RETRY_PASSES && pending.length > 0; pass++) {
518
- const retryQueue: { message: GenericMessage; dataStream?: ReadableStream<Uint8Array> }[] = [];
554
+ const failedCids: string[] = [];
519
555
 
520
556
  for (const entry of pending) {
521
557
  const pullReply = await this.agent.dwn.node.processMessage(did, entry.message, { dataStream: entry.dataStream });
522
558
  if (!SyncEngineLevel.syncMessageReplyIsSuccessful(pullReply)) {
523
- retryQueue.push(entry);
559
+ const cid = await SyncEngineLevel.getMessageCid(entry.message);
560
+ failedCids.push(cid);
524
561
  }
525
562
  }
526
563
 
527
- pending = retryQueue;
564
+ // Re-fetch failed messages from the remote to get fresh data streams.
565
+ if (failedCids.length > 0) {
566
+ const reFetched = await this.fetchRemoteMessages({ did, dwnUrl, delegateDid, protocol, messageCids: failedCids });
567
+ pending = SyncEngineLevel.topologicalSort(reFetched);
568
+ } else {
569
+ pending = [];
570
+ }
528
571
  }
529
572
  }
530
573
 
@@ -735,15 +778,15 @@ export class SyncEngineLevel implements SyncEngine {
735
778
  * - Initial write must come before update writes (same recordId, not initial)
736
779
  * - Permission grant must come before records using that permissionGrantId
737
780
  */
738
- static topologicalSort(
739
- messages: { message: GenericMessage; dataStream?: ReadableStream<Uint8Array> }[]
740
- ): { message: GenericMessage; dataStream?: ReadableStream<Uint8Array> }[] {
781
+ static topologicalSort<T extends { message: GenericMessage }>(
782
+ messages: T[]
783
+ ): T[] {
741
784
  if (messages.length <= 1) {
742
785
  return messages;
743
786
  }
744
787
 
745
788
  // Index messages by various keys for dependency resolution.
746
- const byIndex = new Map<number, { message: GenericMessage; dataStream?: ReadableStream<Uint8Array> }>();
789
+ const byIndex = new Map<number, T>();
747
790
  const protocolConfigureIndex = new Map<string, number>(); // protocol URL -> index
748
791
  const initialWriteIndex = new Map<string, number>(); // recordId -> index of initial write
749
792
  const grantIndex = new Map<string, number>(); // grant recordId -> index
@@ -847,7 +890,7 @@ export class SyncEngineLevel implements SyncEngine {
847
890
  }
848
891
  }
849
892
 
850
- const sorted: { message: GenericMessage; dataStream?: ReadableStream<Uint8Array> }[] = [];
893
+ const sorted: T[] = [];
851
894
  while (queue.length > 0) {
852
895
  const node = queue.shift()!;
853
896
  sorted.push(byIndex.get(node)!);
@@ -7,7 +7,7 @@ import type { Web5PlatformAgent } from './types/agent.js';
7
7
 
8
8
  import { Level } from 'level';
9
9
  import { DataStoreLevel, EventEmitterStream, MessageStoreLevel, ResumableTaskStoreLevel, StateIndexLevel } from '@enbox/dwn-sdk-js';
10
- import { DidDht, DidJwk } from '@enbox/dids';
10
+ import { DidDht, DidJwk, DidResolverCacheMemory } from '@enbox/dids';
11
11
  import { LevelStore, MemoryStore } from '@enbox/common';
12
12
 
13
13
  import { AgentCryptoApi } from './crypto-api.js';
@@ -17,11 +17,10 @@ import { AgentDwnApi } from './dwn-api.js';
17
17
  import { AgentIdentityApi } from './identity-api.js';
18
18
  import { AgentPermissionsApi } from './permissions-api.js';
19
19
  import { AgentSyncApi } from './sync-api.js';
20
- import { DidResolverCacheMemory } from './prototyping/dids/resolver-cache-memory.js';
21
20
  import { HdIdentityVault } from './hd-identity-vault.js';
22
21
  import { LocalKeyManager } from './local-key-manager.js';
23
22
  import { SyncEngineLevel } from './sync-engine-level.js';
24
- import { Web5RpcClient } from './rpc-client.js';
23
+ import { Web5RpcClient } from '@enbox/dwn-clients';
25
24
  import { DwnDidStore, InMemoryDidStore } from './store-did.js';
26
25
  import { DwnIdentityStore, InMemoryIdentityStore } from './store-identity.js';
27
26
  import { DwnKeyStore, InMemoryKeyStore } from './store-key.js';
@@ -140,10 +139,26 @@ export class PlatformAgentTestHarness {
140
139
  }
141
140
 
142
141
  public async createAgentDid(): Promise<void> {
143
- // Create a DID for the Agent using secp256k1, which supports both signing
144
- // and keyAgreement (required by DwnKeyStore for record-level encryption).
145
- this.agent.agentDid = await DidJwk.create({
146
- options: { algorithm: 'secp256k1' }
142
+ // Create a DID for the Agent with Ed25519 (signing) and X25519 (keyAgreement).
143
+ // X25519 is required by DwnKeyStore for JWE record-level encryption.
144
+ // Must be published so the DWN can resolve it for JWS signature verification.
145
+ this.agent.agentDid = await DidDht.create({
146
+ options: {
147
+ publish : true,
148
+ gatewayUri : process.env.DID_DHT_GATEWAY_URI ?? 'http://localhost:7527',
149
+ verificationMethods : [
150
+ {
151
+ algorithm : 'Ed25519',
152
+ id : 'sig',
153
+ purposes : ['assertionMethod', 'authentication']
154
+ },
155
+ {
156
+ algorithm : 'X25519',
157
+ id : 'enc',
158
+ purposes : ['keyAgreement']
159
+ }
160
+ ]
161
+ }
147
162
  });
148
163
  }
149
164
 
@@ -170,7 +185,7 @@ export class PlatformAgentTestHarness {
170
185
  purposes : ['assertionMethod', 'authentication']
171
186
  },
172
187
  {
173
- algorithm : 'secp256k1',
188
+ algorithm : 'X25519',
174
189
  id : 'enc',
175
190
  purposes : ['keyAgreement']
176
191
  }
@@ -7,7 +7,7 @@ import type { AgentKeyManager } from './key-manager.js';
7
7
  import type { AgentPermissionsApi } from '../permissions-api.js';
8
8
  import type { AgentSyncApi } from '../sync-api.js';
9
9
  import type { IdentityVault } from './identity-vault.js';
10
- import type { Web5Rpc } from '../rpc-client.js';
10
+ import type { Web5Rpc } from '@enbox/dwn-clients';
11
11
  import type { AgentDidApi, DidInterface, DidRequest, DidResponse } from '../did-api.js';
12
12
  import type { DwnInterface, DwnResponse, ProcessDwnRequest, SendDwnRequest } from './dwn.js';
13
13
  import type { ProcessVcRequest, SendVcRequest, VcResponse } from './vc.js';
package/src/types/dwn.ts CHANGED
@@ -203,7 +203,7 @@ export type ProcessDwnRequest<T extends DwnInterface> = DwnRequest<T> & {
203
203
  subscriptionHandler?: MessageHandler[T];
204
204
  /**
205
205
  * If true, automatically encrypt protocol records and inject $encryption keys.
206
- * Requires the identity to have a secp256k1 keyAgreement key.
206
+ * Requires the identity to have an X25519 keyAgreement key.
207
207
  */
208
208
  encryption?: boolean;
209
209
  };
@@ -261,7 +261,7 @@ export type DwnMessageWithData<T extends DwnInterface> = {
261
261
  export {
262
262
  DateSort as DwnDateSort,
263
263
  DwnConstant,
264
- EncryptionAlgorithm as DwnEncryptionAlgorithm,
264
+ ContentEncryptionAlgorithm as DwnContentEncryptionAlgorithm,
265
265
  KeyDerivationScheme as DwnKeyDerivationScheme,
266
266
  PermissionGrant as DwnPermissionGrant,
267
267
  PermissionRequest as DwnPermissionRequest,