ox 1.0.5 → 1.1.2

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 (337) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/dist/core/Base64.d.ts +10 -21
  3. package/dist/core/Base64.d.ts.map +1 -1
  4. package/dist/core/Base64.js +8 -127
  5. package/dist/core/Base64.js.map +1 -1
  6. package/dist/core/BinaryStateTree.d.ts.map +1 -1
  7. package/dist/core/BinaryStateTree.js +2 -2
  8. package/dist/core/BinaryStateTree.js.map +1 -1
  9. package/dist/core/Bls.d.ts.map +1 -1
  10. package/dist/core/Bls.js +19 -44
  11. package/dist/core/Bls.js.map +1 -1
  12. package/dist/core/Ed25519.d.ts.map +1 -1
  13. package/dist/core/Ed25519.js +7 -6
  14. package/dist/core/Ed25519.js.map +1 -1
  15. package/dist/core/Engine.d.ts +156 -0
  16. package/dist/core/Engine.d.ts.map +1 -0
  17. package/dist/core/Engine.js +210 -0
  18. package/dist/core/Engine.js.map +1 -0
  19. package/dist/core/Hash.d.ts +4 -4
  20. package/dist/core/Hash.d.ts.map +1 -1
  21. package/dist/core/Hash.js +9 -12
  22. package/dist/core/Hash.js.map +1 -1
  23. package/dist/core/Keystore.d.ts.map +1 -1
  24. package/dist/core/Keystore.js +15 -10
  25. package/dist/core/Keystore.js.map +1 -1
  26. package/dist/core/Mnemonic.d.ts.map +1 -1
  27. package/dist/core/Mnemonic.js +3 -2
  28. package/dist/core/Mnemonic.js.map +1 -1
  29. package/dist/core/P256.d.ts.map +1 -1
  30. package/dist/core/P256.js +8 -9
  31. package/dist/core/P256.js.map +1 -1
  32. package/dist/core/Secp256k1.d.ts.map +1 -1
  33. package/dist/core/Secp256k1.js +8 -9
  34. package/dist/core/Secp256k1.js.map +1 -1
  35. package/dist/core/WebCryptoP256.d.ts.map +1 -1
  36. package/dist/core/WebCryptoP256.js +2 -2
  37. package/dist/core/WebCryptoP256.js.map +1 -1
  38. package/dist/core/X25519.d.ts.map +1 -1
  39. package/dist/core/X25519.js +4 -3
  40. package/dist/core/X25519.js.map +1 -1
  41. package/dist/core/internal/bls.d.ts +12 -0
  42. package/dist/core/internal/bls.d.ts.map +1 -0
  43. package/dist/core/internal/bls.js +79 -0
  44. package/dist/core/internal/bls.js.map +1 -0
  45. package/dist/core/internal/codec/base64.d.ts +84 -0
  46. package/dist/core/internal/codec/base64.d.ts.map +1 -0
  47. package/dist/core/internal/codec/base64.js +177 -0
  48. package/dist/core/internal/codec/base64.js.map +1 -0
  49. package/dist/core/internal/codec/hex.d.ts +49 -4
  50. package/dist/core/internal/codec/hex.d.ts.map +1 -1
  51. package/dist/core/internal/codec/hex.js +109 -35
  52. package/dist/core/internal/codec/hex.js.map +1 -1
  53. package/dist/core/internal/curves.d.ts +17 -0
  54. package/dist/core/internal/curves.d.ts.map +1 -0
  55. package/dist/core/internal/curves.js +17 -0
  56. package/dist/core/internal/curves.js.map +1 -0
  57. package/dist/core/internal/ed25519.d.ts +14 -0
  58. package/dist/core/internal/ed25519.d.ts.map +1 -0
  59. package/dist/core/internal/ed25519.js +29 -0
  60. package/dist/core/internal/ed25519.js.map +1 -0
  61. package/dist/core/internal/engine.d.ts +278 -0
  62. package/dist/core/internal/engine.d.ts.map +1 -0
  63. package/dist/core/internal/engine.js +131 -0
  64. package/dist/core/internal/engine.js.map +1 -0
  65. package/dist/core/internal/hash.d.ts +12 -0
  66. package/dist/core/internal/hash.d.ts.map +1 -0
  67. package/dist/core/internal/hash.js +30 -0
  68. package/dist/core/internal/hash.js.map +1 -0
  69. package/dist/core/internal/keystore.d.ts +14 -0
  70. package/dist/core/internal/keystore.d.ts.map +1 -0
  71. package/dist/core/internal/keystore.js +32 -0
  72. package/dist/core/internal/keystore.js.map +1 -0
  73. package/dist/core/internal/mnemonic.d.ts +4 -0
  74. package/dist/core/internal/mnemonic.d.ts.map +1 -0
  75. package/dist/core/internal/mnemonic.js +14 -0
  76. package/dist/core/internal/mnemonic.js.map +1 -0
  77. package/dist/core/internal/p256.d.ts +14 -0
  78. package/dist/core/internal/p256.d.ts.map +1 -0
  79. package/dist/core/internal/p256.js +36 -0
  80. package/dist/core/internal/p256.js.map +1 -0
  81. package/dist/core/internal/secp256k1.d.ts +14 -0
  82. package/dist/core/internal/secp256k1.d.ts.map +1 -0
  83. package/dist/core/internal/secp256k1.js +36 -0
  84. package/dist/core/internal/secp256k1.js.map +1 -0
  85. package/dist/core/internal/x25519.d.ts +8 -0
  86. package/dist/core/internal/x25519.d.ts.map +1 -0
  87. package/dist/core/internal/x25519.js +20 -0
  88. package/dist/core/internal/x25519.js.map +1 -0
  89. package/dist/index.d.ts +38 -0
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.docs.d.ts +2 -0
  92. package/dist/index.docs.d.ts.map +1 -1
  93. package/dist/index.docs.js +2 -0
  94. package/dist/index.docs.js.map +1 -1
  95. package/dist/index.js +38 -0
  96. package/dist/index.js.map +1 -1
  97. package/dist/node/Ed25519.d.ts +33 -0
  98. package/dist/node/Ed25519.d.ts.map +1 -0
  99. package/dist/node/Ed25519.js +67 -0
  100. package/dist/node/Ed25519.js.map +1 -0
  101. package/dist/node/Engine.d.ts +68 -0
  102. package/dist/node/Engine.d.ts.map +1 -0
  103. package/dist/node/Engine.js +75 -0
  104. package/dist/node/Engine.js.map +1 -0
  105. package/dist/node/Hash.d.ts +37 -0
  106. package/dist/node/Hash.d.ts.map +1 -0
  107. package/dist/node/Hash.js +35 -0
  108. package/dist/node/Hash.js.map +1 -0
  109. package/dist/node/Keystore.d.ts +36 -0
  110. package/dist/node/Keystore.d.ts.map +1 -0
  111. package/dist/node/Keystore.js +72 -0
  112. package/dist/node/Keystore.js.map +1 -0
  113. package/dist/node/Mnemonic.d.ts +35 -0
  114. package/dist/node/Mnemonic.d.ts.map +1 -0
  115. package/dist/node/Mnemonic.js +46 -0
  116. package/dist/node/Mnemonic.js.map +1 -0
  117. package/dist/node/P256.d.ts +32 -0
  118. package/dist/node/P256.d.ts.map +1 -0
  119. package/dist/node/P256.js +34 -0
  120. package/dist/node/P256.js.map +1 -0
  121. package/dist/node/X25519.d.ts +31 -0
  122. package/dist/node/X25519.d.ts.map +1 -0
  123. package/dist/node/X25519.js +71 -0
  124. package/dist/node/X25519.js.map +1 -0
  125. package/dist/node/index.d.ts +126 -0
  126. package/dist/node/index.d.ts.map +1 -0
  127. package/dist/node/index.js +126 -0
  128. package/dist/node/index.js.map +1 -0
  129. package/dist/tempo/VirtualMaster.d.ts +2 -0
  130. package/dist/tempo/VirtualMaster.d.ts.map +1 -1
  131. package/dist/tempo/VirtualMaster.js +19 -5
  132. package/dist/tempo/VirtualMaster.js.map +1 -1
  133. package/dist/tempo/internal/mine.wasm.d.ts +2 -4
  134. package/dist/tempo/internal/mine.wasm.d.ts.map +1 -1
  135. package/dist/tempo/internal/mine.wasm.js +7 -12
  136. package/dist/tempo/internal/mine.wasm.js.map +1 -1
  137. package/dist/tempo/internal/virtualMasterPool.js +4 -1
  138. package/dist/tempo/internal/virtualMasterPool.js.map +1 -1
  139. package/dist/wasm/Ed25519.d.ts +35 -0
  140. package/dist/wasm/Ed25519.d.ts.map +1 -0
  141. package/dist/wasm/Ed25519.js +88 -0
  142. package/dist/wasm/Ed25519.js.map +1 -0
  143. package/dist/wasm/Engine.d.ts +71 -0
  144. package/dist/wasm/Engine.d.ts.map +1 -0
  145. package/dist/wasm/Engine.js +76 -0
  146. package/dist/wasm/Engine.js.map +1 -0
  147. package/dist/wasm/Hash.d.ts +43 -0
  148. package/dist/wasm/Hash.d.ts.map +1 -0
  149. package/dist/wasm/Hash.js +64 -0
  150. package/dist/wasm/Hash.js.map +1 -0
  151. package/dist/wasm/Keystore.d.ts +37 -0
  152. package/dist/wasm/Keystore.d.ts.map +1 -0
  153. package/dist/wasm/Keystore.js +34 -0
  154. package/dist/wasm/Keystore.js.map +1 -0
  155. package/dist/wasm/Mnemonic.d.ts +33 -0
  156. package/dist/wasm/Mnemonic.d.ts.map +1 -0
  157. package/dist/wasm/Mnemonic.js +30 -0
  158. package/dist/wasm/Mnemonic.js.map +1 -0
  159. package/dist/wasm/X25519.d.ts +33 -0
  160. package/dist/wasm/X25519.d.ts.map +1 -0
  161. package/dist/wasm/X25519.js +53 -0
  162. package/dist/wasm/X25519.js.map +1 -0
  163. package/dist/wasm/index.d.ts +115 -0
  164. package/dist/wasm/index.d.ts.map +1 -0
  165. package/dist/wasm/index.js +115 -0
  166. package/dist/wasm/index.js.map +1 -0
  167. package/dist/wasm/internal/blake3.d.ts +11 -0
  168. package/dist/wasm/internal/blake3.d.ts.map +1 -0
  169. package/dist/wasm/internal/blake3.js +31 -0
  170. package/dist/wasm/internal/blake3.js.map +1 -0
  171. package/dist/wasm/internal/blake3.wasm.d.ts +3 -0
  172. package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -0
  173. package/dist/wasm/internal/blake3.wasm.js +10 -0
  174. package/dist/wasm/internal/blake3.wasm.js.map +1 -0
  175. package/dist/wasm/internal/crypto25519.d.ts +16 -0
  176. package/dist/wasm/internal/crypto25519.d.ts.map +1 -0
  177. package/dist/wasm/internal/crypto25519.js +5 -0
  178. package/dist/wasm/internal/crypto25519.js.map +1 -0
  179. package/dist/wasm/internal/crypto25519.wasm.d.ts +3 -0
  180. package/dist/wasm/internal/crypto25519.wasm.d.ts.map +1 -0
  181. package/dist/wasm/internal/crypto25519.wasm.js +10 -0
  182. package/dist/wasm/internal/crypto25519.wasm.js.map +1 -0
  183. package/dist/wasm/internal/ed25519.d.ts +4 -0
  184. package/dist/wasm/internal/ed25519.d.ts.map +1 -0
  185. package/dist/wasm/internal/ed25519.js +21 -0
  186. package/dist/wasm/internal/ed25519.js.map +1 -0
  187. package/dist/wasm/internal/hash.d.ts +9 -0
  188. package/dist/wasm/internal/hash.d.ts.map +1 -0
  189. package/dist/wasm/internal/hash.js +26 -0
  190. package/dist/wasm/internal/hash.js.map +1 -0
  191. package/dist/wasm/internal/hashes.d.ts +12 -0
  192. package/dist/wasm/internal/hashes.d.ts.map +1 -0
  193. package/dist/wasm/internal/hashes.js +8 -0
  194. package/dist/wasm/internal/hashes.js.map +1 -0
  195. package/dist/wasm/internal/hashes.wasm.d.ts +7 -0
  196. package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -0
  197. package/dist/wasm/internal/hashes.wasm.js +14 -0
  198. package/dist/wasm/internal/hashes.wasm.js.map +1 -0
  199. package/dist/wasm/internal/instantiate.d.ts +56 -0
  200. package/dist/wasm/internal/instantiate.d.ts.map +1 -0
  201. package/dist/wasm/internal/instantiate.js +92 -0
  202. package/dist/wasm/internal/instantiate.js.map +1 -0
  203. package/dist/wasm/internal/mnemonic.d.ts +4 -0
  204. package/dist/wasm/internal/mnemonic.d.ts.map +1 -0
  205. package/dist/wasm/internal/mnemonic.js +45 -0
  206. package/dist/wasm/internal/mnemonic.js.map +1 -0
  207. package/dist/wasm/internal/pbkdf2.d.ts +12 -0
  208. package/dist/wasm/internal/pbkdf2.d.ts.map +1 -0
  209. package/dist/wasm/internal/pbkdf2.js +51 -0
  210. package/dist/wasm/internal/pbkdf2.js.map +1 -0
  211. package/dist/wasm/internal/x25519.d.ts +4 -0
  212. package/dist/wasm/internal/x25519.d.ts.map +1 -0
  213. package/dist/wasm/internal/x25519.js +21 -0
  214. package/dist/wasm/internal/x25519.js.map +1 -0
  215. package/dist/zod/TypedData.d.ts +12 -12
  216. package/package.json +81 -1
  217. package/src/core/Base64.ts +19 -166
  218. package/src/core/BinaryStateTree.ts +2 -3
  219. package/src/core/Bls.ts +27 -77
  220. package/src/core/Ed25519.ts +7 -7
  221. package/src/core/Engine.ts +308 -0
  222. package/src/core/Hash.ts +9 -12
  223. package/src/core/Keystore.ts +17 -17
  224. package/src/core/Mnemonic.ts +3 -6
  225. package/src/core/P256.ts +15 -24
  226. package/src/core/Rlp_tx.bench.ts +2 -4
  227. package/src/core/Secp256k1.ts +9 -14
  228. package/src/core/TxEnvelopeEip1559.bench.ts +0 -5
  229. package/src/core/WebCryptoP256.ts +2 -2
  230. package/src/core/X25519.ts +4 -3
  231. package/src/core/_test/AbiParameters.adversarial.fuzz.ts +1 -2
  232. package/src/core/_test/AbiParameters.fuzz.ts +1 -2
  233. package/src/core/_test/Base.fuzz.ts +1 -2
  234. package/src/core/_test/Cbor.fuzz.ts +1 -2
  235. package/src/core/_test/Engine.fuzz.ts +293 -0
  236. package/src/core/_test/Engine.test-d.ts +140 -0
  237. package/src/core/_test/Engine.test.ts +618 -0
  238. package/src/core/_test/Hash.vectors.test.ts +64 -0
  239. package/src/core/_test/Hex.fuzz.ts +1 -2
  240. package/src/core/_test/Rlp.fuzz.ts +1 -2
  241. package/src/core/_test/Signature.fuzz.ts +1 -2
  242. package/src/core/_test/curves.test.ts +7 -0
  243. package/src/core/_test/index.test.ts +1 -0
  244. package/src/core/internal/bls.ts +121 -0
  245. package/src/core/internal/codec/_test/base64.conformance.ts +156 -0
  246. package/src/core/internal/codec/_test/hex.conformance.ts +204 -0
  247. package/src/core/internal/codec/_test/hex.fuzz.ts +234 -0
  248. package/src/core/internal/codec/_test/hex.test.ts +124 -0
  249. package/src/core/internal/codec/base64.ts +222 -0
  250. package/src/core/internal/codec/hex.ts +115 -34
  251. package/src/core/internal/curves.ts +18 -0
  252. package/src/core/internal/ed25519.ts +64 -0
  253. package/src/core/internal/engine.ts +410 -0
  254. package/src/core/internal/hash.ts +48 -0
  255. package/src/core/internal/keystore.ts +107 -0
  256. package/src/core/internal/mnemonic.ts +18 -0
  257. package/src/core/internal/p256.ts +91 -0
  258. package/src/core/internal/secp256k1.ts +91 -0
  259. package/src/core/internal/x25519.ts +40 -0
  260. package/src/index.docs.ts +2 -0
  261. package/src/index.ts +39 -0
  262. package/src/node/Ed25519.ts +87 -0
  263. package/src/node/Engine.ts +125 -0
  264. package/src/node/Hash.ts +51 -0
  265. package/src/node/Keystore.ts +103 -0
  266. package/src/node/Mnemonic.ts +68 -0
  267. package/src/node/P256.ts +48 -0
  268. package/src/node/X25519.ts +93 -0
  269. package/src/node/_test/Curves.fuzz.ts +76 -0
  270. package/src/node/_test/Ed25519.test-d.ts +35 -0
  271. package/src/node/_test/Ed25519.test.ts +220 -0
  272. package/src/node/_test/Engine.test-d.ts +28 -0
  273. package/src/node/_test/Engine.test.ts +102 -0
  274. package/src/node/_test/Hash.test-d.ts +32 -0
  275. package/src/node/_test/Hash.test.ts +101 -0
  276. package/src/node/_test/Keystore.fuzz.ts +58 -0
  277. package/src/node/_test/Keystore.test-d.ts +43 -0
  278. package/src/node/_test/Keystore.test.ts +198 -0
  279. package/src/node/_test/Mnemonic.fuzz.ts +31 -0
  280. package/src/node/_test/Mnemonic.test-d.ts +21 -0
  281. package/src/node/_test/Mnemonic.test.ts +98 -0
  282. package/src/node/_test/P256.test-d.ts +29 -0
  283. package/src/node/_test/P256.test.ts +102 -0
  284. package/src/node/_test/X25519.test-d.ts +28 -0
  285. package/src/node/_test/X25519.test.ts +239 -0
  286. package/src/node/index.ts +132 -0
  287. package/src/tempo/VirtualMaster.test.ts +75 -0
  288. package/src/tempo/VirtualMaster.ts +28 -6
  289. package/src/tempo/internal/mine.wasm.ts +7 -13
  290. package/src/tempo/internal/virtualMasterPool.ts +4 -1
  291. package/src/tsconfig.json +2 -1
  292. package/src/version.ts +1 -1
  293. package/src/wasm/Ed25519.ts +114 -0
  294. package/src/wasm/Engine.ts +121 -0
  295. package/src/wasm/Hash.bench.ts +60 -0
  296. package/src/wasm/Hash.ts +88 -0
  297. package/src/wasm/Keystore.ts +48 -0
  298. package/src/wasm/Mnemonic.ts +44 -0
  299. package/src/wasm/X25519.ts +70 -0
  300. package/src/wasm/_test/Crypto25519.conformance.ts +57 -0
  301. package/src/wasm/_test/Crypto25519.fuzz.ts +187 -0
  302. package/src/wasm/_test/Ed25519.test-d.ts +28 -0
  303. package/src/wasm/_test/Ed25519.test.ts +168 -0
  304. package/src/wasm/_test/Ed25519.vectors.test.ts +73 -0
  305. package/src/wasm/_test/Engine.test-d.ts +28 -0
  306. package/src/wasm/_test/Engine.test.ts +96 -0
  307. package/src/wasm/_test/Hash.browser.test.ts +54 -0
  308. package/src/wasm/_test/Hash.fuzz.ts +223 -0
  309. package/src/wasm/_test/Hash.test-d.ts +33 -0
  310. package/src/wasm/_test/Hash.test.ts +311 -0
  311. package/src/wasm/_test/Hash.vectors.test.ts +124 -0
  312. package/src/wasm/_test/Keystore.browser.test.ts +42 -0
  313. package/src/wasm/_test/Keystore.fuzz.ts +113 -0
  314. package/src/wasm/_test/Keystore.test-d.ts +33 -0
  315. package/src/wasm/_test/Keystore.test.ts +192 -0
  316. package/src/wasm/_test/Keystore.vectors.test.ts +21 -0
  317. package/src/wasm/_test/Mnemonic.test-d.ts +17 -0
  318. package/src/wasm/_test/Mnemonic.test.ts +110 -0
  319. package/src/wasm/_test/Runtime.test.ts +21 -0
  320. package/src/wasm/_test/X25519.test-d.ts +21 -0
  321. package/src/wasm/_test/X25519.test.ts +194 -0
  322. package/src/wasm/_test/fixtures.ts +4 -0
  323. package/src/wasm/_test/runtime.wasm.ts +11 -0
  324. package/src/wasm/index.ts +120 -0
  325. package/src/wasm/internal/blake3.ts +45 -0
  326. package/src/wasm/internal/blake3.wasm.ts +11 -0
  327. package/src/wasm/internal/crypto25519.ts +43 -0
  328. package/src/wasm/internal/crypto25519.wasm.ts +11 -0
  329. package/src/wasm/internal/ed25519.ts +31 -0
  330. package/src/wasm/internal/hash.ts +50 -0
  331. package/src/wasm/internal/hashes.ts +29 -0
  332. package/src/wasm/internal/hashes.wasm.ts +17 -0
  333. package/src/wasm/internal/instantiate.ts +135 -0
  334. package/src/wasm/internal/mnemonic.ts +56 -0
  335. package/src/wasm/internal/pbkdf2.ts +86 -0
  336. package/src/wasm/internal/x25519.ts +29 -0
  337. package/src/tempo/internal/mine.c +0 -182
@@ -1,5 +1,8 @@
1
+ import { Bytes } from 'ox'
1
2
  import { VirtualMaster } from 'ox/tempo'
2
3
  import { describe, expect, test } from 'vp/test'
4
+ import { instantiate } from '../wasm/internal/instantiate.js'
5
+ import { wasmBase64 } from './internal/mine.wasm.js'
3
6
 
4
7
  const address = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
5
8
  const salt =
@@ -123,6 +126,32 @@ describe('mineSaltAsync', () => {
123
126
  `)
124
127
  })
125
128
 
129
+ // `workerCount` is `min(workers, ceil(count / chunkSize))`, so the cases
130
+ // above collapse to one worker and take the JavaScript fallback. Only a
131
+ // chunk size small enough to need two workers reaches the WASM, which is how
132
+ // a miner writing over its own Keccak constants went unnoticed.
133
+ test('agrees with the fallback once the WASM actually runs', async () => {
134
+ const viaFallback = await VirtualMaster.mineSaltAsync({
135
+ address,
136
+ count: 16,
137
+ start: 0xabf52ba0n,
138
+ workers: 1,
139
+ })
140
+
141
+ const viaWasm = await VirtualMaster.mineSaltAsync({
142
+ address,
143
+ chunkSize: 8,
144
+ count: 16,
145
+ start: 0xabf52ba0n,
146
+ workers: 2,
147
+ })
148
+
149
+ expect(viaWasm).toEqual(viaFallback)
150
+ expect(viaWasm?.salt).toMatchInlineSnapshot(
151
+ `"0x00000000000000000000000000000000000000000000000000000000abf52baf"`,
152
+ )
153
+ })
154
+
126
155
  test('finds the same salt with workers', async () => {
127
156
  const result = await VirtualMaster.mineSaltAsync({
128
157
  address,
@@ -150,6 +179,52 @@ describe('mineSaltAsync', () => {
150
179
  expect(result).toBeUndefined()
151
180
  })
152
181
 
182
+ test.each([
183
+ 0,
184
+ -1,
185
+ 1.5,
186
+ Number.NaN,
187
+ Number.POSITIVE_INFINITY,
188
+ 2 ** 32,
189
+ Number.MAX_SAFE_INTEGER + 1,
190
+ ])('rejects chunk size %s outside the uint32 ABI', async (chunkSize) => {
191
+ await expect(
192
+ VirtualMaster.mineSaltAsync({
193
+ address,
194
+ chunkSize,
195
+ count: 1,
196
+ workers: 1,
197
+ }),
198
+ ).rejects.toThrow(
199
+ `Chunk size "${chunkSize}" is invalid. Expected a positive safe integer no greater than 4294967295.`,
200
+ )
201
+ })
202
+
203
+ test('accepts the maximum uint32 chunk size', async () => {
204
+ await expect(
205
+ VirtualMaster.mineSaltAsync({
206
+ address,
207
+ chunkSize: 2 ** 32 - 1,
208
+ count: 1,
209
+ start: 0n,
210
+ workers: 1,
211
+ }),
212
+ ).resolves.toBeUndefined()
213
+ })
214
+
215
+ test('treats the raw WASM count as unsigned', async () => {
216
+ type Exports = { mine(count: number): number }
217
+ const module = await instantiate<Exports>(wasmBase64)
218
+ module.reserve(84)
219
+ module.view().set(Bytes.fromHex(address), module.heapBase)
220
+ module.view().set(Bytes.fromHex(salt), module.heapBase + 20)
221
+
222
+ // 2 ** 31 has its sign bit set in the i32 passed by JavaScript. The first
223
+ // salt is already known to match, so unsigned C returns immediately; the old
224
+ // signed ABI interpreted the count as negative and skipped the loop.
225
+ expect(module.exports.mine(2 ** 31)).toBe(1)
226
+ })
227
+
153
228
  test('reports progress', async () => {
154
229
  const progressCalls: VirtualMaster.mineSaltAsync.Progress[] = []
155
230
 
@@ -1,14 +1,15 @@
1
- import { keccak_256 } from '@noble/hashes/sha3.js'
2
1
  import * as Address from '../core/Address.js'
3
2
  import * as Bytes from '../core/Bytes.js'
4
3
  import * as Errors from '../core/Errors.js'
5
4
  import type * as Hash from '../core/Hash.js'
5
+ import * as hash_ from '../core/internal/hash.js'
6
6
  import * as Hex from '../core/Hex.js'
7
7
  import * as VirtualMasterPool from './internal/virtualMasterPool.js'
8
8
  import * as VirtualAddress from './VirtualAddress.js'
9
9
 
10
10
  const tip20Prefix = '0x20c000000000000000000000'
11
11
  const zeroAddress = '0x0000000000000000000000000000000000000000'
12
+ const maxUint32 = 2 ** 32 - 1
12
13
 
13
14
  /** A valid salt input for TIP-1022 master registration. */
14
15
  export type Salt = Hex.Hex | Bytes.Bytes | number | bigint
@@ -203,7 +204,7 @@ export function mineSalt(
203
204
  saltView.set(toFixedBytes(value.start ?? 0n, 32))
204
205
 
205
206
  for (let i = 0; i < count; i++) {
206
- const hash = keccak_256(input)
207
+ const hash = hash_.keccak256(input)
207
208
 
208
209
  if (hash[0] === 0 && hash[1] === 0 && hash[2] === 0 && hash[3] === 0) {
209
210
  return {
@@ -289,13 +290,14 @@ export async function mineSaltAsync(
289
290
  workers = getDefaultWorkerCount(),
290
291
  } = parameters
291
292
 
292
- const address = resolveAddress(parameters.address)
293
- const start = toFixedHex(start_, 32)
294
-
293
+ assertChunkSize(chunkSize)
295
294
  assertCount(count)
296
295
  if (workers !== undefined) assertWorkers(workers)
297
296
  throwIfAborted(signal)
298
297
 
298
+ const address = resolveAddress(parameters.address)
299
+ const start = toFixedHex(start_, 32)
300
+
299
301
  const workerCount = Math.max(
300
302
  1,
301
303
  Math.min(workers, Math.ceil(count / chunkSize)),
@@ -341,6 +343,8 @@ export declare namespace mineSaltAsync {
341
343
  /**
342
344
  * Number of salts each worker processes before sending a progress update.
343
345
  *
346
+ * Must be a positive integer no greater than 2 ** 32 - 1.
347
+ *
344
348
  * @default 100_000
345
349
  */
346
350
  chunkSize?: number | undefined
@@ -576,6 +580,24 @@ function assertWorkers(workers: number) {
576
580
  )
577
581
  }
578
582
 
583
+ /**
584
+ * Asserts that `chunkSize` fits the miner's unsigned 32-bit WASM ABI.
585
+ *
586
+ * @internal
587
+ */
588
+ function assertChunkSize(chunkSize: number) {
589
+ if (
590
+ Number.isSafeInteger(chunkSize) &&
591
+ chunkSize > 0 &&
592
+ chunkSize <= maxUint32
593
+ )
594
+ return
595
+
596
+ throw new Errors.BaseError(
597
+ `Chunk size "${chunkSize}" is invalid. Expected a positive safe integer no greater than ${maxUint32}.`,
598
+ )
599
+ }
600
+
579
601
  /**
580
602
  * Extracts or creates an error from an `AbortSignal`.
581
603
  *
@@ -679,7 +701,7 @@ function buildRegistrationDigest(
679
701
  const addressBytes = Bytes.fromHex(resolveAddress(address))
680
702
  buffer.set(addressBytes)
681
703
  buffer.set(toFixedBytes(salt, 32), addressBytes.length)
682
- return keccak_256(buffer)
704
+ return hash_.keccak256(buffer)
683
705
  }
684
706
 
685
707
  /**
@@ -1,17 +1,11 @@
1
- // Embedded TIP-1022 WASM keccak256 salt miner (compiled from mine.c).
1
+ // Generated by `pnpm wasm:build --target=mine`. Do not edit.
2
2
  //
3
- // Memory layout at offset 1024:
4
- // [0..19] address (20 bytes, set by JS)
5
- // [20..51] salt (32 bytes, set/read by JS, incremented in-place)
6
- // [52..83] hash out (32 bytes, written on match)
3
+ // Compiled from wasm/src/mine.c, wasm/src/ox_rt.c
4
+ // with wasi-sdk 25.0 + binaryen 123.
7
5
  //
8
- // Exported: mine(count: i32) -> i32 returns 1 if found, 0 if not.
9
- //
10
- // Generated by: pnpm tsx scripts/build-mine-wasm.ts
6
+ // `pnpm wasm:check` rebuilds this file and fails if the bytes differ, so any
7
+ // change to the C or to `wasm/targets.ts` must be followed by `pnpm wasm:build`.
11
8
 
12
- /** Base64-encoded WASM binary for the TIP-1022 salt miner. */
9
+ /** Base64-encoded WASM binary. */
13
10
  export const wasmBase64 =
14
- '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'
15
-
16
- /** Byte offset in WASM linear memory where mining I/O begins. */
17
- export const dataOffset = 1024
11
+ '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'
@@ -185,7 +185,6 @@ main().catch(function(error) {
185
185
  */
186
186
  function getWorkerMineLoop(): string {
187
187
  return `
188
- var dataOffset = 1024
189
188
 
190
189
  function hexToBytes(hex) {
191
190
  var h = hex.startsWith('0x') ? hex.slice(2) : hex
@@ -218,6 +217,10 @@ function mineLoop(data, wasm, mem, postMessage) {
218
217
  var workerIndex = data.workerIndex
219
218
  var startBigInt = BigInt(data.start)
220
219
 
220
+ // Asked of the module rather than baked in: the buffer starts past the
221
+ // static data, wherever the linker put its end.
222
+ var dataOffset = wasm.heap_base()
223
+
221
224
  mem.set(addressBytes, dataOffset)
222
225
 
223
226
  for (
package/src/tsconfig.json CHANGED
@@ -10,6 +10,7 @@
10
10
  "./**/*.bench.ts",
11
11
  "./**/*.bench-d.ts",
12
12
  "./**/*.snap-d.ts",
13
- "./**/*.browser.test.ts"
13
+ "./**/*.browser.test.ts",
14
+ "./**/*.fuzz.ts"
14
15
  ]
15
16
  }
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** @internal */
2
- export const version = '1.0.5'
2
+ export const version = '1.1.2'
@@ -0,0 +1,114 @@
1
+ import type * as Engine from '../core/Engine.js'
2
+ import type * as Errors from '../core/Errors.js'
3
+ import * as crypto25519 from './internal/crypto25519.js'
4
+ import * as ed25519 from './internal/ed25519.js'
5
+ import * as internal from './internal/instantiate.js'
6
+
7
+ export * from '../core/Ed25519.js'
8
+ export { MemoryError } from './internal/instantiate.js'
9
+
10
+ const keySize = 32
11
+ const signatureSize = 64
12
+
13
+ /**
14
+ * Compiles WASM implementations of selected [`Ed25519`](/api/Ed25519)
15
+ * primitives, without installing them.
16
+ *
17
+ * Public-key conversion and random key generation remain on Ox's default
18
+ * implementation. The public conversion is omitted because Monocypher does not
19
+ * reproduce Ox's invalid-point validation.
20
+ *
21
+ * @example
22
+ * ```ts twoslash
23
+ * // @noErrors
24
+ * import { Engine } from 'ox'
25
+ * import { Ed25519 } from 'ox/wasm'
26
+ *
27
+ * await Engine.install({ Ed25519: Ed25519.engine() })
28
+ *
29
+ * Ed25519.getPublicKey({ privateKey: '0x...' })
30
+ * ```
31
+ *
32
+ * @returns The WASM implementation of part of the `Ed25519` slot.
33
+ */
34
+ export async function engine(): Promise<engine.ReturnType> {
35
+ const module = await crypto25519.load()
36
+
37
+ return {
38
+ getPublicKey(privateKey) {
39
+ assertLength(privateKey, keySize, 'private key')
40
+ module.reserve(keySize * 2)
41
+ const privateKeyPtr = module.heapBase
42
+ const publicKeyPtr = privateKeyPtr + keySize
43
+ try {
44
+ module.view().set(privateKey, privateKeyPtr)
45
+ module.exports.ed25519_get_public_key(privateKeyPtr, publicKeyPtr)
46
+ return module.view().slice(publicKeyPtr, publicKeyPtr + keySize)
47
+ } finally {
48
+ module.exports.zero(privateKeyPtr, keySize * 2)
49
+ }
50
+ },
51
+ sign(payload, privateKey) {
52
+ assertLength(privateKey, keySize, 'private key')
53
+ return ed25519.sign(module, payload, privateKey)
54
+ },
55
+ toMontgomerySecret(privateKey) {
56
+ assertLength(privateKey, keySize, 'private key')
57
+ module.reserve(keySize * 2)
58
+ const privateKeyPtr = module.heapBase
59
+ const secretKeyPtr = privateKeyPtr + keySize
60
+ try {
61
+ module.view().set(privateKey, privateKeyPtr)
62
+ module.exports.ed25519_to_montgomery_secret(privateKeyPtr, secretKeyPtr)
63
+ return module.view().slice(secretKeyPtr, secretKeyPtr + keySize)
64
+ } finally {
65
+ module.exports.zero(privateKeyPtr, keySize * 2)
66
+ }
67
+ },
68
+ verify(signature, payload, publicKey) {
69
+ assertLength(signature, signatureSize, 'signature')
70
+ assertLength(publicKey, keySize, 'public key')
71
+ const size = signatureSize + payload.length + keySize
72
+ module.reserve(size)
73
+ const signaturePtr = module.heapBase
74
+ const payloadPtr = signaturePtr + signatureSize
75
+ const publicKeyPtr = payloadPtr + payload.length
76
+ try {
77
+ const memory = module.view()
78
+ memory.set(signature, signaturePtr)
79
+ memory.set(payload, payloadPtr)
80
+ memory.set(publicKey, publicKeyPtr)
81
+ return (
82
+ module.exports.ed25519_verify(
83
+ signaturePtr,
84
+ payloadPtr,
85
+ payload.length,
86
+ publicKeyPtr,
87
+ ) === 1
88
+ )
89
+ } finally {
90
+ module.exports.zero(signaturePtr, size)
91
+ }
92
+ },
93
+ }
94
+ }
95
+
96
+ export declare namespace engine {
97
+ /** Every `Ed25519` primitive this module implements. */
98
+ type ReturnType = {
99
+ [key in
100
+ | 'getPublicKey'
101
+ | 'sign'
102
+ | 'toMontgomerySecret'
103
+ | 'verify']-?: NonNullable<Engine.Eddsa[key]>
104
+ }
105
+
106
+ type ErrorType = internal.MemoryError | Errors.GlobalErrorType
107
+ }
108
+
109
+ function assertLength(value: Uint8Array, length: number, name: string): void {
110
+ if (value.length !== length)
111
+ throw new RangeError(
112
+ `Ed25519 ${name} must be ${length} bytes, got ${value.length}`,
113
+ )
114
+ }
@@ -0,0 +1,121 @@
1
+ import * as CoreEngine from '../core/Engine.js'
2
+ import type * as Errors from '../core/Errors.js'
3
+ import * as Ed25519 from './Ed25519.js'
4
+ import * as Hash from './Hash.js'
5
+ import * as Keystore from './Keystore.js'
6
+ import * as Mnemonic from './Mnemonic.js'
7
+ import * as X25519 from './X25519.js'
8
+ import type * as internal from './internal/instantiate.js'
9
+
10
+ export {
11
+ AsyncScopeError,
12
+ get,
13
+ InvalidSlotValueError,
14
+ reset,
15
+ set,
16
+ UnknownPrimitiveError,
17
+ UnknownSlotError,
18
+ with,
19
+ } from '../core/Engine.js'
20
+ export type {
21
+ Bls,
22
+ Ecdh,
23
+ Ecdsa,
24
+ Eddsa,
25
+ Engine,
26
+ Hash,
27
+ Keystore,
28
+ Mnemonic,
29
+ } from '../core/Engine.js'
30
+
31
+ /**
32
+ * Compiles and installs every WASM implementation this entrypoint provides.
33
+ *
34
+ * Slot compilation starts concurrently. Nothing is installed until every slot
35
+ * resolves successfully.
36
+ *
37
+ * Call this once, during startup, before any crypto call. Ox resolves the
38
+ * engine at call time, so values computed beforehand used whatever was
39
+ * installed then.
40
+ *
41
+ * @example
42
+ * ```ts twoslash
43
+ * // @noErrors
44
+ * import { Engine, Hash } from 'ox/wasm'
45
+ *
46
+ * await Engine.install()
47
+ *
48
+ * Hash.sha256('0xdeadbeef')
49
+ * ```
50
+ *
51
+ * @returns The engine that was installed.
52
+ */
53
+ export async function install(): Promise<install.ReturnType> {
54
+ return CoreEngine.install({
55
+ Ed25519: Ed25519.engine(),
56
+ Hash: Hash.engine(),
57
+ Keystore: Keystore.engine(),
58
+ Mnemonic: Mnemonic.engine(),
59
+ X25519: X25519.engine(),
60
+ })
61
+ }
62
+
63
+ export declare namespace install {
64
+ type ReturnType = engine.ReturnType
65
+
66
+ type ErrorType =
67
+ | engine.ErrorType
68
+ | CoreEngine.install.ErrorType
69
+ | Errors.GlobalErrorType
70
+ }
71
+
72
+ /**
73
+ * Compiles every WASM implementation this entrypoint provides, without
74
+ * installing it.
75
+ *
76
+ * Reach for this where an engine has to exist as a value, such as a benchmark
77
+ * or an [`Engine.with`](/api/Engine/with) scope. Use the individual module's
78
+ * `engine` function to select only some slots.
79
+ *
80
+ * @example
81
+ * ```ts twoslash
82
+ * // @noErrors
83
+ * import { Engine, Hash } from 'ox'
84
+ * import { Engine as Wasm } from 'ox/wasm'
85
+ *
86
+ * const wasm = await Wasm.engine()
87
+ *
88
+ * Engine.with(wasm, () => Hash.sha256('0xdeadbeef'))
89
+ * ```
90
+ *
91
+ * @returns An engine, ready to install.
92
+ */
93
+ export async function engine(): Promise<engine.ReturnType> {
94
+ const [ed25519, hash, keystore, mnemonic, x25519] = await Promise.all([
95
+ Ed25519.engine(),
96
+ Hash.engine(),
97
+ Keystore.engine(),
98
+ Mnemonic.engine(),
99
+ X25519.engine(),
100
+ ])
101
+ return {
102
+ Ed25519: ed25519,
103
+ Hash: hash,
104
+ Keystore: keystore,
105
+ Mnemonic: mnemonic,
106
+ X25519: x25519,
107
+ }
108
+ }
109
+
110
+ export declare namespace engine {
111
+ /** Every slot this entrypoint supplies, each with its primitives present. */
112
+ type ReturnType = {
113
+ Ed25519: Ed25519.engine.ReturnType
114
+ Hash: Hash.engine.ReturnType
115
+ Keystore: Keystore.engine.ReturnType
116
+ Mnemonic: Mnemonic.engine.ReturnType
117
+ X25519: X25519.engine.ReturnType
118
+ }
119
+
120
+ type ErrorType = internal.MemoryError | Errors.GlobalErrorType
121
+ }
@@ -0,0 +1,60 @@
1
+ import { hmac } from '@noble/hashes/hmac.js'
2
+ import { ripemd160 as noble_ripemd160 } from '@noble/hashes/legacy.js'
3
+ import { sha256 as noble_sha256 } from '@noble/hashes/sha2.js'
4
+ import { keccak_256 as noble_keccak256 } from '@noble/hashes/sha3.js'
5
+ import { bench, describe } from 'vp/test'
6
+ import { engine as wasmEngine } from './Hash.js'
7
+
8
+ // Sizes expose fixed boundary overhead and sustained throughput. Crossovers
9
+ // vary by primitive, runtime, and processor.
10
+ //
11
+ // Run `pnpm bench:engines` for the full engine comparison. Vitest cannot
12
+ // run Rust, and this portable benchmark must remain browser-compatible.
13
+ const sizes = [32, 64, 256, 1024, 4096, 65_536, 1_048_576] as const
14
+
15
+ const wasm = await wasmEngine()
16
+ const key = Uint8Array.from({ length: 32 }, (_, index) => index % 97)
17
+
18
+ for (const size of sizes) {
19
+ const bytes = Uint8Array.from({ length: size }, (_, index) => index % 251)
20
+
21
+ describe(`keccak256 (${size} bytes input)`, () => {
22
+ bench('ox', () => {
23
+ noble_keccak256(bytes)
24
+ })
25
+
26
+ bench('ox/wasm', () => {
27
+ wasm.keccak256(bytes)
28
+ })
29
+ })
30
+
31
+ describe(`sha256 (${size} bytes input)`, () => {
32
+ bench('ox', () => {
33
+ noble_sha256(bytes)
34
+ })
35
+
36
+ bench('ox/wasm', () => {
37
+ wasm.sha256(bytes)
38
+ })
39
+ })
40
+
41
+ describe(`ripemd160 (${size} bytes input)`, () => {
42
+ bench('ox', () => {
43
+ noble_ripemd160(bytes)
44
+ })
45
+
46
+ bench('ox/wasm', () => {
47
+ wasm.ripemd160(bytes)
48
+ })
49
+ })
50
+
51
+ describe(`hmacSha256 (${size} bytes input)`, () => {
52
+ bench('ox', () => {
53
+ hmac(noble_sha256, key, bytes)
54
+ })
55
+
56
+ bench('ox/wasm', () => {
57
+ wasm.hmacSha256(key, bytes)
58
+ })
59
+ })
60
+ }
@@ -0,0 +1,88 @@
1
+ import type * as Engine from '../core/Engine.js'
2
+ import type * as Errors from '../core/Errors.js'
3
+ import * as blake3 from './internal/blake3.js'
4
+ import * as hash from './internal/hash.js'
5
+ import * as hashes from './internal/hashes.js'
6
+ import * as internal from './internal/instantiate.js'
7
+
8
+ export * from '../core/Hash.js'
9
+ export { MemoryError } from './internal/instantiate.js'
10
+
11
+ /** Digest sizes, in bytes. */
12
+ const digestSize = { keccak256: 32, ripemd160: 20, sha256: 32 }
13
+
14
+ /**
15
+ * Compiles the WASM implementation of the [`Hash`](/api/Hash) primitives,
16
+ * without installing it.
17
+ *
18
+ * Most callers want
19
+ * [`Engine.install`](/wasm/crypto/Engine/install) instead, which compiles every
20
+ * implementation this entrypoint provides and installs them in one call. Reach
21
+ * for this to take the `Hash` slot on its own, or to hold the implementation
22
+ * without touching the installed engine.
23
+ *
24
+ * :::note
25
+ * Performance varies by primitive, input size, runtime, and processor. Run
26
+ * `pnpm bench:engines` to compare Ox's default, Node, WASM, and Alloy
27
+ * implementations on your target machine.
28
+ * :::
29
+ *
30
+ * @example
31
+ * ```ts twoslash
32
+ * // @noErrors
33
+ * import { Engine } from 'ox'
34
+ * import { Hash } from 'ox/wasm'
35
+ *
36
+ * await Engine.install({ Hash: Hash.engine() })
37
+ *
38
+ * Hash.keccak256('0xdeadbeef')
39
+ * ```
40
+ *
41
+ * @returns The WASM implementation of the `Hash` slot.
42
+ */
43
+ export async function engine(): Promise<engine.ReturnType> {
44
+ {
45
+ const [blake3Module, module] = await Promise.all([
46
+ blake3.load(),
47
+ hashes.load(),
48
+ ])
49
+
50
+ // Copies `input` in, runs `hash`, and copies the digest back out.
51
+ function call(
52
+ hash: 'keccak256' | 'ripemd160' | 'sha256',
53
+ input: Uint8Array,
54
+ ): Uint8Array {
55
+ const out = digestSize[hash]
56
+ module.reserve(input.length + out)
57
+ const inputPtr = module.heapBase
58
+ const outPtr = inputPtr + input.length
59
+ module.view().set(input, inputPtr)
60
+ module.exports[hash](inputPtr, input.length, outPtr)
61
+ // `slice`, not `subarray`: the result must not alias WASM memory, which the
62
+ // next call overwrites and a `grow` detaches entirely.
63
+ return module.view().slice(outPtr, outPtr + out)
64
+ }
65
+
66
+ return {
67
+ blake3: (input) => blake3.hash(blake3Module, input),
68
+ hmacSha256: (key, message) => hash.hmacSha256(module, key, message),
69
+ keccak256: (input) => call('keccak256', input),
70
+ ripemd160: (input) => call('ripemd160', input),
71
+ sha256: (input) => call('sha256', input),
72
+ }
73
+ }
74
+ }
75
+
76
+ export declare namespace engine {
77
+ /** Every `Hash` primitive this module implements. */
78
+ type ReturnType = {
79
+ [key in
80
+ | 'blake3'
81
+ | 'hmacSha256'
82
+ | 'keccak256'
83
+ | 'ripemd160'
84
+ | 'sha256']-?: NonNullable<Engine.Hash[key]>
85
+ }
86
+
87
+ type ErrorType = internal.MemoryError | Errors.GlobalErrorType
88
+ }
@@ -0,0 +1,48 @@
1
+ import type * as Engine from '../core/Engine.js'
2
+ import type * as Errors from '../core/Errors.js'
3
+ import * as hashes from './internal/hashes.js'
4
+ import * as internal from './internal/instantiate.js'
5
+ import * as pbkdf2 from './internal/pbkdf2.js'
6
+
7
+ export * from '../core/Keystore.js'
8
+ export { MemoryError } from './internal/instantiate.js'
9
+
10
+ /**
11
+ * Compiles the WASM implementation of the [`Keystore`](/api/Keystore) PBKDF2
12
+ * primitive, without installing it.
13
+ *
14
+ * Most callers want
15
+ * [`Engine.install`](/wasm/crypto/Engine/install) instead, which compiles every
16
+ * implementation this entrypoint provides and installs them in one call. This
17
+ * provider deliberately stays synchronous and leaves AES, asynchronous PBKDF2,
18
+ * and scrypt on Ox's default implementation.
19
+ *
20
+ * @example
21
+ * ```ts twoslash
22
+ * // @noErrors
23
+ * import { Engine } from 'ox'
24
+ * import { Keystore } from 'ox/wasm'
25
+ *
26
+ * await Engine.install({ Keystore: Keystore.engine() })
27
+ *
28
+ * Keystore.pbkdf2({ password: 'testpassword' })
29
+ * ```
30
+ *
31
+ * @returns The WASM implementation of synchronous PBKDF2-HMAC-SHA256.
32
+ */
33
+ export async function engine(): Promise<engine.ReturnType> {
34
+ const module = await hashes.load()
35
+ return {
36
+ pbkdf2Sha256: (password, salt, options) =>
37
+ pbkdf2.pbkdf2Sha256(module, password, salt, options),
38
+ }
39
+ }
40
+
41
+ export declare namespace engine {
42
+ /** The WASM `Keystore` primitives this module implements. */
43
+ type ReturnType = {
44
+ pbkdf2Sha256: NonNullable<Engine.Keystore['pbkdf2Sha256']>
45
+ }
46
+
47
+ type ErrorType = internal.MemoryError | Errors.GlobalErrorType
48
+ }