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
package/src/core/Bls.ts CHANGED
@@ -4,6 +4,7 @@ import * as BlsPoint from './BlsPoint.js'
4
4
  import * as Bytes from './Bytes.js'
5
5
  import * as Errors from './Errors.js'
6
6
  import * as Hex from './Hex.js'
7
+ import * as engine from './internal/bls.js'
7
8
  import type { OneOf } from './internal/types.js'
8
9
 
9
10
  /**
@@ -116,12 +117,11 @@ export function aggregate(
116
117
  return point
117
118
  })
118
119
 
119
- const first = normalized[0]!
120
+ // A single point aggregates to itself. The engine is not consulted because
121
+ // there is no addition to perform, only the identity.
122
+ if (normalized.length === 1) return normalized[0]!
120
123
 
121
- // Fast path: a single point aggregates to itself.
122
- if (normalized.length === 1) return first
123
-
124
- const isG1 = typeof first.x === 'string'
124
+ const isG1 = typeof normalized[0]!.x === 'string'
125
125
  for (let i = 1; i < normalized.length; i++) {
126
126
  if ((typeof normalized[i]!.x === 'string') !== isG1)
127
127
  throw new Errors.BaseError(
@@ -130,13 +130,13 @@ export function aggregate(
130
130
  }
131
131
 
132
132
  const groupName = isG1 ? 'G1' : 'G2'
133
- const group = isG1 ? bls.G1 : bls.G2
134
- let acc = group.Point.ZERO
135
- for (let i = 0; i < normalized.length; i++) {
136
- const p = normalized[i]!
137
- acc = acc.add(BlsPoint.toNoblePoint(p as any, groupName) as any)
138
- }
139
- return BlsPoint.fromNoblePoint(acc, groupName) as BlsPoint.BlsPoint
133
+ const point = engine.aggregate(
134
+ normalized.map((point) =>
135
+ BlsPoint.toBytes(point as BlsPoint.G1 | BlsPoint.G2),
136
+ ),
137
+ groupName,
138
+ )
139
+ return BlsPoint.fromBytes(point, groupName) as BlsPoint.BlsPoint
140
140
  }
141
141
 
142
142
  export declare namespace aggregate {
@@ -349,14 +349,8 @@ export function getPublicKey<
349
349
  export function getPublicKey(options: getPublicKey.Options): unknown {
350
350
  const { as = 'Object', privateKey, size = 'short-key:long-sig' } = options
351
351
  const groupName = size === 'short-key:long-sig' ? 'G1' : 'G2'
352
- const group = groupName === 'G1' ? bls.G1 : bls.G2
353
- const point = group.Point.BASE.multiply(
354
- group.Point.Fn.fromBytes(Bytes.from(privateKey)),
355
- )
356
- const publicKey = BlsPoint.fromNoblePoint(
357
- point,
358
- groupName,
359
- ) as BlsPoint.BlsPoint
352
+ const point = engine.getPublicKey(Bytes.from(privateKey), groupName)
353
+ const publicKey = BlsPoint.fromBytes(point, groupName) as BlsPoint.BlsPoint
360
354
  return formatBlsPoint(publicKey, as)
361
355
  }
362
356
 
@@ -422,7 +416,7 @@ export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
422
416
  options: randomPrivateKey.Options<as> = {},
423
417
  ): randomPrivateKey.ReturnType<as> {
424
418
  const { as = 'Hex' } = options
425
- const bytes = bls.utils.randomSecretKey()
419
+ const bytes = engine.randomSecretKey()
426
420
  if (as === 'Hex') return Hex.fromBytes(bytes) as never
427
421
  return bytes as never
428
422
  }
@@ -507,18 +501,11 @@ export function sign(options: sign.Options): unknown {
507
501
 
508
502
  const signatureGroupName: 'G1' | 'G2' =
509
503
  size === 'short-key:long-sig' ? 'G2' : 'G1'
510
- const payloadGroup = signatureGroupName === 'G2' ? bls.G2 : bls.G1
511
- const payloadPoint = payloadGroup.hashToCurve(
512
- Bytes.from(payload),
513
- suite ? { DST: Bytes.fromString(suite) } : undefined,
514
- )
515
-
516
- const privateKeyGroup = size === 'short-key:long-sig' ? bls.G1 : bls.G2
517
- const signature = payloadPoint.multiply(
518
- privateKeyGroup.Point.Fn.fromBytes(Bytes.from(privateKey)),
519
- )
520
-
521
- const result = BlsPoint.fromNoblePoint(
504
+ const signature = engine.sign(Bytes.from(payload), Bytes.from(privateKey), {
505
+ dst: suite ? Bytes.fromString(suite) : undefined,
506
+ group: signatureGroupName,
507
+ })
508
+ const result = BlsPoint.fromBytes(
522
509
  signature,
523
510
  signatureGroupName,
524
511
  ) as BlsPoint.BlsPoint
@@ -674,51 +661,14 @@ export function verify(options: verify.Options): boolean {
674
661
  : normalizeBlsPoint(publicKeyRaw as Hex.Hex | Bytes.Bytes, publicKeyGroup)
675
662
  ) as BlsPoint.BlsPoint<any>
676
663
 
677
- const isShortSig = signatureGroup === 'G1'
678
-
679
- const group = isShortSig ? bls.G1 : bls.G2
680
- const payloadPoint = group.hashToCurve(
664
+ return engine.verify(
665
+ BlsPoint.toBytes(signature as BlsPoint.G1 | BlsPoint.G2),
681
666
  Bytes.from(payload),
682
- suite ? { DST: Bytes.fromString(suite) } : undefined,
683
- )
684
-
685
- const shortSigPairing = () =>
686
- bls.pairingBatch([
687
- {
688
- g1: payloadPoint as InstanceType<typeof bls.G1.Point>,
689
- g2: BlsPoint.toNoblePoint(publicKey as any, 'G2') as InstanceType<
690
- typeof bls.G2.Point
691
- >,
692
- },
693
- {
694
- g1: BlsPoint.toNoblePoint(signature as any, 'G1') as InstanceType<
695
- typeof bls.G1.Point
696
- >,
697
- g2: bls.G2.Point.BASE.negate(),
698
- },
699
- ])
700
-
701
- const longSigPairing = () =>
702
- bls.pairingBatch([
703
- {
704
- g1: (
705
- BlsPoint.toNoblePoint(publicKey as any, 'G1') as InstanceType<
706
- typeof bls.G1.Point
707
- >
708
- ).negate(),
709
- g2: payloadPoint as InstanceType<typeof bls.G2.Point>,
710
- },
711
- {
712
- g1: bls.G1.Point.BASE,
713
- g2: BlsPoint.toNoblePoint(signature as any, 'G2') as InstanceType<
714
- typeof bls.G2.Point
715
- >,
716
- },
717
- ])
718
-
719
- return bls.fields.Fp12.eql(
720
- isShortSig ? shortSigPairing() : longSigPairing(),
721
- bls.fields.Fp12.ONE,
667
+ BlsPoint.toBytes(publicKey as BlsPoint.G1 | BlsPoint.G2),
668
+ {
669
+ dst: suite ? Bytes.fromString(suite) : undefined,
670
+ signatureGroup,
671
+ },
722
672
  )
723
673
  }
724
674
 
@@ -2,6 +2,7 @@ import { ed25519 } 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/ed25519.js'
5
6
 
6
7
  /** Re-export of noble/curves Ed25519 utilities. */
7
8
  export const noble = ed25519
@@ -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 = ed25519.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
  }
@@ -122,7 +123,7 @@ export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
122
123
  options: randomPrivateKey.Options<as> = {},
123
124
  ): randomPrivateKey.ReturnType<as> {
124
125
  const { as = 'Hex' } = options
125
- const bytes = ed25519.utils.randomSecretKey()
126
+ const bytes = engine.randomSecretKey()
126
127
  if (as === 'Hex') return Hex.fromBytes(bytes) as never
127
128
  return bytes as never
128
129
  }
@@ -166,7 +167,7 @@ export function sign<as extends 'Hex' | 'Bytes' = 'Hex'>(
166
167
  const { as = 'Hex', payload, privateKey } = options
167
168
  const payloadBytes = Bytes.from(payload)
168
169
  const privateKeyBytes = Bytes.from(privateKey)
169
- const signatureBytes = ed25519.sign(payloadBytes, privateKeyBytes)
170
+ const signatureBytes = engine.sign(payloadBytes, privateKeyBytes)
170
171
  if (as === 'Hex') return Hex.fromBytes(signatureBytes) as never
171
172
  return signatureBytes as never
172
173
  }
@@ -227,7 +228,7 @@ export function verify(options: verify.Options): boolean {
227
228
  const payloadBytes = Bytes.from(payload)
228
229
  const publicKeyBytes = Bytes.from(publicKey)
229
230
  const signatureBytes = Bytes.from(signature)
230
- return ed25519.verify(signatureBytes, payloadBytes, publicKeyBytes)
231
+ return engine.verify(signatureBytes, payloadBytes, publicKeyBytes)
231
232
  }
232
233
 
233
234
  export declare namespace verify {
@@ -268,7 +269,7 @@ export function toX25519PublicKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
268
269
  ): toX25519PublicKey.ReturnType<as> {
269
270
  const { as = 'Hex', publicKey } = options
270
271
  const publicKeyBytes = Bytes.from(publicKey)
271
- const x25519PublicKeyBytes = ed25519.utils.toMontgomery(publicKeyBytes)
272
+ const x25519PublicKeyBytes = engine.toMontgomery(publicKeyBytes)
272
273
  if (as === 'Hex') return Hex.fromBytes(x25519PublicKeyBytes) as never
273
274
  return x25519PublicKeyBytes as never
274
275
  }
@@ -319,8 +320,7 @@ export function toX25519PrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
319
320
  ): toX25519PrivateKey.ReturnType<as> {
320
321
  const { as = 'Hex', privateKey } = options
321
322
  const privateKeyBytes = Bytes.from(privateKey)
322
- const x25519PrivateKeyBytes =
323
- ed25519.utils.toMontgomerySecret(privateKeyBytes)
323
+ const x25519PrivateKeyBytes = engine.toMontgomerySecret(privateKeyBytes)
324
324
  if (as === 'Hex') return Hex.fromBytes(x25519PrivateKeyBytes) as never
325
325
  return x25519PrivateKeyBytes as never
326
326
  }
@@ -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
  }