@btc-vision/bitcoin 6.5.6 → 7.0.0-alpha.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 (455) hide show
  1. package/HOW_TO_WRITE_GOOD_CODE.md +2436 -0
  2. package/benchmark/psbt-2000-inputs.bench.ts +178 -0
  3. package/benchmark/signing.bench.ts +147 -0
  4. package/browser/address.d.ts +56 -9
  5. package/browser/address.d.ts.map +1 -0
  6. package/browser/bech32utils.d.ts +9 -1
  7. package/browser/bech32utils.d.ts.map +1 -0
  8. package/browser/bip66.d.ts +11 -6
  9. package/browser/bip66.d.ts.map +1 -0
  10. package/browser/block.d.ts +117 -11
  11. package/browser/block.d.ts.map +1 -0
  12. package/browser/branded.d.ts +20 -0
  13. package/browser/branded.d.ts.map +1 -0
  14. package/browser/crypto/crypto.d.ts +1 -0
  15. package/browser/crypto/crypto.d.ts.map +1 -0
  16. package/browser/crypto.d.ts +46 -7
  17. package/browser/crypto.d.ts.map +1 -0
  18. package/browser/ecc/context.d.ts +129 -0
  19. package/browser/ecc/context.d.ts.map +1 -0
  20. package/browser/ecc/index.d.ts +11 -0
  21. package/browser/ecc/index.d.ts.map +1 -0
  22. package/browser/ecc/types.d.ts +128 -0
  23. package/browser/ecc/types.d.ts.map +1 -0
  24. package/browser/ecpair.d.ts +99 -0
  25. package/browser/errors.d.ts +124 -0
  26. package/browser/errors.d.ts.map +1 -0
  27. package/browser/index.d.ts +32 -5
  28. package/browser/index.d.ts.map +1 -0
  29. package/browser/index.js +12482 -101
  30. package/browser/io/BinaryReader.d.ts +276 -0
  31. package/browser/io/BinaryReader.d.ts.map +1 -0
  32. package/browser/io/BinaryWriter.d.ts +391 -0
  33. package/browser/io/BinaryWriter.d.ts.map +1 -0
  34. package/browser/io/MemoryPool.d.ts +220 -0
  35. package/browser/io/MemoryPool.d.ts.map +1 -0
  36. package/browser/io/base64.d.ts +13 -0
  37. package/browser/io/base64.d.ts.map +1 -0
  38. package/browser/io/hex.d.ts +67 -0
  39. package/browser/io/hex.d.ts.map +1 -0
  40. package/browser/io/index.d.ts +17 -0
  41. package/browser/io/index.d.ts.map +1 -0
  42. package/browser/io/utils.d.ts +199 -0
  43. package/browser/io/utils.d.ts.map +1 -0
  44. package/browser/merkle.d.ts +10 -1
  45. package/browser/merkle.d.ts.map +1 -0
  46. package/browser/networks.d.ts +70 -9
  47. package/browser/networks.d.ts.map +1 -0
  48. package/browser/opcodes.d.ts +1 -0
  49. package/browser/opcodes.d.ts.map +1 -0
  50. package/browser/payments/bip341.d.ts +35 -9
  51. package/browser/payments/bip341.d.ts.map +1 -0
  52. package/browser/payments/embed.d.ts +112 -1
  53. package/browser/payments/embed.d.ts.map +1 -0
  54. package/browser/payments/index.d.ts +17 -10
  55. package/browser/payments/index.d.ts.map +1 -0
  56. package/browser/payments/p2ms.d.ts +150 -0
  57. package/browser/payments/p2ms.d.ts.map +1 -0
  58. package/browser/payments/p2op.d.ts +150 -24
  59. package/browser/payments/p2op.d.ts.map +1 -0
  60. package/browser/payments/p2pk.d.ts +154 -1
  61. package/browser/payments/p2pk.d.ts.map +1 -0
  62. package/browser/payments/p2pkh.d.ts +176 -1
  63. package/browser/payments/p2pkh.d.ts.map +1 -0
  64. package/browser/payments/p2sh.d.ts +150 -1
  65. package/browser/payments/p2sh.d.ts.map +1 -0
  66. package/browser/payments/p2tr.d.ts +185 -1
  67. package/browser/payments/p2tr.d.ts.map +1 -0
  68. package/browser/payments/p2wpkh.d.ts +161 -1
  69. package/browser/payments/p2wpkh.d.ts.map +1 -0
  70. package/browser/payments/p2wsh.d.ts +146 -1
  71. package/browser/payments/p2wsh.d.ts.map +1 -0
  72. package/browser/payments/types.d.ts +94 -64
  73. package/browser/payments/types.d.ts.map +1 -0
  74. package/browser/psbt/bip371.d.ts +34 -8
  75. package/browser/psbt/bip371.d.ts.map +1 -0
  76. package/browser/psbt/psbtutils.d.ts +56 -16
  77. package/browser/psbt/psbtutils.d.ts.map +1 -0
  78. package/browser/psbt/types.d.ts +245 -0
  79. package/browser/psbt/types.d.ts.map +1 -0
  80. package/browser/psbt/utils.d.ts +64 -0
  81. package/browser/psbt/utils.d.ts.map +1 -0
  82. package/browser/psbt/validation.d.ts +84 -0
  83. package/browser/psbt/validation.d.ts.map +1 -0
  84. package/browser/psbt.d.ts +82 -118
  85. package/browser/psbt.d.ts.map +1 -0
  86. package/browser/pubkey.d.ts +27 -6
  87. package/browser/pubkey.d.ts.map +1 -0
  88. package/browser/push_data.d.ts +24 -2
  89. package/browser/push_data.d.ts.map +1 -0
  90. package/browser/script.d.ts +33 -8
  91. package/browser/script.d.ts.map +1 -0
  92. package/browser/script_number.d.ts +17 -0
  93. package/browser/script_number.d.ts.map +1 -0
  94. package/browser/script_signature.d.ts +23 -5
  95. package/browser/script_signature.d.ts.map +1 -0
  96. package/browser/transaction.d.ts +160 -18
  97. package/browser/transaction.d.ts.map +1 -0
  98. package/browser/types.d.ts +36 -38
  99. package/browser/types.d.ts.map +1 -0
  100. package/browser/workers/WorkerSigningPool.d.ts +143 -0
  101. package/browser/workers/WorkerSigningPool.d.ts.map +1 -0
  102. package/browser/workers/WorkerSigningPool.node.d.ts +116 -0
  103. package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -0
  104. package/browser/workers/ecc-bundle.d.ts +25 -0
  105. package/browser/workers/ecc-bundle.d.ts.map +1 -0
  106. package/browser/workers/index.d.ts +91 -0
  107. package/browser/workers/index.d.ts.map +1 -0
  108. package/browser/workers/psbt-parallel.d.ts +88 -0
  109. package/browser/workers/psbt-parallel.d.ts.map +1 -0
  110. package/browser/workers/signing-worker.d.ts +37 -0
  111. package/browser/workers/signing-worker.d.ts.map +1 -0
  112. package/browser/workers/types.d.ts +365 -0
  113. package/browser/workers/types.d.ts.map +1 -0
  114. package/build/address.d.ts +57 -10
  115. package/build/address.d.ts.map +1 -0
  116. package/build/address.js +80 -24
  117. package/build/address.js.map +1 -0
  118. package/build/bech32utils.d.ts +9 -1
  119. package/build/bech32utils.d.ts.map +1 -0
  120. package/build/bech32utils.js +10 -2
  121. package/build/bech32utils.js.map +1 -0
  122. package/build/bip66.d.ts +11 -6
  123. package/build/bip66.d.ts.map +1 -0
  124. package/build/bip66.js +32 -3
  125. package/build/bip66.js.map +1 -0
  126. package/build/block.d.ts +117 -11
  127. package/build/block.d.ts.map +1 -0
  128. package/build/block.js +204 -72
  129. package/build/block.js.map +1 -0
  130. package/build/branded.d.ts +20 -0
  131. package/build/branded.d.ts.map +1 -0
  132. package/build/branded.js +7 -0
  133. package/build/branded.js.map +1 -0
  134. package/build/crypto/crypto.d.ts +1 -0
  135. package/build/crypto/crypto.d.ts.map +1 -0
  136. package/build/crypto/crypto.js +1 -0
  137. package/build/crypto/crypto.js.map +1 -0
  138. package/build/crypto.d.ts +46 -7
  139. package/build/crypto.d.ts.map +1 -0
  140. package/build/crypto.js +65 -20
  141. package/build/crypto.js.map +1 -0
  142. package/build/ecc/context.d.ts +135 -0
  143. package/build/ecc/context.d.ts.map +1 -0
  144. package/build/ecc/context.js +232 -0
  145. package/build/ecc/context.js.map +1 -0
  146. package/build/ecc/index.d.ts +11 -0
  147. package/build/ecc/index.d.ts.map +1 -0
  148. package/build/ecc/index.js +11 -0
  149. package/build/ecc/index.js.map +1 -0
  150. package/build/ecc/types.d.ts +134 -0
  151. package/build/ecc/types.d.ts.map +1 -0
  152. package/build/ecc/types.js +8 -0
  153. package/build/ecc/types.js.map +1 -0
  154. package/build/errors.d.ts +124 -0
  155. package/build/errors.d.ts.map +1 -0
  156. package/build/errors.js +155 -0
  157. package/build/errors.js.map +1 -0
  158. package/build/index.d.ts +32 -5
  159. package/build/index.d.ts.map +1 -0
  160. package/build/index.js +26 -3
  161. package/build/index.js.map +1 -0
  162. package/build/io/BinaryReader.d.ts +276 -0
  163. package/build/io/BinaryReader.d.ts.map +1 -0
  164. package/build/io/BinaryReader.js +425 -0
  165. package/build/io/BinaryReader.js.map +1 -0
  166. package/build/io/BinaryWriter.d.ts +391 -0
  167. package/build/io/BinaryWriter.d.ts.map +1 -0
  168. package/build/io/BinaryWriter.js +611 -0
  169. package/build/io/BinaryWriter.js.map +1 -0
  170. package/build/io/MemoryPool.d.ts +220 -0
  171. package/build/io/MemoryPool.d.ts.map +1 -0
  172. package/build/io/MemoryPool.js +309 -0
  173. package/build/io/MemoryPool.js.map +1 -0
  174. package/build/io/base64.d.ts +13 -0
  175. package/build/io/base64.d.ts.map +1 -0
  176. package/build/io/base64.js +20 -0
  177. package/build/io/base64.js.map +1 -0
  178. package/build/io/hex.d.ts +67 -0
  179. package/build/io/hex.d.ts.map +1 -0
  180. package/build/io/hex.js +138 -0
  181. package/build/io/hex.js.map +1 -0
  182. package/build/io/index.d.ts +17 -0
  183. package/build/io/index.d.ts.map +1 -0
  184. package/build/io/index.js +23 -0
  185. package/build/io/index.js.map +1 -0
  186. package/build/io/utils.d.ts +199 -0
  187. package/build/io/utils.d.ts.map +1 -0
  188. package/build/io/utils.js +271 -0
  189. package/build/io/utils.js.map +1 -0
  190. package/build/merkle.d.ts +10 -1
  191. package/build/merkle.d.ts.map +1 -0
  192. package/build/merkle.js +12 -1
  193. package/build/merkle.js.map +1 -0
  194. package/build/networks.d.ts +70 -9
  195. package/build/networks.d.ts.map +1 -0
  196. package/build/networks.js +90 -4
  197. package/build/networks.js.map +1 -0
  198. package/build/opcodes.d.ts +1 -0
  199. package/build/opcodes.d.ts.map +1 -0
  200. package/build/opcodes.js +1 -0
  201. package/build/opcodes.js.map +1 -0
  202. package/build/payments/bip341.d.ts +36 -9
  203. package/build/payments/bip341.d.ts.map +1 -0
  204. package/build/payments/bip341.js +35 -15
  205. package/build/payments/bip341.js.map +1 -0
  206. package/build/payments/embed.d.ts +120 -1
  207. package/build/payments/embed.d.ts.map +1 -0
  208. package/build/payments/embed.js +215 -34
  209. package/build/payments/embed.js.map +1 -0
  210. package/build/payments/index.d.ts +17 -10
  211. package/build/payments/index.d.ts.map +1 -0
  212. package/build/payments/index.js +20 -10
  213. package/build/payments/index.js.map +1 -0
  214. package/build/payments/p2ms.d.ts +159 -1
  215. package/build/payments/p2ms.d.ts.map +1 -0
  216. package/build/payments/p2ms.js +427 -108
  217. package/build/payments/p2ms.js.map +1 -0
  218. package/build/payments/p2op.d.ts +158 -24
  219. package/build/payments/p2op.d.ts.map +1 -0
  220. package/build/payments/p2op.js +379 -93
  221. package/build/payments/p2op.js.map +1 -0
  222. package/build/payments/p2pk.d.ts +162 -1
  223. package/build/payments/p2pk.d.ts.map +1 -0
  224. package/build/payments/p2pk.js +327 -58
  225. package/build/payments/p2pk.js.map +1 -0
  226. package/build/payments/p2pkh.d.ts +185 -1
  227. package/build/payments/p2pkh.d.ts.map +1 -0
  228. package/build/payments/p2pkh.js +467 -114
  229. package/build/payments/p2pkh.js.map +1 -0
  230. package/build/payments/p2sh.d.ts +159 -1
  231. package/build/payments/p2sh.d.ts.map +1 -0
  232. package/build/payments/p2sh.js +500 -152
  233. package/build/payments/p2sh.js.map +1 -0
  234. package/build/payments/p2tr.d.ts +193 -1
  235. package/build/payments/p2tr.d.ts.map +1 -0
  236. package/build/payments/p2tr.js +592 -174
  237. package/build/payments/p2tr.js.map +1 -0
  238. package/build/payments/p2wpkh.d.ts +170 -1
  239. package/build/payments/p2wpkh.d.ts.map +1 -0
  240. package/build/payments/p2wpkh.js +429 -104
  241. package/build/payments/p2wpkh.js.map +1 -0
  242. package/build/payments/p2wsh.d.ts +155 -1
  243. package/build/payments/p2wsh.d.ts.map +1 -0
  244. package/build/payments/p2wsh.js +466 -144
  245. package/build/payments/p2wsh.js.map +1 -0
  246. package/build/payments/types.d.ts +98 -64
  247. package/build/payments/types.d.ts.map +1 -0
  248. package/build/payments/types.js +17 -13
  249. package/build/payments/types.js.map +1 -0
  250. package/build/psbt/bip371.d.ts +35 -9
  251. package/build/psbt/bip371.d.ts.map +1 -0
  252. package/build/psbt/bip371.js +113 -28
  253. package/build/psbt/bip371.js.map +1 -0
  254. package/build/psbt/psbtutils.d.ts +56 -16
  255. package/build/psbt/psbtutils.d.ts.map +1 -0
  256. package/build/psbt/psbtutils.js +71 -16
  257. package/build/psbt/psbtutils.js.map +1 -0
  258. package/build/psbt/types.d.ts +249 -0
  259. package/build/psbt/types.d.ts.map +1 -0
  260. package/build/psbt/types.js +6 -0
  261. package/build/psbt/types.js.map +1 -0
  262. package/build/psbt/utils.d.ts +68 -0
  263. package/build/psbt/utils.d.ts.map +1 -0
  264. package/build/psbt/utils.js +171 -0
  265. package/build/psbt/utils.js.map +1 -0
  266. package/build/psbt/validation.d.ts +88 -0
  267. package/build/psbt/validation.d.ts.map +1 -0
  268. package/build/psbt/validation.js +149 -0
  269. package/build/psbt/validation.js.map +1 -0
  270. package/build/psbt.d.ts +84 -120
  271. package/build/psbt.d.ts.map +1 -0
  272. package/build/psbt.js +411 -412
  273. package/build/psbt.js.map +1 -0
  274. package/build/pubkey.d.ts +27 -6
  275. package/build/pubkey.d.ts.map +1 -0
  276. package/build/pubkey.js +36 -12
  277. package/build/pubkey.js.map +1 -0
  278. package/build/push_data.d.ts +24 -2
  279. package/build/push_data.d.ts.map +1 -0
  280. package/build/push_data.js +44 -12
  281. package/build/push_data.js.map +1 -0
  282. package/build/script.d.ts +33 -8
  283. package/build/script.d.ts.map +1 -0
  284. package/build/script.js +100 -36
  285. package/build/script.js.map +1 -0
  286. package/build/script_number.d.ts +17 -0
  287. package/build/script_number.d.ts.map +1 -0
  288. package/build/script_number.js +19 -0
  289. package/build/script_number.js.map +1 -0
  290. package/build/script_signature.d.ts +23 -5
  291. package/build/script_signature.d.ts.map +1 -0
  292. package/build/script_signature.js +48 -15
  293. package/build/script_signature.js.map +1 -0
  294. package/build/transaction.d.ts +160 -18
  295. package/build/transaction.d.ts.map +1 -0
  296. package/build/transaction.js +443 -176
  297. package/build/transaction.js.map +1 -0
  298. package/build/tsconfig.build.tsbuildinfo +1 -0
  299. package/build/types.d.ts +36 -38
  300. package/build/types.d.ts.map +1 -0
  301. package/build/types.js +175 -57
  302. package/build/types.js.map +1 -0
  303. package/build/workers/WorkerSigningPool.d.ts +174 -0
  304. package/build/workers/WorkerSigningPool.d.ts.map +1 -0
  305. package/build/workers/WorkerSigningPool.js +553 -0
  306. package/build/workers/WorkerSigningPool.js.map +1 -0
  307. package/build/workers/WorkerSigningPool.node.d.ts +124 -0
  308. package/build/workers/WorkerSigningPool.node.d.ts.map +1 -0
  309. package/build/workers/WorkerSigningPool.node.js +753 -0
  310. package/build/workers/WorkerSigningPool.node.js.map +1 -0
  311. package/build/workers/ecc-bundle.d.ts +25 -0
  312. package/build/workers/ecc-bundle.d.ts.map +1 -0
  313. package/build/workers/ecc-bundle.js +25 -0
  314. package/build/workers/ecc-bundle.js.map +1 -0
  315. package/build/workers/index.d.ts +91 -0
  316. package/build/workers/index.d.ts.map +1 -0
  317. package/build/workers/index.js +114 -0
  318. package/build/workers/index.js.map +1 -0
  319. package/build/workers/psbt-parallel.d.ts +117 -0
  320. package/build/workers/psbt-parallel.d.ts.map +1 -0
  321. package/build/workers/psbt-parallel.js +233 -0
  322. package/build/workers/psbt-parallel.js.map +1 -0
  323. package/build/workers/signing-worker.d.ts +37 -0
  324. package/build/workers/signing-worker.d.ts.map +1 -0
  325. package/build/workers/signing-worker.js +350 -0
  326. package/build/workers/signing-worker.js.map +1 -0
  327. package/build/workers/types.d.ts +365 -0
  328. package/build/workers/types.d.ts.map +1 -0
  329. package/build/workers/types.js +60 -0
  330. package/build/workers/types.js.map +1 -0
  331. package/package.json +66 -8
  332. package/scripts/bundle-ecc.ts +111 -0
  333. package/src/address.ts +81 -44
  334. package/src/bech32utils.ts +3 -3
  335. package/src/bip66.ts +34 -24
  336. package/src/block.ts +196 -84
  337. package/src/branded.ts +18 -0
  338. package/src/crypto.ts +64 -26
  339. package/src/ecc/context.ts +277 -0
  340. package/src/ecc/index.ts +14 -0
  341. package/src/ecc/types.ts +154 -0
  342. package/src/ecpair.d.ts +99 -0
  343. package/src/errors.ts +163 -0
  344. package/src/index.ts +113 -9
  345. package/src/io/BinaryReader.ts +461 -0
  346. package/src/io/BinaryWriter.ts +696 -0
  347. package/src/io/MemoryPool.ts +343 -0
  348. package/src/io/base64.ts +20 -0
  349. package/src/io/hex.ts +155 -0
  350. package/src/io/index.ts +41 -0
  351. package/src/io/utils.ts +283 -0
  352. package/src/merkle.ts +14 -9
  353. package/src/networks.ts +9 -9
  354. package/src/payments/bip341.ts +34 -33
  355. package/src/payments/embed.ts +244 -41
  356. package/src/payments/index.ts +12 -10
  357. package/src/payments/p2ms.ts +490 -118
  358. package/src/payments/p2op.ts +431 -133
  359. package/src/payments/p2pk.ts +370 -72
  360. package/src/payments/p2pkh.ts +524 -130
  361. package/src/payments/p2sh.ts +572 -172
  362. package/src/payments/p2tr.ts +686 -194
  363. package/src/payments/p2wpkh.ts +484 -107
  364. package/src/payments/p2wsh.ts +526 -164
  365. package/src/payments/types.ts +80 -66
  366. package/src/psbt/bip371.ts +68 -51
  367. package/src/psbt/psbtutils.ts +39 -40
  368. package/src/psbt/types.ts +331 -0
  369. package/src/psbt/utils.ts +188 -0
  370. package/src/psbt/validation.ts +192 -0
  371. package/src/psbt.ts +566 -809
  372. package/src/pubkey.ts +22 -23
  373. package/src/push_data.ts +18 -16
  374. package/src/script.ts +82 -64
  375. package/src/script_number.ts +6 -6
  376. package/src/script_signature.ts +33 -36
  377. package/src/transaction.ts +458 -238
  378. package/src/types.ts +231 -100
  379. package/src/workers/WorkerSigningPool.node.ts +887 -0
  380. package/src/workers/WorkerSigningPool.ts +670 -0
  381. package/src/workers/ecc-bundle.ts +26 -0
  382. package/src/workers/index.ts +165 -0
  383. package/src/workers/psbt-parallel.ts +332 -0
  384. package/src/workers/signing-worker.ts +353 -0
  385. package/src/workers/types.ts +413 -0
  386. package/test/address.spec.ts +9 -6
  387. package/test/bitcoin.core.spec.ts +16 -17
  388. package/test/block.spec.ts +8 -7
  389. package/test/bufferutils.spec.ts +228 -214
  390. package/test/crypto.spec.ts +19 -11
  391. package/test/fixtures/p2pk.json +0 -8
  392. package/test/fixtures/p2pkh.json +1 -1
  393. package/test/fixtures/p2sh.json +1 -1
  394. package/test/fixtures/script.json +1 -1
  395. package/test/fixtures/transaction.json +2 -2
  396. package/test/integration/_regtest.ts +25 -0
  397. package/test/integration/addresses.spec.ts +4 -3
  398. package/test/integration/bip32.spec.ts +2 -1
  399. package/test/integration/blocks.spec.ts +1 -1
  400. package/test/integration/cltv.spec.ts +18 -16
  401. package/test/integration/csv.spec.ts +37 -64
  402. package/test/integration/payments.spec.ts +5 -3
  403. package/test/integration/taproot.spec.ts +76 -83
  404. package/test/integration/transactions.spec.ts +38 -35
  405. package/test/payments.spec.ts +35 -13
  406. package/test/payments.utils.ts +17 -16
  407. package/test/psbt.spec.ts +111 -100
  408. package/test/script.spec.ts +11 -10
  409. package/test/script_signature.spec.ts +9 -11
  410. package/test/taproot-cache.spec.ts +694 -0
  411. package/test/transaction.spec.ts +32 -40
  412. package/test/types.spec.ts +74 -29
  413. package/test/workers-pool.spec.ts +963 -0
  414. package/test/workers-signing.spec.ts +635 -0
  415. package/test/workers.spec.ts +1390 -0
  416. package/tsconfig.base.json +34 -18
  417. package/tsconfig.browser.json +15 -0
  418. package/tsconfig.build.json +5 -0
  419. package/tsconfig.json +5 -14
  420. package/vite.config.browser.ts +3 -42
  421. package/vitest.config.integration.ts +2 -0
  422. package/browser/bufferutils.d.ts +0 -34
  423. package/browser/chunks/crypto-BhCpKpek.js +0 -2033
  424. package/browser/chunks/payments-B1wlSccx.js +0 -1089
  425. package/browser/chunks/psbt-BCNk7JUx.js +0 -4055
  426. package/browser/chunks/script-DyPItFEl.js +0 -318
  427. package/browser/chunks/transaction-C_UbhMGn.js +0 -432
  428. package/browser/chunks/utils-DNZi-T5W.js +0 -761
  429. package/browser/ecc_lib.d.ts +0 -3
  430. package/browser/hooks/AdvancedSignatureManager.d.ts +0 -16
  431. package/browser/hooks/HookedSigner.d.ts +0 -4
  432. package/browser/hooks/SignatureManager.d.ts +0 -13
  433. package/browser/payments/lazy.d.ts +0 -2
  434. package/browser/typeforce.d.ts +0 -38
  435. package/build/bufferutils.d.ts +0 -34
  436. package/build/bufferutils.js +0 -141
  437. package/build/ecc_lib.d.ts +0 -3
  438. package/build/ecc_lib.js +0 -61
  439. package/build/hooks/AdvancedSignatureManager.d.ts +0 -16
  440. package/build/hooks/AdvancedSignatureManager.js +0 -52
  441. package/build/hooks/HookedSigner.d.ts +0 -4
  442. package/build/hooks/HookedSigner.js +0 -64
  443. package/build/hooks/SignatureManager.d.ts +0 -13
  444. package/build/hooks/SignatureManager.js +0 -45
  445. package/build/payments/lazy.d.ts +0 -2
  446. package/build/payments/lazy.js +0 -28
  447. package/build/tsconfig.tsbuildinfo +0 -1
  448. package/src/bufferutils.ts +0 -188
  449. package/src/ecc_lib.ts +0 -94
  450. package/src/hooks/AdvancedSignatureManager.ts +0 -104
  451. package/src/hooks/HookedSigner.ts +0 -108
  452. package/src/hooks/SignatureManager.ts +0 -84
  453. package/src/payments/lazy.ts +0 -28
  454. package/src/typeforce.d.ts +0 -38
  455. package/tsconfig.webpack.json +0 -18
@@ -0,0 +1,1390 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from 'vitest';
2
+ import {
3
+ SignatureType,
4
+ WorkerState,
5
+ isSigningError,
6
+ isSigningResult,
7
+ isWorkerReady,
8
+ type WorkerResponse,
9
+ type SigningResultMessage,
10
+ type SigningErrorMessage,
11
+ type WorkerReadyMessage,
12
+ type SigningTask,
13
+ type ParallelSignerKeyPair,
14
+ } from '../src/workers/types.js';
15
+ import { generateWorkerCode } from '../src/workers/signing-worker.js';
16
+
17
+ describe('Worker Types', () => {
18
+ describe('SignatureType', () => {
19
+ it('should have ECDSA = 0', () => {
20
+ expect(SignatureType.ECDSA).toBe(0);
21
+ });
22
+
23
+ it('should have Schnorr = 1', () => {
24
+ expect(SignatureType.Schnorr).toBe(1);
25
+ });
26
+
27
+ it('should be const (readonly)', () => {
28
+ // TypeScript ensures this at compile time, but verify runtime values exist
29
+ expect(Object.isFrozen(SignatureType)).toBe(false); // as const doesn't freeze
30
+ expect(SignatureType.ECDSA).toBeDefined();
31
+ expect(SignatureType.Schnorr).toBeDefined();
32
+ });
33
+ });
34
+
35
+ describe('WorkerState', () => {
36
+ it('should have correct state values', () => {
37
+ expect(WorkerState.Initializing).toBe(0);
38
+ expect(WorkerState.Idle).toBe(1);
39
+ expect(WorkerState.Busy).toBe(2);
40
+ expect(WorkerState.ShuttingDown).toBe(3);
41
+ expect(WorkerState.Terminated).toBe(4);
42
+ });
43
+
44
+ it('should have unique values', () => {
45
+ const values = Object.values(WorkerState);
46
+ const uniqueValues = new Set(values);
47
+ expect(uniqueValues.size).toBe(values.length);
48
+ });
49
+ });
50
+
51
+ describe('Type Guards', () => {
52
+ describe('isSigningError', () => {
53
+ it('should return true for error responses', () => {
54
+ const errorResponse: SigningErrorMessage = {
55
+ type: 'error',
56
+ taskId: 'test-1',
57
+ error: 'Test error',
58
+ inputIndex: 0,
59
+ };
60
+ expect(isSigningError(errorResponse)).toBe(true);
61
+ });
62
+
63
+ it('should return false for result responses', () => {
64
+ const resultResponse: SigningResultMessage = {
65
+ type: 'result',
66
+ taskId: 'test-1',
67
+ signature: new Uint8Array(64),
68
+ inputIndex: 0,
69
+ publicKey: new Uint8Array(33),
70
+ signatureType: SignatureType.ECDSA,
71
+ };
72
+ expect(isSigningError(resultResponse)).toBe(false);
73
+ });
74
+
75
+ it('should return false for ready responses', () => {
76
+ const readyResponse: WorkerReadyMessage = {
77
+ type: 'ready',
78
+ };
79
+ expect(isSigningError(readyResponse)).toBe(false);
80
+ });
81
+ });
82
+
83
+ describe('isSigningResult', () => {
84
+ it('should return true for result responses', () => {
85
+ const resultResponse: SigningResultMessage = {
86
+ type: 'result',
87
+ taskId: 'test-1',
88
+ signature: new Uint8Array(64),
89
+ inputIndex: 0,
90
+ publicKey: new Uint8Array(33),
91
+ signatureType: SignatureType.Schnorr,
92
+ };
93
+ expect(isSigningResult(resultResponse)).toBe(true);
94
+ });
95
+
96
+ it('should return false for error responses', () => {
97
+ const errorResponse: SigningErrorMessage = {
98
+ type: 'error',
99
+ taskId: 'test-1',
100
+ error: 'Test error',
101
+ inputIndex: 0,
102
+ };
103
+ expect(isSigningResult(errorResponse)).toBe(false);
104
+ });
105
+
106
+ it('should return false for ready responses', () => {
107
+ const readyResponse: WorkerReadyMessage = {
108
+ type: 'ready',
109
+ };
110
+ expect(isSigningResult(readyResponse)).toBe(false);
111
+ });
112
+ });
113
+
114
+ describe('isWorkerReady', () => {
115
+ it('should return true for ready responses', () => {
116
+ const readyResponse: WorkerReadyMessage = {
117
+ type: 'ready',
118
+ };
119
+ expect(isWorkerReady(readyResponse)).toBe(true);
120
+ });
121
+
122
+ it('should return false for result responses', () => {
123
+ const resultResponse: SigningResultMessage = {
124
+ type: 'result',
125
+ taskId: 'test-1',
126
+ signature: new Uint8Array(64),
127
+ inputIndex: 0,
128
+ publicKey: new Uint8Array(33),
129
+ signatureType: SignatureType.ECDSA,
130
+ };
131
+ expect(isWorkerReady(resultResponse)).toBe(false);
132
+ });
133
+
134
+ it('should return false for error responses', () => {
135
+ const errorResponse: SigningErrorMessage = {
136
+ type: 'error',
137
+ taskId: 'test-1',
138
+ error: 'Test error',
139
+ inputIndex: 0,
140
+ };
141
+ expect(isWorkerReady(errorResponse)).toBe(false);
142
+ });
143
+ });
144
+ });
145
+ });
146
+
147
+ describe('Worker Code Generation', () => {
148
+ describe('generateWorkerCode', () => {
149
+ let workerCode: string;
150
+
151
+ beforeEach(() => {
152
+ workerCode = generateWorkerCode();
153
+ });
154
+
155
+ it('should generate non-empty code', () => {
156
+ expect(workerCode).toBeTruthy();
157
+ expect(workerCode.length).toBeGreaterThan(100);
158
+ });
159
+
160
+ it('should contain secureZero function', () => {
161
+ expect(workerCode).toContain('secureZero');
162
+ expect(workerCode).toContain('arr.fill(0)');
163
+ });
164
+
165
+ it('should contain message handler', () => {
166
+ expect(workerCode).toContain('self.onmessage');
167
+ });
168
+
169
+ it('should handle init message type', () => {
170
+ expect(workerCode).toContain("case 'init':");
171
+ });
172
+
173
+ it('should handle sign message type', () => {
174
+ expect(workerCode).toContain("case 'sign':");
175
+ });
176
+
177
+ it('should handle shutdown message type', () => {
178
+ expect(workerCode).toContain("case 'shutdown':");
179
+ });
180
+
181
+ it('should validate hash length (32 bytes)', () => {
182
+ expect(workerCode).toContain('hash.length !== 32');
183
+ });
184
+
185
+ it('should validate private key length (32 bytes)', () => {
186
+ expect(workerCode).toContain('privateKey.length !== 32');
187
+ });
188
+
189
+ it('should zero private key after signing', () => {
190
+ // Check that secureZero is called on privateKey
191
+ expect(workerCode).toContain('secureZero(privateKey)');
192
+ });
193
+
194
+ it('should handle Schnorr signatures (signatureType === 1)', () => {
195
+ expect(workerCode).toContain('signatureType === 1');
196
+ expect(workerCode).toContain('signSchnorr');
197
+ });
198
+
199
+ it('should handle ECDSA signatures', () => {
200
+ expect(workerCode).toContain('eccLib.sign');
201
+ });
202
+
203
+ it('should post ready message after init', () => {
204
+ expect(workerCode).toContain("type: 'ready'");
205
+ });
206
+
207
+ it('should post shutdown-ack message on shutdown', () => {
208
+ expect(workerCode).toContain("type: 'shutdown-ack'");
209
+ });
210
+
211
+ it('should call self.close() on shutdown', () => {
212
+ expect(workerCode).toContain('self.close()');
213
+ });
214
+
215
+ it('should include error handling', () => {
216
+ expect(workerCode).toContain('catch');
217
+ expect(workerCode).toContain("type: 'error'");
218
+ });
219
+
220
+ it('should support lowR for ECDSA', () => {
221
+ expect(workerCode).toContain('lowR');
222
+ });
223
+
224
+ it('should support leafHash for Taproot', () => {
225
+ expect(workerCode).toContain('leafHash');
226
+ });
227
+ });
228
+ });
229
+
230
+ describe('SigningTask Interface', () => {
231
+ it('should accept valid ECDSA task', () => {
232
+ const task: SigningTask = {
233
+ taskId: 'ecdsa-task-1',
234
+ inputIndex: 0,
235
+ hash: new Uint8Array(32),
236
+ signatureType: SignatureType.ECDSA,
237
+ sighashType: 0x01, // SIGHASH_ALL
238
+ };
239
+
240
+ expect(task.taskId).toBe('ecdsa-task-1');
241
+ expect(task.inputIndex).toBe(0);
242
+ expect(task.hash.length).toBe(32);
243
+ expect(task.signatureType).toBe(SignatureType.ECDSA);
244
+ expect(task.sighashType).toBe(0x01);
245
+ });
246
+
247
+ it('should accept valid Schnorr task', () => {
248
+ const task: SigningTask = {
249
+ taskId: 'schnorr-task-1',
250
+ inputIndex: 1,
251
+ hash: new Uint8Array(32).fill(0xab),
252
+ signatureType: SignatureType.Schnorr,
253
+ sighashType: 0x00, // SIGHASH_DEFAULT
254
+ };
255
+
256
+ expect(task.signatureType).toBe(SignatureType.Schnorr);
257
+ expect(task.sighashType).toBe(0x00);
258
+ });
259
+
260
+ it('should accept task with lowR option', () => {
261
+ const task: SigningTask = {
262
+ taskId: 'ecdsa-lowr-1',
263
+ inputIndex: 0,
264
+ hash: new Uint8Array(32),
265
+ signatureType: SignatureType.ECDSA,
266
+ sighashType: 0x01,
267
+ lowR: true,
268
+ };
269
+
270
+ expect(task.lowR).toBe(true);
271
+ });
272
+
273
+ it('should accept task with leafHash for Taproot script-path', () => {
274
+ const leafHash = new Uint8Array(32).fill(0xcd);
275
+ const task: SigningTask = {
276
+ taskId: 'taproot-script-1',
277
+ inputIndex: 2,
278
+ hash: new Uint8Array(32),
279
+ signatureType: SignatureType.Schnorr,
280
+ sighashType: 0x00,
281
+ leafHash,
282
+ };
283
+
284
+ expect(task.leafHash).toBeDefined();
285
+ expect(task.leafHash?.length).toBe(32);
286
+ });
287
+ });
288
+
289
+ describe('ParallelSignerKeyPair Interface', () => {
290
+ it('should accept valid key pair with getPrivateKey', () => {
291
+ const privateKey = new Uint8Array(32).fill(0x42);
292
+ const publicKey = new Uint8Array(33).fill(0x02);
293
+
294
+ const keyPair: ParallelSignerKeyPair = {
295
+ publicKey,
296
+ getPrivateKey: () => privateKey,
297
+ };
298
+
299
+ expect(keyPair.publicKey.length).toBe(33);
300
+ expect(keyPair.getPrivateKey().length).toBe(32);
301
+ });
302
+
303
+ it('should accept key pair with optional sign method', () => {
304
+ const privateKey = new Uint8Array(32).fill(0x42);
305
+ const publicKey = new Uint8Array(33).fill(0x02);
306
+
307
+ const keyPair: ParallelSignerKeyPair = {
308
+ publicKey,
309
+ getPrivateKey: () => privateKey,
310
+ sign: (hash: Uint8Array, _lowR?: boolean) => new Uint8Array(64), // DER signature
311
+ };
312
+
313
+ expect(keyPair.sign).toBeDefined();
314
+ expect(keyPair.sign!(new Uint8Array(32)).length).toBe(64);
315
+ });
316
+
317
+ it('should accept key pair with optional signSchnorr method', () => {
318
+ const privateKey = new Uint8Array(32).fill(0x42);
319
+ const publicKey = new Uint8Array(33).fill(0x02);
320
+
321
+ const keyPair: ParallelSignerKeyPair = {
322
+ publicKey,
323
+ getPrivateKey: () => privateKey,
324
+ signSchnorr: (hash: Uint8Array) => new Uint8Array(64), // Schnorr signature
325
+ };
326
+
327
+ expect(keyPair.signSchnorr).toBeDefined();
328
+ expect(keyPair.signSchnorr!(new Uint8Array(32)).length).toBe(64);
329
+ });
330
+ });
331
+
332
+ describe('SigningResultMessage', () => {
333
+ it('should represent ECDSA result correctly', () => {
334
+ const result: SigningResultMessage = {
335
+ type: 'result',
336
+ taskId: 'test-ecdsa',
337
+ signature: new Uint8Array(71), // DER-encoded ECDSA
338
+ inputIndex: 0,
339
+ publicKey: new Uint8Array(33),
340
+ signatureType: SignatureType.ECDSA,
341
+ };
342
+
343
+ expect(result.type).toBe('result');
344
+ expect(result.signatureType).toBe(SignatureType.ECDSA);
345
+ expect(result.leafHash).toBeUndefined();
346
+ });
347
+
348
+ it('should represent Schnorr key-path result correctly', () => {
349
+ const result: SigningResultMessage = {
350
+ type: 'result',
351
+ taskId: 'test-schnorr-key',
352
+ signature: new Uint8Array(64), // Raw Schnorr
353
+ inputIndex: 1,
354
+ publicKey: new Uint8Array(32), // x-only pubkey for Taproot
355
+ signatureType: SignatureType.Schnorr,
356
+ };
357
+
358
+ expect(result.signatureType).toBe(SignatureType.Schnorr);
359
+ expect(result.signature.length).toBe(64);
360
+ expect(result.leafHash).toBeUndefined();
361
+ });
362
+
363
+ it('should represent Schnorr script-path result correctly', () => {
364
+ const leafHash = new Uint8Array(32).fill(0xef);
365
+ const result: SigningResultMessage = {
366
+ type: 'result',
367
+ taskId: 'test-schnorr-script',
368
+ signature: new Uint8Array(64),
369
+ inputIndex: 2,
370
+ publicKey: new Uint8Array(32),
371
+ signatureType: SignatureType.Schnorr,
372
+ leafHash,
373
+ };
374
+
375
+ expect(result.leafHash).toBeDefined();
376
+ expect(result.leafHash?.length).toBe(32);
377
+ });
378
+ });
379
+
380
+ describe('SigningErrorMessage', () => {
381
+ it('should represent error correctly', () => {
382
+ const error: SigningErrorMessage = {
383
+ type: 'error',
384
+ taskId: 'failed-task',
385
+ error: 'Invalid private key',
386
+ inputIndex: 3,
387
+ };
388
+
389
+ expect(error.type).toBe('error');
390
+ expect(error.error).toBe('Invalid private key');
391
+ expect(error.inputIndex).toBe(3);
392
+ });
393
+
394
+ it('should handle various error messages', () => {
395
+ const errors = [
396
+ 'Invalid hash: must be 32 bytes',
397
+ 'Invalid private key: must be 32 bytes',
398
+ 'ECC library not initialized',
399
+ 'Signing failed',
400
+ 'ECC library does not support Schnorr signatures',
401
+ ];
402
+
403
+ for (const errorMsg of errors) {
404
+ const error: SigningErrorMessage = {
405
+ type: 'error',
406
+ taskId: `error-${errorMsg.slice(0, 10)}`,
407
+ error: errorMsg,
408
+ inputIndex: 0,
409
+ };
410
+ expect(error.error).toBe(errorMsg);
411
+ }
412
+ });
413
+ });
414
+
415
+ describe('Edge Cases', () => {
416
+ describe('Hash Validation', () => {
417
+ it('should reject hash shorter than 32 bytes', () => {
418
+ const task: SigningTask = {
419
+ taskId: 'short-hash',
420
+ inputIndex: 0,
421
+ hash: new Uint8Array(31), // Too short
422
+ signatureType: SignatureType.ECDSA,
423
+ sighashType: 0x01,
424
+ };
425
+
426
+ // The worker would reject this, but we can verify the task structure
427
+ expect(task.hash.length).toBe(31);
428
+ expect(task.hash.length).not.toBe(32);
429
+ });
430
+
431
+ it('should reject hash longer than 32 bytes', () => {
432
+ const task: SigningTask = {
433
+ taskId: 'long-hash',
434
+ inputIndex: 0,
435
+ hash: new Uint8Array(33), // Too long
436
+ signatureType: SignatureType.ECDSA,
437
+ sighashType: 0x01,
438
+ };
439
+
440
+ expect(task.hash.length).toBe(33);
441
+ expect(task.hash.length).not.toBe(32);
442
+ });
443
+
444
+ it('should accept exactly 32-byte hash', () => {
445
+ const task: SigningTask = {
446
+ taskId: 'valid-hash',
447
+ inputIndex: 0,
448
+ hash: new Uint8Array(32),
449
+ signatureType: SignatureType.ECDSA,
450
+ sighashType: 0x01,
451
+ };
452
+
453
+ expect(task.hash.length).toBe(32);
454
+ });
455
+ });
456
+
457
+ describe('Input Index Bounds', () => {
458
+ it('should handle input index 0', () => {
459
+ const task: SigningTask = {
460
+ taskId: 'index-0',
461
+ inputIndex: 0,
462
+ hash: new Uint8Array(32),
463
+ signatureType: SignatureType.ECDSA,
464
+ sighashType: 0x01,
465
+ };
466
+
467
+ expect(task.inputIndex).toBe(0);
468
+ });
469
+
470
+ it('should handle large input indices', () => {
471
+ const task: SigningTask = {
472
+ taskId: 'large-index',
473
+ inputIndex: 999,
474
+ hash: new Uint8Array(32),
475
+ signatureType: SignatureType.ECDSA,
476
+ sighashType: 0x01,
477
+ };
478
+
479
+ expect(task.inputIndex).toBe(999);
480
+ });
481
+
482
+ it('should handle negative input index (edge case)', () => {
483
+ // Note: In practice, this would be validated elsewhere
484
+ const task: SigningTask = {
485
+ taskId: 'negative-index',
486
+ inputIndex: -1,
487
+ hash: new Uint8Array(32),
488
+ signatureType: SignatureType.ECDSA,
489
+ sighashType: 0x01,
490
+ };
491
+
492
+ expect(task.inputIndex).toBe(-1);
493
+ });
494
+ });
495
+
496
+ describe('Sighash Types', () => {
497
+ it('should handle SIGHASH_ALL (0x01)', () => {
498
+ const task: SigningTask = {
499
+ taskId: 'sighash-all',
500
+ inputIndex: 0,
501
+ hash: new Uint8Array(32),
502
+ signatureType: SignatureType.ECDSA,
503
+ sighashType: 0x01,
504
+ };
505
+
506
+ expect(task.sighashType).toBe(0x01);
507
+ });
508
+
509
+ it('should handle SIGHASH_NONE (0x02)', () => {
510
+ const task: SigningTask = {
511
+ taskId: 'sighash-none',
512
+ inputIndex: 0,
513
+ hash: new Uint8Array(32),
514
+ signatureType: SignatureType.ECDSA,
515
+ sighashType: 0x02,
516
+ };
517
+
518
+ expect(task.sighashType).toBe(0x02);
519
+ });
520
+
521
+ it('should handle SIGHASH_SINGLE (0x03)', () => {
522
+ const task: SigningTask = {
523
+ taskId: 'sighash-single',
524
+ inputIndex: 0,
525
+ hash: new Uint8Array(32),
526
+ signatureType: SignatureType.ECDSA,
527
+ sighashType: 0x03,
528
+ };
529
+
530
+ expect(task.sighashType).toBe(0x03);
531
+ });
532
+
533
+ it('should handle SIGHASH_ANYONECANPAY (0x80)', () => {
534
+ const task: SigningTask = {
535
+ taskId: 'sighash-anyonecanpay',
536
+ inputIndex: 0,
537
+ hash: new Uint8Array(32),
538
+ signatureType: SignatureType.ECDSA,
539
+ sighashType: 0x81, // ALL | ANYONECANPAY
540
+ };
541
+
542
+ expect(task.sighashType).toBe(0x81);
543
+ });
544
+
545
+ it('should handle SIGHASH_DEFAULT (0x00) for Taproot', () => {
546
+ const task: SigningTask = {
547
+ taskId: 'sighash-default',
548
+ inputIndex: 0,
549
+ hash: new Uint8Array(32),
550
+ signatureType: SignatureType.Schnorr,
551
+ sighashType: 0x00,
552
+ };
553
+
554
+ expect(task.sighashType).toBe(0x00);
555
+ });
556
+ });
557
+
558
+ describe('Public Key Formats', () => {
559
+ it('should handle compressed public key (33 bytes)', () => {
560
+ const publicKey = new Uint8Array(33);
561
+ publicKey[0] = 0x02; // Even y-coordinate prefix
562
+
563
+ const keyPair: ParallelSignerKeyPair = {
564
+ publicKey,
565
+ getPrivateKey: () => new Uint8Array(32),
566
+ };
567
+
568
+ expect(keyPair.publicKey.length).toBe(33);
569
+ expect(keyPair.publicKey[0]).toBe(0x02);
570
+ });
571
+
572
+ it('should handle compressed public key (odd prefix)', () => {
573
+ const publicKey = new Uint8Array(33);
574
+ publicKey[0] = 0x03; // Odd y-coordinate prefix
575
+
576
+ const keyPair: ParallelSignerKeyPair = {
577
+ publicKey,
578
+ getPrivateKey: () => new Uint8Array(32),
579
+ };
580
+
581
+ expect(keyPair.publicKey[0]).toBe(0x03);
582
+ });
583
+
584
+ it('should handle uncompressed public key (65 bytes)', () => {
585
+ const publicKey = new Uint8Array(65);
586
+ publicKey[0] = 0x04; // Uncompressed prefix
587
+
588
+ const keyPair: ParallelSignerKeyPair = {
589
+ publicKey,
590
+ getPrivateKey: () => new Uint8Array(32),
591
+ };
592
+
593
+ expect(keyPair.publicKey.length).toBe(65);
594
+ expect(keyPair.publicKey[0]).toBe(0x04);
595
+ });
596
+
597
+ it('should handle x-only public key (32 bytes) for Taproot', () => {
598
+ const publicKey = new Uint8Array(32); // x-only, no prefix
599
+
600
+ const keyPair: ParallelSignerKeyPair = {
601
+ publicKey,
602
+ getPrivateKey: () => new Uint8Array(32),
603
+ };
604
+
605
+ expect(keyPair.publicKey.length).toBe(32);
606
+ });
607
+ });
608
+
609
+ describe('Secure Zero Behavior', () => {
610
+ it('should verify secureZero is in worker code', () => {
611
+ const code = generateWorkerCode();
612
+
613
+ // Verify secureZero function exists
614
+ expect(code).toContain('function secureZero(arr)');
615
+
616
+ // Verify it uses fill(0)
617
+ expect(code).toContain('arr.fill(0)');
618
+
619
+ // Verify it's called on privateKey
620
+ const privateKeyZeroCount = (code.match(/secureZero\(privateKey\)/g) || []).length;
621
+ expect(privateKeyZeroCount).toBeGreaterThanOrEqual(2); // At least on success and error paths
622
+ });
623
+ });
624
+
625
+ describe('Empty and Null Cases', () => {
626
+ it('should handle empty task ID', () => {
627
+ const task: SigningTask = {
628
+ taskId: '',
629
+ inputIndex: 0,
630
+ hash: new Uint8Array(32),
631
+ signatureType: SignatureType.ECDSA,
632
+ sighashType: 0x01,
633
+ };
634
+
635
+ expect(task.taskId).toBe('');
636
+ });
637
+
638
+ it('should handle zero-filled hash', () => {
639
+ const task: SigningTask = {
640
+ taskId: 'zero-hash',
641
+ inputIndex: 0,
642
+ hash: new Uint8Array(32).fill(0),
643
+ signatureType: SignatureType.ECDSA,
644
+ sighashType: 0x01,
645
+ };
646
+
647
+ expect(task.hash.every((b) => b === 0)).toBe(true);
648
+ });
649
+
650
+ it('should handle max value hash', () => {
651
+ const task: SigningTask = {
652
+ taskId: 'max-hash',
653
+ inputIndex: 0,
654
+ hash: new Uint8Array(32).fill(0xff),
655
+ signatureType: SignatureType.ECDSA,
656
+ sighashType: 0x01,
657
+ };
658
+
659
+ expect(task.hash.every((b) => b === 0xff)).toBe(true);
660
+ });
661
+ });
662
+
663
+ describe('Concurrent Task IDs', () => {
664
+ it('should allow unique task IDs', () => {
665
+ const tasks: SigningTask[] = [];
666
+ for (let i = 0; i < 100; i++) {
667
+ tasks.push({
668
+ taskId: `task-${i}`,
669
+ inputIndex: i,
670
+ hash: new Uint8Array(32),
671
+ signatureType: SignatureType.ECDSA,
672
+ sighashType: 0x01,
673
+ });
674
+ }
675
+
676
+ const taskIds = tasks.map((t) => t.taskId);
677
+ const uniqueIds = new Set(taskIds);
678
+ expect(uniqueIds.size).toBe(100);
679
+ });
680
+
681
+ it('should allow duplicate task IDs (implementation handles this)', () => {
682
+ const task1: SigningTask = {
683
+ taskId: 'duplicate-id',
684
+ inputIndex: 0,
685
+ hash: new Uint8Array(32),
686
+ signatureType: SignatureType.ECDSA,
687
+ sighashType: 0x01,
688
+ };
689
+
690
+ const task2: SigningTask = {
691
+ taskId: 'duplicate-id', // Same ID
692
+ inputIndex: 1,
693
+ hash: new Uint8Array(32),
694
+ signatureType: SignatureType.ECDSA,
695
+ sighashType: 0x01,
696
+ };
697
+
698
+ // Pool implementation should handle this, but tasks can have same ID
699
+ expect(task1.taskId).toBe(task2.taskId);
700
+ expect(task1.inputIndex).not.toBe(task2.inputIndex);
701
+ });
702
+ });
703
+ });
704
+
705
+ describe('Memory Safety', () => {
706
+ it('should allow getPrivateKey to return fresh array each time', () => {
707
+ let callCount = 0;
708
+ const keyPair: ParallelSignerKeyPair = {
709
+ publicKey: new Uint8Array(33),
710
+ getPrivateKey: () => {
711
+ callCount++;
712
+ return new Uint8Array(32).fill(callCount);
713
+ },
714
+ };
715
+
716
+ const key1 = keyPair.getPrivateKey();
717
+ const key2 = keyPair.getPrivateKey();
718
+
719
+ expect(key1[0]).toBe(1);
720
+ expect(key2[0]).toBe(2);
721
+ expect(callCount).toBe(2);
722
+ });
723
+
724
+ it('should allow zeroing returned private key', () => {
725
+ const originalKey = new Uint8Array(32).fill(0x42);
726
+ const keyPair: ParallelSignerKeyPair = {
727
+ publicKey: new Uint8Array(33),
728
+ getPrivateKey: () => {
729
+ // Return a copy so original isn't affected
730
+ const copy = new Uint8Array(originalKey);
731
+ return copy;
732
+ },
733
+ };
734
+
735
+ const key = keyPair.getPrivateKey();
736
+ expect(key[0]).toBe(0x42);
737
+
738
+ // Zero the key (simulating what worker does)
739
+ key.fill(0);
740
+ expect(key[0]).toBe(0);
741
+
742
+ // Original should be unaffected
743
+ expect(originalKey[0]).toBe(0x42);
744
+ });
745
+ });
746
+
747
+ describe('Signature Verification Helpers', () => {
748
+ it('should identify ECDSA signatures by type', () => {
749
+ const result: SigningResultMessage = {
750
+ type: 'result',
751
+ taskId: 'test',
752
+ signature: new Uint8Array(71),
753
+ inputIndex: 0,
754
+ publicKey: new Uint8Array(33),
755
+ signatureType: SignatureType.ECDSA,
756
+ };
757
+
758
+ expect(result.signatureType === SignatureType.ECDSA).toBe(true);
759
+ expect(result.signatureType === SignatureType.Schnorr).toBe(false);
760
+ });
761
+
762
+ it('should identify Schnorr signatures by type', () => {
763
+ const result: SigningResultMessage = {
764
+ type: 'result',
765
+ taskId: 'test',
766
+ signature: new Uint8Array(64),
767
+ inputIndex: 0,
768
+ publicKey: new Uint8Array(32),
769
+ signatureType: SignatureType.Schnorr,
770
+ };
771
+
772
+ expect(result.signatureType === SignatureType.Schnorr).toBe(true);
773
+ expect(result.signatureType === SignatureType.ECDSA).toBe(false);
774
+ });
775
+
776
+ it('should distinguish key-path from script-path Taproot', () => {
777
+ const keyPathResult: SigningResultMessage = {
778
+ type: 'result',
779
+ taskId: 'keypath',
780
+ signature: new Uint8Array(64),
781
+ inputIndex: 0,
782
+ publicKey: new Uint8Array(32),
783
+ signatureType: SignatureType.Schnorr,
784
+ // No leafHash = key-path
785
+ };
786
+
787
+ const scriptPathResult: SigningResultMessage = {
788
+ type: 'result',
789
+ taskId: 'scriptpath',
790
+ signature: new Uint8Array(64),
791
+ inputIndex: 0,
792
+ publicKey: new Uint8Array(32),
793
+ signatureType: SignatureType.Schnorr,
794
+ leafHash: new Uint8Array(32), // Has leafHash = script-path
795
+ };
796
+
797
+ expect(keyPathResult.leafHash).toBeUndefined();
798
+ expect(scriptPathResult.leafHash).toBeDefined();
799
+ });
800
+ });
801
+
802
+ describe('Worker Code Security', () => {
803
+ describe('Secure Zero Implementation', () => {
804
+ it('should zero Uint8Array correctly', () => {
805
+ // Simulate the secureZero function from worker code
806
+ const secureZero = (arr: Uint8Array | null | undefined): void => {
807
+ if (arr && arr.fill) {
808
+ arr.fill(0);
809
+ }
810
+ };
811
+
812
+ const data = new Uint8Array([1, 2, 3, 4, 5]);
813
+ expect(data[0]).toBe(1);
814
+
815
+ secureZero(data);
816
+
817
+ expect(data[0]).toBe(0);
818
+ expect(data.every((b) => b === 0)).toBe(true);
819
+ });
820
+
821
+ it('should handle null safely', () => {
822
+ const secureZero = (arr: Uint8Array | null | undefined): void => {
823
+ if (arr && arr.fill) {
824
+ arr.fill(0);
825
+ }
826
+ };
827
+
828
+ // Should not throw
829
+ expect(() => secureZero(null)).not.toThrow();
830
+ expect(() => secureZero(undefined)).not.toThrow();
831
+ });
832
+
833
+ it('should handle empty array', () => {
834
+ const secureZero = (arr: Uint8Array | null | undefined): void => {
835
+ if (arr && arr.fill) {
836
+ arr.fill(0);
837
+ }
838
+ };
839
+
840
+ const empty = new Uint8Array(0);
841
+ expect(() => secureZero(empty)).not.toThrow();
842
+ expect(empty.length).toBe(0);
843
+ });
844
+ });
845
+
846
+ describe('Message Type Handling', () => {
847
+ it('should recognize all valid message types', () => {
848
+ const validTypes = ['init', 'sign', 'shutdown'];
849
+ const code = generateWorkerCode();
850
+
851
+ for (const type of validTypes) {
852
+ expect(code).toContain(`case '${type}':`);
853
+ }
854
+ });
855
+
856
+ it('should handle unknown message types', () => {
857
+ const code = generateWorkerCode();
858
+ expect(code).toContain('default:');
859
+ expect(code).toContain('Unknown message type');
860
+ });
861
+ });
862
+
863
+ describe('ECC Library Validation', () => {
864
+ it('should have ECC library bundled at compile time', () => {
865
+ const code = generateWorkerCode();
866
+ // ECC library is bundled directly, no runtime check needed
867
+ expect(code).toContain('eccBundle');
868
+ expect(code).toContain('nobleBundle');
869
+ expect(code).toContain('eccLib');
870
+ });
871
+
872
+ it('should check for Schnorr support', () => {
873
+ const code = generateWorkerCode();
874
+ expect(code).toContain('signSchnorr');
875
+ expect(code).toContain('ECC library does not support Schnorr');
876
+ });
877
+
878
+ it('should check for ECDSA support', () => {
879
+ const code = generateWorkerCode();
880
+ expect(code).toContain('eccLib.sign');
881
+ expect(code).toContain('ECC library does not support ECDSA');
882
+ });
883
+ });
884
+ });
885
+
886
+ describe('Blob URL Creation', () => {
887
+ // Skip these tests if URL.createObjectURL is not available (Node.js)
888
+ const hasURLSupport =
889
+ typeof URL !== 'undefined' &&
890
+ typeof URL.createObjectURL === 'function' &&
891
+ typeof Blob !== 'undefined';
892
+
893
+ it.skipIf(!hasURLSupport)('should create blob URL from worker code', async () => {
894
+ const { createWorkerBlobUrl, revokeWorkerBlobUrl } =
895
+ await import('../src/workers/signing-worker.js');
896
+
897
+ const url = createWorkerBlobUrl();
898
+ expect(url).toMatch(/^blob:/);
899
+
900
+ // Cleanup
901
+ revokeWorkerBlobUrl(url);
902
+ });
903
+
904
+ it('should generate valid JavaScript code', () => {
905
+ const code = generateWorkerCode();
906
+
907
+ // Check it's valid JS by looking for syntax elements
908
+ expect(code).toContain('function');
909
+ expect(code).toContain('self.onmessage');
910
+ expect(code).toContain('self.postMessage');
911
+ expect(code).toContain('switch');
912
+ expect(code).toContain('case');
913
+ expect(code).toContain('try');
914
+ expect(code).toContain('catch');
915
+ });
916
+ });
917
+
918
+ describe('ParallelSigningResult', () => {
919
+ it('should represent successful batch result', () => {
920
+ const signatures = new Map<number, SigningResultMessage>();
921
+ signatures.set(0, {
922
+ type: 'result',
923
+ taskId: 'task-0',
924
+ signature: new Uint8Array(64),
925
+ inputIndex: 0,
926
+ publicKey: new Uint8Array(33),
927
+ signatureType: SignatureType.ECDSA,
928
+ });
929
+ signatures.set(1, {
930
+ type: 'result',
931
+ taskId: 'task-1',
932
+ signature: new Uint8Array(64),
933
+ inputIndex: 1,
934
+ publicKey: new Uint8Array(33),
935
+ signatureType: SignatureType.Schnorr,
936
+ });
937
+
938
+ const result = {
939
+ success: true,
940
+ signatures,
941
+ errors: new Map<number, string>(),
942
+ durationMs: 150,
943
+ };
944
+
945
+ expect(result.success).toBe(true);
946
+ expect(result.signatures.size).toBe(2);
947
+ expect(result.errors.size).toBe(0);
948
+ expect(result.durationMs).toBe(150);
949
+ });
950
+
951
+ it('should represent partial failure result', () => {
952
+ const signatures = new Map<number, SigningResultMessage>();
953
+ signatures.set(0, {
954
+ type: 'result',
955
+ taskId: 'task-0',
956
+ signature: new Uint8Array(64),
957
+ inputIndex: 0,
958
+ publicKey: new Uint8Array(33),
959
+ signatureType: SignatureType.ECDSA,
960
+ });
961
+
962
+ const errors = new Map<number, string>();
963
+ errors.set(1, 'Invalid private key');
964
+ errors.set(2, 'Signing timeout');
965
+
966
+ const result = {
967
+ success: false,
968
+ signatures,
969
+ errors,
970
+ durationMs: 5000,
971
+ };
972
+
973
+ expect(result.success).toBe(false);
974
+ expect(result.signatures.size).toBe(1);
975
+ expect(result.errors.size).toBe(2);
976
+ expect(result.errors.get(1)).toBe('Invalid private key');
977
+ expect(result.errors.get(2)).toBe('Signing timeout');
978
+ });
979
+
980
+ it('should represent empty batch result', () => {
981
+ const result = {
982
+ success: true,
983
+ signatures: new Map<number, SigningResultMessage>(),
984
+ errors: new Map<number, string>(),
985
+ durationMs: 0,
986
+ };
987
+
988
+ expect(result.success).toBe(true);
989
+ expect(result.signatures.size).toBe(0);
990
+ expect(result.errors.size).toBe(0);
991
+ });
992
+ });
993
+
994
+ describe('WorkerPoolConfig', () => {
995
+ it('should accept minimal config', () => {
996
+ const config = {};
997
+ expect(config).toBeDefined();
998
+ });
999
+
1000
+ it('should accept full config', () => {
1001
+ const config = {
1002
+ workerCount: 8,
1003
+ taskTimeoutMs: 60000,
1004
+ maxKeyHoldTimeMs: 10000,
1005
+ verifySignatures: false,
1006
+ preserveWorkers: true,
1007
+ };
1008
+
1009
+ expect(config.workerCount).toBe(8);
1010
+ expect(config.taskTimeoutMs).toBe(60000);
1011
+ expect(config.maxKeyHoldTimeMs).toBe(10000);
1012
+ expect(config.verifySignatures).toBe(false);
1013
+ expect(config.preserveWorkers).toBe(true);
1014
+ });
1015
+
1016
+ it('should have reasonable defaults', () => {
1017
+ // Verify default values are sensible
1018
+ const defaults = {
1019
+ workerCount: 4,
1020
+ taskTimeoutMs: 30000,
1021
+ maxKeyHoldTimeMs: 5000,
1022
+ verifySignatures: true,
1023
+ preserveWorkers: false,
1024
+ };
1025
+
1026
+ expect(defaults.workerCount).toBeGreaterThan(0);
1027
+ expect(defaults.taskTimeoutMs).toBeGreaterThan(defaults.maxKeyHoldTimeMs);
1028
+ expect(defaults.verifySignatures).toBe(true); // Safe default
1029
+ expect(defaults.preserveWorkers).toBe(false); // Secure default
1030
+ });
1031
+ });
1032
+
1033
+ describe('WorkerState Transitions', () => {
1034
+ it('should have valid initial state (Initializing)', () => {
1035
+ expect(WorkerState.Initializing).toBe(0);
1036
+ });
1037
+
1038
+ it('should transition Initializing -> Idle', () => {
1039
+ let state: WorkerState = WorkerState.Initializing;
1040
+ // After worker sends 'ready' message
1041
+ state = WorkerState.Idle;
1042
+ expect(state).toBe(WorkerState.Idle);
1043
+ });
1044
+
1045
+ it('should transition Idle -> Busy', () => {
1046
+ let state: WorkerState = WorkerState.Idle;
1047
+ // When task is assigned
1048
+ state = WorkerState.Busy;
1049
+ expect(state).toBe(WorkerState.Busy);
1050
+ });
1051
+
1052
+ it('should transition Busy -> Idle', () => {
1053
+ let state: WorkerState = WorkerState.Busy;
1054
+ // When task completes
1055
+ state = WorkerState.Idle;
1056
+ expect(state).toBe(WorkerState.Idle);
1057
+ });
1058
+
1059
+ it('should transition to ShuttingDown from any state', () => {
1060
+ const states = [WorkerState.Initializing, WorkerState.Idle, WorkerState.Busy];
1061
+
1062
+ for (const initialState of states) {
1063
+ let state: WorkerState = initialState;
1064
+ state = WorkerState.ShuttingDown;
1065
+ expect(state).toBe(WorkerState.ShuttingDown);
1066
+ }
1067
+ });
1068
+
1069
+ it('should transition ShuttingDown -> Terminated', () => {
1070
+ let state: WorkerState = WorkerState.ShuttingDown;
1071
+ // After worker acknowledges shutdown
1072
+ state = WorkerState.Terminated;
1073
+ expect(state).toBe(WorkerState.Terminated);
1074
+ });
1075
+
1076
+ it('should not transition from Terminated', () => {
1077
+ const state = WorkerState.Terminated;
1078
+ // Terminated is final state
1079
+ expect(state).toBe(WorkerState.Terminated);
1080
+ });
1081
+ });
1082
+
1083
+ describe('Batch Signing Scenarios', () => {
1084
+ it('should handle single input signing', () => {
1085
+ const tasks: SigningTask[] = [
1086
+ {
1087
+ taskId: 'single',
1088
+ inputIndex: 0,
1089
+ hash: new Uint8Array(32).fill(0x11),
1090
+ signatureType: SignatureType.ECDSA,
1091
+ sighashType: 0x01,
1092
+ },
1093
+ ];
1094
+
1095
+ expect(tasks.length).toBe(1);
1096
+ expect(tasks[0].inputIndex).toBe(0);
1097
+ });
1098
+
1099
+ it('should handle multi-input ECDSA signing', () => {
1100
+ const tasks: SigningTask[] = [];
1101
+ for (let i = 0; i < 10; i++) {
1102
+ tasks.push({
1103
+ taskId: `ecdsa-${i}`,
1104
+ inputIndex: i,
1105
+ hash: new Uint8Array(32).fill(i),
1106
+ signatureType: SignatureType.ECDSA,
1107
+ sighashType: 0x01,
1108
+ });
1109
+ }
1110
+
1111
+ expect(tasks.length).toBe(10);
1112
+ expect(tasks.every((t) => t.signatureType === SignatureType.ECDSA)).toBe(true);
1113
+ });
1114
+
1115
+ it('should handle multi-input Schnorr signing', () => {
1116
+ const tasks: SigningTask[] = [];
1117
+ for (let i = 0; i < 10; i++) {
1118
+ tasks.push({
1119
+ taskId: `schnorr-${i}`,
1120
+ inputIndex: i,
1121
+ hash: new Uint8Array(32).fill(i + 100),
1122
+ signatureType: SignatureType.Schnorr,
1123
+ sighashType: 0x00,
1124
+ });
1125
+ }
1126
+
1127
+ expect(tasks.length).toBe(10);
1128
+ expect(tasks.every((t) => t.signatureType === SignatureType.Schnorr)).toBe(true);
1129
+ });
1130
+
1131
+ it('should handle mixed ECDSA and Schnorr signing', () => {
1132
+ const tasks: SigningTask[] = [
1133
+ {
1134
+ taskId: 'ecdsa-0',
1135
+ inputIndex: 0,
1136
+ hash: new Uint8Array(32),
1137
+ signatureType: SignatureType.ECDSA,
1138
+ sighashType: 0x01,
1139
+ },
1140
+ {
1141
+ taskId: 'schnorr-1',
1142
+ inputIndex: 1,
1143
+ hash: new Uint8Array(32),
1144
+ signatureType: SignatureType.Schnorr,
1145
+ sighashType: 0x00,
1146
+ },
1147
+ {
1148
+ taskId: 'ecdsa-2',
1149
+ inputIndex: 2,
1150
+ hash: new Uint8Array(32),
1151
+ signatureType: SignatureType.ECDSA,
1152
+ sighashType: 0x01,
1153
+ },
1154
+ ];
1155
+
1156
+ const ecdsaCount = tasks.filter((t) => t.signatureType === SignatureType.ECDSA).length;
1157
+ const schnorrCount = tasks.filter((t) => t.signatureType === SignatureType.Schnorr).length;
1158
+
1159
+ expect(ecdsaCount).toBe(2);
1160
+ expect(schnorrCount).toBe(1);
1161
+ });
1162
+
1163
+ it('should handle Taproot key-path and script-path in same batch', () => {
1164
+ const tasks: SigningTask[] = [
1165
+ {
1166
+ taskId: 'keypath-0',
1167
+ inputIndex: 0,
1168
+ hash: new Uint8Array(32),
1169
+ signatureType: SignatureType.Schnorr,
1170
+ sighashType: 0x00,
1171
+ // No leafHash = key-path
1172
+ },
1173
+ {
1174
+ taskId: 'scriptpath-1',
1175
+ inputIndex: 1,
1176
+ hash: new Uint8Array(32),
1177
+ signatureType: SignatureType.Schnorr,
1178
+ sighashType: 0x00,
1179
+ leafHash: new Uint8Array(32).fill(0xab), // Has leafHash = script-path
1180
+ },
1181
+ ];
1182
+
1183
+ const keyPathTasks = tasks.filter((t) => !t.leafHash);
1184
+ const scriptPathTasks = tasks.filter((t) => !!t.leafHash);
1185
+
1186
+ expect(keyPathTasks.length).toBe(1);
1187
+ expect(scriptPathTasks.length).toBe(1);
1188
+ });
1189
+ });
1190
+
1191
+ describe('Large Scale Scenarios', () => {
1192
+ it('should handle 100 inputs', () => {
1193
+ const tasks: SigningTask[] = [];
1194
+ for (let i = 0; i < 100; i++) {
1195
+ tasks.push({
1196
+ taskId: `task-${i}`,
1197
+ inputIndex: i,
1198
+ hash: new Uint8Array(32),
1199
+ signatureType: i % 2 === 0 ? SignatureType.ECDSA : SignatureType.Schnorr,
1200
+ sighashType: i % 2 === 0 ? 0x01 : 0x00,
1201
+ });
1202
+ }
1203
+
1204
+ expect(tasks.length).toBe(100);
1205
+ });
1206
+
1207
+ it('should handle 1000 inputs', () => {
1208
+ const tasks: SigningTask[] = [];
1209
+ for (let i = 0; i < 1000; i++) {
1210
+ tasks.push({
1211
+ taskId: `task-${i}`,
1212
+ inputIndex: i,
1213
+ hash: new Uint8Array(32),
1214
+ signatureType: SignatureType.ECDSA,
1215
+ sighashType: 0x01,
1216
+ });
1217
+ }
1218
+
1219
+ expect(tasks.length).toBe(1000);
1220
+ });
1221
+
1222
+ it('should generate unique task IDs for large batches', () => {
1223
+ const taskIds = new Set<string>();
1224
+ for (let i = 0; i < 10000; i++) {
1225
+ const taskId = `batch-${Date.now()}-${i}-${Math.random().toString(36).slice(2)}`;
1226
+ expect(taskIds.has(taskId)).toBe(false);
1227
+ taskIds.add(taskId);
1228
+ }
1229
+ expect(taskIds.size).toBe(10000);
1230
+ });
1231
+ });
1232
+
1233
+ describe('ECC Bundle', () => {
1234
+ // Helper to get noble secp module from the bundle
1235
+ // The bundle exports nobleBundle with { secp, sha256, hmac }
1236
+ // where secp already has hashes configured
1237
+ async function getNobleSecp() {
1238
+ const { ECC_BUNDLE } = await import('../src/workers/ecc-bundle.js');
1239
+
1240
+ const fn = new Function(ECC_BUNDLE + '; return nobleBundle;');
1241
+ const bundle = fn();
1242
+
1243
+ // Return the secp module which has hashes already configured
1244
+ return bundle.secp;
1245
+ }
1246
+
1247
+ it('should export bundled ECC code', async () => {
1248
+ const { ECC_BUNDLE, ECC_BUNDLE_SIZE } = await import('../src/workers/ecc-bundle.js');
1249
+
1250
+ expect(ECC_BUNDLE).toBeDefined();
1251
+ expect(typeof ECC_BUNDLE).toBe('string');
1252
+ expect(ECC_BUNDLE_SIZE).toBeGreaterThan(0);
1253
+ expect(ECC_BUNDLE.length).toBe(ECC_BUNDLE_SIZE);
1254
+ });
1255
+
1256
+ it('should contain noble-secp256k1 IIFE', async () => {
1257
+ const { ECC_BUNDLE } = await import('../src/workers/ecc-bundle.js');
1258
+
1259
+ // Should be an IIFE that creates nobleBundle global
1260
+ expect(ECC_BUNDLE).toContain('nobleBundle');
1261
+ expect(ECC_BUNDLE).toContain('sign');
1262
+ expect(ECC_BUNDLE).toContain('schnorr');
1263
+ });
1264
+
1265
+ it('should be executable and return valid module structure', async () => {
1266
+ const { ECC_BUNDLE } = await import('../src/workers/ecc-bundle.js');
1267
+
1268
+ // Execute the bundle and get the module
1269
+ const fn = new Function(ECC_BUNDLE + '; return nobleBundle;');
1270
+ const bundle = fn();
1271
+
1272
+ // Verify the bundle has the expected structure
1273
+ expect(bundle).toBeDefined();
1274
+ expect(typeof bundle.secp).toBe('object');
1275
+ expect(typeof bundle.sha256).toBe('function');
1276
+ expect(typeof bundle.hmac).toBe('function');
1277
+
1278
+ // Verify the secp module has the expected structure
1279
+ const secp = bundle.secp;
1280
+ expect(typeof secp.sign).toBe('function');
1281
+ expect(typeof secp.verify).toBe('function');
1282
+ expect(typeof secp.getPublicKey).toBe('function');
1283
+ expect(typeof secp.schnorr).toBe('object');
1284
+ expect(typeof secp.schnorr.sign).toBe('function');
1285
+ expect(typeof secp.schnorr.verify).toBe('function');
1286
+ expect(typeof secp.schnorr.getPublicKey).toBe('function');
1287
+ expect(typeof secp.hashes).toBe('object');
1288
+ });
1289
+
1290
+ it('should create valid ECDSA signatures', async () => {
1291
+ const secp = await getNobleSecp();
1292
+
1293
+ // Create a test private key (valid non-zero 32 bytes)
1294
+ const privateKey = new Uint8Array(32);
1295
+ privateKey[31] = 0x01; // Smallest valid private key
1296
+
1297
+ // Create a test hash
1298
+ const hash = new Uint8Array(32).fill(0xab);
1299
+
1300
+ // Sign with ECDSA - returns Uint8Array directly (64 bytes compact format)
1301
+ const sig = secp.sign(hash, privateKey, { lowS: true });
1302
+ expect(sig).toBeDefined();
1303
+ expect(sig).toBeInstanceOf(Uint8Array);
1304
+ expect(sig.length).toBe(64);
1305
+
1306
+ // Verify the signature
1307
+ const pubKey = secp.getPublicKey(privateKey);
1308
+ const isValid = secp.verify(sig, hash, pubKey);
1309
+ expect(isValid).toBe(true);
1310
+ });
1311
+
1312
+ it('should create valid Schnorr signatures', async () => {
1313
+ const secp = await getNobleSecp();
1314
+
1315
+ // Create a test private key
1316
+ const privateKey = new Uint8Array(32);
1317
+ privateKey[31] = 0x02;
1318
+
1319
+ // Create a test hash
1320
+ const hash = new Uint8Array(32).fill(0xcd);
1321
+
1322
+ // Sign with Schnorr (BIP340)
1323
+ const sig = secp.schnorr.sign(hash, privateKey);
1324
+ expect(sig).toBeDefined();
1325
+ expect(sig.length).toBe(64);
1326
+
1327
+ // Verify the signature
1328
+ const pubKey = secp.schnorr.getPublicKey(privateKey);
1329
+ const isValid = secp.schnorr.verify(sig, hash, pubKey);
1330
+ expect(isValid).toBe(true);
1331
+ });
1332
+
1333
+ it('should verify ECDSA signature with wrong key fails', async () => {
1334
+ const secp = await getNobleSecp();
1335
+
1336
+ const privateKey1 = new Uint8Array(32);
1337
+ privateKey1[31] = 0x01;
1338
+
1339
+ const privateKey2 = new Uint8Array(32);
1340
+ privateKey2[31] = 0x02;
1341
+
1342
+ const hash = new Uint8Array(32).fill(0xef);
1343
+
1344
+ // Sign with key1 - returns Uint8Array directly
1345
+ const sig = secp.sign(hash, privateKey1, { lowS: true });
1346
+
1347
+ // Verify with key2's pubkey should fail
1348
+ const pubKey2 = secp.getPublicKey(privateKey2);
1349
+ const isValid = secp.verify(sig, hash, pubKey2);
1350
+ expect(isValid).toBe(false);
1351
+ });
1352
+
1353
+ it('should verify Schnorr signature with wrong key fails', async () => {
1354
+ const secp = await getNobleSecp();
1355
+
1356
+ const privateKey1 = new Uint8Array(32);
1357
+ privateKey1[31] = 0x03;
1358
+
1359
+ const privateKey2 = new Uint8Array(32);
1360
+ privateKey2[31] = 0x04;
1361
+
1362
+ const hash = new Uint8Array(32).fill(0x12);
1363
+
1364
+ // Sign with key1
1365
+ const sig = secp.schnorr.sign(hash, privateKey1);
1366
+
1367
+ // Verify with key2's pubkey should fail
1368
+ const pubKey2 = secp.schnorr.getPublicKey(privateKey2);
1369
+ const isValid = secp.schnorr.verify(sig, hash, pubKey2);
1370
+ expect(isValid).toBe(false);
1371
+ });
1372
+
1373
+ it('should have reasonable bundle size (< 50KB)', async () => {
1374
+ const { ECC_BUNDLE_SIZE } = await import('../src/workers/ecc-bundle.js');
1375
+
1376
+ // Bundle should be reasonably small (minified noble-secp256k1 is ~12KB)
1377
+ expect(ECC_BUNDLE_SIZE).toBeLessThan(50000);
1378
+ expect(ECC_BUNDLE_SIZE).toBeGreaterThan(5000);
1379
+ });
1380
+
1381
+ it('should be embedded in worker code', () => {
1382
+ const code = generateWorkerCode();
1383
+
1384
+ // Worker code should contain the bundled ECC library
1385
+ expect(code).toContain('eccBundle');
1386
+ expect(code).toContain('nobleBundle');
1387
+ expect(code).toContain('eccModule');
1388
+ expect(code).toContain('eccLib');
1389
+ });
1390
+ });