ox 1.1.0 → 1.2.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 (284) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/core/Engine.d.ts +43 -11
  3. package/dist/core/Engine.d.ts.map +1 -1
  4. package/dist/core/Engine.js +40 -10
  5. package/dist/core/Engine.js.map +1 -1
  6. package/dist/core/Hash.d.ts +36 -0
  7. package/dist/core/Hash.d.ts.map +1 -1
  8. package/dist/core/Hash.js +35 -0
  9. package/dist/core/Hash.js.map +1 -1
  10. package/dist/core/internal/engine.d.ts +8 -8
  11. package/dist/core/internal/engine.d.ts.map +1 -1
  12. package/dist/index.d.ts +5 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +5 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist/node/Ed25519.d.ts +33 -0
  17. package/dist/node/Ed25519.d.ts.map +1 -0
  18. package/dist/node/Ed25519.js +67 -0
  19. package/dist/node/Ed25519.js.map +1 -0
  20. package/dist/node/Engine.d.ts +29 -16
  21. package/dist/node/Engine.d.ts.map +1 -1
  22. package/dist/node/Engine.js +38 -14
  23. package/dist/node/Engine.js.map +1 -1
  24. package/dist/node/Hash.d.ts +17 -19
  25. package/dist/node/Hash.d.ts.map +1 -1
  26. package/dist/node/Hash.js +17 -19
  27. package/dist/node/Hash.js.map +1 -1
  28. package/dist/node/Keystore.d.ts +36 -0
  29. package/dist/node/Keystore.d.ts.map +1 -0
  30. package/dist/node/Keystore.js +72 -0
  31. package/dist/node/Keystore.js.map +1 -0
  32. package/dist/node/Mnemonic.d.ts +35 -0
  33. package/dist/node/Mnemonic.d.ts.map +1 -0
  34. package/dist/node/Mnemonic.js +46 -0
  35. package/dist/node/Mnemonic.js.map +1 -0
  36. package/dist/node/P256.d.ts +32 -0
  37. package/dist/node/P256.d.ts.map +1 -0
  38. package/dist/node/P256.js +34 -0
  39. package/dist/node/P256.js.map +1 -0
  40. package/dist/node/X25519.d.ts +31 -0
  41. package/dist/node/X25519.d.ts.map +1 -0
  42. package/dist/node/X25519.js +71 -0
  43. package/dist/node/X25519.js.map +1 -0
  44. package/dist/node/index.d.ts +95 -8
  45. package/dist/node/index.d.ts.map +1 -1
  46. package/dist/node/index.js +95 -8
  47. package/dist/node/index.js.map +1 -1
  48. package/dist/trusted-setups/Paths.d.ts +1 -0
  49. package/dist/trusted-setups/Paths.d.ts.map +1 -1
  50. package/dist/trusted-setups/Paths.js +1 -0
  51. package/dist/trusted-setups/Paths.js.map +1 -1
  52. package/dist/trusted-setups/Setups.d.ts +35 -0
  53. package/dist/trusted-setups/Setups.d.ts.map +1 -0
  54. package/dist/trusted-setups/Setups.js +29 -0
  55. package/dist/trusted-setups/Setups.js.map +1 -0
  56. package/dist/trusted-setups/index.d.ts +20 -0
  57. package/dist/trusted-setups/index.d.ts.map +1 -1
  58. package/dist/trusted-setups/index.js +20 -0
  59. package/dist/trusted-setups/index.js.map +1 -1
  60. package/dist/trusted-setups/internal/paths.d.ts.map +1 -1
  61. package/dist/trusted-setups/internal/paths.js +1 -1
  62. package/dist/trusted-setups/internal/paths.js.map +1 -1
  63. package/dist/trusted-setups/internal/setups/mainnet.d.ts +7 -0
  64. package/dist/trusted-setups/internal/setups/mainnet.d.ts.map +1 -0
  65. package/dist/trusted-setups/internal/setups/mainnet.js +11 -0
  66. package/dist/trusted-setups/internal/setups/mainnet.js.map +1 -0
  67. package/dist/wasm/Ed25519.d.ts +35 -0
  68. package/dist/wasm/Ed25519.d.ts.map +1 -0
  69. package/dist/wasm/Ed25519.js +88 -0
  70. package/dist/wasm/Ed25519.js.map +1 -0
  71. package/dist/wasm/Engine.d.ts +36 -26
  72. package/dist/wasm/Engine.d.ts.map +1 -1
  73. package/dist/wasm/Engine.js +44 -25
  74. package/dist/wasm/Engine.js.map +1 -1
  75. package/dist/wasm/Hash.d.ts +13 -19
  76. package/dist/wasm/Hash.d.ts.map +1 -1
  77. package/dist/wasm/Hash.js +21 -27
  78. package/dist/wasm/Hash.js.map +1 -1
  79. package/dist/wasm/Keystore.d.ts +51 -0
  80. package/dist/wasm/Keystore.d.ts.map +1 -0
  81. package/dist/wasm/Keystore.js +51 -0
  82. package/dist/wasm/Keystore.js.map +1 -0
  83. package/dist/wasm/Kzg.d.ts +112 -0
  84. package/dist/wasm/Kzg.d.ts.map +1 -0
  85. package/dist/wasm/Kzg.js +333 -0
  86. package/dist/wasm/Kzg.js.map +1 -0
  87. package/dist/wasm/Mnemonic.d.ts +33 -0
  88. package/dist/wasm/Mnemonic.d.ts.map +1 -0
  89. package/dist/wasm/Mnemonic.js +30 -0
  90. package/dist/wasm/Mnemonic.js.map +1 -0
  91. package/dist/wasm/Secp256k1.d.ts +55 -0
  92. package/dist/wasm/Secp256k1.d.ts.map +1 -0
  93. package/dist/wasm/Secp256k1.js +181 -0
  94. package/dist/wasm/Secp256k1.js.map +1 -0
  95. package/dist/wasm/X25519.d.ts +33 -0
  96. package/dist/wasm/X25519.d.ts.map +1 -0
  97. package/dist/wasm/X25519.js +53 -0
  98. package/dist/wasm/X25519.js.map +1 -0
  99. package/dist/wasm/index.d.ts +124 -12
  100. package/dist/wasm/index.d.ts.map +1 -1
  101. package/dist/wasm/index.js +124 -12
  102. package/dist/wasm/index.js.map +1 -1
  103. package/dist/wasm/internal/blake3.d.ts +11 -0
  104. package/dist/wasm/internal/blake3.d.ts.map +1 -0
  105. package/dist/wasm/internal/blake3.js +31 -0
  106. package/dist/wasm/internal/blake3.js.map +1 -0
  107. package/dist/wasm/internal/blake3.wasm.d.ts +3 -0
  108. package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -0
  109. package/dist/wasm/internal/blake3.wasm.js +10 -0
  110. package/dist/wasm/internal/blake3.wasm.js.map +1 -0
  111. package/dist/wasm/internal/crypto25519.d.ts +16 -0
  112. package/dist/wasm/internal/crypto25519.d.ts.map +1 -0
  113. package/dist/wasm/internal/crypto25519.js +5 -0
  114. package/dist/wasm/internal/crypto25519.js.map +1 -0
  115. package/dist/wasm/internal/crypto25519.wasm.d.ts +3 -0
  116. package/dist/wasm/internal/crypto25519.wasm.d.ts.map +1 -0
  117. package/dist/wasm/internal/crypto25519.wasm.js +10 -0
  118. package/dist/wasm/internal/crypto25519.wasm.js.map +1 -0
  119. package/dist/wasm/internal/ed25519.d.ts +4 -0
  120. package/dist/wasm/internal/ed25519.d.ts.map +1 -0
  121. package/dist/wasm/internal/ed25519.js +21 -0
  122. package/dist/wasm/internal/ed25519.js.map +1 -0
  123. package/dist/wasm/internal/hashes.d.ts +12 -0
  124. package/dist/wasm/internal/hashes.d.ts.map +1 -0
  125. package/dist/wasm/internal/hashes.js +8 -0
  126. package/dist/wasm/internal/hashes.js.map +1 -0
  127. package/dist/wasm/internal/hashes.wasm.d.ts +4 -2
  128. package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -1
  129. package/dist/wasm/internal/hashes.wasm.js +4 -2
  130. package/dist/wasm/internal/hashes.wasm.js.map +1 -1
  131. package/dist/wasm/internal/instantiate.d.ts +12 -0
  132. package/dist/wasm/internal/instantiate.d.ts.map +1 -1
  133. package/dist/wasm/internal/instantiate.js +23 -7
  134. package/dist/wasm/internal/instantiate.js.map +1 -1
  135. package/dist/wasm/internal/keystore.d.ts +10 -0
  136. package/dist/wasm/internal/keystore.d.ts.map +1 -0
  137. package/dist/wasm/internal/keystore.js +10 -0
  138. package/dist/wasm/internal/keystore.js.map +1 -0
  139. package/dist/wasm/internal/kzg.d.ts +17 -0
  140. package/dist/wasm/internal/kzg.d.ts.map +1 -0
  141. package/dist/wasm/internal/kzg.js +8 -0
  142. package/dist/wasm/internal/kzg.js.map +1 -0
  143. package/dist/wasm/internal/kzg.wasm.d.ts +3 -0
  144. package/dist/wasm/internal/kzg.wasm.d.ts.map +1 -0
  145. package/dist/wasm/internal/kzg.wasm.js +10 -0
  146. package/dist/wasm/internal/kzg.wasm.js.map +1 -0
  147. package/dist/wasm/internal/mnemonic.d.ts +4 -0
  148. package/dist/wasm/internal/mnemonic.d.ts.map +1 -0
  149. package/dist/wasm/internal/mnemonic.js +45 -0
  150. package/dist/wasm/internal/mnemonic.js.map +1 -0
  151. package/dist/wasm/internal/pbkdf2.d.ts +12 -0
  152. package/dist/wasm/internal/pbkdf2.d.ts.map +1 -0
  153. package/dist/wasm/internal/pbkdf2.js +51 -0
  154. package/dist/wasm/internal/pbkdf2.js.map +1 -0
  155. package/dist/wasm/internal/scrypt.d.ts +16 -0
  156. package/dist/wasm/internal/scrypt.d.ts.map +1 -0
  157. package/dist/wasm/internal/scrypt.js +78 -0
  158. package/dist/wasm/internal/scrypt.js.map +1 -0
  159. package/dist/wasm/internal/scrypt.wasm.d.ts +7 -0
  160. package/dist/wasm/internal/scrypt.wasm.d.ts.map +1 -0
  161. package/dist/wasm/internal/scrypt.wasm.js +14 -0
  162. package/dist/wasm/internal/scrypt.wasm.js.map +1 -0
  163. package/dist/wasm/internal/secp256k1.d.ts +16 -0
  164. package/dist/wasm/internal/secp256k1.d.ts.map +1 -0
  165. package/dist/wasm/internal/secp256k1.js +20 -0
  166. package/dist/wasm/internal/secp256k1.js.map +1 -0
  167. package/dist/wasm/internal/secp256k1.wasm.d.ts +3 -0
  168. package/dist/wasm/internal/secp256k1.wasm.d.ts.map +1 -0
  169. package/dist/wasm/internal/secp256k1.wasm.js +10 -0
  170. package/dist/wasm/internal/secp256k1.wasm.js.map +1 -0
  171. package/dist/wasm/internal/x25519.d.ts +4 -0
  172. package/dist/wasm/internal/x25519.d.ts.map +1 -0
  173. package/dist/wasm/internal/x25519.js +21 -0
  174. package/dist/wasm/internal/x25519.js.map +1 -0
  175. package/package.json +64 -2
  176. package/src/core/Engine.ts +84 -11
  177. package/src/core/Hash.ts +59 -0
  178. package/src/core/_test/Block.test.ts +9 -2
  179. package/src/core/_test/Engine.test-d.ts +56 -0
  180. package/src/core/_test/Engine.test.ts +95 -0
  181. package/src/core/_test/Hash.test-d.ts +18 -0
  182. package/src/core/_test/Hash.test.ts +100 -1
  183. package/src/core/_test/Hash.vectors.test.ts +7 -0
  184. package/src/core/_test/Transaction.test.ts +11 -2
  185. package/src/core/internal/engine.ts +8 -8
  186. package/src/index.ts +5 -2
  187. package/src/node/Ed25519.ts +87 -0
  188. package/src/node/Engine.ts +79 -23
  189. package/src/node/Hash.ts +25 -30
  190. package/src/node/Keystore.ts +103 -0
  191. package/src/node/Mnemonic.ts +68 -0
  192. package/src/node/P256.ts +48 -0
  193. package/src/node/X25519.ts +93 -0
  194. package/src/node/_test/Curves.fuzz.ts +76 -0
  195. package/src/node/_test/Ed25519.test-d.ts +35 -0
  196. package/src/node/_test/Ed25519.test.ts +220 -0
  197. package/src/node/_test/Engine.test-d.ts +28 -0
  198. package/src/node/_test/Engine.test.ts +62 -22
  199. package/src/node/_test/Hash.test-d.ts +16 -9
  200. package/src/node/_test/Hash.test.ts +10 -11
  201. package/src/node/_test/Keystore.fuzz.ts +58 -0
  202. package/src/node/_test/Keystore.test-d.ts +43 -0
  203. package/src/node/_test/Keystore.test.ts +198 -0
  204. package/src/node/_test/Mnemonic.fuzz.ts +31 -0
  205. package/src/node/_test/Mnemonic.test-d.ts +21 -0
  206. package/src/node/_test/Mnemonic.test.ts +98 -0
  207. package/src/node/_test/P256.test-d.ts +29 -0
  208. package/src/node/_test/P256.test.ts +102 -0
  209. package/src/node/_test/X25519.test-d.ts +28 -0
  210. package/src/node/_test/X25519.test.ts +239 -0
  211. package/src/node/index.ts +100 -8
  212. package/src/trusted-setups/Paths.ts +1 -0
  213. package/src/trusted-setups/README.md +39 -0
  214. package/src/trusted-setups/Setups.ts +46 -0
  215. package/src/trusted-setups/_test/Paths.test.ts +16 -0
  216. package/src/trusted-setups/_test/Setups.test-d.ts +7 -0
  217. package/src/trusted-setups/_test/Setups.test.ts +43 -0
  218. package/src/trusted-setups/_test/index.test.ts +1 -0
  219. package/src/trusted-setups/index.ts +21 -0
  220. package/src/trusted-setups/internal/paths.ts +4 -1
  221. package/src/trusted-setups/internal/setups/mainnet.source.json +7 -0
  222. package/src/trusted-setups/internal/setups/mainnet.ts +16 -0
  223. package/src/version.ts +1 -1
  224. package/src/wasm/Ed25519.ts +114 -0
  225. package/src/wasm/Engine.ts +78 -31
  226. package/src/wasm/Hash.bench.ts +2 -2
  227. package/src/wasm/Hash.ts +29 -50
  228. package/src/wasm/Keystore.bench.ts +26 -0
  229. package/src/wasm/Keystore.ts +66 -0
  230. package/src/wasm/Kzg.bench.ts +63 -0
  231. package/src/wasm/Kzg.ts +518 -0
  232. package/src/wasm/Mnemonic.ts +44 -0
  233. package/src/wasm/Secp256k1.bench.ts +79 -0
  234. package/src/wasm/Secp256k1.ts +248 -0
  235. package/src/wasm/X25519.ts +70 -0
  236. package/src/wasm/_test/Crypto25519.conformance.ts +57 -0
  237. package/src/wasm/_test/Crypto25519.fuzz.ts +187 -0
  238. package/src/wasm/_test/Ed25519.test-d.ts +28 -0
  239. package/src/wasm/_test/Ed25519.test.ts +168 -0
  240. package/src/wasm/_test/Ed25519.vectors.test.ts +73 -0
  241. package/src/wasm/_test/Engine.test-d.ts +29 -0
  242. package/src/wasm/_test/Engine.test.ts +59 -25
  243. package/src/wasm/_test/Hash.browser.test.ts +14 -7
  244. package/src/wasm/_test/Hash.fuzz.ts +58 -23
  245. package/src/wasm/_test/Hash.test-d.ts +16 -10
  246. package/src/wasm/_test/Hash.test.ts +148 -48
  247. package/src/wasm/_test/Hash.vectors.test.ts +15 -8
  248. package/src/wasm/_test/Keystore.browser.test.ts +73 -0
  249. package/src/wasm/_test/Keystore.fuzz.ts +163 -0
  250. package/src/wasm/_test/Keystore.test-d.ts +42 -0
  251. package/src/wasm/_test/Keystore.test.ts +477 -0
  252. package/src/wasm/_test/Keystore.vectors.test.ts +21 -0
  253. package/src/wasm/_test/Kzg.test-d.ts +19 -0
  254. package/src/wasm/_test/Kzg.test.ts +220 -0
  255. package/src/wasm/_test/Mnemonic.test-d.ts +17 -0
  256. package/src/wasm/_test/Mnemonic.test.ts +110 -0
  257. package/src/wasm/_test/Runtime.test.ts +9 -0
  258. package/src/wasm/_test/Secp256k1.test-d.ts +35 -0
  259. package/src/wasm/_test/Secp256k1.test.ts +354 -0
  260. package/src/wasm/_test/X25519.test-d.ts +21 -0
  261. package/src/wasm/_test/X25519.test.ts +194 -0
  262. package/src/wasm/_test/fixtures.ts +4 -0
  263. package/src/wasm/index.ts +130 -12
  264. package/src/wasm/internal/blake3.ts +45 -0
  265. package/src/wasm/internal/blake3.wasm.ts +11 -0
  266. package/src/wasm/internal/crypto25519.ts +43 -0
  267. package/src/wasm/internal/crypto25519.wasm.ts +11 -0
  268. package/src/wasm/internal/ed25519.ts +31 -0
  269. package/src/wasm/internal/hashes.ts +29 -0
  270. package/src/wasm/internal/hashes.wasm.ts +5 -2
  271. package/src/wasm/internal/instantiate.ts +29 -9
  272. package/src/wasm/internal/keystore.ts +19 -0
  273. package/src/wasm/internal/kzg.ts +50 -0
  274. package/src/wasm/internal/kzg.wasm.ts +11 -0
  275. package/src/wasm/internal/mnemonic.ts +56 -0
  276. package/src/wasm/internal/pbkdf2.ts +86 -0
  277. package/src/wasm/internal/scrypt.ts +131 -0
  278. package/src/wasm/internal/scrypt.wasm.ts +17 -0
  279. package/src/wasm/internal/secp256k1.ts +62 -0
  280. package/src/wasm/internal/secp256k1.wasm.ts +11 -0
  281. package/src/wasm/internal/x25519.ts +29 -0
  282. package/wasm/vendor/c-kzg-4844/LICENSE +201 -0
  283. package/wasm/vendor/c-kzg-4844/blst/LICENSE +201 -0
  284. package/src/trusted-setups/internal/setups/mainnet.txt +0 -4163
@@ -0,0 +1,198 @@
1
+ import { ctr } from '@noble/ciphers/aes.js'
2
+ import { pbkdf2 } from '@noble/hashes/pbkdf2.js'
3
+ import { sha256 } from '@noble/hashes/sha2.js'
4
+ import { Hex } from 'ox'
5
+ import { describe, expect, test } from 'vp/test'
6
+ import * as vectors from '../../../test/vectors/pbkdf2/index.js'
7
+ import * as Keystore from '../Keystore.js'
8
+
9
+ describe('engine', () => {
10
+ test('behavior: matches NIST SP 800-38A AES-CTR vectors', async () => {
11
+ const { aesCtrDecrypt, aesCtrEncrypt } = await Keystore.engine()
12
+ const iv = Hex.toBytes('0xf0f1f2f3f4f5f6f7f8f9fafbfcfdfeff')
13
+ const plaintext = Hex.toBytes('0x6bc1bee22e409f96e93d7e117393172a')
14
+ const vectors = [
15
+ {
16
+ ciphertext: '0x874d6191b620e3261bef6864990db6ce',
17
+ key: '0x2b7e151628aed2a6abf7158809cf4f3c',
18
+ },
19
+ {
20
+ ciphertext: '0x1abc932417521ca24f2b0459fe7e6e0b',
21
+ key: '0x8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b',
22
+ },
23
+ {
24
+ ciphertext: '0x601ec313775789a5b7a7f504bbf3d228',
25
+ key: '0x603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4',
26
+ },
27
+ ] as const
28
+
29
+ expect(
30
+ vectors.map(({ ciphertext, key }) => {
31
+ const encrypted = aesCtrEncrypt(Hex.toBytes(key), iv, plaintext)
32
+ const decrypted = aesCtrDecrypt(
33
+ Hex.toBytes(key),
34
+ iv,
35
+ Hex.toBytes(ciphertext),
36
+ )
37
+ return {
38
+ decrypted: Hex.fromBytes(decrypted),
39
+ encrypted: Hex.fromBytes(encrypted),
40
+ }
41
+ }),
42
+ ).toMatchInlineSnapshot(`
43
+ [
44
+ {
45
+ "decrypted": "0x6bc1bee22e409f96e93d7e117393172a",
46
+ "encrypted": "0x874d6191b620e3261bef6864990db6ce",
47
+ },
48
+ {
49
+ "decrypted": "0x6bc1bee22e409f96e93d7e117393172a",
50
+ "encrypted": "0x1abc932417521ca24f2b0459fe7e6e0b",
51
+ },
52
+ {
53
+ "decrypted": "0x6bc1bee22e409f96e93d7e117393172a",
54
+ "encrypted": "0x601ec313775789a5b7a7f504bbf3d228",
55
+ },
56
+ ]
57
+ `)
58
+ })
59
+
60
+ test('behavior: matches RFC 7914 PBKDF2-HMAC-SHA256 vectors', async () => {
61
+ const { pbkdf2Sha256 } = await Keystore.engine()
62
+
63
+ for (const { iterations, key, password, salt } of vectors.vectors)
64
+ expect(
65
+ pbkdf2Sha256(password, salt, {
66
+ c: iterations,
67
+ dkLen: key.length,
68
+ }),
69
+ ).toEqual(key)
70
+ })
71
+
72
+ test('behavior: agrees with the defaults across boundary sizes', async () => {
73
+ const node = await Keystore.engine()
74
+ const iv = Uint8Array.from(
75
+ { length: 20 },
76
+ (_, index) => (index * 13) % 251,
77
+ ).subarray(2, 18)
78
+
79
+ for (const keySize of [16, 24, 32]) {
80
+ const key = Uint8Array.from(
81
+ { length: keySize + 4 },
82
+ (_, index) => (index * 17) % 251,
83
+ ).subarray(2, keySize + 2)
84
+
85
+ for (const size of [0, 1, 15, 16, 17, 31, 32, 33]) {
86
+ const data = Uint8Array.from(
87
+ { length: size + 6 },
88
+ (_, index) => (index * 29) % 251,
89
+ ).subarray(3, size + 3)
90
+ const encrypted = node.aesCtrEncrypt(key, iv, data)
91
+
92
+ expect(encrypted).toEqual(ctr(key, iv).encrypt(data))
93
+ expect(node.aesCtrDecrypt(key, iv, encrypted)).toEqual(data)
94
+ }
95
+ }
96
+
97
+ const password = Uint8Array.from(
98
+ { length: 37 },
99
+ (_, index) => (index * 31) % 251,
100
+ ).subarray(3, 34)
101
+ const salt = Uint8Array.from(
102
+ { length: 41 },
103
+ (_, index) => (index * 37) % 251,
104
+ ).subarray(5, 37)
105
+
106
+ for (const options of [
107
+ { c: 1, dkLen: 1 },
108
+ { c: 2, dkLen: 31 },
109
+ { c: 3, dkLen: 32 },
110
+ { c: 4, dkLen: 33 },
111
+ { c: 16, dkLen: 64 },
112
+ ]) {
113
+ const expected = pbkdf2(sha256, password, salt, options)
114
+ expect(node.pbkdf2Sha256(password, salt, options)).toEqual(expected)
115
+ expect(await node.pbkdf2Sha256Async(password, salt, options)).toEqual(
116
+ expected,
117
+ )
118
+ }
119
+ })
120
+
121
+ test('behavior: does not mutate inputs and returns owned arrays', async () => {
122
+ const node = await Keystore.engine()
123
+ const data = Uint8Array.of(1, 2, 3, 4, 5)
124
+ const iv = new Uint8Array(16).fill(2)
125
+ const key = new Uint8Array(16).fill(3)
126
+ const password = Uint8Array.of(4, 5, 6)
127
+ const salt = Uint8Array.of(7, 8, 9)
128
+ const inputs = [data, iv, key, password, salt]
129
+ const before = inputs.map((input) => input.slice())
130
+
131
+ const outputs = [
132
+ node.aesCtrEncrypt(key, iv, data),
133
+ node.aesCtrDecrypt(key, iv, data),
134
+ node.pbkdf2Sha256(password, salt, { c: 1, dkLen: 32 }),
135
+ await node.pbkdf2Sha256Async(password, salt, { c: 1, dkLen: 32 }),
136
+ ]
137
+
138
+ expect(inputs).toEqual(before)
139
+ expect(outputs.map((output) => output.constructor === Uint8Array))
140
+ .toMatchInlineSnapshot(`
141
+ [
142
+ true,
143
+ true,
144
+ true,
145
+ true,
146
+ ]
147
+ `)
148
+ expect(
149
+ node.aesCtrEncrypt(key, iv, data) === node.aesCtrEncrypt(key, iv, data),
150
+ ).toMatchInlineSnapshot('false')
151
+ })
152
+
153
+ test('behavior: rejects malformed AES and PBKDF2 parameters', async () => {
154
+ const node = await Keystore.engine()
155
+ const data = new Uint8Array()
156
+ const iv = new Uint8Array(16)
157
+ const key = new Uint8Array(16)
158
+
159
+ for (const keyLength of [0, 15, 17, 23, 25, 31, 33]) {
160
+ expect(() => ctr(new Uint8Array(keyLength), iv).encrypt(data)).toThrow()
161
+ expect(() =>
162
+ node.aesCtrEncrypt(new Uint8Array(keyLength), iv, data),
163
+ ).toThrow()
164
+ expect(() =>
165
+ node.aesCtrDecrypt(new Uint8Array(keyLength), iv, data),
166
+ ).toThrow()
167
+ }
168
+ for (const ivLength of [0, 15, 17]) {
169
+ expect(() => ctr(key, new Uint8Array(ivLength)).encrypt(data)).toThrow()
170
+ expect(() =>
171
+ node.aesCtrEncrypt(key, new Uint8Array(ivLength), data),
172
+ ).toThrow()
173
+ expect(() =>
174
+ node.aesCtrDecrypt(key, new Uint8Array(ivLength), data),
175
+ ).toThrow()
176
+ }
177
+
178
+ for (const options of [
179
+ { c: 0, dkLen: 32 },
180
+ { c: 1.5, dkLen: 32 },
181
+ { c: 1, dkLen: 0 },
182
+ { c: 1, dkLen: 1.5 },
183
+ ]) {
184
+ expect(() => pbkdf2(sha256, data, data, options)).toThrow()
185
+ expect(() => node.pbkdf2Sha256(data, data, options)).toThrow()
186
+ await expect(
187
+ node.pbkdf2Sha256Async(data, data, options),
188
+ ).rejects.toThrow()
189
+ }
190
+ })
191
+
192
+ test('behavior: returns a fresh engine', async () => {
193
+ const first = await Keystore.engine()
194
+ const second = await Keystore.engine()
195
+
196
+ expect(first === second).toMatchInlineSnapshot('false')
197
+ })
198
+ })
@@ -0,0 +1,31 @@
1
+ import { mnemonicToSeedSync } from '@scure/bip39'
2
+ import { fc, test } from '@fast-check/vitest'
3
+ import { expect } from 'vp/test'
4
+ import { numRuns } from '../../../test/fuzz/numRuns.js'
5
+ import * as Mnemonic from '../Mnemonic.js'
6
+
7
+ const arbitraryWord = fc.oneof(
8
+ fc
9
+ .string({ maxLength: 16, minLength: 1 })
10
+ .filter((value) => !value.normalize('NFKD').includes(' ')),
11
+ fc.constantFrom('café', 'cafe\u0301', 'あおぞら', '㍍ガバヴァ'),
12
+ )
13
+
14
+ test.prop(
15
+ {
16
+ mnemonic: fc
17
+ .array(arbitraryWord, { maxLength: 12, minLength: 12 })
18
+ .map((words) => words.join(' ')),
19
+ passphrase: fc.string({ maxLength: 32 }),
20
+ },
21
+ { numRuns },
22
+ )(
23
+ 'Node BIP-39 seed derivation agrees with the default',
24
+ async ({ mnemonic, passphrase }) => {
25
+ const { toSeed } = await Mnemonic.engine()
26
+
27
+ expect(toSeed(mnemonic, passphrase)).toEqual(
28
+ mnemonicToSeedSync(mnemonic, passphrase),
29
+ )
30
+ },
31
+ )
@@ -0,0 +1,21 @@
1
+ import { expectTypeOf, test } from 'vp/test'
2
+ import type * as Engine from '../../core/Engine.js'
3
+ import * as core_Mnemonic from '../../core/Mnemonic.js'
4
+ import * as NodeMnemonic from '../Mnemonic.js'
5
+
6
+ type Slot = Awaited<ReturnType<typeof NodeMnemonic.engine>>
7
+
8
+ test('every implemented primitive is present', () => {
9
+ expectTypeOf<Slot['toSeed']>().toEqualTypeOf<
10
+ (mnemonic: string, passphrase?: string) => Uint8Array
11
+ >()
12
+ })
13
+
14
+ test('the result is the raw slot', () => {
15
+ expectTypeOf<{ Mnemonic: Slot }>().toExtend<Engine.Engine>()
16
+ })
17
+
18
+ test('the Node namespace exposes the public Mnemonic API', () => {
19
+ expectTypeOf(NodeMnemonic.toSeed).toEqualTypeOf(core_Mnemonic.toSeed)
20
+ expectTypeOf<typeof NodeMnemonic>().not.toHaveProperty('create')
21
+ })
@@ -0,0 +1,98 @@
1
+ import { mnemonicToSeedSync } from '@scure/bip39'
2
+ import { Hex } from 'ox'
3
+ import { describe, expect, test } from 'vp/test'
4
+ import * as bip39 from '../../../test/vectors/bip39/index.js'
5
+ import * as Mnemonic from '../Mnemonic.js'
6
+
7
+ describe('engine', () => {
8
+ test('behavior: matches the BIP-39 English vector', async () => {
9
+ const { toSeed } = await Mnemonic.engine()
10
+ const { mnemonic, passphrase, seed } = bip39.vectors.english
11
+
12
+ expect(Hex.fromBytes(toSeed(mnemonic, passphrase))).toBe(`0x${seed}`)
13
+ })
14
+
15
+ test('behavior: matches the BIP-39 Japanese Unicode vector', async () => {
16
+ const { toSeed } = await Mnemonic.engine()
17
+ const { mnemonic, passphrase, seed } = bip39.vectors.japanese
18
+
19
+ expect(Hex.fromBytes(toSeed(mnemonic, passphrase))).toBe(`0x${seed}`)
20
+ })
21
+
22
+ test('behavior: applies BIP-39 NFKD normalization', async () => {
23
+ const { toSeed } = await Mnemonic.engine()
24
+ const composed = Array.from({ length: 12 }, () => 'café').join(' ')
25
+ const decomposed = Array.from({ length: 12 }, () => 'cafe\u0301').join(' ')
26
+
27
+ expect(toSeed(composed, 'pássphrase')).toEqual(
28
+ toSeed(decomposed, 'pa\u0301ssphrase'),
29
+ )
30
+ expect(toSeed(composed, 'pássphrase')).toEqual(
31
+ mnemonicToSeedSync(composed, 'pássphrase'),
32
+ )
33
+ })
34
+
35
+ test('behavior: accepts every supported phrase length', async () => {
36
+ const { toSeed } = await Mnemonic.engine()
37
+
38
+ expect(
39
+ [12, 15, 18, 21, 24].map(
40
+ (length) =>
41
+ toSeed(Array.from({ length }, () => 'word').join(' ')).length,
42
+ ),
43
+ ).toMatchInlineSnapshot(`
44
+ [
45
+ 64,
46
+ 64,
47
+ 64,
48
+ 64,
49
+ 64,
50
+ ]
51
+ `)
52
+ })
53
+
54
+ test('behavior: rejects unsupported phrase lengths', async () => {
55
+ const { toSeed } = await Mnemonic.engine()
56
+
57
+ for (const length of [0, 1, 11, 13, 23, 25])
58
+ expect(() =>
59
+ toSeed(Array.from({ length }, () => 'word').join(' ')),
60
+ ).toThrowErrorMatchingInlineSnapshot(`[Error: Invalid mnemonic]`)
61
+ })
62
+
63
+ test('behavior: agrees with the default for localized input', async () => {
64
+ const { toSeed } = await Mnemonic.engine()
65
+ const mnemonic = Array.from({ length: 12 }, () => 'あおぞら').join(' ')
66
+ const passphrase = '㍍ガバヴァぱばぐゞちぢ十人十色'
67
+
68
+ expect(toSeed(mnemonic, passphrase)).toEqual(
69
+ mnemonicToSeedSync(mnemonic, passphrase),
70
+ )
71
+ })
72
+
73
+ test('behavior: rejects non-string mnemonics like the default', async () => {
74
+ const { toSeed } = await Mnemonic.engine()
75
+
76
+ expect(() => toSeed(1 as never)).toThrowErrorMatchingInlineSnapshot(
77
+ `[TypeError: invalid mnemonic type: number]`,
78
+ )
79
+ })
80
+
81
+ test('behavior: returns owned Uint8Array values', async () => {
82
+ const { toSeed } = await Mnemonic.engine()
83
+ const mnemonic = Array.from({ length: 12 }, () => 'word').join(' ')
84
+ const first = toSeed(mnemonic)
85
+ const second = toSeed(mnemonic)
86
+
87
+ expect(first.constructor === Uint8Array).toMatchInlineSnapshot('true')
88
+ expect(first === second).toMatchInlineSnapshot('false')
89
+ expect(first).toEqual(second)
90
+ })
91
+
92
+ test('behavior: returns a fresh engine', async () => {
93
+ const first = await Mnemonic.engine()
94
+ const second = await Mnemonic.engine()
95
+
96
+ expect(first === second).toMatchInlineSnapshot('false')
97
+ })
98
+ })
@@ -0,0 +1,29 @@
1
+ import { expectTypeOf, test } from 'vp/test'
2
+ import type * as Engine from '../../core/Engine.js'
3
+ import * as core_P256 from '../../core/P256.js'
4
+ import * as NodeP256 from '../P256.js'
5
+
6
+ type Slot = Awaited<ReturnType<typeof NodeP256.engine>>
7
+
8
+ test('public-key derivation is present', () => {
9
+ expectTypeOf<Slot['getPublicKey']>().toEqualTypeOf<
10
+ (privateKey: Uint8Array) => Uint8Array
11
+ >()
12
+ })
13
+
14
+ test('unsupported primitives are absent', () => {
15
+ expectTypeOf<Slot>().not.toHaveProperty('getSharedSecret')
16
+ expectTypeOf<Slot>().not.toHaveProperty('randomSecretKey')
17
+ expectTypeOf<Slot>().not.toHaveProperty('recoverPublicKey')
18
+ expectTypeOf<Slot>().not.toHaveProperty('sign')
19
+ expectTypeOf<Slot>().not.toHaveProperty('verify')
20
+ })
21
+
22
+ test('the result is the raw slot', () => {
23
+ expectTypeOf<{ P256: Slot }>().toExtend<Engine.Engine>()
24
+ })
25
+
26
+ test('the Node namespace exposes the public P256 API', () => {
27
+ expectTypeOf(NodeP256.getPublicKey).toEqualTypeOf(core_P256.getPublicKey)
28
+ expectTypeOf<typeof NodeP256>().not.toHaveProperty('create')
29
+ })
@@ -0,0 +1,102 @@
1
+ import { p256 } from '@noble/curves/nist.js'
2
+ import { Hex } from 'ox'
3
+ import { describe, expect, test } from 'vp/test'
4
+ import * as P256 from '../P256.js'
5
+
6
+ const order = 'ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'
7
+
8
+ describe('engine', () => {
9
+ test('behavior: exposes only public-key derivation', async () => {
10
+ const engine = await P256.engine()
11
+
12
+ expect(Object.keys(engine)).toMatchInlineSnapshot(`
13
+ [
14
+ "getPublicKey",
15
+ ]
16
+ `)
17
+ })
18
+
19
+ test('behavior: matches the SEC 2 generator vector', async () => {
20
+ const engine = await P256.engine()
21
+ const privateKey = new Uint8Array(32)
22
+ privateKey[31] = 1
23
+
24
+ expect(
25
+ Hex.fromBytes(engine.getPublicKey(privateKey)),
26
+ ).toMatchInlineSnapshot(
27
+ `"0x046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"`,
28
+ )
29
+ })
30
+
31
+ test('behavior: matches the default across valid scalars', async () => {
32
+ const engine = await P256.engine()
33
+ const privateKeys = [
34
+ `${'00'.repeat(31)}01`,
35
+ `${'00'.repeat(31)}02`,
36
+ '7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
37
+ 'dde57ae9b9ed6f76fa5358c24d5ca2057ebc1ece18b7273121450a29c96ec8e5',
38
+ 'ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632550',
39
+ ]
40
+
41
+ for (const privateKey of privateKeys) {
42
+ const bytes = fromHex(privateKey)
43
+ expect(engine.getPublicKey(bytes)).toEqual(
44
+ p256.getPublicKey(bytes, false),
45
+ )
46
+ }
47
+ })
48
+
49
+ test('behavior: respects typed-array offsets without mutating inputs', async () => {
50
+ const engine = await P256.engine()
51
+ const privateKey = offsetView(
52
+ fromHex(
53
+ 'dde57ae9b9ed6f76fa5358c24d5ca2057ebc1ece18b7273121450a29c96ec8e5',
54
+ ),
55
+ )
56
+ const before = privateKey.slice()
57
+
58
+ expect(engine.getPublicKey(privateKey)).toEqual(
59
+ p256.getPublicKey(privateKey, false),
60
+ )
61
+ expect(privateKey).toEqual(before)
62
+ })
63
+
64
+ test('behavior: rejects malformed and out-of-range private keys', async () => {
65
+ const engine = await P256.engine()
66
+
67
+ for (const size of [0, 1, 31, 33, 64])
68
+ expect(() => engine.getPublicKey(new Uint8Array(size))).toThrowError(
69
+ `P256 private key must be 32 bytes, got ${size}`,
70
+ )
71
+
72
+ expect(() => engine.getPublicKey(new Uint8Array(32))).toThrowError()
73
+ expect(() => engine.getPublicKey(fromHex(order))).toThrowError()
74
+ })
75
+
76
+ test('behavior: returns owned Uint8Array values', async () => {
77
+ const engine = await P256.engine()
78
+ const privateKey = fromHex(`${'00'.repeat(31)}01`)
79
+ const first = engine.getPublicKey(privateKey)
80
+ const second = engine.getPublicKey(privateKey)
81
+
82
+ expect(first.constructor === Uint8Array).toMatchInlineSnapshot('true')
83
+ expect(first === second).toMatchInlineSnapshot('false')
84
+ })
85
+
86
+ test('behavior: returns a fresh engine', async () => {
87
+ const first = await P256.engine()
88
+ const second = await P256.engine()
89
+
90
+ expect(first === second).toMatchInlineSnapshot('false')
91
+ })
92
+ })
93
+
94
+ function fromHex(value: string): Uint8Array {
95
+ return Hex.toBytes(`0x${value}`)
96
+ }
97
+
98
+ function offsetView(value: Uint8Array): Uint8Array {
99
+ const bytes = new Uint8Array(value.length + 4).fill(0xff)
100
+ bytes.set(value, 2)
101
+ return bytes.subarray(2, -2)
102
+ }
@@ -0,0 +1,28 @@
1
+ import { expectTypeOf, test } from 'vp/test'
2
+ import type * as Engine from '../../core/Engine.js'
3
+ import * as core_X25519 from '../../core/X25519.js'
4
+ import * as NodeX25519 from '../X25519.js'
5
+
6
+ type Slot = Awaited<ReturnType<typeof NodeX25519.engine>>
7
+
8
+ test('every implemented primitive is present', () => {
9
+ expectTypeOf<Slot['getPublicKey']>().toEqualTypeOf<
10
+ (privateKey: Uint8Array) => Uint8Array
11
+ >()
12
+ expectTypeOf<Slot['getSharedSecret']>().toEqualTypeOf<
13
+ (privateKey: Uint8Array, publicKey: Uint8Array) => Uint8Array
14
+ >()
15
+ })
16
+
17
+ test('unsupported primitives are absent', () => {
18
+ expectTypeOf<Slot>().not.toHaveProperty('randomSecretKey')
19
+ })
20
+
21
+ test('the result is the raw slot', () => {
22
+ expectTypeOf<{ X25519: Slot }>().toExtend<Engine.Engine>()
23
+ })
24
+
25
+ test('the Node namespace exposes the public X25519 API', () => {
26
+ expectTypeOf(NodeX25519.getPublicKey).toEqualTypeOf(core_X25519.getPublicKey)
27
+ expectTypeOf<typeof NodeX25519>().not.toHaveProperty('create')
28
+ })