ox 1.0.4 → 1.1.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 (230) hide show
  1. package/CHANGELOG.md +62 -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 +124 -0
  16. package/dist/core/Engine.d.ts.map +1 -0
  17. package/dist/core/Engine.js +180 -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 +35 -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 +35 -0
  96. package/dist/index.js.map +1 -1
  97. package/dist/node/Engine.d.ts +55 -0
  98. package/dist/node/Engine.d.ts.map +1 -0
  99. package/dist/node/Engine.js +51 -0
  100. package/dist/node/Engine.js.map +1 -0
  101. package/dist/node/Hash.d.ts +39 -0
  102. package/dist/node/Hash.d.ts.map +1 -0
  103. package/dist/node/Hash.js +37 -0
  104. package/dist/node/Hash.js.map +1 -0
  105. package/dist/node/index.d.ts +39 -0
  106. package/dist/node/index.d.ts.map +1 -0
  107. package/dist/node/index.js +39 -0
  108. package/dist/node/index.js.map +1 -0
  109. package/dist/tempo/VirtualMaster.d.ts +2 -0
  110. package/dist/tempo/VirtualMaster.d.ts.map +1 -1
  111. package/dist/tempo/VirtualMaster.js +19 -5
  112. package/dist/tempo/VirtualMaster.js.map +1 -1
  113. package/dist/tempo/ZoneId.d.ts +35 -17
  114. package/dist/tempo/ZoneId.d.ts.map +1 -1
  115. package/dist/tempo/ZoneId.js +41 -16
  116. package/dist/tempo/ZoneId.js.map +1 -1
  117. package/dist/tempo/index.d.ts +5 -6
  118. package/dist/tempo/index.d.ts.map +1 -1
  119. package/dist/tempo/index.js +5 -6
  120. package/dist/tempo/index.js.map +1 -1
  121. package/dist/tempo/internal/mine.wasm.d.ts +2 -4
  122. package/dist/tempo/internal/mine.wasm.d.ts.map +1 -1
  123. package/dist/tempo/internal/mine.wasm.js +7 -12
  124. package/dist/tempo/internal/mine.wasm.js.map +1 -1
  125. package/dist/tempo/internal/virtualMasterPool.js +4 -1
  126. package/dist/tempo/internal/virtualMasterPool.js.map +1 -1
  127. package/dist/wasm/Engine.d.ts +62 -0
  128. package/dist/wasm/Engine.d.ts.map +1 -0
  129. package/dist/wasm/Engine.js +57 -0
  130. package/dist/wasm/Engine.js.map +1 -0
  131. package/dist/wasm/Hash.d.ts +49 -0
  132. package/dist/wasm/Hash.d.ts.map +1 -0
  133. package/dist/wasm/Hash.js +70 -0
  134. package/dist/wasm/Hash.js.map +1 -0
  135. package/dist/wasm/index.d.ts +46 -0
  136. package/dist/wasm/index.d.ts.map +1 -0
  137. package/dist/wasm/index.js +46 -0
  138. package/dist/wasm/index.js.map +1 -0
  139. package/dist/wasm/internal/hash.d.ts +9 -0
  140. package/dist/wasm/internal/hash.d.ts.map +1 -0
  141. package/dist/wasm/internal/hash.js +26 -0
  142. package/dist/wasm/internal/hash.js.map +1 -0
  143. package/dist/wasm/internal/hashes.wasm.d.ts +5 -0
  144. package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -0
  145. package/dist/wasm/internal/hashes.wasm.js +12 -0
  146. package/dist/wasm/internal/hashes.wasm.js.map +1 -0
  147. package/dist/wasm/internal/instantiate.d.ts +56 -0
  148. package/dist/wasm/internal/instantiate.d.ts.map +1 -0
  149. package/dist/wasm/internal/instantiate.js +92 -0
  150. package/dist/wasm/internal/instantiate.js.map +1 -0
  151. package/dist/zod/TypedData.d.ts +12 -12
  152. package/package.json +36 -1
  153. package/src/core/Base64.ts +19 -166
  154. package/src/core/BinaryStateTree.ts +2 -3
  155. package/src/core/Bls.ts +27 -77
  156. package/src/core/Ed25519.ts +7 -7
  157. package/src/core/Engine.ts +235 -0
  158. package/src/core/Hash.ts +9 -12
  159. package/src/core/Keystore.ts +17 -17
  160. package/src/core/Mnemonic.ts +3 -6
  161. package/src/core/P256.ts +15 -24
  162. package/src/core/Rlp_tx.bench.ts +2 -4
  163. package/src/core/Secp256k1.ts +9 -14
  164. package/src/core/TxEnvelopeEip1559.bench.ts +0 -5
  165. package/src/core/WebCryptoP256.ts +2 -2
  166. package/src/core/X25519.ts +4 -3
  167. package/src/core/_test/AbiParameters.adversarial.fuzz.ts +1 -2
  168. package/src/core/_test/AbiParameters.fuzz.ts +1 -2
  169. package/src/core/_test/Base.fuzz.ts +1 -2
  170. package/src/core/_test/Cbor.fuzz.ts +1 -2
  171. package/src/core/_test/Engine.fuzz.ts +293 -0
  172. package/src/core/_test/Engine.test-d.ts +84 -0
  173. package/src/core/_test/Engine.test.ts +523 -0
  174. package/src/core/_test/Hash.vectors.test.ts +56 -0
  175. package/src/core/_test/Hex.fuzz.ts +1 -2
  176. package/src/core/_test/Rlp.fuzz.ts +1 -2
  177. package/src/core/_test/Signature.fuzz.ts +1 -2
  178. package/src/core/_test/curves.test.ts +7 -0
  179. package/src/core/_test/index.test.ts +1 -0
  180. package/src/core/internal/bls.ts +121 -0
  181. package/src/core/internal/codec/_test/base64.conformance.ts +156 -0
  182. package/src/core/internal/codec/_test/hex.conformance.ts +204 -0
  183. package/src/core/internal/codec/_test/hex.fuzz.ts +234 -0
  184. package/src/core/internal/codec/_test/hex.test.ts +124 -0
  185. package/src/core/internal/codec/base64.ts +222 -0
  186. package/src/core/internal/codec/hex.ts +115 -34
  187. package/src/core/internal/curves.ts +18 -0
  188. package/src/core/internal/ed25519.ts +64 -0
  189. package/src/core/internal/engine.ts +410 -0
  190. package/src/core/internal/hash.ts +48 -0
  191. package/src/core/internal/keystore.ts +107 -0
  192. package/src/core/internal/mnemonic.ts +18 -0
  193. package/src/core/internal/p256.ts +91 -0
  194. package/src/core/internal/secp256k1.ts +91 -0
  195. package/src/core/internal/x25519.ts +40 -0
  196. package/src/index.docs.ts +2 -0
  197. package/src/index.ts +36 -0
  198. package/src/node/Engine.ts +69 -0
  199. package/src/node/Hash.ts +56 -0
  200. package/src/node/_test/Engine.test.ts +62 -0
  201. package/src/node/_test/Hash.test-d.ts +26 -0
  202. package/src/node/_test/Hash.test.ts +102 -0
  203. package/src/node/index.ts +40 -0
  204. package/src/tempo/VirtualMaster.test.ts +75 -0
  205. package/src/tempo/VirtualMaster.ts +28 -6
  206. package/src/tempo/ZoneId.test-d.ts +16 -0
  207. package/src/tempo/ZoneId.test.ts +48 -13
  208. package/src/tempo/ZoneId.ts +55 -19
  209. package/src/tempo/index.ts +5 -6
  210. package/src/tempo/internal/mine.wasm.ts +7 -13
  211. package/src/tempo/internal/virtualMasterPool.ts +4 -1
  212. package/src/tsconfig.json +2 -1
  213. package/src/version.ts +1 -1
  214. package/src/wasm/Engine.ts +76 -0
  215. package/src/wasm/Hash.bench.ts +60 -0
  216. package/src/wasm/Hash.ts +109 -0
  217. package/src/wasm/_test/Engine.test.ts +62 -0
  218. package/src/wasm/_test/Hash.browser.test.ts +50 -0
  219. package/src/wasm/_test/Hash.fuzz.ts +188 -0
  220. package/src/wasm/_test/Hash.test-d.ts +28 -0
  221. package/src/wasm/_test/Hash.test.ts +211 -0
  222. package/src/wasm/_test/Hash.vectors.test.ts +117 -0
  223. package/src/wasm/_test/Runtime.test.ts +21 -0
  224. package/src/wasm/_test/runtime.wasm.ts +11 -0
  225. package/src/wasm/index.ts +47 -0
  226. package/src/wasm/internal/hash.ts +50 -0
  227. package/src/wasm/internal/hashes.wasm.ts +14 -0
  228. package/src/wasm/internal/instantiate.ts +135 -0
  229. package/src/zod/tempo/_test/ZoneId.test.ts +2 -2
  230. package/src/tempo/internal/mine.c +0 -182
@@ -0,0 +1,235 @@
1
+ import * as Caches from './Caches.js'
2
+ import * as Errors from './Errors.js'
3
+ import * as engine from './internal/engine.js'
4
+
5
+ export type {
6
+ Bls,
7
+ Ecdh,
8
+ Ecdsa,
9
+ Eddsa,
10
+ Engine,
11
+ Hash,
12
+ Keystore,
13
+ Mnemonic,
14
+ } from './internal/engine.js'
15
+
16
+ /**
17
+ * Installs crypto implementations, replacing the `@noble/*` implementations ox
18
+ * uses by default.
19
+ *
20
+ * Slots and their functions are optional. Omissions preserve earlier
21
+ * overrides, or use Ox's default when none exists. Calls merge, so a later
22
+ * engine can override one primitive.
23
+ *
24
+ * Call this once, during application startup, before any crypto call. ox
25
+ * resolves the engine at call time, so values computed beforehand used whatever
26
+ * implementation was installed then.
27
+ *
28
+ * @example
29
+ * ```ts twoslash
30
+ * // @noErrors
31
+ * import { Engine } from 'ox/wasm'
32
+ *
33
+ * await Engine.load()
34
+ * ```
35
+ *
36
+ * @example
37
+ * ### Overriding a Single Primitive
38
+ *
39
+ * ```ts twoslash
40
+ * import { Engine, Hash } from 'ox'
41
+ *
42
+ * Engine.set({
43
+ * Hash: { keccak256: () => new Uint8Array(32) }
44
+ * })
45
+ *
46
+ * Hash.keccak256('0xdeadbeef')
47
+ * // @log: '0x0000000000000000000000000000000000000000000000000000000000000000'
48
+ * ```
49
+ *
50
+ * @param value - Engine to install.
51
+ */
52
+ export function set(value: engine.Engine): void {
53
+ for (const [slot, primitives] of Object.entries(value)) {
54
+ if (!(engine.slots as readonly string[]).includes(slot))
55
+ throw new UnknownSlotError(slot)
56
+ const known = engine.primitives[slot as keyof engine.Engine]
57
+ // `primitives` is undefined where the caller is clearing the slot.
58
+ for (const primitive of Object.keys(primitives ?? {}))
59
+ if (!(known as readonly string[]).includes(primitive))
60
+ throw new UnknownPrimitiveError(slot, primitive)
61
+ }
62
+ engine.merge(value)
63
+ Caches.clear()
64
+ }
65
+
66
+ export declare namespace set {
67
+ type ErrorType =
68
+ | UnknownSlotError
69
+ | UnknownPrimitiveError
70
+ | Errors.GlobalErrorType
71
+ }
72
+
73
+ /**
74
+ * Returns the installed engine.
75
+ *
76
+ * Only overrides are returned -- slots left on ox's defaults are absent, so an
77
+ * empty object means ox is entirely on its default implementations.
78
+ *
79
+ * @example
80
+ * ```ts twoslash
81
+ * import { Engine } from 'ox'
82
+ *
83
+ * Engine.get()
84
+ * // @log: {}
85
+ * ```
86
+ *
87
+ * @returns The installed engine.
88
+ */
89
+ export function get(): engine.Engine {
90
+ // Slots are copied too, not just the root: a shared slot lets a caller write
91
+ // `get().Hash!.keccak256 = …` straight into the live registry, changing what
92
+ // ox calls without going through `set` and so without clearing the caches
93
+ // derived from it.
94
+ const copy: Record<string, unknown> = {}
95
+ for (const [name, slot] of Object.entries(engine.overrides))
96
+ copy[name] = { ...slot }
97
+ return copy as engine.Engine
98
+ }
99
+
100
+ export declare namespace get {
101
+ type ErrorType = Errors.GlobalErrorType
102
+ }
103
+
104
+ /**
105
+ * Restores ox's default implementations.
106
+ *
107
+ * @example
108
+ * ```ts twoslash
109
+ * import { Engine } from 'ox'
110
+ *
111
+ * Engine.reset('Hash')
112
+ * Engine.reset()
113
+ * ```
114
+ *
115
+ * @param slot - Slot to reset. Resets every slot when omitted.
116
+ */
117
+ export function reset(slot?: keyof engine.Engine): void {
118
+ // Deleting an unknown key succeeds silently, so without this a misspelled
119
+ // slot reports nothing and leaves the override it was meant to remove
120
+ // installed.
121
+ if (slot !== undefined && !(engine.slots as readonly string[]).includes(slot))
122
+ throw new UnknownSlotError(slot)
123
+ engine.reset(slot)
124
+ Caches.clear()
125
+ }
126
+
127
+ export declare namespace reset {
128
+ type ErrorType = UnknownSlotError | Errors.GlobalErrorType
129
+ }
130
+
131
+ /**
132
+ * Runs a function with an engine installed, then restores the previous engine.
133
+ *
134
+ * Only safe for synchronous functions: the engine is process-wide for the
135
+ * duration of the call, so concurrent asynchronous work would observe it too.
136
+ * Passing a function that returns a promise throws
137
+ * {@link ox#Engine.AsyncScopeError}.
138
+ *
139
+ * @example
140
+ * ```ts twoslash
141
+ * import { Engine, Hash } from 'ox'
142
+ *
143
+ * const hash = Engine.with(
144
+ * { Hash: { keccak256: () => new Uint8Array(32) } },
145
+ * () => Hash.keccak256('0xdeadbeef')
146
+ * )
147
+ * // @log: '0x0000000000000000000000000000000000000000000000000000000000000000'
148
+ * ```
149
+ *
150
+ * @param value - Engine to install for the duration of the call.
151
+ * @param fn - Synchronous function to run.
152
+ * @returns The return value of `fn`.
153
+ */
154
+ // Declared unexported and surfaced only through the alias below: exporting the
155
+ // backing name too would put an undocumented `Engine.with_` in the public
156
+ // surface, which is then breaking to take away.
157
+ function with_<returnType>(
158
+ value: engine.Engine,
159
+ fn: () => returnType,
160
+ ): returnType {
161
+ const previous = get()
162
+ try {
163
+ set(value)
164
+ const result = fn()
165
+ const thenable = result as
166
+ | { then?: (ok: () => void, err: () => void) => void }
167
+ | undefined
168
+ if (typeof thenable?.then === 'function') {
169
+ // Settle the promise we are about to discard. Otherwise its rejection is
170
+ // never observed, and Node can take the process down over it after the
171
+ // caller has already handled the `AsyncScopeError` thrown here.
172
+ thenable.then(
173
+ () => {},
174
+ () => {},
175
+ )
176
+ throw new AsyncScopeError()
177
+ }
178
+ return result
179
+ } finally {
180
+ engine.reset()
181
+ engine.merge(previous)
182
+ Caches.clear()
183
+ }
184
+ }
185
+
186
+ export { with_ as with }
187
+
188
+ declare namespace with_ {
189
+ type ErrorType =
190
+ | AsyncScopeError
191
+ | set.ErrorType
192
+ | get.ErrorType
193
+ | Errors.GlobalErrorType
194
+ }
195
+
196
+ /** Thrown when an unrecognized engine slot is supplied. */
197
+ export class UnknownSlotError extends Errors.BaseError {
198
+ override readonly name = 'Engine.UnknownSlotError'
199
+
200
+ constructor(slot: string) {
201
+ super(`\`${slot}\` is not a valid engine slot.`, {
202
+ metaMessages: [`Valid slots: ${engine.slots.join(', ')}`],
203
+ })
204
+ }
205
+ }
206
+
207
+ /** Thrown when a slot is given an unrecognized primitive name. */
208
+ export class UnknownPrimitiveError extends Errors.BaseError {
209
+ override readonly name = 'Engine.UnknownPrimitiveError'
210
+
211
+ constructor(slot: string, primitive: string) {
212
+ // The class is public, so `slot` is not necessarily one the table knows;
213
+ // an error that throws while being constructed hides the real failure.
214
+ const known: readonly string[] | undefined =
215
+ engine.primitives[slot as keyof engine.Engine]
216
+ super(
217
+ `\`${primitive}\` is not a valid primitive for the \`${slot}\` slot.`,
218
+ known ? { metaMessages: [`Valid primitives: ${known.join(', ')}`] } : {},
219
+ )
220
+ }
221
+ }
222
+
223
+ /** Thrown when {@link ox#Engine.with} is given an asynchronous function. */
224
+ export class AsyncScopeError extends Errors.BaseError {
225
+ override readonly name = 'Engine.AsyncScopeError'
226
+
227
+ constructor() {
228
+ super('`Engine.with` cannot be used with an asynchronous function.', {
229
+ metaMessages: [
230
+ 'The engine is process-wide, so a scoped override cannot be held across an `await`.',
231
+ 'Use `Engine.set` instead.',
232
+ ],
233
+ })
234
+ }
235
+ }
package/src/core/Hash.ts CHANGED
@@ -1,15 +1,12 @@
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
1
  import * as Bytes from './Bytes.js'
6
2
  import type * as Errors from './Errors.js'
7
3
  import * as Hex from './Hex.js'
4
+ import * as engine from './internal/hash.js'
8
5
 
9
6
  /**
10
7
  * Calculates the [Keccak256](https://en.wikipedia.org/wiki/SHA-3) hash of a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
11
8
  *
12
- * This function is a re-export of `keccak_256` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library.
9
+ * Backed by `keccak_256` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library, unless another implementation is installed with {@link ox#Engine.set}.
13
10
  *
14
11
  * @example
15
12
  * ```ts twoslash
@@ -54,7 +51,7 @@ export function keccak256<
54
51
  ): keccak256.ReturnType<as> {
55
52
  const isBytes = value instanceof Uint8Array
56
53
  const { as = isBytes ? 'Bytes' : 'Hex' } = options
57
- const bytes = noble_keccak256(isBytes ? value : Bytes.from(value))
54
+ const bytes = engine.keccak256(isBytes ? value : Bytes.from(value))
58
55
  if (as === 'Bytes') return bytes as never
59
56
  return Hex.fromBytes(bytes) as never
60
57
  }
@@ -78,7 +75,7 @@ export declare namespace keccak256 {
78
75
  /**
79
76
  * Calculates the [HMAC-SHA256](https://en.wikipedia.org/wiki/HMAC) of a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
80
77
  *
81
- * This function is a re-export of `hmac` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library.
78
+ * Backed by `hmac` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library, unless another implementation is installed with {@link ox#Engine.set}.
82
79
  *
83
80
  * @example
84
81
  * ```ts twoslash
@@ -119,7 +116,7 @@ export function hmac256<
119
116
  const { as = isBytes ? 'Bytes' : 'Hex' } = options
120
117
  const keyBytes = key instanceof Uint8Array ? key : Bytes.from(key)
121
118
  const valueBytes = isBytes ? value : Bytes.from(value)
122
- const bytes = hmac(noble_sha256, keyBytes, valueBytes)
119
+ const bytes = engine.hmacSha256(keyBytes, valueBytes)
123
120
  if (as === 'Bytes') return bytes as never
124
121
  return Hex.fromBytes(bytes) as never
125
122
  }
@@ -143,7 +140,7 @@ export declare namespace hmac256 {
143
140
  /**
144
141
  * Calculates the [Ripemd160](https://en.wikipedia.org/wiki/RIPEMD) hash of a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
145
142
  *
146
- * This function is a re-export of `ripemd160` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library.
143
+ * Backed by `ripemd160` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library, unless another implementation is installed with {@link ox#Engine.set}.
147
144
  *
148
145
  * @example
149
146
  * ```ts twoslash
@@ -168,7 +165,7 @@ export function ripemd160<
168
165
  ): ripemd160.ReturnType<as> {
169
166
  const isBytes = value instanceof Uint8Array
170
167
  const { as = isBytes ? 'Bytes' : 'Hex' } = options
171
- const bytes = noble_ripemd160(isBytes ? value : Bytes.from(value))
168
+ const bytes = engine.ripemd160(isBytes ? value : Bytes.from(value))
172
169
  if (as === 'Bytes') return bytes as never
173
170
  return Hex.fromBytes(bytes) as never
174
171
  }
@@ -192,7 +189,7 @@ export declare namespace ripemd160 {
192
189
  /**
193
190
  * Calculates the [Sha256](https://en.wikipedia.org/wiki/SHA-256) hash of a {@link ox#Bytes.Bytes} or {@link ox#Hex.Hex} value.
194
191
  *
195
- * This function is a re-export of `sha256` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library.
192
+ * Backed by `sha256` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes), an audited & minimal JS hashing library, unless another implementation is installed with {@link ox#Engine.set}.
196
193
  *
197
194
  * @example
198
195
  * ```ts twoslash
@@ -217,7 +214,7 @@ export function sha256<
217
214
  ): sha256.ReturnType<as> {
218
215
  const isBytes = value instanceof Uint8Array
219
216
  const { as = isBytes ? 'Bytes' : 'Hex' } = options
220
- const bytes = noble_sha256(isBytes ? value : Bytes.from(value))
217
+ const bytes = engine.sha256(isBytes ? value : Bytes.from(value))
221
218
  if (as === 'Bytes') return bytes as never
222
219
  return Hex.fromBytes(bytes) as never
223
220
  }
@@ -1,15 +1,6 @@
1
- import { ctr } from '@noble/ciphers/aes.js'
2
- import {
3
- pbkdf2 as pbkdf2_noble,
4
- pbkdf2Async as pbkdf2Async_noble,
5
- } from '@noble/hashes/pbkdf2.js'
6
- import {
7
- scrypt as scrypt_noble,
8
- scryptAsync as scryptAsync_noble,
9
- } from '@noble/hashes/scrypt.js'
10
- import { sha256 } from '@noble/hashes/sha2.js'
11
1
  import * as Bytes from './Bytes.js'
12
2
  import type * as Errors from './Errors.js'
3
+ import * as engine from './internal/keystore.js'
13
4
  import * as Hash from './Hash.js'
14
5
  import type * as Hex from './Hex.js'
15
6
  import type { OneOf } from './internal/types.js'
@@ -113,10 +104,11 @@ export function decrypt<as extends 'Hex' | 'Bytes' = 'Hex'>(
113
104
  if (!Bytes.isEqual(mac, Bytes.from(`0x${keystore.crypto.mac}`)))
114
105
  throw new Error('corrupt keystore')
115
106
 
116
- const data = ctr(
107
+ const data = engine.aesCtrDecrypt(
117
108
  encKey,
118
109
  Bytes.from(`0x${keystore.crypto.cipherparams.iv}`),
119
- ).decrypt(ciphertext)
110
+ ciphertext,
111
+ )
120
112
 
121
113
  if (as === 'Hex') return Bytes.toHex(data) as never
122
114
  return data as never
@@ -194,7 +186,7 @@ export function encrypt(
194
186
  const encKey = Bytes.slice(key_, 0, 16)
195
187
  const macKey = Bytes.slice(key_, 16, 32)
196
188
 
197
- const ciphertext = ctr(encKey, iv).encrypt(value_)
189
+ const ciphertext = engine.aesCtrEncrypt(encKey, iv, value_)
198
190
  const mac = Hash.keccak256(Bytes.concat(macKey, ciphertext))
199
191
 
200
192
  return {
@@ -239,7 +231,10 @@ export function pbkdf2(options: pbkdf2.Options) {
239
231
 
240
232
  const salt = options.salt ? Bytes.from(options.salt) : Bytes.random(32)
241
233
  const key = Bytes.toHex(
242
- pbkdf2_noble(sha256, password, salt, { c: iterations, dkLen: 32 }),
234
+ engine.pbkdf2Sha256(Bytes.fromString(password), salt, {
235
+ c: iterations,
236
+ dkLen: 32,
237
+ }),
243
238
  )
244
239
 
245
240
  return defineKey(() => key, {
@@ -288,7 +283,7 @@ export async function pbkdf2Async(options: pbkdf2.Options) {
288
283
 
289
284
  const salt = options.salt ? Bytes.from(options.salt) : Bytes.random(32)
290
285
  const key = Bytes.toHex(
291
- await pbkdf2Async_noble(sha256, password, salt, {
286
+ await engine.pbkdf2Sha256Async(Bytes.fromString(password), salt, {
292
287
  c: iterations,
293
288
  dkLen: 32,
294
289
  }),
@@ -331,7 +326,7 @@ export function scrypt(options: scrypt.Options) {
331
326
 
332
327
  const salt = options.salt ? Bytes.from(options.salt) : Bytes.random(32)
333
328
  const key = Bytes.toHex(
334
- scrypt_noble(password, salt, { N: n, dkLen: 32, r, p }),
329
+ engine.scrypt(Bytes.fromString(password), salt, { N: n, dkLen: 32, p, r }),
335
330
  )
336
331
 
337
332
  return defineKey(() => key, {
@@ -385,7 +380,12 @@ export async function scryptAsync(options: scrypt.Options) {
385
380
 
386
381
  const salt = options.salt ? Bytes.from(options.salt) : Bytes.random(32)
387
382
  const key = Bytes.toHex(
388
- await scryptAsync_noble(password, salt, { N: n, dkLen: 32, r, p }),
383
+ await engine.scryptAsync(Bytes.fromString(password), salt, {
384
+ N: n,
385
+ dkLen: 32,
386
+ p,
387
+ r,
388
+ }),
389
389
  )
390
390
 
391
391
  return defineKey(() => key, {
@@ -1,12 +1,9 @@
1
- import {
2
- generateMnemonic,
3
- mnemonicToSeedSync,
4
- validateMnemonic,
5
- } from '@scure/bip39'
1
+ import { generateMnemonic, validateMnemonic } from '@scure/bip39'
6
2
  import * as Bytes from './Bytes.js'
7
3
  import type * as Errors from './Errors.js'
8
4
  import * as HdKey from './HdKey.js'
9
5
  import type * as Hex from './Hex.js'
6
+ import * as engine from './internal/mnemonic.js'
10
7
 
11
8
  export { path } from './HdKey.js'
12
9
 
@@ -184,7 +181,7 @@ export function toSeed<as extends 'Bytes' | 'Hex' = 'Bytes'>(
184
181
  options: toSeed.Options<as> = {},
185
182
  ): toSeed.ReturnType<as> {
186
183
  const { passphrase } = options
187
- const seed = mnemonicToSeedSync(mnemonic, passphrase)
184
+ const seed = engine.toSeed(mnemonic, passphrase)
188
185
  if (options.as === 'Hex') return Bytes.toHex(seed) as never
189
186
  return seed as never
190
187
  }
package/src/core/P256.ts CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  normalizePublicKey,
9
9
  normalizeSignature,
10
10
  } from './internal/cryptoIo.js'
11
+ import * as engine from './internal/p256.js'
11
12
  import * as Entropy from './internal/entropy.js'
12
13
  import {
13
14
  fromRecoveredBytes,
@@ -85,7 +86,7 @@ export function getPublicKey<as extends 'Hex' | 'Bytes' | 'Object' = 'Object'>(
85
86
  options: getPublicKey.Options<as>,
86
87
  ): getPublicKey.ReturnType<as> {
87
88
  const { as = 'Object', privateKey } = options
88
- const bytes = noble_p256.getPublicKey(Bytes.from(privateKey), false)
89
+ const bytes = engine.getPublicKey(Bytes.from(privateKey))
89
90
  const publicKey = PublicKey.fromBytes(bytes)
90
91
  return formatPublicKey(publicKey, as) as never
91
92
  }
@@ -134,10 +135,9 @@ export function getSharedSecret<as extends 'Hex' | 'Bytes' = 'Hex'>(
134
135
  options: getSharedSecret.Options<as>,
135
136
  ): getSharedSecret.ReturnType<as> {
136
137
  const { as = 'Hex', privateKey, publicKey } = options
137
- const sharedSecret = noble_p256.getSharedSecret(
138
+ const sharedSecret = engine.getSharedSecret(
138
139
  Bytes.from(privateKey),
139
140
  PublicKey.toBytes(normalizePublicKey(publicKey)),
140
- true, // compressed
141
141
  )
142
142
  if (as === 'Hex') return Hex.fromBytes(sharedSecret) as never
143
143
  return sharedSecret as never
@@ -190,7 +190,7 @@ export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
190
190
  options: randomPrivateKey.Options<as> = {},
191
191
  ): randomPrivateKey.ReturnType<as> {
192
192
  const { as = 'Hex' } = options
193
- const bytes = noble_p256.utils.randomSecretKey()
193
+ const bytes = engine.randomSecretKey()
194
194
  if (as === 'Hex') return Hex.fromBytes(bytes) as never
195
195
  return bytes as never
196
196
  }
@@ -238,11 +238,8 @@ export function recoverPublicKey<
238
238
  >(options: recoverPublicKey.Options<as>): recoverPublicKey.ReturnType<as> {
239
239
  const { as = 'Object', payload, signature } = options
240
240
  const sigBytes = toRecoveredBytes(normalizeSignature<true>(signature))
241
- const point = noble_p256.Signature.fromBytes(
242
- sigBytes,
243
- 'recovered',
244
- ).recoverPublicKey(Bytes.from(payload))
245
- const publicKey = PublicKey.fromBytes(point.toBytes(false))
241
+ const bytes = engine.recoverPublicKey(sigBytes, Bytes.from(payload))
242
+ const publicKey = PublicKey.fromBytes(bytes)
246
243
  return formatPublicKey(publicKey, as) as never
247
244
  }
248
245
 
@@ -302,19 +299,13 @@ export function sign<as extends 'Hex' | 'Bytes' | 'Object' = 'Object'>(
302
299
  payload,
303
300
  privateKey,
304
301
  } = options
305
- const sigBytes = noble_p256.sign(
306
- Bytes.from(payload),
307
- Bytes.from(privateKey),
308
- {
309
- extraEntropy:
310
- typeof extraEntropy === 'boolean'
311
- ? extraEntropy
312
- : Bytes.from(extraEntropy),
313
- lowS: true,
314
- prehash: hash === true,
315
- format: 'recovered',
316
- },
317
- )
302
+ const sigBytes = engine.sign(Bytes.from(payload), Bytes.from(privateKey), {
303
+ extraEntropy:
304
+ typeof extraEntropy === 'boolean'
305
+ ? extraEntropy
306
+ : Bytes.from(extraEntropy),
307
+ prehash: hash === true,
308
+ })
318
309
  const signature = fromRecoveredBytes(sigBytes)
319
310
  return formatSignature(signature, as) as never
320
311
  }
@@ -381,11 +372,11 @@ export declare namespace sign {
381
372
  */
382
373
  export function verify(options: verify.Options): boolean {
383
374
  const { hash, payload, publicKey, signature } = options
384
- return noble_p256.verify(
375
+ return engine.verify(
385
376
  toCompactBytes(normalizeSignature(signature)),
386
377
  Bytes.from(payload),
387
378
  PublicKey.toBytes(normalizePublicKey(publicKey)),
388
- { lowS: true, prehash: hash === true },
379
+ { prehash: hash === true },
389
380
  )
390
381
  }
391
382
 
@@ -1,7 +1,5 @@
1
- // Track B / transactions: bench coverage for the RLP encode/decode hot
2
- // paths exercised by every TxEnvelope codec. The encoding thread owns
3
- // codec-only bench naming under `src/core/Rlp.bench.ts`; this file scopes
4
- // to transaction-shaped inputs to avoid collision.
1
+ // Scoped to transaction-shaped inputs, the RLP paths every TxEnvelope codec
2
+ // exercises. `src/core/Rlp.bench.ts` covers RLP on its own terms.
5
3
 
6
4
  import { bench, describe } from 'vp/test'
7
5
  import * as Hex from './Hex.js'
@@ -9,6 +9,7 @@ import {
9
9
  normalizePublicKey,
10
10
  normalizeSignature,
11
11
  } from './internal/cryptoIo.js'
12
+ import * as engine from './internal/secp256k1.js'
12
13
  import * as Entropy from './internal/entropy.js'
13
14
  import {
14
15
  fromRecoveredBytes,
@@ -89,7 +90,7 @@ export function getPublicKey<as extends 'Hex' | 'Bytes' | 'Object' = 'Object'>(
89
90
  options: getPublicKey.Options<as>,
90
91
  ): getPublicKey.ReturnType<as> {
91
92
  const { as = 'Object', privateKey } = options
92
- const bytes = secp256k1.getPublicKey(Bytes.from(privateKey), false)
93
+ const bytes = engine.getPublicKey(Bytes.from(privateKey))
93
94
  const publicKey = PublicKey.fromBytes(bytes)
94
95
  return formatPublicKey(publicKey, as) as never
95
96
  }
@@ -142,10 +143,9 @@ export function getSharedSecret<as extends 'Hex' | 'Bytes' = 'Hex'>(
142
143
  options: getSharedSecret.Options<as>,
143
144
  ): getSharedSecret.ReturnType<as> {
144
145
  const { as = 'Hex', privateKey, publicKey } = options
145
- const sharedSecret = secp256k1.getSharedSecret(
146
+ const sharedSecret = engine.getSharedSecret(
146
147
  Bytes.from(privateKey),
147
148
  PublicKey.toBytes(normalizePublicKey(publicKey)),
148
- true, // compressed
149
149
  )
150
150
  if (as === 'Hex') return Hex.fromBytes(sharedSecret) as never
151
151
  return sharedSecret as never
@@ -199,7 +199,7 @@ export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
199
199
  options: randomPrivateKey.Options<as> = {},
200
200
  ): randomPrivateKey.ReturnType<as> {
201
201
  const { as = 'Hex' } = options
202
- const bytes = secp256k1.utils.randomSecretKey()
202
+ const bytes = engine.randomSecretKey()
203
203
  if (as === 'Hex') return Hex.fromBytes(bytes) as never
204
204
  return bytes as never
205
205
  }
@@ -296,11 +296,8 @@ export function recoverPublicKey<
296
296
  >(options: recoverPublicKey.Options<as>): recoverPublicKey.ReturnType<as> {
297
297
  const { as = 'Object', payload, signature } = options
298
298
  const sigBytes = toRecoveredBytes(normalizeSignature<true>(signature))
299
- const point = secp256k1.Signature.fromBytes(
300
- sigBytes,
301
- 'recovered',
302
- ).recoverPublicKey(Bytes.from(payload))
303
- const publicKey = PublicKey.fromBytes(point.toBytes(false))
299
+ const bytes = engine.recoverPublicKey(sigBytes, Bytes.from(payload))
300
+ const publicKey = PublicKey.fromBytes(bytes)
304
301
  return formatPublicKey(publicKey, as) as never
305
302
  }
306
303
 
@@ -360,14 +357,12 @@ export function sign<as extends 'Hex' | 'Bytes' | 'Object' = 'Object'>(
360
357
  payload,
361
358
  privateKey,
362
359
  } = options
363
- const sigBytes = secp256k1.sign(Bytes.from(payload), Bytes.from(privateKey), {
360
+ const sigBytes = engine.sign(Bytes.from(payload), Bytes.from(privateKey), {
364
361
  extraEntropy:
365
362
  typeof extraEntropy === 'boolean'
366
363
  ? extraEntropy
367
364
  : Bytes.from(extraEntropy),
368
- lowS: true,
369
365
  prehash: hash === true,
370
- format: 'recovered',
371
366
  })
372
367
  const signature = fromRecoveredBytes(sigBytes)
373
368
  return formatSignature(signature, as) as never
@@ -462,11 +457,11 @@ export function verify(options: verify.Options): boolean {
462
457
  recoverAddress({ payload, signature: options.signature }),
463
458
  )
464
459
  const sig = normalizeSignature(options.signature)
465
- return secp256k1.verify(
460
+ return engine.verify(
466
461
  toCompactBytes(sig),
467
462
  Bytes.from(payload),
468
463
  PublicKey.toBytes(normalizePublicKey(options.publicKey)),
469
- { lowS: true, prehash: hash === true },
464
+ { prehash: hash === true },
470
465
  )
471
466
  }
472
467
 
@@ -1,8 +1,3 @@
1
- // Track B / transactions: bench coverage for the EIP-1559 envelope
2
- // serialize / deserialize / hash hot paths. Targets per
3
- // `tasks/perf-api-audit-transactions.md` Phase 1: ≥ 2× faster envelope
4
- // serialize and deserialize at the same input.
5
-
6
1
  import { bench, describe } from 'vp/test'
7
2
  import * as TxEnvelopeEip1559 from './TxEnvelopeEip1559.js'
8
3
 
@@ -1,4 +1,3 @@
1
- import { p256 } from '@noble/curves/nist.js'
2
1
  import * as Bytes from './Bytes.js'
3
2
  import * as Errors from './Errors.js'
4
3
  import * as Hex from './Hex.js'
@@ -7,12 +6,13 @@ import {
7
6
  normalizePublicKey,
8
7
  normalizeSignature,
9
8
  } from './internal/cryptoIo.js'
9
+ import { p256N } from './internal/curves.js'
10
10
  import type { Compute } from './internal/types.js'
11
11
  import * as PublicKey from './PublicKey.js'
12
12
  import type * as Signature from './Signature.js'
13
13
 
14
14
  /** secp256r1 / P-256 curve order. */
15
- const N = p256.Point.CURVE().n
15
+ const N = p256N
16
16
 
17
17
  /**
18
18
  * Generates an ECDSA P256 key pair that includes:
@@ -2,6 +2,7 @@ import { x25519 } from '@noble/curves/ed25519.js'
2
2
  import * as Bytes from './Bytes.js'
3
3
  import type * as Errors from './Errors.js'
4
4
  import * as Hex from './Hex.js'
5
+ import * as engine from './internal/x25519.js'
5
6
 
6
7
  /** Re-export of noble/curves X25519 utilities. */
7
8
  export const noble = x25519
@@ -77,7 +78,7 @@ export function getPublicKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
77
78
  ): getPublicKey.ReturnType<as> {
78
79
  const { as = 'Hex', privateKey } = options
79
80
  const privateKeyBytes = Bytes.from(privateKey)
80
- const publicKeyBytes = x25519.getPublicKey(privateKeyBytes)
81
+ const publicKeyBytes = engine.getPublicKey(privateKeyBytes)
81
82
  if (as === 'Hex') return Hex.fromBytes(publicKeyBytes) as never
82
83
  return publicKeyBytes as never
83
84
  }
@@ -130,7 +131,7 @@ export function getSharedSecret<as extends 'Hex' | 'Bytes' = 'Hex'>(
130
131
  const { as = 'Hex', privateKey, publicKey } = options
131
132
  const privateKeyBytes = Bytes.from(privateKey)
132
133
  const publicKeyBytes = Bytes.from(publicKey)
133
- const sharedSecretBytes = x25519.getSharedSecret(
134
+ const sharedSecretBytes = engine.getSharedSecret(
134
135
  privateKeyBytes,
135
136
  publicKeyBytes,
136
137
  )
@@ -182,7 +183,7 @@ export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
182
183
  options: randomPrivateKey.Options<as> = {},
183
184
  ): randomPrivateKey.ReturnType<as> {
184
185
  const { as = 'Hex' } = options
185
- const bytes = x25519.utils.randomSecretKey()
186
+ const bytes = engine.randomSecretKey()
186
187
  if (as === 'Hex') return Hex.fromBytes(bytes) as never
187
188
  return bytes as never
188
189
  }
@@ -3,8 +3,7 @@ import { AbiParameters, Bytes, Hex } from 'ox'
3
3
  import { describe, expect } from 'vp/test'
4
4
 
5
5
  import { arbitraryAbiCase } from '../../../test/fuzz/arbitraries/abi.js'
6
-
7
- const numRuns = Number(process.env.FC_NUM_RUNS) || 100
6
+ import { numRuns } from '../../../test/fuzz/numRuns.js'
8
7
 
9
8
  /**
10
9
  * Whitelist of error names ox is allowed to throw on adversarial-but-