ox 1.0.5 → 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 (217) hide show
  1. package/CHANGELOG.md +50 -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/internal/mine.wasm.d.ts +2 -4
  114. package/dist/tempo/internal/mine.wasm.d.ts.map +1 -1
  115. package/dist/tempo/internal/mine.wasm.js +7 -12
  116. package/dist/tempo/internal/mine.wasm.js.map +1 -1
  117. package/dist/tempo/internal/virtualMasterPool.js +4 -1
  118. package/dist/tempo/internal/virtualMasterPool.js.map +1 -1
  119. package/dist/wasm/Engine.d.ts +62 -0
  120. package/dist/wasm/Engine.d.ts.map +1 -0
  121. package/dist/wasm/Engine.js +57 -0
  122. package/dist/wasm/Engine.js.map +1 -0
  123. package/dist/wasm/Hash.d.ts +49 -0
  124. package/dist/wasm/Hash.d.ts.map +1 -0
  125. package/dist/wasm/Hash.js +70 -0
  126. package/dist/wasm/Hash.js.map +1 -0
  127. package/dist/wasm/index.d.ts +46 -0
  128. package/dist/wasm/index.d.ts.map +1 -0
  129. package/dist/wasm/index.js +46 -0
  130. package/dist/wasm/index.js.map +1 -0
  131. package/dist/wasm/internal/hash.d.ts +9 -0
  132. package/dist/wasm/internal/hash.d.ts.map +1 -0
  133. package/dist/wasm/internal/hash.js +26 -0
  134. package/dist/wasm/internal/hash.js.map +1 -0
  135. package/dist/wasm/internal/hashes.wasm.d.ts +5 -0
  136. package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -0
  137. package/dist/wasm/internal/hashes.wasm.js +12 -0
  138. package/dist/wasm/internal/hashes.wasm.js.map +1 -0
  139. package/dist/wasm/internal/instantiate.d.ts +56 -0
  140. package/dist/wasm/internal/instantiate.d.ts.map +1 -0
  141. package/dist/wasm/internal/instantiate.js +92 -0
  142. package/dist/wasm/internal/instantiate.js.map +1 -0
  143. package/dist/zod/TypedData.d.ts +12 -12
  144. package/package.json +36 -1
  145. package/src/core/Base64.ts +19 -166
  146. package/src/core/BinaryStateTree.ts +2 -3
  147. package/src/core/Bls.ts +27 -77
  148. package/src/core/Ed25519.ts +7 -7
  149. package/src/core/Engine.ts +235 -0
  150. package/src/core/Hash.ts +9 -12
  151. package/src/core/Keystore.ts +17 -17
  152. package/src/core/Mnemonic.ts +3 -6
  153. package/src/core/P256.ts +15 -24
  154. package/src/core/Rlp_tx.bench.ts +2 -4
  155. package/src/core/Secp256k1.ts +9 -14
  156. package/src/core/TxEnvelopeEip1559.bench.ts +0 -5
  157. package/src/core/WebCryptoP256.ts +2 -2
  158. package/src/core/X25519.ts +4 -3
  159. package/src/core/_test/AbiParameters.adversarial.fuzz.ts +1 -2
  160. package/src/core/_test/AbiParameters.fuzz.ts +1 -2
  161. package/src/core/_test/Base.fuzz.ts +1 -2
  162. package/src/core/_test/Cbor.fuzz.ts +1 -2
  163. package/src/core/_test/Engine.fuzz.ts +293 -0
  164. package/src/core/_test/Engine.test-d.ts +84 -0
  165. package/src/core/_test/Engine.test.ts +523 -0
  166. package/src/core/_test/Hash.vectors.test.ts +56 -0
  167. package/src/core/_test/Hex.fuzz.ts +1 -2
  168. package/src/core/_test/Rlp.fuzz.ts +1 -2
  169. package/src/core/_test/Signature.fuzz.ts +1 -2
  170. package/src/core/_test/curves.test.ts +7 -0
  171. package/src/core/_test/index.test.ts +1 -0
  172. package/src/core/internal/bls.ts +121 -0
  173. package/src/core/internal/codec/_test/base64.conformance.ts +156 -0
  174. package/src/core/internal/codec/_test/hex.conformance.ts +204 -0
  175. package/src/core/internal/codec/_test/hex.fuzz.ts +234 -0
  176. package/src/core/internal/codec/_test/hex.test.ts +124 -0
  177. package/src/core/internal/codec/base64.ts +222 -0
  178. package/src/core/internal/codec/hex.ts +115 -34
  179. package/src/core/internal/curves.ts +18 -0
  180. package/src/core/internal/ed25519.ts +64 -0
  181. package/src/core/internal/engine.ts +410 -0
  182. package/src/core/internal/hash.ts +48 -0
  183. package/src/core/internal/keystore.ts +107 -0
  184. package/src/core/internal/mnemonic.ts +18 -0
  185. package/src/core/internal/p256.ts +91 -0
  186. package/src/core/internal/secp256k1.ts +91 -0
  187. package/src/core/internal/x25519.ts +40 -0
  188. package/src/index.docs.ts +2 -0
  189. package/src/index.ts +36 -0
  190. package/src/node/Engine.ts +69 -0
  191. package/src/node/Hash.ts +56 -0
  192. package/src/node/_test/Engine.test.ts +62 -0
  193. package/src/node/_test/Hash.test-d.ts +26 -0
  194. package/src/node/_test/Hash.test.ts +102 -0
  195. package/src/node/index.ts +40 -0
  196. package/src/tempo/VirtualMaster.test.ts +75 -0
  197. package/src/tempo/VirtualMaster.ts +28 -6
  198. package/src/tempo/internal/mine.wasm.ts +7 -13
  199. package/src/tempo/internal/virtualMasterPool.ts +4 -1
  200. package/src/tsconfig.json +2 -1
  201. package/src/version.ts +1 -1
  202. package/src/wasm/Engine.ts +76 -0
  203. package/src/wasm/Hash.bench.ts +60 -0
  204. package/src/wasm/Hash.ts +109 -0
  205. package/src/wasm/_test/Engine.test.ts +62 -0
  206. package/src/wasm/_test/Hash.browser.test.ts +50 -0
  207. package/src/wasm/_test/Hash.fuzz.ts +188 -0
  208. package/src/wasm/_test/Hash.test-d.ts +28 -0
  209. package/src/wasm/_test/Hash.test.ts +211 -0
  210. package/src/wasm/_test/Hash.vectors.test.ts +117 -0
  211. package/src/wasm/_test/Runtime.test.ts +21 -0
  212. package/src/wasm/_test/runtime.wasm.ts +11 -0
  213. package/src/wasm/index.ts +47 -0
  214. package/src/wasm/internal/hash.ts +50 -0
  215. package/src/wasm/internal/hashes.wasm.ts +14 -0
  216. package/src/wasm/internal/instantiate.ts +135 -0
  217. package/src/tempo/internal/mine.c +0 -182
@@ -0,0 +1,48 @@
1
+ import { blake3 as noble_blake3 } from '@noble/hashes/blake3.js'
2
+ import { hmac } from '@noble/hashes/hmac.js'
3
+ import { ripemd160 as noble_ripemd160 } from '@noble/hashes/legacy.js'
4
+ import { sha256 as noble_sha256 } from '@noble/hashes/sha2.js'
5
+ import { keccak_256 as noble_keccak256 } from '@noble/hashes/sha3.js'
6
+ import { type Complete, type Hash, overrides } from './engine.js'
7
+
8
+ /**
9
+ * Resolvers for the `Hash` slot, and ox's defaults for it, backed by
10
+ * `@noble/hashes`.
11
+ *
12
+ * Declaring the defaults against the slot contract is what keeps them honest: a
13
+ * default that goes missing, or whose signature drifts, fails to compile rather
14
+ * than failing at the call site.
15
+ */
16
+
17
+ const blake3Default: Complete<Hash>['blake3'] = (input) => noble_blake3(input)
18
+
19
+ const hmacSha256Default: Complete<Hash>['hmacSha256'] = (key, message) =>
20
+ hmac(noble_sha256, key, message)
21
+
22
+ const keccak256Default: Complete<Hash>['keccak256'] = (input) =>
23
+ noble_keccak256(input)
24
+
25
+ const ripemd160Default: Complete<Hash>['ripemd160'] = (input) =>
26
+ noble_ripemd160(input)
27
+
28
+ const sha256Default: Complete<Hash>['sha256'] = (input) => noble_sha256(input)
29
+
30
+ /** @internal */
31
+ export const blake3: Complete<Hash>['blake3'] = (input) =>
32
+ (overrides.Hash?.blake3 ?? blake3Default)(input)
33
+
34
+ /** @internal */
35
+ export const hmacSha256: Complete<Hash>['hmacSha256'] = (key, message) =>
36
+ (overrides.Hash?.hmacSha256 ?? hmacSha256Default)(key, message)
37
+
38
+ /** @internal */
39
+ export const keccak256: Complete<Hash>['keccak256'] = (input) =>
40
+ (overrides.Hash?.keccak256 ?? keccak256Default)(input)
41
+
42
+ /** @internal */
43
+ export const ripemd160: Complete<Hash>['ripemd160'] = (input) =>
44
+ (overrides.Hash?.ripemd160 ?? ripemd160Default)(input)
45
+
46
+ /** @internal */
47
+ export const sha256: Complete<Hash>['sha256'] = (input) =>
48
+ (overrides.Hash?.sha256 ?? sha256Default)(input)
@@ -0,0 +1,107 @@
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
+ import { type Complete, type Keystore, overrides } from './engine.js'
12
+
13
+ /**
14
+ * Resolvers for the `Keystore` slot, and ox's defaults for it, backed by
15
+ * `@noble/ciphers` and `@noble/hashes`.
16
+ *
17
+ * Declaring the defaults against the slot contract is what keeps them honest: a
18
+ * default that goes missing, or whose signature drifts, fails to compile rather
19
+ * than failing at the call site.
20
+ */
21
+
22
+ const aesCtrDecryptDefault: Complete<Keystore>['aesCtrDecrypt'] = (
23
+ key,
24
+ iv,
25
+ data,
26
+ ) => ctr(key, iv).decrypt(data)
27
+
28
+ const aesCtrEncryptDefault: Complete<Keystore>['aesCtrEncrypt'] = (
29
+ key,
30
+ iv,
31
+ data,
32
+ ) => ctr(key, iv).encrypt(data)
33
+
34
+ const pbkdf2Sha256Default: Complete<Keystore>['pbkdf2Sha256'] = (
35
+ password,
36
+ salt,
37
+ options,
38
+ ) => pbkdf2_noble(sha256, password, salt, options)
39
+
40
+ const pbkdf2Sha256AsyncDefault: Complete<Keystore>['pbkdf2Sha256Async'] = (
41
+ password,
42
+ salt,
43
+ options,
44
+ ) => pbkdf2Async_noble(sha256, password, salt, options)
45
+
46
+ const scryptDefault: Complete<Keystore>['scrypt'] = (password, salt, options) =>
47
+ scrypt_noble(password, salt, options)
48
+
49
+ const scryptAsyncDefault: Complete<Keystore>['scryptAsync'] = (
50
+ password,
51
+ salt,
52
+ options,
53
+ ) => scryptAsync_noble(password, salt, options)
54
+
55
+ /** @internal */
56
+ export const aesCtrDecrypt: Complete<Keystore>['aesCtrDecrypt'] = (
57
+ key,
58
+ iv,
59
+ data,
60
+ ) => (overrides.Keystore?.aesCtrDecrypt ?? aesCtrDecryptDefault)(key, iv, data)
61
+
62
+ /** @internal */
63
+ export const aesCtrEncrypt: Complete<Keystore>['aesCtrEncrypt'] = (
64
+ key,
65
+ iv,
66
+ data,
67
+ ) => (overrides.Keystore?.aesCtrEncrypt ?? aesCtrEncryptDefault)(key, iv, data)
68
+
69
+ /** @internal */
70
+ export const pbkdf2Sha256: Complete<Keystore>['pbkdf2Sha256'] = (
71
+ password,
72
+ salt,
73
+ options,
74
+ ) =>
75
+ (overrides.Keystore?.pbkdf2Sha256 ?? pbkdf2Sha256Default)(
76
+ password,
77
+ salt,
78
+ options,
79
+ )
80
+
81
+ /** @internal */
82
+ export const pbkdf2Sha256Async: Complete<Keystore>['pbkdf2Sha256Async'] = (
83
+ password,
84
+ salt,
85
+ options,
86
+ ) =>
87
+ (overrides.Keystore?.pbkdf2Sha256Async ?? pbkdf2Sha256AsyncDefault)(
88
+ password,
89
+ salt,
90
+ options,
91
+ )
92
+
93
+ /** @internal */
94
+ export const scrypt: Complete<Keystore>['scrypt'] = (password, salt, options) =>
95
+ (overrides.Keystore?.scrypt ?? scryptDefault)(password, salt, options)
96
+
97
+ /** @internal */
98
+ export const scryptAsync: Complete<Keystore>['scryptAsync'] = (
99
+ password,
100
+ salt,
101
+ options,
102
+ ) =>
103
+ (overrides.Keystore?.scryptAsync ?? scryptAsyncDefault)(
104
+ password,
105
+ salt,
106
+ options,
107
+ )
@@ -0,0 +1,18 @@
1
+ import { mnemonicToSeedSync } from '@scure/bip39'
2
+ import { type Complete, type Mnemonic, overrides } from './engine.js'
3
+
4
+ /**
5
+ * Resolvers for the `Mnemonic` slot, and ox's defaults for it, backed by
6
+ * `@scure/bip39`.
7
+ *
8
+ * Declaring the defaults against the slot contract is what keeps them honest: a
9
+ * default that goes missing, or whose signature drifts, fails to compile rather
10
+ * than failing at the call site.
11
+ */
12
+
13
+ const toSeedDefault: Complete<Mnemonic>['toSeed'] = (mnemonic, passphrase) =>
14
+ mnemonicToSeedSync(mnemonic, passphrase)
15
+
16
+ /** @internal */
17
+ export const toSeed: Complete<Mnemonic>['toSeed'] = (mnemonic, passphrase) =>
18
+ (overrides.Mnemonic?.toSeed ?? toSeedDefault)(mnemonic, passphrase)
@@ -0,0 +1,91 @@
1
+ import { p256 } from '@noble/curves/nist.js'
2
+ import { type Complete, type Ecdsa, overrides } from './engine.js'
3
+
4
+ /**
5
+ * Resolvers for the `P256` slot, and ox's defaults for it, backed by
6
+ * `@noble/curves`.
7
+ *
8
+ * Declaring the defaults against the slot contract is what keeps them honest: a
9
+ * default that goes missing, or whose signature drifts, fails to compile rather
10
+ * than failing at the call site. `lowS` and the recovered signature format are
11
+ * pinned here rather than in the contract, so an engine cannot opt out of them.
12
+ */
13
+
14
+ const getPublicKeyDefault: Complete<Ecdsa>['getPublicKey'] = (privateKey) =>
15
+ p256.getPublicKey(privateKey, false)
16
+
17
+ const getSharedSecretDefault: Complete<Ecdsa>['getSharedSecret'] = (
18
+ privateKey,
19
+ publicKey,
20
+ ) => p256.getSharedSecret(privateKey, publicKey, true)
21
+
22
+ const randomSecretKeyDefault: Complete<Ecdsa>['randomSecretKey'] = () =>
23
+ p256.utils.randomSecretKey()
24
+
25
+ const recoverPublicKeyDefault: Complete<Ecdsa>['recoverPublicKey'] = (
26
+ signature,
27
+ payload,
28
+ ) =>
29
+ p256.Signature.fromBytes(signature, 'recovered')
30
+ .recoverPublicKey(payload)
31
+ .toBytes(false)
32
+
33
+ const signDefault: Complete<Ecdsa>['sign'] = (payload, privateKey, options) =>
34
+ p256.sign(payload, privateKey, {
35
+ ...options,
36
+ format: 'recovered',
37
+ lowS: true,
38
+ })
39
+
40
+ const verifyDefault: Complete<Ecdsa>['verify'] = (
41
+ signature,
42
+ payload,
43
+ publicKey,
44
+ options,
45
+ ) => p256.verify(signature, payload, publicKey, { ...options, lowS: true })
46
+
47
+ /** @internal */
48
+ export const getPublicKey: Complete<Ecdsa>['getPublicKey'] = (privateKey) =>
49
+ (overrides.P256?.getPublicKey ?? getPublicKeyDefault)(privateKey)
50
+
51
+ /** @internal */
52
+ export const getSharedSecret: Complete<Ecdsa>['getSharedSecret'] = (
53
+ privateKey,
54
+ publicKey,
55
+ ) =>
56
+ (overrides.P256?.getSharedSecret ?? getSharedSecretDefault)(
57
+ privateKey,
58
+ publicKey,
59
+ )
60
+
61
+ /** @internal */
62
+ export const randomSecretKey: Complete<Ecdsa>['randomSecretKey'] = () =>
63
+ (overrides.P256?.randomSecretKey ?? randomSecretKeyDefault)()
64
+
65
+ /** @internal */
66
+ export const recoverPublicKey: Complete<Ecdsa>['recoverPublicKey'] = (
67
+ signature,
68
+ payload,
69
+ ) =>
70
+ (overrides.P256?.recoverPublicKey ?? recoverPublicKeyDefault)(
71
+ signature,
72
+ payload,
73
+ )
74
+
75
+ /** @internal */
76
+ export const sign: Complete<Ecdsa>['sign'] = (payload, privateKey, options) =>
77
+ (overrides.P256?.sign ?? signDefault)(payload, privateKey, options)
78
+
79
+ /** @internal */
80
+ export const verify: Complete<Ecdsa>['verify'] = (
81
+ signature,
82
+ payload,
83
+ publicKey,
84
+ options,
85
+ ) =>
86
+ (overrides.P256?.verify ?? verifyDefault)(
87
+ signature,
88
+ payload,
89
+ publicKey,
90
+ options,
91
+ )
@@ -0,0 +1,91 @@
1
+ import { secp256k1 } from '@noble/curves/secp256k1.js'
2
+ import { type Complete, type Ecdsa, overrides } from './engine.js'
3
+
4
+ /**
5
+ * Resolvers for the `Secp256k1` slot, and ox's defaults for it, backed by
6
+ * `@noble/curves`.
7
+ *
8
+ * Declaring the defaults against the slot contract is what keeps them honest: a
9
+ * default that goes missing, or whose signature drifts, fails to compile rather
10
+ * than failing at the call site. `lowS` and the recovered signature format are
11
+ * pinned here rather than in the contract, so an engine cannot opt out of them.
12
+ */
13
+
14
+ const getPublicKeyDefault: Complete<Ecdsa>['getPublicKey'] = (privateKey) =>
15
+ secp256k1.getPublicKey(privateKey, false)
16
+
17
+ const getSharedSecretDefault: Complete<Ecdsa>['getSharedSecret'] = (
18
+ privateKey,
19
+ publicKey,
20
+ ) => secp256k1.getSharedSecret(privateKey, publicKey, true)
21
+
22
+ const randomSecretKeyDefault: Complete<Ecdsa>['randomSecretKey'] = () =>
23
+ secp256k1.utils.randomSecretKey()
24
+
25
+ const recoverPublicKeyDefault: Complete<Ecdsa>['recoverPublicKey'] = (
26
+ signature,
27
+ payload,
28
+ ) =>
29
+ secp256k1.Signature.fromBytes(signature, 'recovered')
30
+ .recoverPublicKey(payload)
31
+ .toBytes(false)
32
+
33
+ const signDefault: Complete<Ecdsa>['sign'] = (payload, privateKey, options) =>
34
+ secp256k1.sign(payload, privateKey, {
35
+ ...options,
36
+ format: 'recovered',
37
+ lowS: true,
38
+ })
39
+
40
+ const verifyDefault: Complete<Ecdsa>['verify'] = (
41
+ signature,
42
+ payload,
43
+ publicKey,
44
+ options,
45
+ ) => secp256k1.verify(signature, payload, publicKey, { ...options, lowS: true })
46
+
47
+ /** @internal */
48
+ export const getPublicKey: Complete<Ecdsa>['getPublicKey'] = (privateKey) =>
49
+ (overrides.Secp256k1?.getPublicKey ?? getPublicKeyDefault)(privateKey)
50
+
51
+ /** @internal */
52
+ export const getSharedSecret: Complete<Ecdsa>['getSharedSecret'] = (
53
+ privateKey,
54
+ publicKey,
55
+ ) =>
56
+ (overrides.Secp256k1?.getSharedSecret ?? getSharedSecretDefault)(
57
+ privateKey,
58
+ publicKey,
59
+ )
60
+
61
+ /** @internal */
62
+ export const randomSecretKey: Complete<Ecdsa>['randomSecretKey'] = () =>
63
+ (overrides.Secp256k1?.randomSecretKey ?? randomSecretKeyDefault)()
64
+
65
+ /** @internal */
66
+ export const recoverPublicKey: Complete<Ecdsa>['recoverPublicKey'] = (
67
+ signature,
68
+ payload,
69
+ ) =>
70
+ (overrides.Secp256k1?.recoverPublicKey ?? recoverPublicKeyDefault)(
71
+ signature,
72
+ payload,
73
+ )
74
+
75
+ /** @internal */
76
+ export const sign: Complete<Ecdsa>['sign'] = (payload, privateKey, options) =>
77
+ (overrides.Secp256k1?.sign ?? signDefault)(payload, privateKey, options)
78
+
79
+ /** @internal */
80
+ export const verify: Complete<Ecdsa>['verify'] = (
81
+ signature,
82
+ payload,
83
+ publicKey,
84
+ options,
85
+ ) =>
86
+ (overrides.Secp256k1?.verify ?? verifyDefault)(
87
+ signature,
88
+ payload,
89
+ publicKey,
90
+ options,
91
+ )
@@ -0,0 +1,40 @@
1
+ import { x25519 } from '@noble/curves/ed25519.js'
2
+ import { type Complete, type Ecdh, overrides } from './engine.js'
3
+
4
+ /**
5
+ * Resolvers for the `X25519` slot, and ox's defaults for it, backed by
6
+ * `@noble/curves`.
7
+ *
8
+ * Declaring the defaults against the slot contract is what keeps them honest: a
9
+ * default that goes missing, or whose signature drifts, fails to compile rather
10
+ * than failing at the call site.
11
+ */
12
+
13
+ const getPublicKeyDefault: Complete<Ecdh>['getPublicKey'] = (privateKey) =>
14
+ x25519.getPublicKey(privateKey)
15
+
16
+ const getSharedSecretDefault: Complete<Ecdh>['getSharedSecret'] = (
17
+ privateKey,
18
+ publicKey,
19
+ ) => x25519.getSharedSecret(privateKey, publicKey)
20
+
21
+ const randomSecretKeyDefault: Complete<Ecdh>['randomSecretKey'] = () =>
22
+ x25519.utils.randomSecretKey()
23
+
24
+ /** @internal */
25
+ export const getPublicKey: Complete<Ecdh>['getPublicKey'] = (privateKey) =>
26
+ (overrides.X25519?.getPublicKey ?? getPublicKeyDefault)(privateKey)
27
+
28
+ /** @internal */
29
+ export const getSharedSecret: Complete<Ecdh>['getSharedSecret'] = (
30
+ privateKey,
31
+ publicKey,
32
+ ) =>
33
+ (overrides.X25519?.getSharedSecret ?? getSharedSecretDefault)(
34
+ privateKey,
35
+ publicKey,
36
+ )
37
+
38
+ /** @internal */
39
+ export const randomSecretKey: Complete<Ecdh>['randomSecretKey'] = () =>
40
+ (overrides.X25519?.randomSecretKey ?? randomSecretKeyDefault)()
package/src/index.docs.ts CHANGED
@@ -7,6 +7,8 @@ export * from './erc6492/index.js'
7
7
  export * from './erc7821/index.js'
8
8
  export * from './erc8010/index.js'
9
9
  export * from './erc8021/index.js'
10
+ export * from './node/index.js'
10
11
  export * from './webauthn/index.js'
11
12
  export * from './tempo/index.js'
13
+ export * from './wasm/index.js'
12
14
  export * from './zod/index.js'
package/src/index.ts CHANGED
@@ -1520,6 +1520,42 @@ export * as CoseKey from './core/CoseKey.js'
1520
1520
  */
1521
1521
  export * as Ed25519 from './core/Ed25519.js'
1522
1522
 
1523
+ /**
1524
+ * Functions for delegating ox's cryptography to a different implementation.
1525
+ *
1526
+ * Ox uses [`@noble`](https://github.com/paulmillr/noble-hashes) and
1527
+ * [`@scure`](https://github.com/paulmillr/scure-bip32) by default. An engine
1528
+ * replaces those implementations with your own — for example a WASM build of an
1529
+ * audited C library.
1530
+ *
1531
+ * @example
1532
+ * ### Installing an Engine
1533
+ *
1534
+ * Engine slots are named after ox modules, and everything is optional: any slot
1535
+ * or function you leave out keeps using ox's default implementation.
1536
+ *
1537
+ * ```ts twoslash
1538
+ * // @noErrors
1539
+ * import { Engine } from 'ox/wasm'
1540
+ *
1541
+ * await Engine.load()
1542
+ * ```
1543
+ *
1544
+ * @example
1545
+ * ### Overriding a Single Primitive
1546
+ *
1547
+ * ```ts twoslash
1548
+ * import { Engine } from 'ox'
1549
+ *
1550
+ * Engine.set({
1551
+ * Hash: { keccak256: () => new Uint8Array(32) }
1552
+ * })
1553
+ * ```
1554
+ *
1555
+ * @category Crypto
1556
+ */
1557
+ export * as Engine from './core/Engine.js'
1558
+
1523
1559
  /**
1524
1560
  * Utility functions for working with ENS names.
1525
1561
  *
@@ -0,0 +1,69 @@
1
+ import * as CoreEngine from '../core/Engine.js'
2
+ import type * as Errors from '../core/Errors.js'
3
+ import * as Hash from './Hash.js'
4
+
5
+ /**
6
+ * Creates and installs every Node.js implementation this entrypoint provides.
7
+ *
8
+ * The function is asynchronous to match the `ox/wasm` entrypoint, even though
9
+ * Node's built-in cryptography needs no compilation. Call it once during
10
+ * startup, before any cryptographic operation.
11
+ *
12
+ * @example
13
+ * ```ts twoslash
14
+ * // @noErrors
15
+ * import { Hash } from 'ox'
16
+ * import { Engine } from 'ox/node'
17
+ *
18
+ * await Engine.load()
19
+ *
20
+ * Hash.sha256('0xdeadbeef')
21
+ * ```
22
+ *
23
+ * @returns The engine that was installed.
24
+ */
25
+ export async function load(): Promise<load.ReturnType> {
26
+ const engine = await create()
27
+ CoreEngine.set(engine)
28
+ return engine
29
+ }
30
+
31
+ export declare namespace load {
32
+ type ReturnType = create.ReturnType
33
+
34
+ type ErrorType =
35
+ | create.ErrorType
36
+ | CoreEngine.set.ErrorType
37
+ | Errors.GlobalErrorType
38
+ }
39
+
40
+ /**
41
+ * Creates every Node.js implementation this entrypoint provides, without
42
+ * installing it.
43
+ *
44
+ * Reach for this where an engine has to exist as a value, such as a benchmark
45
+ * or an [`Engine.with`](/api/Engine/with) scope.
46
+ *
47
+ * @example
48
+ * ```ts twoslash
49
+ * // @noErrors
50
+ * import { Engine, Hash } from 'ox'
51
+ * import { Engine as NodeEngine } from 'ox/node'
52
+ *
53
+ * const node = await NodeEngine.create()
54
+ *
55
+ * Engine.with(node, () => Hash.sha256('0xdeadbeef'))
56
+ * ```
57
+ *
58
+ * @returns An engine, ready to install.
59
+ */
60
+ export async function create(): Promise<create.ReturnType> {
61
+ return { ...(await Hash.create()) }
62
+ }
63
+
64
+ export declare namespace create {
65
+ /** Every slot this entrypoint supplies, each with its primitives present. */
66
+ type ReturnType = Hash.create.ReturnType
67
+
68
+ type ErrorType = Hash.create.ErrorType | Errors.GlobalErrorType
69
+ }
@@ -0,0 +1,56 @@
1
+ import * as crypto from 'node:crypto'
2
+ import type * as Engine from '../core/Engine.js'
3
+ import type * as Errors from '../core/Errors.js'
4
+
5
+ /**
6
+ * Creates Node.js implementations of the [`Hash`](/api/Hash) primitives, without
7
+ * installing them.
8
+ *
9
+ * Most callers want {@link ox#Engine.load} instead, which installs every
10
+ * implementation this entrypoint provides. Reach for this to take the `Hash`
11
+ * slot on its own, or to hold the implementation without touching the
12
+ * installed engine.
13
+ *
14
+ * Node's `sha3-256` is not Ethereum Keccak256, so this engine deliberately
15
+ * omits `keccak256`. Any earlier override remains installed; otherwise Ox uses
16
+ * its default implementation.
17
+ *
18
+ * @example
19
+ * ```ts twoslash
20
+ * // @noErrors
21
+ * import { Engine, Hash } from 'ox'
22
+ * import * as NodeHash from 'ox/node/Hash'
23
+ *
24
+ * Engine.set(await NodeHash.create())
25
+ *
26
+ * Hash.sha256('0xdeadbeef')
27
+ * ```
28
+ *
29
+ * @returns An engine supplying the `Hash` slot.
30
+ */
31
+ export function create(): Promise<create.ReturnType> {
32
+ return Promise.resolve({
33
+ Hash: {
34
+ hmacSha256: (key, message) =>
35
+ new Uint8Array(
36
+ crypto.createHmac('sha256', key).update(message).digest(),
37
+ ),
38
+ ripemd160: (input) =>
39
+ new Uint8Array(crypto.hash('ripemd160', input, 'buffer')),
40
+ sha256: (input) => new Uint8Array(crypto.hash('sha256', input, 'buffer')),
41
+ },
42
+ })
43
+ }
44
+
45
+ export declare namespace create {
46
+ /** The `Hash` slot, carrying every primitive this module implements. */
47
+ type ReturnType = {
48
+ Hash: {
49
+ [key in 'hmacSha256' | 'ripemd160' | 'sha256']-?: NonNullable<
50
+ Engine.Hash[key]
51
+ >
52
+ }
53
+ }
54
+
55
+ type ErrorType = Errors.GlobalErrorType
56
+ }
@@ -0,0 +1,62 @@
1
+ import { Engine as CoreEngine, Hash } from 'ox'
2
+ import { Engine } from 'ox/node'
3
+ import { describe, expect, test } from 'vp/test'
4
+
5
+ describe('create', () => {
6
+ test('behavior: does not install', async () => {
7
+ const engine = await Engine.create()
8
+
9
+ expect(Object.keys(engine)).toMatchInlineSnapshot(`
10
+ [
11
+ "Hash",
12
+ ]
13
+ `)
14
+ expect(CoreEngine.get()).toMatchInlineSnapshot('{}')
15
+ })
16
+
17
+ test('behavior: installs for the duration of a call', async () => {
18
+ const node = await Engine.create()
19
+ const digest = CoreEngine.with(node, () => Hash.sha256('0xdeadbeef'))
20
+
21
+ expect(digest).toMatchInlineSnapshot(
22
+ `"0x5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953"`,
23
+ )
24
+ expect(CoreEngine.get()).toMatchInlineSnapshot('{}')
25
+ })
26
+ })
27
+
28
+ describe('load', () => {
29
+ test('behavior: installs and returns what it installed', async () => {
30
+ const engine = await Engine.load()
31
+
32
+ expect(Object.keys(CoreEngine.get())).toEqual(Object.keys(engine))
33
+ expect(Object.keys(CoreEngine.get().Hash ?? {}).sort())
34
+ .toMatchInlineSnapshot(`
35
+ [
36
+ "hmacSha256",
37
+ "ripemd160",
38
+ "sha256",
39
+ ]
40
+ `)
41
+ })
42
+
43
+ test('behavior: leaves unsupported primitives on the default', async () => {
44
+ await Engine.load()
45
+
46
+ expect(Hash.keccak256('0xdeadbeef')).toMatchInlineSnapshot(
47
+ `"0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1"`,
48
+ )
49
+ })
50
+
51
+ test('behavior: merges with later engines', async () => {
52
+ await Engine.load()
53
+ CoreEngine.set({ Mnemonic: { toSeed: () => new Uint8Array(64) } })
54
+
55
+ expect(Object.keys(CoreEngine.get()).sort()).toMatchInlineSnapshot(`
56
+ [
57
+ "Hash",
58
+ "Mnemonic",
59
+ ]
60
+ `)
61
+ })
62
+ })
@@ -0,0 +1,26 @@
1
+ import type { Engine } from 'ox'
2
+ import { Hash as NodeHash } from 'ox/node'
3
+ import { expectTypeOf, test } from 'vp/test'
4
+
5
+ type Created = Awaited<ReturnType<typeof NodeHash.create>>
6
+
7
+ test('every implemented primitive is present', () => {
8
+ expectTypeOf<Created['Hash']['hmacSha256']>().toEqualTypeOf<
9
+ (key: Uint8Array, message: Uint8Array) => Uint8Array
10
+ >()
11
+ expectTypeOf<Created['Hash']['ripemd160']>().toEqualTypeOf<
12
+ (input: Uint8Array) => Uint8Array
13
+ >()
14
+ expectTypeOf<Created['Hash']['sha256']>().toEqualTypeOf<
15
+ (input: Uint8Array) => Uint8Array
16
+ >()
17
+ })
18
+
19
+ test('unsupported primitives are absent', () => {
20
+ expectTypeOf<Created['Hash']>().not.toHaveProperty('blake3')
21
+ expectTypeOf<Created['Hash']>().not.toHaveProperty('keccak256')
22
+ })
23
+
24
+ test('the result is still an engine', () => {
25
+ expectTypeOf<Created>().toExtend<Engine.Engine>()
26
+ })