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,5 @@
1
1
  import { pbkdf2 as pbkdf2_noble } from '@noble/hashes/pbkdf2.js'
2
+ import { scrypt as scrypt_noble } from '@noble/hashes/scrypt.js'
2
3
  import { sha256 } from '@noble/hashes/sha2.js'
3
4
  import { describe, expect, test } from 'vp/test'
4
5
  import * as Bytes from '../../core/Bytes.js'
@@ -15,6 +16,9 @@ describe('engine', () => {
15
16
  expect(engine.pbkdf2Sha256(password, salt, { c: 3, dkLen: 65 })).toEqual(
16
17
  pbkdf2_noble(sha256, password, salt, { c: 3, dkLen: 65 }),
17
18
  )
19
+ expect(
20
+ engine.scrypt(password, salt, { N: 1024, dkLen: 65, p: 2, r: 1 }),
21
+ ).toEqual(scrypt_noble(password, salt, { N: 1024, dkLen: 65, p: 2, r: 1 }))
18
22
  })
19
23
 
20
24
  test('behavior: ox uses synchronous WASM PBKDF2 once installed', async () => {
@@ -39,4 +43,31 @@ describe('engine', () => {
39
43
  Engine.reset()
40
44
  }
41
45
  })
46
+
47
+ test('behavior: ox uses synchronous WASM scrypt once installed', async () => {
48
+ const engine = await WasmKeystore.engine()
49
+ await Engine.install({ Keystore: engine })
50
+ try {
51
+ const salt = new Uint8Array(32).fill(7)
52
+ const [key] = Keystore.scrypt({
53
+ n: 1024,
54
+ p: 2,
55
+ password: 'testpassword',
56
+ r: 1,
57
+ salt,
58
+ })
59
+ expect(key()).toBe(
60
+ Bytes.toHex(
61
+ scrypt_noble(Bytes.fromString('testpassword'), salt, {
62
+ N: 1024,
63
+ dkLen: 32,
64
+ p: 2,
65
+ r: 1,
66
+ }),
67
+ ),
68
+ )
69
+ } finally {
70
+ Engine.reset()
71
+ }
72
+ })
42
73
  })
@@ -1,5 +1,6 @@
1
1
  import { fc, test } from '@fast-check/vitest'
2
2
  import { pbkdf2 as pbkdf2_noble } from '@noble/hashes/pbkdf2.js'
3
+ import { scrypt as scrypt_noble } from '@noble/hashes/scrypt.js'
3
4
  import { sha256 } from '@noble/hashes/sha2.js'
4
5
  import { beforeAll, describe, expect } from 'vp/test'
5
6
  import { numRuns } from '../../../test/fuzz/numRuns.js'
@@ -111,3 +112,52 @@ describe('pbkdf2Sha256', () => {
111
112
  expect(derived).toEqual(snapshot)
112
113
  })
113
114
  })
115
+
116
+ describe('scrypt', () => {
117
+ test.prop(
118
+ {
119
+ dkLen: arbitraryDkLen,
120
+ logN: fc.integer({ max: 7, min: 1 }),
121
+ p: fc.integer({ max: 3, min: 1 }),
122
+ password: arbitraryPassword,
123
+ r: fc.integer({ max: 4, min: 1 }),
124
+ salt: arbitrarySalt,
125
+ },
126
+ { numRuns },
127
+ )(
128
+ 'matches @noble/hashes for arbitrary parameters and inputs',
129
+ ({ dkLen, logN, p, password, r, salt }) => {
130
+ const options = { N: 2 ** logN, dkLen, p, r }
131
+ expect(keystore.scrypt(password, salt, options)).toEqual(
132
+ scrypt_noble(password, salt, options),
133
+ )
134
+ },
135
+ )
136
+
137
+ test.prop(
138
+ {
139
+ dkLen: arbitraryDkLen,
140
+ logN: fc.integer({ max: 7, min: 1 }),
141
+ p: fc.integer({ max: 3, min: 1 }),
142
+ password: arbitraryPassword,
143
+ r: fc.integer({ max: 4, min: 1 }),
144
+ salt: arbitrarySalt,
145
+ },
146
+ { numRuns },
147
+ )(
148
+ 'handles subviews without mutating either backing buffer',
149
+ ({ dkLen, logN, p, password, r, salt }) => {
150
+ const password_ = asSubview(password)
151
+ const salt_ = asSubview(salt)
152
+ const passwordSnapshot = password_.backing.slice()
153
+ const saltSnapshot = salt_.backing.slice()
154
+ const options = { N: 2 ** logN, dkLen, p, r }
155
+
156
+ expect(keystore.scrypt(password_.view, salt_.view, options)).toEqual(
157
+ scrypt_noble(password_.view, salt_.view, options),
158
+ )
159
+ expect(password_.backing).toEqual(passwordSnapshot)
160
+ expect(salt_.backing).toEqual(saltSnapshot)
161
+ },
162
+ )
163
+ })
@@ -15,11 +15,20 @@ test('synchronous PBKDF2 is present', () => {
15
15
  >()
16
16
  })
17
17
 
18
+ test('synchronous scrypt is present', () => {
19
+ expectTypeOf<Slot['scrypt']>().toEqualTypeOf<
20
+ (
21
+ password: Uint8Array,
22
+ salt: Uint8Array,
23
+ options: { N: number; dkLen: number; p: number; r: number },
24
+ ) => Uint8Array
25
+ >()
26
+ })
27
+
18
28
  test('unsupported primitives are absent', () => {
19
29
  expectTypeOf<Slot>().not.toHaveProperty('aesCtrDecrypt')
20
30
  expectTypeOf<Slot>().not.toHaveProperty('aesCtrEncrypt')
21
31
  expectTypeOf<Slot>().not.toHaveProperty('pbkdf2Sha256Async')
22
- expectTypeOf<Slot>().not.toHaveProperty('scrypt')
23
32
  expectTypeOf<Slot>().not.toHaveProperty('scryptAsync')
24
33
  })
25
34
 
@@ -1,4 +1,5 @@
1
1
  import { pbkdf2 as pbkdf2_noble } from '@noble/hashes/pbkdf2.js'
2
+ import { scrypt as scrypt_noble } from '@noble/hashes/scrypt.js'
2
3
  import { sha256 } from '@noble/hashes/sha2.js'
3
4
  import { beforeAll, describe, expect, test } from 'vp/test'
4
5
  import * as Bytes from '../../core/Bytes.js'
@@ -6,9 +7,11 @@ import * as Engine from '../../core/Engine.js'
6
7
  import * as Keystore from '../../core/Keystore.js'
7
8
  import * as WasmKeystore from '../Keystore.js'
8
9
  import * as hashes from '../internal/hashes.js'
9
- import { wasmBase64 } from '../internal/hashes.wasm.js'
10
+ import { wasmBase64 as hashesWasmBase64 } from '../internal/hashes.wasm.js'
10
11
  import * as internal from '../internal/instantiate.js'
11
12
  import * as pbkdf2 from '../internal/pbkdf2.js'
13
+ import * as scrypt from '../internal/scrypt.js'
14
+ import { wasmBase64 as scryptWasmBase64 } from '../internal/scrypt.wasm.js'
12
15
 
13
16
  let engine: WasmKeystore.engine.ReturnType
14
17
 
@@ -25,6 +28,7 @@ describe('engine', () => {
25
28
  expect(Object.keys(await WasmKeystore.engine())).toMatchInlineSnapshot(`
26
29
  [
27
30
  "pbkdf2Sha256",
31
+ "scrypt",
28
32
  ]
29
33
  `)
30
34
  })
@@ -34,6 +38,11 @@ describe('engine', () => {
34
38
  expect(a).toBe(b)
35
39
  })
36
40
 
41
+ test('behavior: shares the compiled scrypt instance', async () => {
42
+ const [a, b] = await Promise.all([scrypt.load(), scrypt.load()])
43
+ expect(a).toBe(b)
44
+ })
45
+
37
46
  test('behavior: hands every caller its own engine', async () => {
38
47
  const [a, b] = await Promise.all([
39
48
  WasmKeystore.engine(),
@@ -105,7 +114,7 @@ describe('pbkdf2Sha256', () => {
105
114
  })
106
115
 
107
116
  test('behavior: clears passwords, salts, outputs, and scratch', async () => {
108
- const module = await internal.instantiate<hashes.Exports>(wasmBase64)
117
+ const module = await internal.instantiate<hashes.Exports>(hashesWasmBase64)
109
118
  const password = input(65)
110
119
  const salt = input(52)
111
120
  const stack = module.view().slice(0, module.heapBase)
@@ -120,7 +129,7 @@ describe('pbkdf2Sha256', () => {
120
129
  })
121
130
 
122
131
  test('behavior: clears the complete region after a late trap', async () => {
123
- const module = await internal.instantiate<hashes.Exports>(wasmBase64)
132
+ const module = await internal.instantiate<hashes.Exports>(hashesWasmBase64)
124
133
  const password = input(65)
125
134
  const salt = input(52)
126
135
  const exports: pbkdf2.Exports = {
@@ -143,7 +152,7 @@ describe('pbkdf2Sha256', () => {
143
152
  })
144
153
 
145
154
  test('behavior: rejects a workspace that overflows wasm32 before growing memory', async () => {
146
- const module = await internal.instantiate<hashes.Exports>(wasmBase64)
155
+ const module = await internal.instantiate<hashes.Exports>(hashesWasmBase64)
147
156
  const memory = module.view().length
148
157
 
149
158
  expect(() =>
@@ -167,6 +176,236 @@ describe('pbkdf2Sha256', () => {
167
176
  })
168
177
  })
169
178
 
179
+ const scryptCases = [
180
+ { N: 16, dkLen: 64, p: 1, password: 0, r: 1, salt: 0 },
181
+ { N: 1024, dkLen: 32, p: 1, password: 8, r: 1, salt: 16 },
182
+ { N: 1024, dkLen: 64, p: 1, password: 65, r: 8, salt: 52 },
183
+ { N: 1024, dkLen: 33, p: 2, password: 9, r: 4, salt: 17 },
184
+ ] as const
185
+
186
+ describe('scrypt', () => {
187
+ test.each(scryptCases)(
188
+ 'matches the default for password=$password salt=$salt N=$N r=$r p=$p dkLen=$dkLen',
189
+ ({ N, dkLen, p, password: passwordLength, r, salt: saltLength }) => {
190
+ const password = input(passwordLength)
191
+ const salt = input(saltLength)
192
+ const options = { N, dkLen, p, r }
193
+ expect(engine.scrypt(password, salt, options)).toEqual(
194
+ scrypt_noble(password, salt, options),
195
+ )
196
+ },
197
+ )
198
+
199
+ test.each([
200
+ {
201
+ N: 16,
202
+ expected:
203
+ '0x77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906',
204
+ p: 1,
205
+ password: '',
206
+ r: 1,
207
+ salt: '',
208
+ },
209
+ {
210
+ N: 1024,
211
+ expected:
212
+ '0xfdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640',
213
+ p: 16,
214
+ password: 'password',
215
+ r: 8,
216
+ salt: 'NaCl',
217
+ },
218
+ {
219
+ N: 16_384,
220
+ expected:
221
+ '0x7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887',
222
+ p: 1,
223
+ password: 'pleaseletmein',
224
+ r: 8,
225
+ salt: 'SodiumChloride',
226
+ },
227
+ ])(
228
+ 'matches the RFC 7914 vector for N=$N r=$r p=$p',
229
+ ({ N, expected, p, password, r, salt }) => {
230
+ expect(
231
+ Bytes.toHex(
232
+ engine.scrypt(Bytes.fromString(password), Bytes.fromString(salt), {
233
+ N,
234
+ dkLen: 64,
235
+ p,
236
+ r,
237
+ }),
238
+ ),
239
+ ).toBe(expected)
240
+ },
241
+ )
242
+
243
+ test('behavior: reads non-zero-offset views without mutating their backing buffers', () => {
244
+ const passwordBacking = new Uint8Array(80).fill(0xa5)
245
+ const saltBacking = new Uint8Array(90).fill(0x5a)
246
+ const password = passwordBacking.subarray(7, 72)
247
+ const salt = saltBacking.subarray(11, 63)
248
+ password.set(input(password.length))
249
+ salt.set(input(salt.length))
250
+ const passwordSnapshot = passwordBacking.slice()
251
+ const saltSnapshot = saltBacking.slice()
252
+ const options = { N: 1024, dkLen: 65, p: 2, r: 1 }
253
+
254
+ expect(engine.scrypt(password, salt, options)).toEqual(
255
+ scrypt_noble(password, salt, options),
256
+ )
257
+ expect(passwordBacking).toEqual(passwordSnapshot)
258
+ expect(saltBacking).toEqual(saltSnapshot)
259
+ })
260
+
261
+ test('behavior: results are fresh and never alias WASM memory', () => {
262
+ const first = engine.scrypt(input(65), input(52), {
263
+ N: 16,
264
+ dkLen: 65,
265
+ p: 1,
266
+ r: 1,
267
+ })
268
+ const snapshot = first.slice()
269
+ const second = engine.scrypt(input(5), input(9), {
270
+ N: 32,
271
+ dkLen: 97,
272
+ p: 1,
273
+ r: 1,
274
+ })
275
+
276
+ expect(first).not.toBe(second)
277
+ expect(first).toEqual(snapshot)
278
+ })
279
+
280
+ test('behavior: clears inputs, outputs, and every workspace', async () => {
281
+ const module = await internal.instantiate<scrypt.Exports>(scryptWasmBase64)
282
+ const password = input(65)
283
+ const salt = input(52)
284
+ const options = { N: 16, dkLen: 65, p: 2, r: 2 }
285
+ const stack = module.view().slice(0, module.heapBase)
286
+
287
+ expect(scrypt.derive(module, password, salt, options)).toEqual(
288
+ scrypt_noble(password, salt, options),
289
+ )
290
+ expect(module.view().slice(0, module.heapBase)).toEqual(stack)
291
+ expect(module.view().slice(module.heapBase)).toEqual(
292
+ new Uint8Array(module.view().length - module.heapBase),
293
+ )
294
+ })
295
+
296
+ test('behavior: clears the complete region after a late trap', async () => {
297
+ const module = await internal.instantiate<scrypt.Exports>(scryptWasmBase64)
298
+ const password = input(65)
299
+ const salt = input(52)
300
+ const exports: scrypt.Exports = {
301
+ scrypt(...parameters) {
302
+ module.exports.scrypt(...parameters)
303
+ throw new WebAssembly.RuntimeError('forced late trap')
304
+ },
305
+ zero: (ptr, length) => module.exports.zero(ptr, length),
306
+ }
307
+
308
+ expect(() =>
309
+ scrypt.derive({ ...module, exports }, password, salt, {
310
+ N: 16,
311
+ dkLen: 65,
312
+ p: 2,
313
+ r: 2,
314
+ }),
315
+ ).toThrow(WebAssembly.RuntimeError)
316
+ expect(module.view().slice(module.heapBase)).toEqual(
317
+ new Uint8Array(module.view().length - module.heapBase),
318
+ )
319
+ })
320
+
321
+ test('behavior: rejects the workspace limit before growing memory', async () => {
322
+ const module = await internal.instantiate<scrypt.Exports>(scryptWasmBase64)
323
+ const memory = module.view().length
324
+
325
+ expect(() =>
326
+ scrypt.derive(module, new Uint8Array(), new Uint8Array(), {
327
+ N: 1_048_576,
328
+ dkLen: 32,
329
+ p: 1,
330
+ r: 16,
331
+ }),
332
+ ).toThrow(
333
+ '"maxmem" limit was hit: memUsed(128*r*(N+p+1))=2147487744, maxmem=1073742848',
334
+ )
335
+ expect(module.view()).toHaveLength(memory)
336
+ })
337
+
338
+ test('behavior: rejects the WASM memory limit before growing memory', async () => {
339
+ const module = await internal.instantiate<scrypt.Exports>(scryptWasmBase64)
340
+ const memory = module.view().length
341
+
342
+ expect(() =>
343
+ scrypt.derive(module, new Uint8Array(), new Uint8Array(), {
344
+ N: 2,
345
+ dkLen: 1_074_790_400,
346
+ p: 1,
347
+ r: 1,
348
+ }),
349
+ ).toThrow(internal.MemoryError)
350
+ expect(module.view()).toHaveLength(memory)
351
+ })
352
+
353
+ test('behavior: rejects reentrant use of one instance without corrupting the outer call', async () => {
354
+ const module = await internal.instantiate<scrypt.Exports>(scryptWasmBase64)
355
+ const password = input(8)
356
+ const salt = input(16)
357
+ const options = { N: 16, dkLen: 32, p: 1, r: 1 }
358
+ let reentered = false
359
+ const wrapper: internal.Module<scrypt.Exports> = {
360
+ ...module,
361
+ exports: {
362
+ scrypt(...parameters) {
363
+ expect(() => scrypt.derive(wrapper, password, salt, options)).toThrow(
364
+ 'The scrypt WASM instance is already deriving a key.',
365
+ )
366
+ reentered = true
367
+ module.exports.scrypt(...parameters)
368
+ },
369
+ zero: (ptr, length) => module.exports.zero(ptr, length),
370
+ },
371
+ }
372
+
373
+ expect(scrypt.derive(wrapper, password, salt, options)).toEqual(
374
+ scrypt_noble(password, salt, options),
375
+ )
376
+ expect(reentered).toBe(true)
377
+ })
378
+
379
+ test.each([
380
+ { N: 1, dkLen: 32, p: 1, r: 8 },
381
+ { N: 3, dkLen: 32, p: 1, r: 8 },
382
+ { N: 1024.5, dkLen: 32, p: 1, r: 8 },
383
+ { N: 1024, dkLen: 32, p: 1, r: -1 },
384
+ { N: 1024, dkLen: 32, p: 0, r: 8 },
385
+ { N: 1024, dkLen: 0, p: 1, r: 8 },
386
+ { N: 1024, dkLen: 32, p: 1, r: 0 },
387
+ ])(
388
+ 'behavior: matches the default error for N=$N r=$r p=$p dkLen=$dkLen',
389
+ (options) => {
390
+ const getError = (fn: () => unknown) => {
391
+ try {
392
+ fn()
393
+ } catch (error) {
394
+ return {
395
+ message: (error as Error).message,
396
+ name: (error as Error).constructor.name,
397
+ }
398
+ }
399
+ throw new Error('Expected derivation to throw.')
400
+ }
401
+
402
+ expect(
403
+ getError(() => engine.scrypt(input(8), input(16), options)),
404
+ ).toEqual(getError(() => scrypt_noble(input(8), input(16), options)))
405
+ },
406
+ )
407
+ })
408
+
170
409
  describe('Engine.install', () => {
171
410
  test('behavior: ox uses synchronous WASM PBKDF2 once installed', async () => {
172
411
  await Engine.install({ Keystore: engine })
@@ -189,4 +428,50 @@ describe('Engine.install', () => {
189
428
  Engine.reset()
190
429
  }
191
430
  })
431
+
432
+ test('behavior: ox uses synchronous WASM scrypt once installed', async () => {
433
+ const wasm = engine.scrypt
434
+ let calls = 0
435
+ await Engine.install({
436
+ Keystore: {
437
+ ...engine,
438
+ scrypt(...parameters) {
439
+ calls++
440
+ return wasm(...parameters)
441
+ },
442
+ },
443
+ })
444
+ try {
445
+ const salt = input(32)
446
+ const [key] = Keystore.scrypt({
447
+ n: 1024,
448
+ p: 2,
449
+ password: 'testpassword',
450
+ r: 1,
451
+ salt,
452
+ })
453
+ expect(key()).toBe(
454
+ Bytes.toHex(
455
+ scrypt_noble(Bytes.fromString('testpassword'), salt, {
456
+ N: 1024,
457
+ dkLen: 32,
458
+ p: 2,
459
+ r: 1,
460
+ }),
461
+ ),
462
+ )
463
+ expect(calls).toBe(1)
464
+
465
+ await Keystore.scryptAsync({
466
+ n: 1024,
467
+ p: 1,
468
+ password: 'testpassword',
469
+ r: 1,
470
+ salt,
471
+ })
472
+ expect(calls).toBe(1)
473
+ } finally {
474
+ Engine.reset()
475
+ }
476
+ })
192
477
  })
@@ -0,0 +1,19 @@
1
+ import { expectTypeOf, test } from 'vp/test'
2
+ import type * as CoreKzg from '../../core/Kzg.js'
3
+ import { mainnet as trustedSetup } from '../../trusted-setups/Setups.js'
4
+ import * as Kzg from '../Kzg.js'
5
+
6
+ test('create returns a disposable Kzg.Kzg implementation', async () => {
7
+ const instance = await Kzg.create({ trustedSetup })
8
+
9
+ expectTypeOf(instance).toMatchTypeOf<CoreKzg.Kzg>()
10
+ expectTypeOf<Kzg.create.ReturnType['dispose']>().toEqualTypeOf<() => void>()
11
+ })
12
+
13
+ test('trusted setup accepts packed bytes', () => {
14
+ expectTypeOf<Kzg.TrustedSetup>().toEqualTypeOf<{
15
+ readonly g1_lagrange: Uint8Array | readonly string[]
16
+ readonly g1_monomial: Uint8Array | readonly string[]
17
+ readonly g2_monomial: Uint8Array | readonly string[]
18
+ }>()
19
+ })