ox 1.1.2 → 1.3.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 (296) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/core/AbiFunction.d.ts +1 -1
  3. package/dist/core/AbiFunction.d.ts.map +1 -1
  4. package/dist/core/AbiFunction.js +6 -2
  5. package/dist/core/AbiFunction.js.map +1 -1
  6. package/dist/core/AbiParameters.d.ts +1 -1
  7. package/dist/core/AbiParameters.d.ts.map +1 -1
  8. package/dist/core/AbiParameters.js +1 -13
  9. package/dist/core/AbiParameters.js.map +1 -1
  10. package/dist/core/AesGcm.d.ts +36 -1
  11. package/dist/core/AesGcm.d.ts.map +1 -1
  12. package/dist/core/AesGcm.js +44 -0
  13. package/dist/core/AesGcm.js.map +1 -1
  14. package/dist/core/Ed25519.d.ts +46 -1
  15. package/dist/core/Ed25519.d.ts.map +1 -1
  16. package/dist/core/Ed25519.js +43 -0
  17. package/dist/core/Ed25519.js.map +1 -1
  18. package/dist/core/Engine.d.ts +1 -1
  19. package/dist/core/Engine.d.ts.map +1 -1
  20. package/dist/core/Engine.js.map +1 -1
  21. package/dist/core/Hash.d.ts +200 -1
  22. package/dist/core/Hash.d.ts.map +1 -1
  23. package/dist/core/Hash.js +207 -0
  24. package/dist/core/Hash.js.map +1 -1
  25. package/dist/core/Hex.d.ts.map +1 -1
  26. package/dist/core/Hex.js +1 -4
  27. package/dist/core/Hex.js.map +1 -1
  28. package/dist/core/Rlp.d.ts +32 -0
  29. package/dist/core/Rlp.d.ts.map +1 -1
  30. package/dist/core/Rlp.js +146 -0
  31. package/dist/core/Rlp.js.map +1 -1
  32. package/dist/core/Secp256k1.d.ts +46 -1
  33. package/dist/core/Secp256k1.d.ts.map +1 -1
  34. package/dist/core/Secp256k1.js +48 -0
  35. package/dist/core/Secp256k1.js.map +1 -1
  36. package/dist/core/WebAuthn.d.ts +224 -0
  37. package/dist/core/WebAuthn.d.ts.map +1 -0
  38. package/dist/core/WebAuthn.js +343 -0
  39. package/dist/core/WebAuthn.js.map +1 -0
  40. package/dist/core/WebAuthnP256.d.ts +46 -50
  41. package/dist/core/WebAuthnP256.d.ts.map +1 -1
  42. package/dist/core/WebAuthnP256.js +44 -50
  43. package/dist/core/WebAuthnP256.js.map +1 -1
  44. package/dist/core/internal/abiParameters.d.ts +7 -87
  45. package/dist/core/internal/abiParameters.d.ts.map +1 -1
  46. package/dist/core/internal/abiParameters.js +339 -194
  47. package/dist/core/internal/abiParameters.js.map +1 -1
  48. package/dist/core/internal/engine.d.ts +35 -2
  49. package/dist/core/internal/engine.d.ts.map +1 -1
  50. package/dist/core/internal/engine.js +12 -1
  51. package/dist/core/internal/engine.js.map +1 -1
  52. package/dist/core/internal/hash.d.ts +10 -0
  53. package/dist/core/internal/hash.d.ts.map +1 -1
  54. package/dist/core/internal/hash.js +26 -1
  55. package/dist/core/internal/hash.js.map +1 -1
  56. package/dist/index.d.ts +23 -14
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +23 -14
  59. package/dist/index.js.map +1 -1
  60. package/dist/node/Engine.d.ts +1 -1
  61. package/dist/node/Engine.d.ts.map +1 -1
  62. package/dist/node/Engine.js.map +1 -1
  63. package/dist/node/Hash.d.ts +6 -4
  64. package/dist/node/Hash.d.ts.map +1 -1
  65. package/dist/node/Hash.js +35 -3
  66. package/dist/node/Hash.js.map +1 -1
  67. package/dist/tempo/AuthorizationTempo.d.ts +6 -6
  68. package/dist/tempo/AuthorizationTempo.js +6 -6
  69. package/dist/tempo/KeyAuthorization.d.ts +3 -8
  70. package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
  71. package/dist/tempo/KeyAuthorization.js +3 -8
  72. package/dist/tempo/KeyAuthorization.js.map +1 -1
  73. package/dist/tempo/SignatureEnvelope.d.ts +8 -8
  74. package/dist/tempo/SignatureEnvelope.js +8 -8
  75. package/dist/trusted-setups/Paths.d.ts +1 -0
  76. package/dist/trusted-setups/Paths.d.ts.map +1 -1
  77. package/dist/trusted-setups/Paths.js +1 -0
  78. package/dist/trusted-setups/Paths.js.map +1 -1
  79. package/dist/trusted-setups/Setups.d.ts +35 -0
  80. package/dist/trusted-setups/Setups.d.ts.map +1 -0
  81. package/dist/trusted-setups/Setups.js +29 -0
  82. package/dist/trusted-setups/Setups.js.map +1 -0
  83. package/dist/trusted-setups/index.d.ts +20 -0
  84. package/dist/trusted-setups/index.d.ts.map +1 -1
  85. package/dist/trusted-setups/index.js +20 -0
  86. package/dist/trusted-setups/index.js.map +1 -1
  87. package/dist/trusted-setups/internal/paths.d.ts.map +1 -1
  88. package/dist/trusted-setups/internal/paths.js +1 -1
  89. package/dist/trusted-setups/internal/paths.js.map +1 -1
  90. package/dist/trusted-setups/internal/setups/mainnet.d.ts +7 -0
  91. package/dist/trusted-setups/internal/setups/mainnet.d.ts.map +1 -0
  92. package/dist/trusted-setups/internal/setups/mainnet.js +11 -0
  93. package/dist/trusted-setups/internal/setups/mainnet.js.map +1 -0
  94. package/dist/wasm/Engine.d.ts +4 -3
  95. package/dist/wasm/Engine.d.ts.map +1 -1
  96. package/dist/wasm/Engine.js +5 -5
  97. package/dist/wasm/Engine.js.map +1 -1
  98. package/dist/wasm/Hash.d.ts +1 -1
  99. package/dist/wasm/Hash.d.ts.map +1 -1
  100. package/dist/wasm/Hash.js +5 -0
  101. package/dist/wasm/Hash.js.map +1 -1
  102. package/dist/wasm/Keystore.d.ts +23 -9
  103. package/dist/wasm/Keystore.d.ts.map +1 -1
  104. package/dist/wasm/Keystore.js +30 -13
  105. package/dist/wasm/Keystore.js.map +1 -1
  106. package/dist/wasm/Kzg.d.ts +112 -0
  107. package/dist/wasm/Kzg.d.ts.map +1 -0
  108. package/dist/wasm/Kzg.js +333 -0
  109. package/dist/wasm/Kzg.js.map +1 -0
  110. package/dist/wasm/Secp256k1.d.ts +55 -0
  111. package/dist/wasm/Secp256k1.d.ts.map +1 -0
  112. package/dist/wasm/Secp256k1.js +181 -0
  113. package/dist/wasm/Secp256k1.js.map +1 -0
  114. package/dist/wasm/index.d.ts +44 -1
  115. package/dist/wasm/index.d.ts.map +1 -1
  116. package/dist/wasm/index.js +44 -1
  117. package/dist/wasm/index.js.map +1 -1
  118. package/dist/wasm/internal/blake3.d.ts +10 -1
  119. package/dist/wasm/internal/blake3.d.ts.map +1 -1
  120. package/dist/wasm/internal/blake3.js +12 -1
  121. package/dist/wasm/internal/blake3.js.map +1 -1
  122. package/dist/wasm/internal/blake3.wasm.d.ts +3 -1
  123. package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -1
  124. package/dist/wasm/internal/blake3.wasm.js +3 -1
  125. package/dist/wasm/internal/blake3.wasm.js.map +1 -1
  126. package/dist/wasm/internal/hash.d.ts +9 -0
  127. package/dist/wasm/internal/hash.d.ts.map +1 -1
  128. package/dist/wasm/internal/hash.js +13 -1
  129. package/dist/wasm/internal/hash.js.map +1 -1
  130. package/dist/wasm/internal/hashState.d.ts +25 -0
  131. package/dist/wasm/internal/hashState.d.ts.map +1 -0
  132. package/dist/wasm/internal/hashState.js +105 -0
  133. package/dist/wasm/internal/hashState.js.map +1 -0
  134. package/dist/wasm/internal/hashes.d.ts +12 -1
  135. package/dist/wasm/internal/hashes.d.ts.map +1 -1
  136. package/dist/wasm/internal/hashes.js +18 -1
  137. package/dist/wasm/internal/hashes.js.map +1 -1
  138. package/dist/wasm/internal/hashes.wasm.d.ts +11 -3
  139. package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -1
  140. package/dist/wasm/internal/hashes.wasm.js +11 -3
  141. package/dist/wasm/internal/hashes.wasm.js.map +1 -1
  142. package/dist/wasm/internal/instantiate.d.ts +12 -0
  143. package/dist/wasm/internal/instantiate.d.ts.map +1 -1
  144. package/dist/wasm/internal/instantiate.js +23 -7
  145. package/dist/wasm/internal/instantiate.js.map +1 -1
  146. package/dist/wasm/internal/keystore.d.ts +10 -0
  147. package/dist/wasm/internal/keystore.d.ts.map +1 -0
  148. package/dist/wasm/internal/keystore.js +10 -0
  149. package/dist/wasm/internal/keystore.js.map +1 -0
  150. package/dist/wasm/internal/kzg.d.ts +17 -0
  151. package/dist/wasm/internal/kzg.d.ts.map +1 -0
  152. package/dist/wasm/internal/kzg.js +8 -0
  153. package/dist/wasm/internal/kzg.js.map +1 -0
  154. package/dist/wasm/internal/kzg.wasm.d.ts +3 -0
  155. package/dist/wasm/internal/kzg.wasm.d.ts.map +1 -0
  156. package/dist/wasm/internal/kzg.wasm.js +10 -0
  157. package/dist/wasm/internal/kzg.wasm.js.map +1 -0
  158. package/dist/wasm/internal/scrypt.d.ts +16 -0
  159. package/dist/wasm/internal/scrypt.d.ts.map +1 -0
  160. package/dist/wasm/internal/scrypt.js +78 -0
  161. package/dist/wasm/internal/scrypt.js.map +1 -0
  162. package/dist/wasm/internal/scrypt.wasm.d.ts +7 -0
  163. package/dist/wasm/internal/scrypt.wasm.d.ts.map +1 -0
  164. package/dist/wasm/internal/scrypt.wasm.js +14 -0
  165. package/dist/wasm/internal/scrypt.wasm.js.map +1 -0
  166. package/dist/wasm/internal/secp256k1.d.ts +16 -0
  167. package/dist/wasm/internal/secp256k1.d.ts.map +1 -0
  168. package/dist/wasm/internal/secp256k1.js +20 -0
  169. package/dist/wasm/internal/secp256k1.js.map +1 -0
  170. package/dist/wasm/internal/secp256k1.wasm.d.ts +3 -0
  171. package/dist/wasm/internal/secp256k1.wasm.d.ts.map +1 -0
  172. package/dist/wasm/internal/secp256k1.wasm.js +10 -0
  173. package/dist/wasm/internal/secp256k1.wasm.js.map +1 -0
  174. package/dist/webauthn/Authentication.d.ts +2 -0
  175. package/dist/webauthn/Authentication.d.ts.map +1 -1
  176. package/dist/webauthn/Authentication.js +2 -1
  177. package/dist/webauthn/Authentication.js.map +1 -1
  178. package/dist/webauthn/Registration.d.ts.map +1 -1
  179. package/dist/webauthn/Registration.js +2 -1
  180. package/dist/webauthn/Registration.js.map +1 -1
  181. package/dist/webauthn/Types.d.ts +27 -6
  182. package/dist/webauthn/Types.d.ts.map +1 -1
  183. package/dist/webauthn/internal/utils.d.ts.map +1 -1
  184. package/dist/webauthn/internal/utils.js +35 -9
  185. package/dist/webauthn/internal/utils.js.map +1 -1
  186. package/dist/zod/TypedData.d.ts +2 -2
  187. package/package.json +27 -2
  188. package/src/benchmarks/Ox.bench.ts +6 -0
  189. package/src/benchmarks/OxNode.bench.ts +8 -0
  190. package/src/benchmarks/OxV0.bench.ts +4 -0
  191. package/src/benchmarks/OxWasm.bench.ts +22 -0
  192. package/src/core/AbiFunction.ts +5 -5
  193. package/src/core/AbiParameters.ts +8 -20
  194. package/src/core/AesGcm.ts +86 -1
  195. package/src/core/Ed25519.ts +87 -1
  196. package/src/core/Engine.ts +1 -0
  197. package/src/core/Hash.ts +321 -1
  198. package/src/core/Hex.ts +1 -4
  199. package/src/core/Rlp.ts +172 -5
  200. package/src/core/Secp256k1.ts +92 -1
  201. package/src/core/WebAuthn.ts +579 -0
  202. package/src/core/WebAuthnP256.ts +47 -50
  203. package/src/core/_test/AbiFunction.test.ts +9 -0
  204. package/src/core/_test/AbiParameters.differential.fuzz.ts +156 -0
  205. package/src/core/_test/AbiParameters.encode.test.ts +22 -0
  206. package/src/core/_test/AbiParameters.fuzz.ts +4 -0
  207. package/src/core/_test/AesGcm.test.ts +76 -0
  208. package/src/core/_test/Block.test.ts +9 -2
  209. package/src/core/_test/Ed25519.test-d.ts +13 -1
  210. package/src/core/_test/Ed25519.test.ts +120 -1
  211. package/src/core/_test/Engine.test-d.ts +9 -0
  212. package/src/core/_test/Engine.test.ts +1 -1
  213. package/src/core/_test/Hash.test-d.ts +41 -0
  214. package/src/core/_test/Hash.test.ts +278 -1
  215. package/src/core/_test/Hash.vectors.test.ts +1 -2
  216. package/src/core/_test/Hex.test.ts +2 -0
  217. package/src/core/_test/Rlp.test-d.ts +18 -0
  218. package/src/core/_test/Rlp.test.ts +109 -0
  219. package/src/core/_test/Secp256k1.test-d.ts +14 -0
  220. package/src/core/_test/Secp256k1.test.ts +91 -1
  221. package/src/core/_test/Transaction.test.ts +11 -2
  222. package/src/core/_test/WebAuthn.test-d.ts +142 -0
  223. package/src/core/_test/WebAuthn.test.ts +766 -0
  224. package/src/core/_test/index.test.ts +1 -0
  225. package/src/core/internal/abiParameters.ts +466 -326
  226. package/src/core/internal/engine.ts +47 -2
  227. package/src/core/internal/hash.ts +53 -1
  228. package/src/index.ts +24 -14
  229. package/src/node/Engine.ts +1 -0
  230. package/src/node/Hash.ts +43 -6
  231. package/src/node/_test/Engine.test-d.ts +1 -0
  232. package/src/node/_test/Engine.test.ts +2 -0
  233. package/src/node/_test/Hash.test-d.ts +11 -0
  234. package/src/node/_test/Hash.test.ts +46 -0
  235. package/src/tempo/AuthorizationTempo.ts +6 -6
  236. package/src/tempo/KeyAuthorization.ts +3 -8
  237. package/src/tempo/SignatureEnvelope.ts +8 -8
  238. package/src/trusted-setups/Paths.ts +1 -0
  239. package/src/trusted-setups/README.md +39 -0
  240. package/src/trusted-setups/Setups.ts +46 -0
  241. package/src/trusted-setups/_test/Paths.test.ts +16 -0
  242. package/src/trusted-setups/_test/Setups.test-d.ts +7 -0
  243. package/src/trusted-setups/_test/Setups.test.ts +43 -0
  244. package/src/trusted-setups/_test/index.test.ts +1 -0
  245. package/src/trusted-setups/index.ts +21 -0
  246. package/src/trusted-setups/internal/paths.ts +4 -1
  247. package/src/trusted-setups/internal/setups/mainnet.source.json +7 -0
  248. package/src/trusted-setups/internal/setups/mainnet.ts +16 -0
  249. package/src/version.ts +1 -1
  250. package/src/wasm/Engine.ts +9 -6
  251. package/src/wasm/Hash.ts +10 -0
  252. package/src/wasm/Keystore.bench.ts +26 -0
  253. package/src/wasm/Keystore.ts +32 -14
  254. package/src/wasm/Kzg.bench.ts +63 -0
  255. package/src/wasm/Kzg.ts +518 -0
  256. package/src/wasm/Secp256k1.bench.ts +79 -0
  257. package/src/wasm/Secp256k1.ts +248 -0
  258. package/src/wasm/_test/Engine.test-d.ts +2 -0
  259. package/src/wasm/_test/Engine.test.ts +5 -0
  260. package/src/wasm/_test/Hash.browser.test.ts +31 -0
  261. package/src/wasm/_test/Hash.test-d.ts +17 -0
  262. package/src/wasm/_test/Hash.test.ts +252 -3
  263. package/src/wasm/_test/Keystore.browser.test.ts +31 -0
  264. package/src/wasm/_test/Keystore.fuzz.ts +50 -0
  265. package/src/wasm/_test/Keystore.test-d.ts +10 -1
  266. package/src/wasm/_test/Keystore.test.ts +289 -4
  267. package/src/wasm/_test/Kzg.test-d.ts +19 -0
  268. package/src/wasm/_test/Kzg.test.ts +220 -0
  269. package/src/wasm/_test/Runtime.test.ts +9 -0
  270. package/src/wasm/_test/Secp256k1.test-d.ts +35 -0
  271. package/src/wasm/_test/Secp256k1.test.ts +354 -0
  272. package/src/wasm/index.ts +46 -1
  273. package/src/wasm/internal/blake3.ts +23 -2
  274. package/src/wasm/internal/blake3.wasm.ts +4 -1
  275. package/src/wasm/internal/hash.ts +27 -1
  276. package/src/wasm/internal/hashState.ts +154 -0
  277. package/src/wasm/internal/hashes.ts +56 -15
  278. package/src/wasm/internal/hashes.wasm.ts +15 -3
  279. package/src/wasm/internal/instantiate.ts +29 -9
  280. package/src/wasm/internal/keystore.ts +19 -0
  281. package/src/wasm/internal/kzg.ts +50 -0
  282. package/src/wasm/internal/kzg.wasm.ts +11 -0
  283. package/src/wasm/internal/scrypt.ts +131 -0
  284. package/src/wasm/internal/scrypt.wasm.ts +17 -0
  285. package/src/wasm/internal/secp256k1.ts +62 -0
  286. package/src/wasm/internal/secp256k1.wasm.ts +11 -0
  287. package/src/webauthn/Authentication.ts +4 -0
  288. package/src/webauthn/Registration.ts +2 -0
  289. package/src/webauthn/Types.ts +32 -2
  290. package/src/webauthn/_test/Authentication.test.ts +123 -1
  291. package/src/webauthn/_test/Registration.test.ts +26 -6
  292. package/src/webauthn/_test/WebAuthn.browser.test.ts +28 -0
  293. package/src/webauthn/internal/utils.ts +41 -8
  294. package/wasm/vendor/c-kzg-4844/LICENSE +201 -0
  295. package/wasm/vendor/c-kzg-4844/blst/LICENSE +201 -0
  296. package/src/trusted-setups/internal/setups/mainnet.txt +0 -4163
@@ -1,4 +1,4 @@
1
- import { Bytes, Ed25519, Hex, X25519 } from 'ox'
1
+ import { Bytes, Ed25519, Engine, Hex, X25519 } from 'ox'
2
2
  import { describe, expect, test } from 'vp/test'
3
3
 
4
4
  describe('createKeyPair', () => {
@@ -44,6 +44,108 @@ describe('createKeyPair', () => {
44
44
  })
45
45
  })
46
46
 
47
+ describe('fromPrf', () => {
48
+ test.each([
49
+ {
50
+ privateKey:
51
+ '0x2c513679b40b7572cbfaf5aee41680258ab23de9ec68d6eaf243470c28e7cea3',
52
+ prf: '0x0000000000000000000000000000000000000000000000000000000000000000',
53
+ },
54
+ {
55
+ privateKey:
56
+ '0x7ad5cfcdff4bd56cf35bd854b794c9e18f9bcc3e6e12f9ecc0ef44bb23c6d920',
57
+ prf: '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
58
+ },
59
+ ] as const)('vector: $prf', ({ privateKey, prf }) => {
60
+ expect(Ed25519.fromPrf(prf)).toBe(privateKey)
61
+ })
62
+
63
+ test('value: Bytes', () => {
64
+ const prf = Bytes.fromHex(
65
+ '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
66
+ )
67
+ expect(Ed25519.fromPrf(prf)).toMatchInlineSnapshot(
68
+ `"0x7ad5cfcdff4bd56cf35bd854b794c9e18f9bcc3e6e12f9ecc0ef44bb23c6d920"`,
69
+ )
70
+ })
71
+
72
+ test('options: as', () => {
73
+ const privateKey = Ed25519.fromPrf(
74
+ '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
75
+ { as: 'Bytes' },
76
+ )
77
+ expect(privateKey).toEqual(
78
+ Bytes.fromHex(
79
+ '0x7ad5cfcdff4bd56cf35bd854b794c9e18f9bcc3e6e12f9ecc0ef44bb23c6d920',
80
+ ),
81
+ )
82
+ })
83
+
84
+ test('behavior: output signs and verifies', () => {
85
+ const privateKey = Ed25519.fromPrf(Bytes.random(32))
86
+ const publicKey = Ed25519.getPublicKey({ privateKey })
87
+ const payload = '0xdeadbeef'
88
+ const signature = Ed25519.sign({ payload, privateKey })
89
+
90
+ expect(Ed25519.verify({ payload, publicKey, signature })).toBe(true)
91
+ })
92
+
93
+ test('behavior: uses versioned label and zero counter', () => {
94
+ const messages: Hex.Hex[] = []
95
+ Engine.with(
96
+ {
97
+ Hash: {
98
+ hmacSha256: (_key, message) => {
99
+ messages.push(Hex.fromBytes(message))
100
+ return new Uint8Array(32)
101
+ },
102
+ },
103
+ },
104
+ () =>
105
+ Ed25519.fromPrf(
106
+ '0x0000000000000000000000000000000000000000000000000000000000000000',
107
+ ),
108
+ )
109
+
110
+ expect(messages).toMatchInlineSnapshot(`
111
+ [
112
+ "0x6f782e656432353531392e66726f6d5072662e763100000000",
113
+ ]
114
+ `)
115
+ })
116
+
117
+ test('behavior: zeroes intermediate key for Hex output', () => {
118
+ const candidate = new Uint8Array(32).fill(1)
119
+ Engine.with(
120
+ {
121
+ Hash: {
122
+ hmacSha256: () => candidate,
123
+ },
124
+ },
125
+ () =>
126
+ Ed25519.fromPrf(
127
+ '0x0000000000000000000000000000000000000000000000000000000000000000',
128
+ ),
129
+ )
130
+
131
+ expect(candidate).toEqual(new Uint8Array(32))
132
+ })
133
+
134
+ test('error: PRF output is too short', () => {
135
+ expect(() => Ed25519.fromPrf(new Uint8Array(31)))
136
+ .toThrowErrorMatchingInlineSnapshot(`
137
+ [Ed25519.InvalidPrfSizeError: PRF output must be exactly 32 bytes. Received 31 bytes.]
138
+ `)
139
+ })
140
+
141
+ test('error: PRF output is too long', () => {
142
+ expect(() => Ed25519.fromPrf(new Uint8Array(33)))
143
+ .toThrowErrorMatchingInlineSnapshot(`
144
+ [Ed25519.InvalidPrfSizeError: PRF output must be exactly 32 bytes. Received 33 bytes.]
145
+ `)
146
+ })
147
+ })
148
+
47
149
  describe('getPublicKey', () => {
48
150
  const privateKey =
49
151
  '0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60'
@@ -436,3 +538,20 @@ describe('noble export', () => {
436
538
  expect(Ed25519.noble.getPublicKey).toBeDefined()
437
539
  })
438
540
  })
541
+
542
+ test('exports', () => {
543
+ expect(Object.keys(Ed25519)).toMatchInlineSnapshot(`
544
+ [
545
+ "noble",
546
+ "createKeyPair",
547
+ "fromPrf",
548
+ "getPublicKey",
549
+ "randomPrivateKey",
550
+ "sign",
551
+ "verify",
552
+ "toX25519PublicKey",
553
+ "toX25519PrivateKey",
554
+ "InvalidPrfSizeError",
555
+ ]
556
+ `)
557
+ })
@@ -136,5 +136,14 @@ describe('Engine', () => {
136
136
  expectTypeOf<NonNullable<Engine.Hash['keccak256']>>().toEqualTypeOf<
137
137
  (input: Uint8Array) => Uint8Array
138
138
  >()
139
+ expectTypeOf<NonNullable<Engine.Hash['createKeccak256']>>().toEqualTypeOf<
140
+ () => Engine.HashState
141
+ >()
142
+ expectTypeOf<Engine.HashState>().toEqualTypeOf<{
143
+ clone(): Engine.HashState
144
+ destroy(): void
145
+ digestInto(output: Uint8Array): void
146
+ update(input: Uint8Array): void
147
+ }>()
139
148
  })
140
149
  })
@@ -266,7 +266,7 @@ describe('set', () => {
266
266
  ).toThrowErrorMatchingInlineSnapshot(`
267
267
  [Engine.UnknownPrimitiveError: \`keccak_256\` is not a valid primitive for the \`Hash\` slot.
268
268
 
269
- Valid primitives: blake3, hmacSha256, keccak256, ripemd160, sha256]
269
+ Valid primitives: blake3, createBlake3, createHmacSha256, createKeccak256, createRipemd160, createSha256, hmacSha256, keccak256, ripemd160, sha256]
270
270
  `)
271
271
  })
272
272
 
@@ -0,0 +1,41 @@
1
+ import { type Bytes, Hash, type Hex } from 'ox'
2
+ import { describe, expectTypeOf, test } from 'vp/test'
3
+
4
+ describe('blake3', () => {
5
+ test('default', () => {
6
+ expectTypeOf(Hash.blake3('0x')).toEqualTypeOf<Hex.Hex>()
7
+ expectTypeOf(Hash.blake3(new Uint8Array())).toEqualTypeOf<Bytes.Bytes>()
8
+ })
9
+
10
+ test('as', () => {
11
+ expectTypeOf(
12
+ Hash.blake3('0x', { as: 'Bytes' }),
13
+ ).toEqualTypeOf<Bytes.Bytes>()
14
+ expectTypeOf(
15
+ Hash.blake3(new Uint8Array(), { as: 'Hex' }),
16
+ ).toEqualTypeOf<Hex.Hex>()
17
+ })
18
+ })
19
+
20
+ describe('incremental', () => {
21
+ test('factories', () => {
22
+ expectTypeOf(Hash.createBlake3()).toEqualTypeOf<Hash.Hasher>()
23
+ expectTypeOf(Hash.createHmac256('0x')).toEqualTypeOf<Hash.Hasher>()
24
+ expectTypeOf(Hash.createKeccak256()).toEqualTypeOf<Hash.Hasher>()
25
+ expectTypeOf(Hash.createRipemd160()).toEqualTypeOf<Hash.Hasher>()
26
+ expectTypeOf(Hash.createSha256()).toEqualTypeOf<Hash.Hasher>()
27
+ })
28
+
29
+ test('Hasher', () => {
30
+ const hash = Hash.createSha256()
31
+
32
+ expectTypeOf(hash.update('0x')).toEqualTypeOf<Hash.Hasher>()
33
+ expectTypeOf(hash.update(new Uint8Array())).toEqualTypeOf<Hash.Hasher>()
34
+ expectTypeOf(hash.clone()).toEqualTypeOf<Hash.Hasher>()
35
+ expectTypeOf(hash.digest()).toEqualTypeOf<Hex.Hex>()
36
+ expectTypeOf(hash.digest({ as: 'Hex' })).toEqualTypeOf<Hex.Hex>()
37
+ expectTypeOf(hash.digest({ as: 'Bytes' })).toEqualTypeOf<Bytes.Bytes>()
38
+ expectTypeOf(hash.digestInto(new Uint8Array())).toEqualTypeOf<void>()
39
+ expectTypeOf(hash.destroy()).toEqualTypeOf<void>()
40
+ })
41
+ })
@@ -1,6 +1,249 @@
1
- import { Hash } from 'ox'
1
+ import { type Bytes, Engine, Hash, type Hex } from 'ox'
2
2
  import { describe, expect, test } from 'vp/test'
3
3
 
4
+ type Factory = {
5
+ create(): Hash.Hasher
6
+ digest(value: Hex.Hex | Bytes.Bytes): Bytes.Bytes
7
+ digestSize: number
8
+ name: string
9
+ }
10
+
11
+ const factories = [
12
+ {
13
+ create: () => Hash.createBlake3(),
14
+ digest: (value) => Hash.blake3(value, { as: 'Bytes' }),
15
+ digestSize: 32,
16
+ name: 'createBlake3',
17
+ },
18
+ {
19
+ create: () => Hash.createHmac256('0x6b6579'),
20
+ digest: (value) => Hash.hmac256('0x6b6579', value, { as: 'Bytes' }),
21
+ digestSize: 32,
22
+ name: 'createHmac256',
23
+ },
24
+ {
25
+ create: () => Hash.createKeccak256(),
26
+ digest: (value) => Hash.keccak256(value, { as: 'Bytes' }),
27
+ digestSize: 32,
28
+ name: 'createKeccak256',
29
+ },
30
+ {
31
+ create: () => Hash.createRipemd160(),
32
+ digest: (value) => Hash.ripemd160(value, { as: 'Bytes' }),
33
+ digestSize: 20,
34
+ name: 'createRipemd160',
35
+ },
36
+ {
37
+ create: () => Hash.createSha256(),
38
+ digest: (value) => Hash.sha256(value, { as: 'Bytes' }),
39
+ digestSize: 32,
40
+ name: 'createSha256',
41
+ },
42
+ ] as const satisfies readonly Factory[]
43
+
44
+ describe('incremental', () => {
45
+ test.each(factories)(
46
+ '$name: chunked input matches the one-shot function',
47
+ ({ create, digest }) => {
48
+ const hash = create()
49
+ hash.update('0xdead').update(Uint8Array.of(0xbe, 0xef))
50
+ expect(hash.digest({ as: 'Bytes' })).toEqual(digest('0xdeadbeef'))
51
+ },
52
+ )
53
+
54
+ test.each(factories)(
55
+ '$name: empty input matches the one-shot function',
56
+ ({ create, digest }) => {
57
+ expect(create().digest({ as: 'Bytes' })).toEqual(digest('0x'))
58
+ },
59
+ )
60
+
61
+ test.each(factories)(
62
+ '$name: clone branches from the same prefix',
63
+ ({ create, digest }) => {
64
+ const first = create().update('0xdead')
65
+ const second = first.clone()
66
+
67
+ first.update('0xbeef')
68
+ second.update('0xcafe')
69
+
70
+ expect(first.digest({ as: 'Bytes' })).toEqual(digest('0xdeadbeef'))
71
+ expect(second.digest({ as: 'Bytes' })).toEqual(digest('0xdeadcafe'))
72
+ },
73
+ )
74
+
75
+ test.each(factories)(
76
+ '$name: digestInto validates bounds without consuming the state',
77
+ ({ create, digest, digestSize }) => {
78
+ const hash = create().update('0xdeadbeef')
79
+
80
+ expect(() =>
81
+ hash.digestInto(new Uint8Array(digestSize - 1)),
82
+ ).toThrowError(Hash.InvalidDigestSizeError)
83
+
84
+ const output = new Uint8Array(digestSize + 2).fill(0xff)
85
+ hash.digestInto(output)
86
+
87
+ expect(output.slice(0, digestSize)).toEqual(digest('0xdeadbeef'))
88
+ expect(output.slice(digestSize)).toEqual(Uint8Array.of(0xff, 0xff))
89
+ expect(() => hash.update('0x')).toThrowError(Hash.HasherDestroyedError)
90
+ },
91
+ )
92
+
93
+ test.each(factories)(
94
+ '$name: digest consumes the state and destroy is idempotent',
95
+ ({ create }) => {
96
+ const hash = create()
97
+ hash.digest()
98
+
99
+ expect(() => hash.clone()).toThrowError(Hash.HasherDestroyedError)
100
+ expect(() => hash.digest()).toThrowError(Hash.HasherDestroyedError)
101
+ expect(() => hash.digestInto(new Uint8Array(32))).toThrowError(
102
+ Hash.HasherDestroyedError,
103
+ )
104
+ expect(() => hash.update('0x')).toThrowError(Hash.HasherDestroyedError)
105
+ expect(() => {
106
+ hash.destroy()
107
+ hash.destroy()
108
+ }).not.toThrow()
109
+ },
110
+ )
111
+
112
+ test.each(factories)(
113
+ '$name: destroy consumes the state and is idempotent',
114
+ ({ create }) => {
115
+ const hash = create()
116
+ hash.destroy()
117
+ hash.destroy()
118
+
119
+ expect(() => hash.clone()).toThrowError(Hash.HasherDestroyedError)
120
+ expect(() => hash.digest()).toThrowError(Hash.HasherDestroyedError)
121
+ expect(() => hash.update('0x')).toThrowError(Hash.HasherDestroyedError)
122
+ },
123
+ )
124
+
125
+ test('behavior: independent states can be interleaved', () => {
126
+ const first = Hash.createSha256().update('0xaa')
127
+ const second = Hash.createSha256().update('0xbb')
128
+
129
+ first.update('0xcc')
130
+ second.update('0xdd')
131
+
132
+ expect(first.digest()).toEqual(Hash.sha256('0xaacc'))
133
+ expect(second.digest()).toEqual(Hash.sha256('0xbbdd'))
134
+ })
135
+
136
+ test('behavior: a state keeps the provider captured at creation', () => {
137
+ Engine.set({ Hash: { createSha256: () => sentinelState(1) } })
138
+ const first = Hash.createSha256()
139
+
140
+ Engine.set({ Hash: { createSha256: () => sentinelState(2) } })
141
+
142
+ expect(first.digest({ as: 'Bytes' })[0]).toMatchInlineSnapshot('1')
143
+ expect(
144
+ Hash.createSha256().digest({ as: 'Bytes' })[0],
145
+ ).toMatchInlineSnapshot('2')
146
+ })
147
+ })
148
+
149
+ describe('blake3', () => {
150
+ test('default', () => {
151
+ expect(Hash.blake3('0x')).toMatchInlineSnapshot(
152
+ `"0xaf1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262"`,
153
+ )
154
+
155
+ expect(Hash.blake3(new Uint8Array())).toMatchInlineSnapshot(`
156
+ Uint8Array [
157
+ 175,
158
+ 19,
159
+ 73,
160
+ 185,
161
+ 245,
162
+ 249,
163
+ 161,
164
+ 166,
165
+ 160,
166
+ 64,
167
+ 77,
168
+ 234,
169
+ 54,
170
+ 220,
171
+ 201,
172
+ 73,
173
+ 155,
174
+ 203,
175
+ 37,
176
+ 201,
177
+ 173,
178
+ 193,
179
+ 18,
180
+ 183,
181
+ 204,
182
+ 154,
183
+ 147,
184
+ 202,
185
+ 228,
186
+ 31,
187
+ 50,
188
+ 98,
189
+ ]
190
+ `)
191
+ })
192
+
193
+ test('as: Hex', () => {
194
+ expect(Hash.blake3(new Uint8Array(), { as: 'Hex' })).toMatchInlineSnapshot(
195
+ `"0xaf1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262"`,
196
+ )
197
+ })
198
+
199
+ test('as: Bytes', () => {
200
+ expect(Hash.blake3('0x', { as: 'Bytes' })).toMatchInlineSnapshot(`
201
+ Uint8Array [
202
+ 175,
203
+ 19,
204
+ 73,
205
+ 185,
206
+ 245,
207
+ 249,
208
+ 161,
209
+ 166,
210
+ 160,
211
+ 64,
212
+ 77,
213
+ 234,
214
+ 54,
215
+ 220,
216
+ 201,
217
+ 73,
218
+ 155,
219
+ 203,
220
+ 37,
221
+ 201,
222
+ 173,
223
+ 193,
224
+ 18,
225
+ 183,
226
+ 204,
227
+ 154,
228
+ 147,
229
+ 202,
230
+ 228,
231
+ 31,
232
+ 50,
233
+ 98,
234
+ ]
235
+ `)
236
+ })
237
+
238
+ test('behavior: routes through the installed engine', () => {
239
+ Engine.set({ Hash: { blake3: () => new Uint8Array(32).fill(1) } })
240
+
241
+ expect(Hash.blake3('0x')).toMatchInlineSnapshot(
242
+ `"0x0101010101010101010101010101010101010101010101010101010101010101"`,
243
+ )
244
+ })
245
+ })
246
+
4
247
  describe('hmac256', () => {
5
248
  test('default', () => {
6
249
  expect(
@@ -527,14 +770,48 @@ describe('validate', () => {
527
770
  })
528
771
  })
529
772
 
773
+ function sentinelState(byte: number): Engine.HashState {
774
+ let active = true
775
+
776
+ const assertActive = () => {
777
+ if (!active) throw new Error('destroyed')
778
+ }
779
+
780
+ return {
781
+ clone: () => {
782
+ assertActive()
783
+ return sentinelState(byte)
784
+ },
785
+ destroy: () => {
786
+ active = false
787
+ },
788
+ digestInto: (output) => {
789
+ assertActive()
790
+ active = false
791
+ output.fill(byte, 0, 32)
792
+ },
793
+ update: () => {
794
+ assertActive()
795
+ },
796
+ }
797
+ }
798
+
530
799
  test('exports', () => {
531
800
  expect(Object.keys(Hash)).toMatchInlineSnapshot(`
532
801
  [
802
+ "createBlake3",
803
+ "createHmac256",
804
+ "createKeccak256",
805
+ "createRipemd160",
806
+ "createSha256",
807
+ "blake3",
533
808
  "keccak256",
534
809
  "hmac256",
535
810
  "ripemd160",
536
811
  "sha256",
537
812
  "validate",
813
+ "HasherDestroyedError",
814
+ "InvalidDigestSizeError",
538
815
  ]
539
816
  `)
540
817
  })
@@ -1,7 +1,6 @@
1
1
  import { Hash } from 'ox'
2
2
  import { describe, expect, test } from 'vp/test'
3
3
  import * as vectors from '../../../test/vectors/hashes/index.js'
4
- import * as hash from '../internal/hash.js'
5
4
 
6
5
  /**
7
6
  * Published vectors against ox's default (`@noble/hashes`) implementations.
@@ -15,7 +14,7 @@ import * as hash from '../internal/hash.js'
15
14
  describe('blake3', () => {
16
15
  test(`matches ${vectors.blake3.length} official BLAKE3 vectors`, () => {
17
16
  for (const { digest, message } of vectors.blake3)
18
- expect(hash.blake3(message)).toEqual(digest)
17
+ expect(Hash.blake3(message, { as: 'Bytes' })).toEqual(digest)
19
18
  })
20
19
  })
21
20
 
@@ -30,6 +30,8 @@ describe('assert', () => {
30
30
 
31
31
  describe('concat', () => {
32
32
  test('default', () => {
33
+ expect(Hex.concat()).toMatchInlineSnapshot(`"0x"`)
34
+ expect(Hex.concat('0x1234')).toMatchInlineSnapshot(`"0x1234"`)
33
35
  expect(Hex.concat('0x0', '0x1')).toBe('0x01')
34
36
  expect(Hex.concat('0x1', '0x69', '0x420')).toBe('0x169420')
35
37
  expect(Hex.concat('0x00000001', '0x00000069', '0x00000420')).toBe(
@@ -2,6 +2,24 @@ import { Bytes, type Hex, Rlp } from 'ox'
2
2
  import { describe, expectTypeOf, test } from 'vp/test'
3
3
  import type { RecursiveArray } from '../internal/types.js'
4
4
 
5
+ describe('Rlp.encodeTo', () => {
6
+ test('write', () => {
7
+ expectTypeOf(
8
+ Rlp.encodeTo('0x', (value) => {
9
+ expectTypeOf(value).toEqualTypeOf<Bytes.Bytes>()
10
+ }),
11
+ ).toEqualTypeOf<void>()
12
+ })
13
+
14
+ test('rejects asynchronous callbacks', () => {
15
+ Rlp.encodeTo(
16
+ '0x',
17
+ // @ts-expect-error RLP write callbacks are synchronous.
18
+ async () => {},
19
+ )
20
+ })
21
+ })
22
+
5
23
  describe('Rlp.to', () => {
6
24
  test('default', () => {
7
25
  expectTypeOf(Rlp.toHex('0x')).toEqualTypeOf<RecursiveArray<Hex.Hex>>()
@@ -10,6 +10,7 @@ test('exports', () => {
10
10
  "decodeRlpCursor",
11
11
  "readLength",
12
12
  "readList",
13
+ "encodeTo",
13
14
  "from",
14
15
  "fromBytes",
15
16
  "fromHex",
@@ -32,6 +33,114 @@ const generateList = (length: number) => {
32
33
  return bytes
33
34
  }
34
35
 
36
+ function encodeToBytes(value: Parameters<typeof Rlp.encodeTo>[0]) {
37
+ const chunks: Uint8Array[] = []
38
+ Rlp.encodeTo(value, (chunk) => {
39
+ chunks.push(chunk)
40
+ })
41
+ return Bytes.concat(...chunks)
42
+ }
43
+
44
+ describe('Rlp.encodeTo', () => {
45
+ test('matches `from` for nested Hex values', () => {
46
+ const values = [
47
+ '0x',
48
+ '0x00',
49
+ '0x7f',
50
+ '0x80',
51
+ '0x1',
52
+ '0xabc',
53
+ ['0x', '0x80', ['0x1', `0x${'ab'.repeat(56)}`], `0x${'cd'.repeat(256)}`],
54
+ ] as const
55
+
56
+ for (const value of values)
57
+ expect(encodeToBytes(value)).toEqual(Rlp.from(value, { as: 'Bytes' }))
58
+ })
59
+
60
+ test('matches `from` for nested byte values', () => {
61
+ const values = [
62
+ new Uint8Array(),
63
+ Uint8Array.of(0),
64
+ Uint8Array.of(0x7f),
65
+ Uint8Array.of(0x80),
66
+ [
67
+ new Uint8Array(),
68
+ Uint8Array.of(0x80),
69
+ [generateBytes(56), generateBytes(256)],
70
+ ],
71
+ ] as const
72
+
73
+ for (const value of values)
74
+ expect(encodeToBytes(value)).toEqual(Rlp.from(value, { as: 'Bytes' }))
75
+ })
76
+
77
+ test('does not mutate emitted chunks', () => {
78
+ const chunks: Uint8Array[] = []
79
+ const values: Hex.Hex[] = []
80
+
81
+ Rlp.encodeTo(['0x01', `0x${'ab'.repeat(16_386)}`, '0x80'], (chunk) => {
82
+ chunks.push(chunk)
83
+ values.push(Hex.fromBytes(chunk))
84
+ })
85
+
86
+ expect(chunks.map((chunk) => Hex.fromBytes(chunk))).toEqual(values)
87
+ })
88
+
89
+ test('passes byte leaves without copying', () => {
90
+ const leaf = generateBytes(64)
91
+ let found = false
92
+
93
+ Rlp.encodeTo(leaf, (chunk) => {
94
+ if (chunk === leaf) found = true
95
+ })
96
+
97
+ expect(found).toMatchInlineSnapshot(`true`)
98
+ })
99
+
100
+ test('validates every Hex leaf before writing', () => {
101
+ let writes = 0
102
+
103
+ expect(() =>
104
+ Rlp.encodeTo(['0x01', ['0x02', '0xzz' as Hex.Hex]], () => {
105
+ writes++
106
+ }),
107
+ ).toThrowErrorMatchingInlineSnapshot(
108
+ `[BaseError: Invalid hex string \`0xzz\`.]`,
109
+ )
110
+ expect(writes).toMatchInlineSnapshot(`0`)
111
+ })
112
+
113
+ test('propagates callback errors after partial output', () => {
114
+ const chunks: Uint8Array[] = []
115
+
116
+ expect(() =>
117
+ Rlp.encodeTo([Uint8Array.of(1), Uint8Array.of(2)], (chunk) => {
118
+ chunks.push(chunk)
119
+ if (chunks.length === 2) throw new Error('write failed')
120
+ }),
121
+ ).toThrowErrorMatchingInlineSnapshot(`[Error: write failed]`)
122
+ expect(chunks.map((chunk) => Hex.fromBytes(chunk))).toMatchInlineSnapshot(`
123
+ [
124
+ "0xc2",
125
+ "0x01",
126
+ ]
127
+ `)
128
+ })
129
+
130
+ test('snapshots list structure before writing', () => {
131
+ const value: Hex.Hex[] = ['0x01']
132
+ const expected = Rlp.from(value, { as: 'Bytes' })
133
+ const chunks: Uint8Array[] = []
134
+
135
+ Rlp.encodeTo(value, (chunk) => {
136
+ chunks.push(chunk)
137
+ if (chunks.length === 1) value.push('0x02')
138
+ })
139
+
140
+ expect(Bytes.concat(...chunks)).toEqual(expected)
141
+ })
142
+ })
143
+
35
144
  describe('Rlp.to', () => {
36
145
  test('no bytes', () => {
37
146
  const rlpHex = '0x'
@@ -0,0 +1,14 @@
1
+ import { type Bytes, type Hex, Secp256k1 } from 'ox'
2
+ import { expectTypeOf, test } from 'vp/test'
3
+
4
+ test('fromPrf', () => {
5
+ const prf =
6
+ '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'
7
+
8
+ expectTypeOf(Secp256k1.fromPrf(prf)).toEqualTypeOf<Hex.Hex>()
9
+ expectTypeOf(Secp256k1.fromPrf(new Uint8Array(32))).toEqualTypeOf<Hex.Hex>()
10
+ expectTypeOf(Secp256k1.fromPrf(prf, { as: 'Hex' })).toEqualTypeOf<Hex.Hex>()
11
+ expectTypeOf(
12
+ Secp256k1.fromPrf(prf, { as: 'Bytes' }),
13
+ ).toEqualTypeOf<Bytes.Bytes>()
14
+ })