ox 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/core/Engine.d.ts +43 -11
  3. package/dist/core/Engine.d.ts.map +1 -1
  4. package/dist/core/Engine.js +40 -10
  5. package/dist/core/Engine.js.map +1 -1
  6. package/dist/core/Hash.d.ts +36 -0
  7. package/dist/core/Hash.d.ts.map +1 -1
  8. package/dist/core/Hash.js +35 -0
  9. package/dist/core/Hash.js.map +1 -1
  10. package/dist/core/internal/engine.d.ts +8 -8
  11. package/dist/core/internal/engine.d.ts.map +1 -1
  12. package/dist/index.d.ts +5 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +5 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist/node/Ed25519.d.ts +33 -0
  17. package/dist/node/Ed25519.d.ts.map +1 -0
  18. package/dist/node/Ed25519.js +67 -0
  19. package/dist/node/Ed25519.js.map +1 -0
  20. package/dist/node/Engine.d.ts +29 -16
  21. package/dist/node/Engine.d.ts.map +1 -1
  22. package/dist/node/Engine.js +38 -14
  23. package/dist/node/Engine.js.map +1 -1
  24. package/dist/node/Hash.d.ts +17 -19
  25. package/dist/node/Hash.d.ts.map +1 -1
  26. package/dist/node/Hash.js +17 -19
  27. package/dist/node/Hash.js.map +1 -1
  28. package/dist/node/Keystore.d.ts +36 -0
  29. package/dist/node/Keystore.d.ts.map +1 -0
  30. package/dist/node/Keystore.js +72 -0
  31. package/dist/node/Keystore.js.map +1 -0
  32. package/dist/node/Mnemonic.d.ts +35 -0
  33. package/dist/node/Mnemonic.d.ts.map +1 -0
  34. package/dist/node/Mnemonic.js +46 -0
  35. package/dist/node/Mnemonic.js.map +1 -0
  36. package/dist/node/P256.d.ts +32 -0
  37. package/dist/node/P256.d.ts.map +1 -0
  38. package/dist/node/P256.js +34 -0
  39. package/dist/node/P256.js.map +1 -0
  40. package/dist/node/X25519.d.ts +31 -0
  41. package/dist/node/X25519.d.ts.map +1 -0
  42. package/dist/node/X25519.js +71 -0
  43. package/dist/node/X25519.js.map +1 -0
  44. package/dist/node/index.d.ts +95 -8
  45. package/dist/node/index.d.ts.map +1 -1
  46. package/dist/node/index.js +95 -8
  47. package/dist/node/index.js.map +1 -1
  48. package/dist/trusted-setups/Paths.d.ts +1 -0
  49. package/dist/trusted-setups/Paths.d.ts.map +1 -1
  50. package/dist/trusted-setups/Paths.js +1 -0
  51. package/dist/trusted-setups/Paths.js.map +1 -1
  52. package/dist/trusted-setups/Setups.d.ts +35 -0
  53. package/dist/trusted-setups/Setups.d.ts.map +1 -0
  54. package/dist/trusted-setups/Setups.js +29 -0
  55. package/dist/trusted-setups/Setups.js.map +1 -0
  56. package/dist/trusted-setups/index.d.ts +20 -0
  57. package/dist/trusted-setups/index.d.ts.map +1 -1
  58. package/dist/trusted-setups/index.js +20 -0
  59. package/dist/trusted-setups/index.js.map +1 -1
  60. package/dist/trusted-setups/internal/paths.d.ts.map +1 -1
  61. package/dist/trusted-setups/internal/paths.js +1 -1
  62. package/dist/trusted-setups/internal/paths.js.map +1 -1
  63. package/dist/trusted-setups/internal/setups/mainnet.d.ts +7 -0
  64. package/dist/trusted-setups/internal/setups/mainnet.d.ts.map +1 -0
  65. package/dist/trusted-setups/internal/setups/mainnet.js +11 -0
  66. package/dist/trusted-setups/internal/setups/mainnet.js.map +1 -0
  67. package/dist/wasm/Ed25519.d.ts +35 -0
  68. package/dist/wasm/Ed25519.d.ts.map +1 -0
  69. package/dist/wasm/Ed25519.js +88 -0
  70. package/dist/wasm/Ed25519.js.map +1 -0
  71. package/dist/wasm/Engine.d.ts +36 -26
  72. package/dist/wasm/Engine.d.ts.map +1 -1
  73. package/dist/wasm/Engine.js +44 -25
  74. package/dist/wasm/Engine.js.map +1 -1
  75. package/dist/wasm/Hash.d.ts +13 -19
  76. package/dist/wasm/Hash.d.ts.map +1 -1
  77. package/dist/wasm/Hash.js +21 -27
  78. package/dist/wasm/Hash.js.map +1 -1
  79. package/dist/wasm/Keystore.d.ts +51 -0
  80. package/dist/wasm/Keystore.d.ts.map +1 -0
  81. package/dist/wasm/Keystore.js +51 -0
  82. package/dist/wasm/Keystore.js.map +1 -0
  83. package/dist/wasm/Kzg.d.ts +112 -0
  84. package/dist/wasm/Kzg.d.ts.map +1 -0
  85. package/dist/wasm/Kzg.js +333 -0
  86. package/dist/wasm/Kzg.js.map +1 -0
  87. package/dist/wasm/Mnemonic.d.ts +33 -0
  88. package/dist/wasm/Mnemonic.d.ts.map +1 -0
  89. package/dist/wasm/Mnemonic.js +30 -0
  90. package/dist/wasm/Mnemonic.js.map +1 -0
  91. package/dist/wasm/Secp256k1.d.ts +55 -0
  92. package/dist/wasm/Secp256k1.d.ts.map +1 -0
  93. package/dist/wasm/Secp256k1.js +181 -0
  94. package/dist/wasm/Secp256k1.js.map +1 -0
  95. package/dist/wasm/X25519.d.ts +33 -0
  96. package/dist/wasm/X25519.d.ts.map +1 -0
  97. package/dist/wasm/X25519.js +53 -0
  98. package/dist/wasm/X25519.js.map +1 -0
  99. package/dist/wasm/index.d.ts +124 -12
  100. package/dist/wasm/index.d.ts.map +1 -1
  101. package/dist/wasm/index.js +124 -12
  102. package/dist/wasm/index.js.map +1 -1
  103. package/dist/wasm/internal/blake3.d.ts +11 -0
  104. package/dist/wasm/internal/blake3.d.ts.map +1 -0
  105. package/dist/wasm/internal/blake3.js +31 -0
  106. package/dist/wasm/internal/blake3.js.map +1 -0
  107. package/dist/wasm/internal/blake3.wasm.d.ts +3 -0
  108. package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -0
  109. package/dist/wasm/internal/blake3.wasm.js +10 -0
  110. package/dist/wasm/internal/blake3.wasm.js.map +1 -0
  111. package/dist/wasm/internal/crypto25519.d.ts +16 -0
  112. package/dist/wasm/internal/crypto25519.d.ts.map +1 -0
  113. package/dist/wasm/internal/crypto25519.js +5 -0
  114. package/dist/wasm/internal/crypto25519.js.map +1 -0
  115. package/dist/wasm/internal/crypto25519.wasm.d.ts +3 -0
  116. package/dist/wasm/internal/crypto25519.wasm.d.ts.map +1 -0
  117. package/dist/wasm/internal/crypto25519.wasm.js +10 -0
  118. package/dist/wasm/internal/crypto25519.wasm.js.map +1 -0
  119. package/dist/wasm/internal/ed25519.d.ts +4 -0
  120. package/dist/wasm/internal/ed25519.d.ts.map +1 -0
  121. package/dist/wasm/internal/ed25519.js +21 -0
  122. package/dist/wasm/internal/ed25519.js.map +1 -0
  123. package/dist/wasm/internal/hashes.d.ts +12 -0
  124. package/dist/wasm/internal/hashes.d.ts.map +1 -0
  125. package/dist/wasm/internal/hashes.js +8 -0
  126. package/dist/wasm/internal/hashes.js.map +1 -0
  127. package/dist/wasm/internal/hashes.wasm.d.ts +4 -2
  128. package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -1
  129. package/dist/wasm/internal/hashes.wasm.js +4 -2
  130. package/dist/wasm/internal/hashes.wasm.js.map +1 -1
  131. package/dist/wasm/internal/instantiate.d.ts +12 -0
  132. package/dist/wasm/internal/instantiate.d.ts.map +1 -1
  133. package/dist/wasm/internal/instantiate.js +23 -7
  134. package/dist/wasm/internal/instantiate.js.map +1 -1
  135. package/dist/wasm/internal/keystore.d.ts +10 -0
  136. package/dist/wasm/internal/keystore.d.ts.map +1 -0
  137. package/dist/wasm/internal/keystore.js +10 -0
  138. package/dist/wasm/internal/keystore.js.map +1 -0
  139. package/dist/wasm/internal/kzg.d.ts +17 -0
  140. package/dist/wasm/internal/kzg.d.ts.map +1 -0
  141. package/dist/wasm/internal/kzg.js +8 -0
  142. package/dist/wasm/internal/kzg.js.map +1 -0
  143. package/dist/wasm/internal/kzg.wasm.d.ts +3 -0
  144. package/dist/wasm/internal/kzg.wasm.d.ts.map +1 -0
  145. package/dist/wasm/internal/kzg.wasm.js +10 -0
  146. package/dist/wasm/internal/kzg.wasm.js.map +1 -0
  147. package/dist/wasm/internal/mnemonic.d.ts +4 -0
  148. package/dist/wasm/internal/mnemonic.d.ts.map +1 -0
  149. package/dist/wasm/internal/mnemonic.js +45 -0
  150. package/dist/wasm/internal/mnemonic.js.map +1 -0
  151. package/dist/wasm/internal/pbkdf2.d.ts +12 -0
  152. package/dist/wasm/internal/pbkdf2.d.ts.map +1 -0
  153. package/dist/wasm/internal/pbkdf2.js +51 -0
  154. package/dist/wasm/internal/pbkdf2.js.map +1 -0
  155. package/dist/wasm/internal/scrypt.d.ts +16 -0
  156. package/dist/wasm/internal/scrypt.d.ts.map +1 -0
  157. package/dist/wasm/internal/scrypt.js +78 -0
  158. package/dist/wasm/internal/scrypt.js.map +1 -0
  159. package/dist/wasm/internal/scrypt.wasm.d.ts +7 -0
  160. package/dist/wasm/internal/scrypt.wasm.d.ts.map +1 -0
  161. package/dist/wasm/internal/scrypt.wasm.js +14 -0
  162. package/dist/wasm/internal/scrypt.wasm.js.map +1 -0
  163. package/dist/wasm/internal/secp256k1.d.ts +16 -0
  164. package/dist/wasm/internal/secp256k1.d.ts.map +1 -0
  165. package/dist/wasm/internal/secp256k1.js +20 -0
  166. package/dist/wasm/internal/secp256k1.js.map +1 -0
  167. package/dist/wasm/internal/secp256k1.wasm.d.ts +3 -0
  168. package/dist/wasm/internal/secp256k1.wasm.d.ts.map +1 -0
  169. package/dist/wasm/internal/secp256k1.wasm.js +10 -0
  170. package/dist/wasm/internal/secp256k1.wasm.js.map +1 -0
  171. package/dist/wasm/internal/x25519.d.ts +4 -0
  172. package/dist/wasm/internal/x25519.d.ts.map +1 -0
  173. package/dist/wasm/internal/x25519.js +21 -0
  174. package/dist/wasm/internal/x25519.js.map +1 -0
  175. package/package.json +64 -2
  176. package/src/core/Engine.ts +84 -11
  177. package/src/core/Hash.ts +59 -0
  178. package/src/core/_test/Block.test.ts +9 -2
  179. package/src/core/_test/Engine.test-d.ts +56 -0
  180. package/src/core/_test/Engine.test.ts +95 -0
  181. package/src/core/_test/Hash.test-d.ts +18 -0
  182. package/src/core/_test/Hash.test.ts +100 -1
  183. package/src/core/_test/Hash.vectors.test.ts +7 -0
  184. package/src/core/_test/Transaction.test.ts +11 -2
  185. package/src/core/internal/engine.ts +8 -8
  186. package/src/index.ts +5 -2
  187. package/src/node/Ed25519.ts +87 -0
  188. package/src/node/Engine.ts +79 -23
  189. package/src/node/Hash.ts +25 -30
  190. package/src/node/Keystore.ts +103 -0
  191. package/src/node/Mnemonic.ts +68 -0
  192. package/src/node/P256.ts +48 -0
  193. package/src/node/X25519.ts +93 -0
  194. package/src/node/_test/Curves.fuzz.ts +76 -0
  195. package/src/node/_test/Ed25519.test-d.ts +35 -0
  196. package/src/node/_test/Ed25519.test.ts +220 -0
  197. package/src/node/_test/Engine.test-d.ts +28 -0
  198. package/src/node/_test/Engine.test.ts +62 -22
  199. package/src/node/_test/Hash.test-d.ts +16 -9
  200. package/src/node/_test/Hash.test.ts +10 -11
  201. package/src/node/_test/Keystore.fuzz.ts +58 -0
  202. package/src/node/_test/Keystore.test-d.ts +43 -0
  203. package/src/node/_test/Keystore.test.ts +198 -0
  204. package/src/node/_test/Mnemonic.fuzz.ts +31 -0
  205. package/src/node/_test/Mnemonic.test-d.ts +21 -0
  206. package/src/node/_test/Mnemonic.test.ts +98 -0
  207. package/src/node/_test/P256.test-d.ts +29 -0
  208. package/src/node/_test/P256.test.ts +102 -0
  209. package/src/node/_test/X25519.test-d.ts +28 -0
  210. package/src/node/_test/X25519.test.ts +239 -0
  211. package/src/node/index.ts +100 -8
  212. package/src/trusted-setups/Paths.ts +1 -0
  213. package/src/trusted-setups/README.md +39 -0
  214. package/src/trusted-setups/Setups.ts +46 -0
  215. package/src/trusted-setups/_test/Paths.test.ts +16 -0
  216. package/src/trusted-setups/_test/Setups.test-d.ts +7 -0
  217. package/src/trusted-setups/_test/Setups.test.ts +43 -0
  218. package/src/trusted-setups/_test/index.test.ts +1 -0
  219. package/src/trusted-setups/index.ts +21 -0
  220. package/src/trusted-setups/internal/paths.ts +4 -1
  221. package/src/trusted-setups/internal/setups/mainnet.source.json +7 -0
  222. package/src/trusted-setups/internal/setups/mainnet.ts +16 -0
  223. package/src/version.ts +1 -1
  224. package/src/wasm/Ed25519.ts +114 -0
  225. package/src/wasm/Engine.ts +78 -31
  226. package/src/wasm/Hash.bench.ts +2 -2
  227. package/src/wasm/Hash.ts +29 -50
  228. package/src/wasm/Keystore.bench.ts +26 -0
  229. package/src/wasm/Keystore.ts +66 -0
  230. package/src/wasm/Kzg.bench.ts +63 -0
  231. package/src/wasm/Kzg.ts +518 -0
  232. package/src/wasm/Mnemonic.ts +44 -0
  233. package/src/wasm/Secp256k1.bench.ts +79 -0
  234. package/src/wasm/Secp256k1.ts +248 -0
  235. package/src/wasm/X25519.ts +70 -0
  236. package/src/wasm/_test/Crypto25519.conformance.ts +57 -0
  237. package/src/wasm/_test/Crypto25519.fuzz.ts +187 -0
  238. package/src/wasm/_test/Ed25519.test-d.ts +28 -0
  239. package/src/wasm/_test/Ed25519.test.ts +168 -0
  240. package/src/wasm/_test/Ed25519.vectors.test.ts +73 -0
  241. package/src/wasm/_test/Engine.test-d.ts +29 -0
  242. package/src/wasm/_test/Engine.test.ts +59 -25
  243. package/src/wasm/_test/Hash.browser.test.ts +14 -7
  244. package/src/wasm/_test/Hash.fuzz.ts +58 -23
  245. package/src/wasm/_test/Hash.test-d.ts +16 -10
  246. package/src/wasm/_test/Hash.test.ts +148 -48
  247. package/src/wasm/_test/Hash.vectors.test.ts +15 -8
  248. package/src/wasm/_test/Keystore.browser.test.ts +73 -0
  249. package/src/wasm/_test/Keystore.fuzz.ts +163 -0
  250. package/src/wasm/_test/Keystore.test-d.ts +42 -0
  251. package/src/wasm/_test/Keystore.test.ts +477 -0
  252. package/src/wasm/_test/Keystore.vectors.test.ts +21 -0
  253. package/src/wasm/_test/Kzg.test-d.ts +19 -0
  254. package/src/wasm/_test/Kzg.test.ts +220 -0
  255. package/src/wasm/_test/Mnemonic.test-d.ts +17 -0
  256. package/src/wasm/_test/Mnemonic.test.ts +110 -0
  257. package/src/wasm/_test/Runtime.test.ts +9 -0
  258. package/src/wasm/_test/Secp256k1.test-d.ts +35 -0
  259. package/src/wasm/_test/Secp256k1.test.ts +354 -0
  260. package/src/wasm/_test/X25519.test-d.ts +21 -0
  261. package/src/wasm/_test/X25519.test.ts +194 -0
  262. package/src/wasm/_test/fixtures.ts +4 -0
  263. package/src/wasm/index.ts +130 -12
  264. package/src/wasm/internal/blake3.ts +45 -0
  265. package/src/wasm/internal/blake3.wasm.ts +11 -0
  266. package/src/wasm/internal/crypto25519.ts +43 -0
  267. package/src/wasm/internal/crypto25519.wasm.ts +11 -0
  268. package/src/wasm/internal/ed25519.ts +31 -0
  269. package/src/wasm/internal/hashes.ts +29 -0
  270. package/src/wasm/internal/hashes.wasm.ts +5 -2
  271. package/src/wasm/internal/instantiate.ts +29 -9
  272. package/src/wasm/internal/keystore.ts +19 -0
  273. package/src/wasm/internal/kzg.ts +50 -0
  274. package/src/wasm/internal/kzg.wasm.ts +11 -0
  275. package/src/wasm/internal/mnemonic.ts +56 -0
  276. package/src/wasm/internal/pbkdf2.ts +86 -0
  277. package/src/wasm/internal/scrypt.ts +131 -0
  278. package/src/wasm/internal/scrypt.wasm.ts +17 -0
  279. package/src/wasm/internal/secp256k1.ts +62 -0
  280. package/src/wasm/internal/secp256k1.wasm.ts +11 -0
  281. package/src/wasm/internal/x25519.ts +29 -0
  282. package/wasm/vendor/c-kzg-4844/LICENSE +201 -0
  283. package/wasm/vendor/c-kzg-4844/blst/LICENSE +201 -0
  284. package/src/trusted-setups/internal/setups/mainnet.txt +0 -4163
@@ -0,0 +1,248 @@
1
+ import type * as Engine from '../core/Engine.js'
2
+ import * as Errors from '../core/Errors.js'
3
+ import * as internal from './internal/instantiate.js'
4
+ import * as secp256k1 from './internal/secp256k1.js'
5
+
6
+ export * from '../core/Secp256k1.js'
7
+ export { MemoryError } from './internal/instantiate.js'
8
+
9
+ const privateKeySize = 32
10
+ const publicKeySize = 65
11
+ const sharedSecretSize = 33
12
+ const compactSignatureSize = 64
13
+ const recoveredSignatureSize = 65
14
+ const maxRawMessageSize = 8192
15
+
16
+ /**
17
+ * Compiles WASM implementations of deterministic
18
+ * [`Secp256k1`](/api/Secp256k1) primitives, without installing them.
19
+ *
20
+ * Random key generation remains on Ox's host-backed default implementation.
21
+ *
22
+ * @example
23
+ * ```ts twoslash
24
+ * // @noErrors
25
+ * import { Engine } from 'ox'
26
+ * import { Secp256k1 } from 'ox/wasm'
27
+ *
28
+ * await Engine.install({ Secp256k1: Secp256k1.engine() })
29
+ *
30
+ * Secp256k1.getPublicKey({ privateKey: '0x...' })
31
+ * ```
32
+ *
33
+ * @returns The WASM implementation of the deterministic `Secp256k1` primitives.
34
+ */
35
+ export async function engine(): Promise<engine.ReturnType> {
36
+ const module = await secp256k1.load()
37
+
38
+ return {
39
+ getPublicKey(privateKey) {
40
+ assertLength(privateKey, privateKeySize, 'private key')
41
+ const size = privateKeySize + publicKeySize
42
+ module.reserve(size)
43
+ const privateKeyPtr = module.heapBase
44
+ const publicKeyPtr = privateKeyPtr + privateKeySize
45
+ try {
46
+ module.view().set(privateKey, privateKeyPtr)
47
+ if (
48
+ module.exports.secp256k1_get_public_key(
49
+ privateKeyPtr,
50
+ publicKeyPtr,
51
+ ) !== 1
52
+ )
53
+ throw new InvalidInputError({ operation: 'getPublicKey' })
54
+ return module.view().slice(publicKeyPtr, publicKeyPtr + publicKeySize)
55
+ } finally {
56
+ module.exports.zero(privateKeyPtr, size)
57
+ }
58
+ },
59
+ getSharedSecret(privateKey, publicKey) {
60
+ assertLength(privateKey, privateKeySize, 'private key')
61
+ assertPublicKeyLength(publicKey)
62
+ const size = privateKeySize + publicKey.length + sharedSecretSize
63
+ module.reserve(size)
64
+ const privateKeyPtr = module.heapBase
65
+ const publicKeyPtr = privateKeyPtr + privateKeySize
66
+ const sharedSecretPtr = publicKeyPtr + publicKey.length
67
+ try {
68
+ const memory = module.view()
69
+ memory.set(privateKey, privateKeyPtr)
70
+ memory.set(publicKey, publicKeyPtr)
71
+ if (
72
+ module.exports.secp256k1_get_shared_secret(
73
+ privateKeyPtr,
74
+ publicKeyPtr,
75
+ publicKey.length,
76
+ sharedSecretPtr,
77
+ ) !== 1
78
+ )
79
+ throw new InvalidInputError({ operation: 'getSharedSecret' })
80
+ return module
81
+ .view()
82
+ .slice(sharedSecretPtr, sharedSecretPtr + sharedSecretSize)
83
+ } finally {
84
+ module.exports.zero(privateKeyPtr, size)
85
+ }
86
+ },
87
+ recoverPublicKey(signature, payload) {
88
+ assertLength(signature, recoveredSignatureSize, 'signature')
89
+ assertRawMessageLength(payload)
90
+ const size = recoveredSignatureSize + payload.length + publicKeySize
91
+ module.reserve(size)
92
+ const signaturePtr = module.heapBase
93
+ const payloadPtr = signaturePtr + recoveredSignatureSize
94
+ const publicKeyPtr = payloadPtr + payload.length
95
+ try {
96
+ const memory = module.view()
97
+ memory.set(signature, signaturePtr)
98
+ memory.set(payload, payloadPtr)
99
+ if (
100
+ module.exports.secp256k1_recover_public_key(
101
+ signaturePtr,
102
+ payloadPtr,
103
+ payload.length,
104
+ publicKeyPtr,
105
+ ) !== 1
106
+ )
107
+ throw new InvalidInputError({ operation: 'recoverPublicKey' })
108
+ return module.view().slice(publicKeyPtr, publicKeyPtr + publicKeySize)
109
+ } finally {
110
+ module.exports.zero(signaturePtr, size)
111
+ }
112
+ },
113
+ sign(payload, privateKey, options) {
114
+ assertLength(privateKey, privateKeySize, 'private key')
115
+ if (!options.prehash) assertRawMessageLength(payload)
116
+ const entropy =
117
+ options.extraEntropy === true
118
+ ? crypto.getRandomValues(new Uint8Array(privateKeySize))
119
+ : options.extraEntropy === false
120
+ ? undefined
121
+ : options.extraEntropy
122
+ const entropySize = entropy?.length ?? 0
123
+ const size =
124
+ payload.length + privateKeySize + entropySize + recoveredSignatureSize
125
+ module.reserve(size)
126
+ const payloadPtr = module.heapBase
127
+ const privateKeyPtr = payloadPtr + payload.length
128
+ const entropyPtr = entropy ? privateKeyPtr + privateKeySize : 0
129
+ const signaturePtr = privateKeyPtr + privateKeySize + entropySize
130
+ try {
131
+ const memory = module.view()
132
+ memory.set(payload, payloadPtr)
133
+ memory.set(privateKey, privateKeyPtr)
134
+ if (entropy) memory.set(entropy, entropyPtr)
135
+ if (
136
+ module.exports.secp256k1_sign(
137
+ payloadPtr,
138
+ payload.length,
139
+ privateKeyPtr,
140
+ entropyPtr,
141
+ entropySize,
142
+ Number(options.prehash),
143
+ signaturePtr,
144
+ ) !== 1
145
+ )
146
+ throw new InvalidInputError({ operation: 'sign' })
147
+ return module
148
+ .view()
149
+ .slice(signaturePtr, signaturePtr + recoveredSignatureSize)
150
+ } finally {
151
+ module.exports.zero(payloadPtr, size)
152
+ }
153
+ },
154
+ verify(signature, payload, publicKey, options) {
155
+ assertLength(signature, compactSignatureSize, 'signature')
156
+ assertPublicKeyLength(publicKey)
157
+ if (!options.prehash && payload.length > maxRawMessageSize) return false
158
+ const size = compactSignatureSize + payload.length + publicKey.length
159
+ module.reserve(size)
160
+ const signaturePtr = module.heapBase
161
+ const payloadPtr = signaturePtr + compactSignatureSize
162
+ const publicKeyPtr = payloadPtr + payload.length
163
+ try {
164
+ const memory = module.view()
165
+ memory.set(signature, signaturePtr)
166
+ memory.set(payload, payloadPtr)
167
+ memory.set(publicKey, publicKeyPtr)
168
+ return (
169
+ module.exports.secp256k1_verify(
170
+ signaturePtr,
171
+ payloadPtr,
172
+ payload.length,
173
+ publicKeyPtr,
174
+ publicKey.length,
175
+ Number(options.prehash),
176
+ ) === 1
177
+ )
178
+ } finally {
179
+ module.exports.zero(signaturePtr, size)
180
+ }
181
+ },
182
+ }
183
+ }
184
+
185
+ export declare namespace engine {
186
+ /** Every `Secp256k1` primitive this module implements. */
187
+ type ReturnType = {
188
+ [key in
189
+ | 'getPublicKey'
190
+ | 'getSharedSecret'
191
+ | 'recoverPublicKey'
192
+ | 'sign'
193
+ | 'verify']-?: NonNullable<Engine.Ecdsa[key]>
194
+ }
195
+
196
+ type ErrorType =
197
+ | InvalidInputError
198
+ | internal.MemoryError
199
+ | Errors.GlobalErrorType
200
+ }
201
+
202
+ function assertLength(value: Uint8Array, length: number, name: string): void {
203
+ if (value.length !== length)
204
+ throw new RangeError(
205
+ `Secp256k1 ${name} must be ${length} bytes, got ${value.length}`,
206
+ )
207
+ }
208
+
209
+ function assertPublicKeyLength(publicKey: Uint8Array): void {
210
+ if (
211
+ publicKey.length !== sharedSecretSize &&
212
+ publicKey.length !== publicKeySize
213
+ )
214
+ throw new RangeError(
215
+ `Secp256k1 public key must be 33 or 65 bytes, got ${publicKey.length}`,
216
+ )
217
+ }
218
+
219
+ function assertRawMessageLength(payload: Uint8Array): void {
220
+ if (payload.length > maxRawMessageSize)
221
+ throw new RangeError(
222
+ `Secp256k1 unhashed payload must not exceed ${maxRawMessageSize} bytes, got ${payload.length}`,
223
+ )
224
+ }
225
+
226
+ /**
227
+ * Thrown when libsecp256k1 rejects a key or recovered signature.
228
+ *
229
+ * @example
230
+ * ```ts twoslash
231
+ * import { Secp256k1 } from 'ox/wasm'
232
+ *
233
+ * try {
234
+ * const engine = await Secp256k1.engine()
235
+ * engine.getPublicKey(new Uint8Array(32))
236
+ * } catch (error) {
237
+ * if (error instanceof Secp256k1.InvalidInputError)
238
+ * console.error(error.message)
239
+ * }
240
+ * ```
241
+ */
242
+ export class InvalidInputError extends Errors.BaseError {
243
+ override readonly name = 'Secp256k1.InvalidInputError'
244
+
245
+ constructor({ operation }: { operation: string }) {
246
+ super(`WASM secp256k1 ${operation} received invalid input.`)
247
+ }
248
+ }
@@ -0,0 +1,70 @@
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 internal from './internal/instantiate.js'
5
+ import * as x25519 from './internal/x25519.js'
6
+
7
+ export * from '../core/X25519.js'
8
+ export { MemoryError } from './internal/instantiate.js'
9
+
10
+ const keySize = 32
11
+
12
+ /**
13
+ * Compiles WASM implementations of selected [`X25519`](/api/X25519)
14
+ * primitives, without installing them.
15
+ *
16
+ * Random key generation remains on Ox's default implementation.
17
+ *
18
+ * @example
19
+ * ```ts twoslash
20
+ * // @noErrors
21
+ * import { Engine } from 'ox'
22
+ * import { X25519 } from 'ox/wasm'
23
+ *
24
+ * await Engine.install({ X25519: X25519.engine() })
25
+ *
26
+ * X25519.getPublicKey({ privateKey: '0x...' })
27
+ * ```
28
+ *
29
+ * @returns The WASM implementation of part of the `X25519` slot.
30
+ */
31
+ export async function engine(): Promise<engine.ReturnType> {
32
+ const module = await crypto25519.load()
33
+
34
+ return {
35
+ getPublicKey(privateKey) {
36
+ assertLength(privateKey, 'private')
37
+ module.reserve(keySize * 2)
38
+ const privateKeyPtr = module.heapBase
39
+ const publicKeyPtr = privateKeyPtr + keySize
40
+ try {
41
+ module.view().set(privateKey, privateKeyPtr)
42
+ module.exports.x25519_get_public_key(privateKeyPtr, publicKeyPtr)
43
+ return module.view().slice(publicKeyPtr, publicKeyPtr + keySize)
44
+ } finally {
45
+ module.exports.zero(privateKeyPtr, keySize * 2)
46
+ }
47
+ },
48
+ getSharedSecret(privateKey, publicKey) {
49
+ assertLength(privateKey, 'private')
50
+ assertLength(publicKey, 'public')
51
+ return x25519.getSharedSecret(module, privateKey, publicKey)
52
+ },
53
+ }
54
+ }
55
+
56
+ export declare namespace engine {
57
+ /** Every `X25519` primitive this module implements. */
58
+ type ReturnType = {
59
+ [key in 'getPublicKey' | 'getSharedSecret']-?: NonNullable<Engine.Ecdh[key]>
60
+ }
61
+
62
+ type ErrorType = internal.MemoryError | Errors.GlobalErrorType
63
+ }
64
+
65
+ function assertLength(key: Uint8Array, type: 'private' | 'public'): void {
66
+ if (key.length !== keySize)
67
+ throw new RangeError(
68
+ `X25519 ${type} key must be ${keySize} bytes, got ${key.length}`,
69
+ )
70
+ }
@@ -0,0 +1,57 @@
1
+ import { ed25519, x25519 } from '@noble/curves/ed25519.js'
2
+ import { mnemonicToSeedSync } from '@scure/bip39'
3
+ import { describe, expect, test } from 'vp/test'
4
+ import { vectors } from '../../../test/vectors/bip39/index.js'
5
+ import * as Ed25519 from '../Ed25519.js'
6
+ import * as Mnemonic from '../Mnemonic.js'
7
+ import * as X25519 from '../X25519.js'
8
+
9
+ describe('crypto25519 WASM', () => {
10
+ test('behavior: Ed25519 works in this runtime', async () => {
11
+ const engine = await Ed25519.engine()
12
+ const privateKey = fromHex(
13
+ '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60',
14
+ )
15
+ const payload = new TextEncoder().encode('browser conformance')
16
+ const publicKey = engine.getPublicKey(privateKey)
17
+ const signature = engine.sign(payload, privateKey)
18
+
19
+ expect(publicKey).toEqual(ed25519.getPublicKey(privateKey))
20
+ expect(signature).toEqual(ed25519.sign(payload, privateKey))
21
+ expect(engine.verify(signature, payload, publicKey)).toBe(true)
22
+ })
23
+
24
+ test('behavior: X25519 works in this runtime', async () => {
25
+ const engine = await X25519.engine()
26
+ const privateKey = fromHex(
27
+ '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a',
28
+ )
29
+ const peerPrivateKey = fromHex(
30
+ '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb',
31
+ )
32
+ const publicKey = x25519.getPublicKey(peerPrivateKey)
33
+
34
+ expect(engine.getPublicKey(privateKey)).toEqual(
35
+ x25519.getPublicKey(privateKey),
36
+ )
37
+ expect(engine.getSharedSecret(privateKey, publicKey)).toEqual(
38
+ x25519.getSharedSecret(privateKey, publicKey),
39
+ )
40
+ })
41
+
42
+ test('behavior: Unicode BIP-39 works in this runtime', async () => {
43
+ const engine = await Mnemonic.engine()
44
+ const vector = vectors.japanese
45
+
46
+ expect(engine.toSeed(vector.mnemonic, vector.passphrase)).toEqual(
47
+ mnemonicToSeedSync(vector.mnemonic, vector.passphrase),
48
+ )
49
+ })
50
+ })
51
+
52
+ function fromHex(value: string): Uint8Array {
53
+ const bytes = new Uint8Array(value.length / 2)
54
+ for (let index = 0; index < bytes.length; index++)
55
+ bytes[index] = Number.parseInt(value.slice(index * 2, index * 2 + 2), 16)
56
+ return bytes
57
+ }
@@ -0,0 +1,187 @@
1
+ import { fc, test } from '@fast-check/vitest'
2
+ import { ed25519, x25519 } from '@noble/curves/ed25519.js'
3
+ import { mnemonicToSeedSync } from '@scure/bip39'
4
+ import { beforeAll, describe, expect } from 'vp/test'
5
+ import { numRuns } from '../../../test/fuzz/numRuns.js'
6
+ import * as Ed25519 from '../Ed25519.js'
7
+ import * as Mnemonic from '../Mnemonic.js'
8
+ import * as X25519 from '../X25519.js'
9
+ import { x25519LowOrder } from './fixtures.js'
10
+
11
+ let ed25519Engine: Ed25519.engine.ReturnType
12
+ let mnemonicEngine: Mnemonic.engine.ReturnType
13
+ let x25519Engine: X25519.engine.ReturnType
14
+
15
+ beforeAll(async () => {
16
+ ed25519Engine = await Ed25519.engine()
17
+ mnemonicEngine = await Mnemonic.engine()
18
+ x25519Engine = await X25519.engine()
19
+ })
20
+
21
+ const arbitraryKey = fc.uint8Array({ maxLength: 32, minLength: 32 })
22
+ const arbitraryPayload = fc.oneof(
23
+ fc.uint8Array({ maxLength: 512 }),
24
+ fc
25
+ .constantFrom(0, 1, 31, 32, 63, 64, 65, 127, 128, 129, 1024, 4096)
26
+ .chain((size) => fc.uint8Array({ maxLength: size, minLength: size })),
27
+ )
28
+ const arbitraryWord = fc.oneof(
29
+ fc
30
+ .string({ maxLength: 16, minLength: 1 })
31
+ .filter((value) => !value.normalize('NFKD').includes(' ')),
32
+ fc.constantFrom('café', 'cafe\u0301', 'あおぞら', '㍍ガバヴァ'),
33
+ )
34
+ const arbitraryMnemonic = fc
35
+ .tuple(
36
+ fc.constantFrom(12, 15, 18, 21, 24),
37
+ fc.array(arbitraryWord, { maxLength: 24, minLength: 24 }),
38
+ )
39
+ .map(([count, words]) => words.slice(0, count).join(' '))
40
+
41
+ describe('Ed25519', () => {
42
+ test.prop(
43
+ { payload: arbitraryPayload, privateKey: arbitraryKey },
44
+ { numRuns },
45
+ )('matches the default for arbitrary subviews', (options) => {
46
+ const payload = offsetView(options.payload)
47
+ const privateKey = offsetView(options.privateKey)
48
+ const publicKey = ed25519Engine.getPublicKey(privateKey)
49
+ const signature = ed25519Engine.sign(payload, privateKey)
50
+
51
+ expect(publicKey).toEqual(ed25519.getPublicKey(privateKey))
52
+ expect(signature).toEqual(ed25519.sign(payload, privateKey))
53
+ expect(ed25519Engine.verify(signature, payload, publicKey)).toBe(true)
54
+ expect(
55
+ ed25519Engine.verify(signature, Uint8Array.of(...payload, 1), publicKey),
56
+ ).toBe(false)
57
+ expect(ed25519Engine.toMontgomerySecret(privateKey)).toEqual(
58
+ ed25519.utils.toMontgomerySecret(privateKey),
59
+ )
60
+ })
61
+
62
+ test.prop(
63
+ {
64
+ payload: arbitraryPayload,
65
+ publicKey: arbitraryKey,
66
+ signature: fc.uint8Array({ maxLength: 64, minLength: 64 }),
67
+ },
68
+ { numRuns },
69
+ )('verification matches ZIP-215 for arbitrary encodings', (options) => {
70
+ expect(
71
+ ed25519Engine.verify(
72
+ options.signature,
73
+ options.payload,
74
+ options.publicKey,
75
+ ),
76
+ ).toBe(
77
+ ed25519.verify(options.signature, options.payload, options.publicKey),
78
+ )
79
+ })
80
+ })
81
+
82
+ describe('X25519', () => {
83
+ test.prop(
84
+ { privateKey: arbitraryKey, publicKeySeed: arbitraryKey },
85
+ { numRuns },
86
+ )('matches the default for arbitrary subviews', (options) => {
87
+ const privateKey = offsetView(options.privateKey)
88
+ const publicKey = offsetView(x25519.getPublicKey(options.publicKeySeed))
89
+
90
+ expect(x25519Engine.getPublicKey(privateKey)).toEqual(
91
+ x25519.getPublicKey(privateKey),
92
+ )
93
+ expect(x25519Engine.getSharedSecret(privateKey, publicKey)).toEqual(
94
+ x25519.getSharedSecret(privateKey, publicKey),
95
+ )
96
+ })
97
+
98
+ test.prop(
99
+ {
100
+ highBit: fc.boolean(),
101
+ privateKey: arbitraryKey,
102
+ vector: fc.constantFrom(...x25519LowOrder),
103
+ },
104
+ { numRuns },
105
+ )(
106
+ 'rejects arbitrary private keys paired with low-order points',
107
+ (options) => {
108
+ const publicKey = fromHex(options.vector.publicKey)
109
+ if (options.highBit) publicKey[31]! |= 0x80
110
+ expect(() =>
111
+ x25519Engine.getSharedSecret(options.privateKey, publicKey),
112
+ ).toThrow()
113
+ },
114
+ )
115
+ })
116
+
117
+ describe('Mnemonic', () => {
118
+ test.prop(
119
+ {
120
+ mnemonic: arbitraryMnemonic,
121
+ passphrase: fc.string({ maxLength: 64 }),
122
+ },
123
+ { numRuns },
124
+ )('matches the default for arbitrary normalized text', (options) => {
125
+ expect(mnemonicEngine.toSeed(options.mnemonic, options.passphrase)).toEqual(
126
+ mnemonicToSeedSync(options.mnemonic, options.passphrase),
127
+ )
128
+ })
129
+ })
130
+
131
+ describe('memory', () => {
132
+ test.prop(
133
+ {
134
+ operations: fc.array(
135
+ fc.record({
136
+ payload: arbitraryPayload,
137
+ privateKey: arbitraryKey,
138
+ publicKeySeed: arbitraryKey,
139
+ }),
140
+ { maxLength: 8, minLength: 2 },
141
+ ),
142
+ },
143
+ { numRuns },
144
+ )(
145
+ 'interleaved providers remain isolated and outputs stay owned',
146
+ (options) => {
147
+ const held: Uint8Array[] = []
148
+ const snapshots: Uint8Array[] = []
149
+
150
+ for (const operation of options.operations) {
151
+ const edPublicKey = ed25519Engine.getPublicKey(operation.privateKey)
152
+ const signature = ed25519Engine.sign(
153
+ operation.payload,
154
+ operation.privateKey,
155
+ )
156
+ const xPublicKey = x25519.getPublicKey(operation.publicKeySeed)
157
+ const sharedSecret = x25519Engine.getSharedSecret(
158
+ operation.privateKey,
159
+ xPublicKey,
160
+ )
161
+ expect(
162
+ ed25519Engine.verify(signature, operation.payload, edPublicKey),
163
+ ).toBe(true)
164
+ expect(sharedSecret).toEqual(
165
+ x25519.getSharedSecret(operation.privateKey, xPublicKey),
166
+ )
167
+ held.push(signature, sharedSecret)
168
+ snapshots.push(signature.slice(), sharedSecret.slice())
169
+ }
170
+
171
+ expect(held).toEqual(snapshots)
172
+ },
173
+ )
174
+ })
175
+
176
+ function offsetView(value: Uint8Array): Uint8Array {
177
+ const bytes = new Uint8Array(value.length + 4).fill(0xff)
178
+ bytes.set(value, 2)
179
+ return bytes.subarray(2, -2)
180
+ }
181
+
182
+ function fromHex(value: string): Uint8Array {
183
+ const bytes = new Uint8Array(value.length / 2)
184
+ for (let index = 0; index < bytes.length; index++)
185
+ bytes[index] = Number.parseInt(value.slice(index * 2, index * 2 + 2), 16)
186
+ return bytes
187
+ }
@@ -0,0 +1,28 @@
1
+ import { expectTypeOf, test } from 'vp/test'
2
+ import type * as Engine from '../../core/Engine.js'
3
+ import * as core_Ed25519 from '../../core/Ed25519.js'
4
+ import * as Ed25519 from '../Ed25519.js'
5
+
6
+ type Slot = Awaited<ReturnType<typeof Ed25519.engine>>
7
+
8
+ test('return type exposes only implemented Ed25519 primitives', () => {
9
+ expectTypeOf<Slot['getPublicKey']>().toEqualTypeOf<
10
+ NonNullable<Engine.Eddsa['getPublicKey']>
11
+ >()
12
+ expectTypeOf<Slot['sign']>().toEqualTypeOf<
13
+ NonNullable<Engine.Eddsa['sign']>
14
+ >()
15
+ expectTypeOf<Slot['toMontgomerySecret']>().toEqualTypeOf<
16
+ NonNullable<Engine.Eddsa['toMontgomerySecret']>
17
+ >()
18
+ expectTypeOf<Slot['verify']>().toEqualTypeOf<
19
+ NonNullable<Engine.Eddsa['verify']>
20
+ >()
21
+ expectTypeOf<Slot>().not.toHaveProperty('randomSecretKey')
22
+ expectTypeOf<Slot>().not.toHaveProperty('toMontgomery')
23
+ })
24
+
25
+ test('the WASM namespace exposes the public Ed25519 API', () => {
26
+ expectTypeOf(Ed25519.getPublicKey).toEqualTypeOf(core_Ed25519.getPublicKey)
27
+ expectTypeOf<typeof Ed25519>().not.toHaveProperty('create')
28
+ })