@bsv/sdk 1.1.32 → 1.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 (229) hide show
  1. package/dist/cjs/mod.js +4 -0
  2. package/dist/cjs/mod.js.map +1 -1
  3. package/dist/cjs/package.json +4 -3
  4. package/dist/cjs/src/auth/Certificate.js +163 -0
  5. package/dist/cjs/src/auth/Certificate.js.map +1 -0
  6. package/dist/cjs/src/auth/index.js +9 -0
  7. package/dist/cjs/src/auth/index.js.map +1 -0
  8. package/dist/cjs/src/compat/BSM.js +17 -7
  9. package/dist/cjs/src/compat/BSM.js.map +1 -1
  10. package/dist/cjs/src/compat/ECIES.js +17 -7
  11. package/dist/cjs/src/compat/ECIES.js.map +1 -1
  12. package/dist/cjs/src/compat/HD.js +17 -7
  13. package/dist/cjs/src/compat/HD.js.map +1 -1
  14. package/dist/cjs/src/compat/Mnemonic.js +17 -7
  15. package/dist/cjs/src/compat/Mnemonic.js.map +1 -1
  16. package/dist/cjs/src/compat/index.js +17 -7
  17. package/dist/cjs/src/compat/index.js.map +1 -1
  18. package/dist/cjs/src/messages/index.js +17 -7
  19. package/dist/cjs/src/messages/index.js.map +1 -1
  20. package/dist/cjs/src/overlay-tools/LookupResolver.js +170 -0
  21. package/dist/cjs/src/overlay-tools/LookupResolver.js.map +1 -0
  22. package/dist/cjs/src/overlay-tools/OverlayAdminTokenTemplate.js +69 -0
  23. package/dist/cjs/src/overlay-tools/OverlayAdminTokenTemplate.js.map +1 -0
  24. package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js +336 -0
  25. package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js.map +1 -0
  26. package/dist/cjs/src/overlay-tools/index.js +29 -0
  27. package/dist/cjs/src/overlay-tools/index.js.map +1 -0
  28. package/dist/cjs/src/primitives/PrivateKey.js +17 -7
  29. package/dist/cjs/src/primitives/PrivateKey.js.map +1 -1
  30. package/dist/cjs/src/primitives/TransactionSignature.js +17 -7
  31. package/dist/cjs/src/primitives/TransactionSignature.js.map +1 -1
  32. package/dist/cjs/src/primitives/index.js +17 -7
  33. package/dist/cjs/src/primitives/index.js.map +1 -1
  34. package/dist/cjs/src/script/Spend.js +17 -7
  35. package/dist/cjs/src/script/Spend.js.map +1 -1
  36. package/dist/cjs/src/script/templates/PushDrop.js +218 -0
  37. package/dist/cjs/src/script/templates/PushDrop.js.map +1 -0
  38. package/dist/cjs/src/script/templates/index.js +3 -1
  39. package/dist/cjs/src/script/templates/index.js.map +1 -1
  40. package/dist/cjs/src/transaction/Beef.js +35 -6
  41. package/dist/cjs/src/transaction/Beef.js.map +1 -1
  42. package/dist/cjs/src/transaction/Transaction.js +13 -4
  43. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  44. package/dist/cjs/src/transaction/http/DefaultHttpClient.js +1 -1
  45. package/dist/cjs/src/transaction/http/DefaultHttpClient.js.map +1 -1
  46. package/dist/cjs/src/wallet/CachedKeyDeriver.js +177 -0
  47. package/dist/cjs/src/wallet/CachedKeyDeriver.js.map +1 -0
  48. package/dist/cjs/src/wallet/KeyDeriver.js +174 -0
  49. package/dist/cjs/src/wallet/KeyDeriver.js.map +1 -0
  50. package/dist/cjs/src/wallet/ProtoWallet.js +245 -0
  51. package/dist/cjs/src/wallet/ProtoWallet.js.map +1 -0
  52. package/dist/cjs/src/wallet/Wallet.interfaces.js +3 -0
  53. package/dist/cjs/src/wallet/Wallet.interfaces.js.map +1 -0
  54. package/dist/cjs/src/wallet/WalletClient.js +181 -0
  55. package/dist/cjs/src/wallet/WalletClient.js.map +1 -0
  56. package/dist/cjs/src/wallet/WalletError.js +28 -0
  57. package/dist/cjs/src/wallet/WalletError.js.map +1 -0
  58. package/dist/cjs/src/wallet/index.js +34 -0
  59. package/dist/cjs/src/wallet/index.js.map +1 -0
  60. package/dist/cjs/src/wallet/substrates/HTTPWalletWire.js +45 -0
  61. package/dist/cjs/src/wallet/substrates/HTTPWalletWire.js.map +1 -0
  62. package/dist/cjs/src/wallet/substrates/WalletWire.js +3 -0
  63. package/dist/cjs/src/wallet/substrates/WalletWire.js.map +1 -0
  64. package/dist/cjs/src/wallet/substrates/WalletWireCalls.js +36 -0
  65. package/dist/cjs/src/wallet/substrates/WalletWireCalls.js.map +1 -0
  66. package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js +1821 -0
  67. package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js.map +1 -0
  68. package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js +1305 -0
  69. package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js.map +1 -0
  70. package/dist/cjs/src/wallet/substrates/XDM.js +130 -0
  71. package/dist/cjs/src/wallet/substrates/XDM.js.map +1 -0
  72. package/dist/cjs/src/wallet/substrates/index.js +33 -0
  73. package/dist/cjs/src/wallet/substrates/index.js.map +1 -0
  74. package/dist/cjs/src/wallet/substrates/window.CWI.js +102 -0
  75. package/dist/cjs/src/wallet/substrates/window.CWI.js.map +1 -0
  76. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  77. package/dist/esm/mod.js +4 -0
  78. package/dist/esm/mod.js.map +1 -1
  79. package/dist/esm/src/auth/Certificate.js +185 -0
  80. package/dist/esm/src/auth/Certificate.js.map +1 -0
  81. package/dist/esm/src/auth/index.js +2 -0
  82. package/dist/esm/src/auth/index.js.map +1 -0
  83. package/dist/esm/src/overlay-tools/LookupResolver.js +167 -0
  84. package/dist/esm/src/overlay-tools/LookupResolver.js.map +1 -0
  85. package/dist/esm/src/overlay-tools/OverlayAdminTokenTemplate.js +64 -0
  86. package/dist/esm/src/overlay-tools/OverlayAdminTokenTemplate.js.map +1 -0
  87. package/dist/esm/src/overlay-tools/SHIPBroadcaster.js +335 -0
  88. package/dist/esm/src/overlay-tools/SHIPBroadcaster.js.map +1 -0
  89. package/dist/esm/src/overlay-tools/index.js +6 -0
  90. package/dist/esm/src/overlay-tools/index.js.map +1 -0
  91. package/dist/esm/src/script/templates/PushDrop.js +215 -0
  92. package/dist/esm/src/script/templates/PushDrop.js.map +1 -0
  93. package/dist/esm/src/script/templates/index.js +1 -0
  94. package/dist/esm/src/script/templates/index.js.map +1 -1
  95. package/dist/esm/src/transaction/Beef.js +35 -6
  96. package/dist/esm/src/transaction/Beef.js.map +1 -1
  97. package/dist/esm/src/transaction/Transaction.js +13 -4
  98. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  99. package/dist/esm/src/transaction/http/DefaultHttpClient.js +1 -1
  100. package/dist/esm/src/transaction/http/DefaultHttpClient.js.map +1 -1
  101. package/dist/esm/src/wallet/CachedKeyDeriver.js +174 -0
  102. package/dist/esm/src/wallet/CachedKeyDeriver.js.map +1 -0
  103. package/dist/esm/src/wallet/KeyDeriver.js +172 -0
  104. package/dist/esm/src/wallet/KeyDeriver.js.map +1 -0
  105. package/dist/esm/src/wallet/ProtoWallet.js +207 -0
  106. package/dist/esm/src/wallet/ProtoWallet.js.map +1 -0
  107. package/dist/esm/src/wallet/Wallet.interfaces.js +2 -0
  108. package/dist/esm/src/wallet/Wallet.interfaces.js.map +1 -0
  109. package/dist/esm/src/wallet/WalletClient.js +177 -0
  110. package/dist/esm/src/wallet/WalletClient.js.map +1 -0
  111. package/dist/esm/src/wallet/WalletError.js +25 -0
  112. package/dist/esm/src/wallet/WalletError.js.map +1 -0
  113. package/dist/esm/src/wallet/index.js +9 -0
  114. package/dist/esm/src/wallet/index.js.map +1 -0
  115. package/dist/esm/src/wallet/substrates/HTTPWalletWire.js +42 -0
  116. package/dist/esm/src/wallet/substrates/HTTPWalletWire.js.map +1 -0
  117. package/dist/esm/src/wallet/substrates/WalletWire.js +2 -0
  118. package/dist/esm/src/wallet/substrates/WalletWire.js.map +1 -0
  119. package/dist/esm/src/wallet/substrates/WalletWireCalls.js +34 -0
  120. package/dist/esm/src/wallet/substrates/WalletWireCalls.js.map +1 -0
  121. package/dist/esm/src/wallet/substrates/WalletWireProcessor.js +1816 -0
  122. package/dist/esm/src/wallet/substrates/WalletWireProcessor.js.map +1 -0
  123. package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js +1300 -0
  124. package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js.map +1 -0
  125. package/dist/esm/src/wallet/substrates/XDM.js +128 -0
  126. package/dist/esm/src/wallet/substrates/XDM.js.map +1 -0
  127. package/dist/esm/src/wallet/substrates/index.js +8 -0
  128. package/dist/esm/src/wallet/substrates/index.js.map +1 -0
  129. package/dist/esm/src/wallet/substrates/window.CWI.js +100 -0
  130. package/dist/esm/src/wallet/substrates/window.CWI.js.map +1 -0
  131. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  132. package/dist/types/mod.d.ts +4 -0
  133. package/dist/types/mod.d.ts.map +1 -1
  134. package/dist/types/src/auth/Certificate.d.ts +76 -0
  135. package/dist/types/src/auth/Certificate.d.ts.map +1 -0
  136. package/dist/types/src/auth/index.d.ts +2 -0
  137. package/dist/types/src/auth/index.d.ts.map +1 -0
  138. package/dist/types/src/overlay-tools/LookupResolver.d.ts +71 -0
  139. package/dist/types/src/overlay-tools/LookupResolver.d.ts.map +1 -0
  140. package/dist/types/src/overlay-tools/OverlayAdminTokenTemplate.d.ts +44 -0
  141. package/dist/types/src/overlay-tools/OverlayAdminTokenTemplate.d.ts.map +1 -0
  142. package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts +90 -0
  143. package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts.map +1 -0
  144. package/dist/types/src/overlay-tools/index.d.ts +6 -0
  145. package/dist/types/src/overlay-tools/index.d.ts.map +1 -0
  146. package/dist/types/src/script/templates/PushDrop.d.ts +53 -0
  147. package/dist/types/src/script/templates/PushDrop.d.ts.map +1 -0
  148. package/dist/types/src/script/templates/index.d.ts +1 -0
  149. package/dist/types/src/script/templates/index.d.ts.map +1 -1
  150. package/dist/types/src/transaction/Beef.d.ts +16 -1
  151. package/dist/types/src/transaction/Beef.d.ts.map +1 -1
  152. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  153. package/dist/types/src/wallet/CachedKeyDeriver.d.ts +92 -0
  154. package/dist/types/src/wallet/CachedKeyDeriver.d.ts.map +1 -0
  155. package/dist/types/src/wallet/KeyDeriver.d.ts +72 -0
  156. package/dist/types/src/wallet/KeyDeriver.d.ts.map +1 -0
  157. package/dist/types/src/wallet/ProtoWallet.d.ts +415 -0
  158. package/dist/types/src/wallet/ProtoWallet.d.ts.map +1 -0
  159. package/dist/types/src/wallet/Wallet.interfaces.d.ts +996 -0
  160. package/dist/types/src/wallet/Wallet.interfaces.d.ts.map +1 -0
  161. package/dist/types/src/wallet/WalletClient.d.ts +182 -0
  162. package/dist/types/src/wallet/WalletClient.d.ts.map +1 -0
  163. package/dist/types/src/wallet/WalletError.d.ts +14 -0
  164. package/dist/types/src/wallet/WalletError.d.ts.map +1 -0
  165. package/dist/types/src/wallet/index.d.ts +9 -0
  166. package/dist/types/src/wallet/index.d.ts.map +1 -0
  167. package/dist/types/src/wallet/substrates/HTTPWalletWire.d.ts +9 -0
  168. package/dist/types/src/wallet/substrates/HTTPWalletWire.d.ts.map +1 -0
  169. package/dist/types/src/wallet/substrates/WalletWire.d.ts +7 -0
  170. package/dist/types/src/wallet/substrates/WalletWire.d.ts.map +1 -0
  171. package/dist/types/src/wallet/substrates/WalletWireCalls.d.ts +33 -0
  172. package/dist/types/src/wallet/substrates/WalletWireCalls.d.ts.map +1 -0
  173. package/dist/types/src/wallet/substrates/WalletWireProcessor.d.ts +18 -0
  174. package/dist/types/src/wallet/substrates/WalletWireProcessor.d.ts.map +1 -0
  175. package/dist/types/src/wallet/substrates/WalletWireTransceiver.d.ts +196 -0
  176. package/dist/types/src/wallet/substrates/WalletWireTransceiver.d.ts.map +1 -0
  177. package/dist/types/src/wallet/substrates/XDM.d.ts +412 -0
  178. package/dist/types/src/wallet/substrates/XDM.d.ts.map +1 -0
  179. package/dist/types/src/wallet/substrates/index.d.ts +8 -0
  180. package/dist/types/src/wallet/substrates/index.d.ts.map +1 -0
  181. package/dist/types/src/wallet/substrates/window.CWI.d.ts +410 -0
  182. package/dist/types/src/wallet/substrates/window.CWI.d.ts.map +1 -0
  183. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  184. package/dist/umd/bundle.js +1 -1
  185. package/docs/overlay-tools.md +551 -0
  186. package/docs/script.md +135 -0
  187. package/docs/totp.md +119 -0
  188. package/docs/transaction.md +25 -0
  189. package/docs/wallet-substrates.md +10 -0
  190. package/docs/wallet.md +4182 -0
  191. package/mod.ts +5 -1
  192. package/package.json +44 -3
  193. package/src/auth/Certificate.ts +233 -0
  194. package/src/auth/__tests/Certificate.test.ts +282 -0
  195. package/src/auth/index.ts +1 -0
  196. package/src/overlay-tools/LookupResolver.ts +228 -0
  197. package/src/overlay-tools/OverlayAdminTokenTemplate.ts +79 -0
  198. package/src/overlay-tools/SHIPBroadcaster.ts +405 -0
  199. package/src/overlay-tools/__tests/LookupResolver.test.ts +1403 -0
  200. package/src/overlay-tools/__tests/OverlayAdminTokenTemplate.test.ts +69 -0
  201. package/src/overlay-tools/__tests/SHIPBroadcaster.test.ts +904 -0
  202. package/src/overlay-tools/index.ts +5 -0
  203. package/src/script/templates/PushDrop.ts +246 -0
  204. package/src/script/templates/__tests/PushDrop.test.ts +158 -0
  205. package/src/script/templates/index.ts +1 -0
  206. package/src/transaction/Beef.ts +36 -6
  207. package/src/transaction/Transaction.ts +13 -4
  208. package/src/transaction/__tests/Beef.test.ts +20 -6
  209. package/src/transaction/http/DefaultHttpClient.ts +1 -1
  210. package/src/wallet/CachedKeyDeriver.ts +193 -0
  211. package/src/wallet/KeyDeriver.ts +178 -0
  212. package/src/wallet/ProtoWallet.ts +732 -0
  213. package/src/wallet/Wallet.interfaces.ts +1170 -0
  214. package/src/wallet/WalletClient.ts +201 -0
  215. package/src/wallet/WalletError.ts +27 -0
  216. package/src/wallet/__tests/CachedKeyDeriver.test.ts +322 -0
  217. package/src/wallet/__tests/KeyDeriver.test.ts +118 -0
  218. package/src/wallet/__tests/ProtoWallet.test.ts +543 -0
  219. package/src/wallet/index.ts +8 -0
  220. package/src/wallet/substrates/HTTPWalletWire.ts +47 -0
  221. package/src/wallet/substrates/WalletWire.ts +6 -0
  222. package/src/wallet/substrates/WalletWireCalls.ts +34 -0
  223. package/src/wallet/substrates/WalletWireProcessor.ts +2046 -0
  224. package/src/wallet/substrates/WalletWireTransceiver.ts +1454 -0
  225. package/src/wallet/substrates/XDM.ts +157 -0
  226. package/src/wallet/substrates/__tests/WalletWire.integration.test.ts +2194 -0
  227. package/src/wallet/substrates/__tests/XDM.test.ts +659 -0
  228. package/src/wallet/substrates/index.ts +7 -0
  229. package/src/wallet/substrates/window.CWI.ts +133 -0
@@ -0,0 +1,201 @@
1
+ import { AcquireCertificateArgs, AcquireCertificateResult, Base64String, BasketStringUnder300Bytes, BEEF, BooleanDefaultFalse, BooleanDefaultTrue, Byte, CertificateFieldNameUnder50Bytes, CreateActionArgs, CreateActionResult, DescriptionString5to50Bytes, DiscoverCertificatesResult, EntityIconURLStringMax500Bytes, EntityNameStringMax100Bytes, HexString, InternalizeActionArgs, ISOTimestampString, KeyIDStringUnder800Bytes, LabelStringUnder300Bytes, ListActionsArgs, ListActionsResult, ListCertificatesResult, ListOutputsArgs, ListOutputsResult, OriginatorDomainNameStringUnder250Bytes, OutpointString, OutputTagStringUnder300Bytes, PositiveInteger, PositiveIntegerDefault10Max10000, PositiveIntegerMax10, PositiveIntegerOrZero, ProtocolString5To400Bytes, ProveCertificateArgs, ProveCertificateResult, PubKeyHex, SatoshiValue, SignActionArgs, SignActionResult, TXIDHexString, VersionString7To30Bytes, Wallet } from './Wallet.interfaces.js'
2
+ import WindowCWISubstrate from './substrates/window.CWI.js'
3
+ import XDMSubstrate from './substrates/XDM.js'
4
+ import WalletWireTransceiver from './substrates/WalletWireTransceiver.js'
5
+ import HTTPWalletWire from './substrates/HTTPWalletWire.js'
6
+
7
+ const MAX_XDM_RESPONSE_WAIT = 200
8
+
9
+ /**
10
+ * The SDK is how applications communicate with wallets over a communications substrate.
11
+ */
12
+ export default class WalletClient implements Wallet {
13
+ public substrate: 'auto' | Wallet
14
+ originator?: OriginatorDomainNameStringUnder250Bytes
15
+ constructor(substrate: 'auto' | 'Cicada' | 'XDM' | 'window.CWI' | Wallet = 'auto', originator?: OriginatorDomainNameStringUnder250Bytes) {
16
+ if (substrate === 'Cicada') substrate = new WalletWireTransceiver(new HTTPWalletWire(originator))
17
+ if (substrate === 'window.CWI') substrate = new WindowCWISubstrate()
18
+ if (substrate === 'XDM') substrate = new XDMSubstrate()
19
+ this.substrate = substrate
20
+ this.originator = originator
21
+ }
22
+
23
+ async connectToSubstrate() {
24
+ if (typeof this.substrate === 'object') {
25
+ return // substrate is already connected
26
+ }
27
+ let sub: Wallet
28
+ const checkSub = async (timeout?: number) => {
29
+ let result
30
+ if (typeof timeout === 'number') {
31
+ result = await Promise.race([
32
+ sub.getVersion({}),
33
+ new Promise<never>((_, reject) => setTimeout(() => reject(new Error('Timed out.')), timeout))
34
+ ])
35
+ } else {
36
+ result = await sub.getVersion({})
37
+ }
38
+ if (typeof result !== 'object' || typeof result.version !== 'string') {
39
+ throw new Error('Failed to use substrate.')
40
+ }
41
+ }
42
+ try {
43
+ sub = new WindowCWISubstrate()
44
+ await checkSub()
45
+ this.substrate = sub
46
+ } catch (e) {
47
+ try {
48
+ sub = new XDMSubstrate()
49
+ await checkSub(MAX_XDM_RESPONSE_WAIT)
50
+ this.substrate = sub
51
+ } catch (e) {
52
+ try {
53
+ sub = new WalletWireTransceiver(new HTTPWalletWire(this.originator))
54
+ await checkSub()
55
+ this.substrate = sub
56
+ } catch (e) {
57
+ throw new Error('No wallet available over any communication substrate. Install a BSV wallet today!')
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ async createAction(args: CreateActionArgs): Promise<CreateActionResult> {
64
+ await this.connectToSubstrate()
65
+ return await (this.substrate as Wallet).createAction(args, this.originator)
66
+ }
67
+
68
+ async signAction(args: SignActionArgs): Promise<SignActionResult> {
69
+ await this.connectToSubstrate()
70
+ return await (this.substrate as Wallet).signAction(args, this.originator)
71
+ }
72
+
73
+ async abortAction(args: { reference: Base64String }): Promise<{ aborted: true }> {
74
+ await this.connectToSubstrate()
75
+ return await (this.substrate as Wallet).abortAction(args, this.originator)
76
+ }
77
+
78
+ async listActions(args: ListActionsArgs): Promise<ListActionsResult> {
79
+ await this.connectToSubstrate()
80
+ return await (this.substrate as Wallet).listActions(args, this.originator)
81
+ }
82
+
83
+ async internalizeAction(args: InternalizeActionArgs): Promise<{ accepted: true }> {
84
+ await this.connectToSubstrate()
85
+ return await (this.substrate as Wallet).internalizeAction(args, this.originator)
86
+ }
87
+
88
+ async listOutputs(args: ListOutputsArgs): Promise<ListOutputsResult> {
89
+ await this.connectToSubstrate()
90
+ return await (this.substrate as Wallet).listOutputs(args, this.originator)
91
+ }
92
+
93
+ async relinquishOutput(args: { basket: BasketStringUnder300Bytes, output: OutpointString }): Promise<{ relinquished: true }> {
94
+ await this.connectToSubstrate()
95
+ return await (this.substrate as Wallet).relinquishOutput(args, this.originator)
96
+ }
97
+
98
+ async getPublicKey(args: { identityKey?: true, protocolID?: [0 | 1 | 2, ProtocolString5To400Bytes], keyID?: KeyIDStringUnder800Bytes, privileged?: BooleanDefaultFalse, privilegedReason?: DescriptionString5to50Bytes, counterparty?: PubKeyHex | 'self' | 'anyone', forSelf?: BooleanDefaultFalse }): Promise<{ publicKey: PubKeyHex }> {
99
+ await this.connectToSubstrate()
100
+ return await (this.substrate as Wallet).getPublicKey(args, this.originator)
101
+ }
102
+
103
+ async revealCounterpartyKeyLinkage(args: { counterparty: PubKeyHex, verifier: PubKeyHex, privilegedReason?: DescriptionString5to50Bytes, privileged?: BooleanDefaultFalse }): Promise<{ prover: PubKeyHex, verifier: PubKeyHex, counterparty: PubKeyHex, revelationTime: ISOTimestampString, encryptedLinkage: Byte[], encryptedLinkageProof: Byte[] }> {
104
+ await this.connectToSubstrate()
105
+ return await (this.substrate as Wallet).revealCounterpartyKeyLinkage(args, this.originator)
106
+ }
107
+
108
+ async revealSpecificKeyLinkage(args: { counterparty: PubKeyHex, verifier: PubKeyHex, protocolID: [0 | 1 | 2, ProtocolString5To400Bytes], keyID: KeyIDStringUnder800Bytes, privilegedReason?: DescriptionString5to50Bytes, privileged?: BooleanDefaultFalse }): Promise<{ prover: PubKeyHex, verifier: PubKeyHex, counterparty: PubKeyHex, protocolID: [0 | 1 | 2, ProtocolString5To400Bytes], keyID: KeyIDStringUnder800Bytes, encryptedLinkage: Byte[], encryptedLinkageProof: Byte[], proofType: Byte }> {
109
+ await this.connectToSubstrate()
110
+ return await (this.substrate as Wallet).revealSpecificKeyLinkage(args, this.originator)
111
+ }
112
+
113
+ async encrypt(args: { plaintext: Byte[], protocolID: [0 | 1 | 2, ProtocolString5To400Bytes], keyID: KeyIDStringUnder800Bytes, privilegedReason?: DescriptionString5to50Bytes, counterparty?: PubKeyHex | 'self' | 'anyone', privileged?: BooleanDefaultFalse }): Promise<{ ciphertext: Byte[] }> {
114
+ await this.connectToSubstrate()
115
+ return await (this.substrate as Wallet).encrypt(args, this.originator)
116
+ }
117
+
118
+ async decrypt(args: { ciphertext: Byte[], protocolID: [0 | 1 | 2, ProtocolString5To400Bytes], keyID: KeyIDStringUnder800Bytes, privilegedReason?: DescriptionString5to50Bytes, counterparty?: PubKeyHex | 'self' | 'anyone', privileged?: BooleanDefaultFalse }): Promise<{ plaintext: Byte[] }> {
119
+ return await (this.substrate as Wallet).decrypt(args, this.originator)
120
+ }
121
+
122
+ async createHmac(args: { data: Byte[], protocolID: [0 | 1 | 2, ProtocolString5To400Bytes], keyID: KeyIDStringUnder800Bytes, privilegedReason?: DescriptionString5to50Bytes, counterparty?: PubKeyHex | 'self' | 'anyone', privileged?: BooleanDefaultFalse }): Promise<{ hmac: Byte[] }> {
123
+ await this.connectToSubstrate()
124
+ return await (this.substrate as Wallet).createHmac(args, this.originator)
125
+ }
126
+
127
+ async verifyHmac(args: { data: Byte[], hmac: Byte[], protocolID: [0 | 1 | 2, ProtocolString5To400Bytes], keyID: KeyIDStringUnder800Bytes, privilegedReason?: DescriptionString5to50Bytes, counterparty?: PubKeyHex | 'self' | 'anyone', privileged?: BooleanDefaultFalse }): Promise<{ valid: true }> {
128
+ await this.connectToSubstrate()
129
+ return await (this.substrate as Wallet).verifyHmac(args, this.originator)
130
+ }
131
+
132
+ async createSignature(args: { data?: Byte[], hashToDirectlySign?: Byte[], protocolID: [0 | 1 | 2, ProtocolString5To400Bytes], keyID: KeyIDStringUnder800Bytes, privilegedReason?: DescriptionString5to50Bytes, counterparty?: PubKeyHex | 'self' | 'anyone', privileged?: BooleanDefaultFalse }): Promise<{ signature: Byte[] }> {
133
+ await this.connectToSubstrate()
134
+ return await (this.substrate as Wallet).createSignature(args, this.originator)
135
+ }
136
+
137
+ async verifySignature(args: { data?: Byte[], hashToDirectlyVerify?: Byte[], signature: Byte[], protocolID: [0 | 1 | 2, ProtocolString5To400Bytes], keyID: KeyIDStringUnder800Bytes, privilegedReason?: DescriptionString5to50Bytes, counterparty?: PubKeyHex | 'self' | 'anyone', forSelf?: BooleanDefaultFalse, privileged?: BooleanDefaultFalse }): Promise<{ valid: true }> {
138
+ await this.connectToSubstrate()
139
+ return await (this.substrate as Wallet).verifySignature(args, this.originator)
140
+ }
141
+
142
+ async acquireCertificate(args: AcquireCertificateArgs): Promise<AcquireCertificateResult> {
143
+ await this.connectToSubstrate()
144
+ return await (this.substrate as Wallet).acquireCertificate(args, this.originator)
145
+ }
146
+
147
+ async listCertificates(args: { certifiers: PubKeyHex[], types: Base64String[], limit?: PositiveIntegerDefault10Max10000, offset?: PositiveIntegerOrZero, privileged?: BooleanDefaultFalse, privilegedReason?: DescriptionString5to50Bytes }): Promise<ListCertificatesResult> {
148
+ await this.connectToSubstrate()
149
+ return await (this.substrate as Wallet).listCertificates(args, this.originator)
150
+ }
151
+
152
+ async proveCertificate(args: ProveCertificateArgs): Promise<ProveCertificateResult> {
153
+ await this.connectToSubstrate()
154
+ return await (this.substrate as Wallet).proveCertificate(args, this.originator)
155
+ }
156
+
157
+ async relinquishCertificate(args: { type: Base64String, serialNumber: Base64String, certifier: PubKeyHex }): Promise<{ relinquished: true }> {
158
+ await this.connectToSubstrate()
159
+ return await (this.substrate as Wallet).relinquishCertificate(args, this.originator)
160
+ }
161
+
162
+ async discoverByIdentityKey(args: { identityKey: PubKeyHex, limit?: PositiveIntegerDefault10Max10000, offset?: PositiveIntegerOrZero }): Promise<DiscoverCertificatesResult> {
163
+ await this.connectToSubstrate()
164
+ return await (this.substrate as Wallet).discoverByIdentityKey(args, this.originator)
165
+ }
166
+
167
+ async discoverByAttributes(args: { attributes: Record<CertificateFieldNameUnder50Bytes, string>, limit?: PositiveIntegerDefault10Max10000, offset?: PositiveIntegerOrZero }): Promise<DiscoverCertificatesResult> {
168
+ await this.connectToSubstrate()
169
+ return await (this.substrate as Wallet).discoverByAttributes(args, this.originator)
170
+ }
171
+
172
+ async isAuthenticated(args: {} = {}): Promise<{ authenticated: boolean }> {
173
+ await this.connectToSubstrate()
174
+ return await (this.substrate as Wallet).isAuthenticated(args, this.originator)
175
+ }
176
+
177
+ async waitForAuthentication(args: {} = {}): Promise<{ authenticated: true }> {
178
+ await this.connectToSubstrate()
179
+ return await (this.substrate as Wallet).waitForAuthentication(args, this.originator)
180
+ }
181
+
182
+ async getHeight(args: {} = {}): Promise<{ height: PositiveInteger }> {
183
+ await this.connectToSubstrate()
184
+ return await (this.substrate as Wallet).getHeight(args, this.originator)
185
+ }
186
+
187
+ async getHeaderForHeight(args: { height: PositiveInteger }): Promise<{ header: HexString }> {
188
+ await this.connectToSubstrate()
189
+ return await (this.substrate as Wallet).getHeaderForHeight(args, this.originator)
190
+ }
191
+
192
+ async getNetwork(args: {} = {}): Promise<{ network: 'mainnet' | 'testnet' }> {
193
+ await this.connectToSubstrate()
194
+ return await (this.substrate as Wallet).getNetwork(args, this.originator)
195
+ }
196
+
197
+ async getVersion(args: {} = {}): Promise<{ version: VersionString7To30Bytes }> {
198
+ await this.connectToSubstrate()
199
+ return await (this.substrate as Wallet).getVersion(args, this.originator)
200
+ }
201
+ }
@@ -0,0 +1,27 @@
1
+ export class WalletError extends Error {
2
+ code: number
3
+ isError: boolean = true
4
+
5
+ constructor(message: string, code = 1, stack?: string) {
6
+ super(message)
7
+ this.code = code
8
+ this.name = this.constructor.name
9
+
10
+ if (stack) {
11
+ this.stack = stack
12
+ } else if (Error.captureStackTrace) {
13
+ Error.captureStackTrace(this, this.constructor)
14
+ }
15
+ }
16
+ }
17
+
18
+ // NOTE: Enum values must not exceed the UInt8 range (0–255)
19
+ enum walletErrors {
20
+ unknownError = 1,
21
+ unsupportedAction = 2,
22
+ invalidHmac = 3,
23
+ invalidSignature = 4,
24
+ }
25
+
26
+ export default walletErrors
27
+ export type WalletErrorCode = keyof typeof walletErrors
@@ -0,0 +1,322 @@
1
+ import { PrivateKey, PublicKey, SymmetricKey } from '../../../dist/cjs/src/primitives/index.js'
2
+ import CachedKeyDeriver from '../../../dist/cjs/src/wallet/CachedKeyDeriver.js'
3
+ import KeyDeriver from '../../../dist/cjs/src/wallet/KeyDeriver.js'
4
+
5
+ describe('CachedKeyDeriver', () => {
6
+ let mockKeyDeriver: jest.Mocked<KeyDeriver>
7
+ let cachedKeyDeriver: CachedKeyDeriver
8
+ const rootKey = new PrivateKey(1)
9
+
10
+ beforeEach(() => {
11
+ // Reset the mocks and create a new CachedKeyDeriver instance before each test
12
+ jest.clearAllMocks()
13
+ mockKeyDeriver = new KeyDeriver(rootKey) as jest.Mocked<KeyDeriver>
14
+ // Mock the methods of KeyDeriver
15
+ mockKeyDeriver.derivePublicKey = jest.fn()
16
+ mockKeyDeriver.derivePrivateKey = jest.fn()
17
+ mockKeyDeriver.deriveSymmetricKey = jest.fn()
18
+ mockKeyDeriver.revealCounterpartySecret = jest.fn()
19
+ mockKeyDeriver.revealSpecificSecret = jest.fn()
20
+
21
+ // Replace the internal keyDeriver instance with the mocked one
22
+ cachedKeyDeriver = new CachedKeyDeriver(rootKey)
23
+ cachedKeyDeriver.keyDeriver = mockKeyDeriver
24
+ })
25
+
26
+ describe('derivePublicKey', () => {
27
+ it('should call derivePublicKey on KeyDeriver and cache the result', () => {
28
+ const protocolID: [0, string] = [0, 'testprotocol']
29
+ const keyID = 'key1'
30
+ const counterparty = 'self'
31
+ const publicKey = new PublicKey(0)
32
+
33
+ mockKeyDeriver.derivePublicKey.mockReturnValue(publicKey)
34
+
35
+ // First call - should invoke the underlying method
36
+ const result1 = cachedKeyDeriver.derivePublicKey(protocolID, keyID, counterparty)
37
+ expect(mockKeyDeriver.derivePublicKey).toHaveBeenCalledTimes(1)
38
+ expect(result1).toBe(publicKey)
39
+
40
+ // Second call with the same parameters - should retrieve from cache
41
+ const result2 = cachedKeyDeriver.derivePublicKey(protocolID, keyID, counterparty)
42
+ expect(mockKeyDeriver.derivePublicKey).toHaveBeenCalledTimes(1) // No additional calls
43
+ expect(result2).toBe(publicKey)
44
+ })
45
+
46
+ it('should handle different parameters correctly', () => {
47
+ const protocolID1: [0, string] = [0, 'protocol1']
48
+ const protocolID2: [1, string] = [1, 'protocol2']
49
+ const keyID1 = 'key1'
50
+ const keyID2 = 'key2'
51
+ const counterparty1 = 'self'
52
+ const counterparty2 = 'anyone'
53
+ const publicKey1 = new PublicKey(0)
54
+ const publicKey2 = new PublicKey(0)
55
+
56
+ mockKeyDeriver.derivePublicKey
57
+ .mockReturnValueOnce(publicKey1)
58
+ .mockReturnValueOnce(publicKey2)
59
+
60
+ // Different parameters - should not hit cache
61
+ const result1 = cachedKeyDeriver.derivePublicKey(protocolID1, keyID1, counterparty1)
62
+ const result2 = cachedKeyDeriver.derivePublicKey(protocolID2, keyID2, counterparty2)
63
+ expect(mockKeyDeriver.derivePublicKey).toHaveBeenCalledTimes(2)
64
+ expect(result1).toBe(publicKey1)
65
+ expect(result2).toBe(publicKey2)
66
+ })
67
+ })
68
+
69
+ describe('derivePrivateKey', () => {
70
+ it('should call derivePrivateKey on KeyDeriver and cache the result', () => {
71
+ const protocolID: [1, string] = [1, 'testprotocol']
72
+ const keyID = 'key1'
73
+ const counterparty = 'anyone'
74
+ const privateKey = new PrivateKey()
75
+
76
+ mockKeyDeriver.derivePrivateKey.mockReturnValue(privateKey)
77
+
78
+ // First call - should invoke the underlying method
79
+ const result1 = cachedKeyDeriver.derivePrivateKey(protocolID, keyID, counterparty)
80
+ expect(mockKeyDeriver.derivePrivateKey).toHaveBeenCalledTimes(1)
81
+ expect(result1).toBe(privateKey)
82
+
83
+ // Second call with the same parameters - should retrieve from cache
84
+ const result2 = cachedKeyDeriver.derivePrivateKey(protocolID, keyID, counterparty)
85
+ expect(mockKeyDeriver.derivePrivateKey).toHaveBeenCalledTimes(1)
86
+ expect(result2).toBe(privateKey)
87
+ })
88
+
89
+ it('should differentiate cache entries based on parameters', () => {
90
+ const protocolID: [1, string] = [1, 'testprotocol']
91
+ const keyID = 'key1'
92
+ const counterparty = 'anyone'
93
+ const privateKey1 = new PrivateKey()
94
+ const privateKey2 = new PrivateKey()
95
+
96
+ mockKeyDeriver.derivePrivateKey
97
+ .mockReturnValueOnce(privateKey1)
98
+ .mockReturnValueOnce(privateKey2)
99
+
100
+ // First call
101
+ const result1 = cachedKeyDeriver.derivePrivateKey(protocolID, keyID, counterparty)
102
+ expect(result1).toBe(privateKey1)
103
+
104
+ // Second call with different keyID
105
+ const result2 = cachedKeyDeriver.derivePrivateKey(protocolID, 'key2', counterparty)
106
+ expect(result2).toBe(privateKey2)
107
+ expect(mockKeyDeriver.derivePrivateKey).toHaveBeenCalledTimes(2)
108
+ })
109
+ })
110
+
111
+ describe('deriveSymmetricKey', () => {
112
+ it('should call deriveSymmetricKey on KeyDeriver and cache the result', () => {
113
+ const protocolID: [2, string] = [2, 'testprotocol']
114
+ const keyID = 'key1'
115
+ const counterparty = new PublicKey(0)
116
+ const symmetricKey = new SymmetricKey(0)
117
+
118
+ mockKeyDeriver.deriveSymmetricKey.mockReturnValue(symmetricKey)
119
+
120
+ // First call
121
+ const result1 = cachedKeyDeriver.deriveSymmetricKey(protocolID, keyID, counterparty)
122
+ expect(mockKeyDeriver.deriveSymmetricKey).toHaveBeenCalledTimes(1)
123
+ expect(result1).toBe(symmetricKey)
124
+
125
+ // Second call with same parameters
126
+ const result2 = cachedKeyDeriver.deriveSymmetricKey(protocolID, keyID, counterparty)
127
+ expect(mockKeyDeriver.deriveSymmetricKey).toHaveBeenCalledTimes(1)
128
+ expect(result2).toBe(symmetricKey)
129
+ })
130
+
131
+ it('should throw an error when KeyDeriver throws an error', () => {
132
+ const protocolID: [2, string] = [2, 'testprotocol']
133
+ const keyID = 'key1'
134
+ const counterparty = 'anyone'
135
+
136
+ mockKeyDeriver.deriveSymmetricKey.mockImplementation(() => {
137
+ throw new Error('Test error')
138
+ })
139
+
140
+ expect(() => {
141
+ cachedKeyDeriver.deriveSymmetricKey(protocolID, keyID, counterparty)
142
+ }).toThrow('Test error')
143
+ })
144
+ })
145
+
146
+ describe('revealCounterpartySecret', () => {
147
+ it('should call revealCounterpartySecret on KeyDeriver and cache the result', () => {
148
+ const counterparty = new PublicKey(0)
149
+ const secret = [1, 2, 3]
150
+
151
+ mockKeyDeriver.revealCounterpartySecret.mockReturnValue(secret)
152
+
153
+ // First call
154
+ const result1 = cachedKeyDeriver.revealCounterpartySecret(counterparty)
155
+ expect(mockKeyDeriver.revealCounterpartySecret).toHaveBeenCalledTimes(1)
156
+ expect(result1).toBe(secret)
157
+
158
+ // Second call with same parameters
159
+ const result2 = cachedKeyDeriver.revealCounterpartySecret(counterparty)
160
+ expect(mockKeyDeriver.revealCounterpartySecret).toHaveBeenCalledTimes(1)
161
+ expect(result2).toBe(secret)
162
+ })
163
+ })
164
+
165
+ describe('revealSpecificSecret', () => {
166
+ it('should call revealSpecificSecret on KeyDeriver and cache the result', () => {
167
+ const counterparty = 'self'
168
+ const protocolID: [0, string] = [0, 'testprotocol']
169
+ const keyID = 'key1'
170
+ const secret = [4, 5, 6]
171
+
172
+ mockKeyDeriver.revealSpecificSecret.mockReturnValue(secret)
173
+
174
+ // First call
175
+ const result1 = cachedKeyDeriver.revealSpecificSecret(counterparty, protocolID, keyID)
176
+ expect(mockKeyDeriver.revealSpecificSecret).toHaveBeenCalledTimes(1)
177
+ expect(result1).toBe(secret)
178
+
179
+ // Second call with same parameters
180
+ const result2 = cachedKeyDeriver.revealSpecificSecret(counterparty, protocolID, keyID)
181
+ expect(mockKeyDeriver.revealSpecificSecret).toHaveBeenCalledTimes(1)
182
+ expect(result2).toBe(secret)
183
+ })
184
+
185
+ it('should handle different parameters correctly', () => {
186
+ const counterparty = 'self'
187
+ const protocolID1: [0, string] = [0, 'protocol1']
188
+ const protocolID2: [1, string] = [1, 'protocol2']
189
+ const keyID1 = 'key1'
190
+ const keyID2 = 'key2'
191
+ const secret1 = [4, 5, 6]
192
+ const secret2 = [7, 8, 9]
193
+
194
+ mockKeyDeriver.revealSpecificSecret
195
+ .mockReturnValueOnce(secret1)
196
+ .mockReturnValueOnce(secret2)
197
+
198
+ // First call
199
+ const result1 = cachedKeyDeriver.revealSpecificSecret(counterparty, protocolID1, keyID1)
200
+ expect(result1).toBe(secret1)
201
+
202
+ // Second call with different parameters
203
+ const result2 = cachedKeyDeriver.revealSpecificSecret(counterparty, protocolID2, keyID2)
204
+ expect(result2).toBe(secret2)
205
+ expect(mockKeyDeriver.revealSpecificSecret).toHaveBeenCalledTimes(2)
206
+ })
207
+ })
208
+
209
+ describe('Cache management', () => {
210
+ it('should not exceed the max cache size and evict least recently used items', () => {
211
+ const maxCacheSize = 5
212
+ // Create a new CachedKeyDeriver with a small cache size
213
+ cachedKeyDeriver = new CachedKeyDeriver(rootKey, { maxCacheSize })
214
+ cachedKeyDeriver.keyDeriver = mockKeyDeriver
215
+
216
+ const protocolID: [0, string] = [0, 'testprotocol']
217
+ const counterparty = 'self'
218
+
219
+ // Mock return values
220
+ const mockResults = [1, 2, 3, 4, 5, 6].map((n) => new PublicKey(0))
221
+
222
+ mockKeyDeriver.derivePublicKey
223
+ .mockReturnValueOnce(mockResults[0])
224
+ .mockReturnValueOnce(mockResults[1])
225
+ .mockReturnValueOnce(mockResults[2])
226
+ .mockReturnValueOnce(mockResults[3])
227
+ .mockReturnValueOnce(mockResults[4])
228
+ .mockReturnValueOnce(mockResults[5])
229
+
230
+ // Add entries to fill the cache
231
+ for (let i = 0; i < maxCacheSize; i++) {
232
+ cachedKeyDeriver.derivePublicKey(protocolID, `key${i}`, counterparty)
233
+ }
234
+
235
+ // Cache should be full now
236
+ expect(cachedKeyDeriver.cache.size).toBe(maxCacheSize)
237
+
238
+ // Access one of the earlier keys to make it recently used
239
+ cachedKeyDeriver.derivePublicKey(protocolID, 'key0', counterparty)
240
+
241
+ // Add one more entry to exceed the cache size
242
+ cachedKeyDeriver.derivePublicKey(protocolID, 'key5', counterparty)
243
+
244
+ // Cache size should still be maxCacheSize
245
+ expect(cachedKeyDeriver.cache.size).toBe(maxCacheSize)
246
+
247
+ // The least recently used item (key1) should have been evicted
248
+ // The cache should contain keys: key0, key2, key3, key4, key5
249
+ expect(Array.from(cachedKeyDeriver.cache.keys())).toEqual([
250
+ expect.stringContaining('key2'),
251
+ expect.stringContaining('key3'),
252
+ expect.stringContaining('key4'),
253
+ expect.stringContaining('key0'),
254
+ expect.stringContaining('key5')
255
+ ])
256
+ })
257
+
258
+ it('should update the recentness of cache entries on access', () => {
259
+ const maxCacheSize = 3
260
+ cachedKeyDeriver = new CachedKeyDeriver(rootKey, { maxCacheSize })
261
+ cachedKeyDeriver.keyDeriver = mockKeyDeriver
262
+
263
+ const protocolID: [0, string] = [0, 'testprotocol']
264
+ const counterparty = 'self'
265
+ const keys = ['key1', 'key2', 'key3']
266
+ const publicKeys = keys.map(() => new PublicKey(0))
267
+
268
+ mockKeyDeriver.derivePublicKey
269
+ .mockReturnValueOnce(publicKeys[0])
270
+ .mockReturnValueOnce(publicKeys[1])
271
+ .mockReturnValueOnce(publicKeys[2])
272
+
273
+ // Fill the cache
274
+ keys.forEach((keyID) => {
275
+ cachedKeyDeriver.derivePublicKey(protocolID, keyID, counterparty)
276
+ })
277
+
278
+ // Access 'key1' to make it most recently used
279
+ cachedKeyDeriver.derivePublicKey(protocolID, 'key1', counterparty)
280
+
281
+ // Add a new key to trigger eviction
282
+ const newKeyID = 'key4'
283
+ const newPublicKey = new PublicKey(0)
284
+ mockKeyDeriver.derivePublicKey.mockReturnValueOnce(newPublicKey)
285
+ cachedKeyDeriver.derivePublicKey(protocolID, newKeyID, counterparty)
286
+
287
+ // 'key2' should be evicted as it is the least recently used
288
+ expect(Array.from(cachedKeyDeriver.cache.keys())).toEqual([
289
+ expect.stringContaining('key3'),
290
+ expect.stringContaining('key1'),
291
+ expect.stringContaining('key4')
292
+ ])
293
+ })
294
+ })
295
+
296
+ describe('Performance considerations', () => {
297
+ it('should improve performance by caching expensive operations', () => {
298
+ const protocolID: [0, string] = [0, 'testprotocol']
299
+ const keyID = 'key1'
300
+ const counterparty = 'self'
301
+ const publicKey = new PublicKey(0)
302
+
303
+ // Simulate an expensive operation
304
+ mockKeyDeriver.derivePublicKey.mockImplementation(() => {
305
+ const start = Date.now()
306
+ while (Date.now() - start < 50) { } // Busy wait for 50ms
307
+ return publicKey
308
+ })
309
+
310
+ const startTime = Date.now()
311
+ cachedKeyDeriver.derivePublicKey(protocolID, keyID, counterparty)
312
+ const firstCallDuration = Date.now() - startTime
313
+
314
+ const startTime2 = Date.now()
315
+ cachedKeyDeriver.derivePublicKey(protocolID, keyID, counterparty)
316
+ const secondCallDuration = Date.now() - startTime2
317
+
318
+ expect(firstCallDuration).toBeGreaterThanOrEqual(50)
319
+ expect(secondCallDuration).toBeLessThan(10) // Should be much faster due to caching
320
+ })
321
+ })
322
+ })
@@ -0,0 +1,118 @@
1
+ import { PrivateKey, PublicKey, SymmetricKey, Utils, Hash } from '../../../dist/cjs/src/primitives/index.js'
2
+ import KeyDeriver from '../../../dist/cjs/src/wallet/KeyDeriver.js'
3
+
4
+ describe('KeyDeriver', () => {
5
+ const rootPrivateKey = new PrivateKey(42)
6
+ const rootPublicKey = rootPrivateKey.toPublicKey()
7
+ const counterpartyPrivateKey = new PrivateKey(69)
8
+ const counterpartyPublicKey = counterpartyPrivateKey.toPublicKey()
9
+ const anyonePublicKey = new PrivateKey(1).toPublicKey()
10
+
11
+ const protocolID: [0 | 1 | 2, string] = [0, 'testprotocol']
12
+ const keyID = '12345'
13
+
14
+ let keyDeriver: KeyDeriver
15
+
16
+ beforeEach(() => {
17
+ keyDeriver = new KeyDeriver(rootPrivateKey)
18
+ })
19
+
20
+ test('should compute the correct invoice number', () => {
21
+ const invoiceNumber = (keyDeriver as any).computeInvoiceNumber(protocolID, keyID)
22
+ expect(invoiceNumber).toBe('0-testprotocol-12345')
23
+ })
24
+
25
+ test('should throw if no co counterparty given', () => {
26
+ expect(() => (keyDeriver as any).normalizeCounterparty()).toThrow()
27
+ })
28
+
29
+ test('should normalize counterparty correctly for self', () => {
30
+ const normalized = (keyDeriver as any).normalizeCounterparty('self')
31
+ expect(normalized.toString()).toBe(rootPublicKey.toString())
32
+ })
33
+
34
+ test('should normalize counterparty correctly for anyone', () => {
35
+ const normalized = (keyDeriver as any).normalizeCounterparty('anyone')
36
+ expect(normalized.toString()).toBe(anyonePublicKey.toString())
37
+ })
38
+
39
+ test('should normalize counterparty correctly when given as a hex string', () => {
40
+ const normalized = (keyDeriver as any).normalizeCounterparty(counterpartyPublicKey.toString())
41
+ expect(normalized.toString()).toBe(counterpartyPublicKey.toString())
42
+ })
43
+
44
+ test('should normalize counterparty correctly when given as a public key', () => {
45
+ const normalized = (keyDeriver as any).normalizeCounterparty(counterpartyPublicKey)
46
+ expect(normalized.toString()).toBe(counterpartyPublicKey.toString())
47
+ })
48
+
49
+ test('should allow public key derivation as anyone', () => {
50
+ const anyoneDeriver = new KeyDeriver('anyone')
51
+ const derivedPublicKey = anyoneDeriver.derivePublicKey(protocolID, keyID, counterpartyPublicKey)
52
+ expect(derivedPublicKey).toBeInstanceOf(PublicKey)
53
+ expect(derivedPublicKey.toString()).toEqual(counterpartyPublicKey.deriveChild(new PrivateKey(1), '0-testprotocol-12345').toString())
54
+ })
55
+
56
+ test('should derive the correct public key for counterparty', () => {
57
+ const derivedPublicKey = keyDeriver.derivePublicKey(protocolID, keyID, counterpartyPublicKey)
58
+ expect(derivedPublicKey).toBeInstanceOf(PublicKey)
59
+ expect(derivedPublicKey.toString()).toEqual(counterpartyPublicKey.deriveChild(rootPrivateKey, '0-testprotocol-12345').toString())
60
+ })
61
+
62
+ test('should derive the correct public key for self', () => {
63
+ const derivedPublicKey = keyDeriver.derivePublicKey(protocolID, keyID, counterpartyPublicKey, true)
64
+ expect(derivedPublicKey).toBeInstanceOf(PublicKey)
65
+ expect(derivedPublicKey.toString()).toEqual(rootPrivateKey.deriveChild(counterpartyPublicKey, '0-testprotocol-12345').toPublicKey().toString())
66
+ })
67
+
68
+ test('should derive the correct private key', () => {
69
+ const derivedPrivateKey = keyDeriver.derivePrivateKey(protocolID, keyID, counterpartyPublicKey)
70
+ expect(derivedPrivateKey).toBeInstanceOf(PrivateKey)
71
+ expect(derivedPrivateKey.toString()).toEqual(rootPrivateKey.deriveChild(counterpartyPublicKey, '0-testprotocol-12345').toString())
72
+ })
73
+
74
+ test('should derive the correct symmetric key', () => {
75
+ const derivedSymmetricKey = keyDeriver.deriveSymmetricKey(protocolID, keyID, counterpartyPublicKey)
76
+ expect(derivedSymmetricKey).toBeInstanceOf(SymmetricKey)
77
+ const priv = rootPrivateKey.deriveChild(counterpartyPublicKey, '0-testprotocol-12345')
78
+ const pub = counterpartyPublicKey.deriveChild(rootPrivateKey, '0-testprotocol-12345')
79
+ expect(derivedSymmetricKey.toHex()).toEqual(new SymmetricKey(priv.deriveSharedSecret(pub).x?.toArray()).toHex())
80
+ })
81
+
82
+ test('should not derive symmetric key with anyone', () => {
83
+ expect(() => keyDeriver.deriveSymmetricKey(protocolID, keyID, 'anyone')).toThrow()
84
+ })
85
+
86
+ test('should reveal the correct counterparty shared secret', () => {
87
+ const sharedSecret = keyDeriver.revealCounterpartySecret(counterpartyPublicKey)
88
+ expect(sharedSecret).toBeInstanceOf(Array)
89
+ expect(sharedSecret.length).toBeGreaterThan(0)
90
+ expect(sharedSecret).toEqual(rootPrivateKey.deriveSharedSecret(counterpartyPublicKey).encode(true))
91
+ })
92
+
93
+ test('should not reveal shared secret for self', () => {
94
+ expect(() => keyDeriver.revealCounterpartySecret('self')).toThrow()
95
+ expect(() => keyDeriver.revealCounterpartySecret(rootPublicKey)).toThrow()
96
+ })
97
+
98
+ test('should reveal the specific key association', () => {
99
+ const specificSecret = keyDeriver.revealSpecificSecret(counterpartyPublicKey, protocolID, keyID)
100
+ expect(specificSecret).toBeInstanceOf(Array)
101
+ expect(specificSecret.length).toBeGreaterThan(0)
102
+ const sharedSecret = rootPrivateKey.deriveSharedSecret(counterpartyPublicKey)
103
+ const invoiceNumberBin = Utils.toArray((keyDeriver as any).computeInvoiceNumber(protocolID, keyID), 'utf8')
104
+ expect(specificSecret).toEqual(Hash.sha256hmac(sharedSecret.encode(true), invoiceNumberBin))
105
+ })
106
+
107
+ test('should throw an error for invalid protocol names', () => {
108
+ expect(() => (keyDeriver as any).computeInvoiceNumber(protocolID, 'long' + 'a'.repeat(800))).toThrow()
109
+ expect(() => (keyDeriver as any).computeInvoiceNumber(protocolID, '')).toThrow()
110
+ expect(() => (keyDeriver as any).computeInvoiceNumber([-3, 'otherwise valid'], keyID)).toThrow()
111
+ expect(() => (keyDeriver as any).computeInvoiceNumber([2, 'double space'], keyID)).toThrow()
112
+ expect(() => (keyDeriver as any).computeInvoiceNumber([0, ''], keyID)).toThrow()
113
+ expect(() => (keyDeriver as any).computeInvoiceNumber([0, ' a'], keyID)).toThrow()
114
+ expect(() => (keyDeriver as any).computeInvoiceNumber([0, 'long' + 'a'.repeat(400)], keyID)).toThrow()
115
+ expect(() => (keyDeriver as any).computeInvoiceNumber([2, 'redundant protocol protocol'], keyID)).toThrow()
116
+ expect(() => (keyDeriver as any).computeInvoiceNumber([2, 'üñî√é®sål ©0på'], keyID)).toThrow()
117
+ })
118
+ })