ox 1.4.0 → 1.6.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 (74) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/core/Engine.d.ts +1 -1
  3. package/dist/core/Engine.d.ts.map +1 -1
  4. package/dist/core/Engine.js.map +1 -1
  5. package/dist/core/MlDsa44.d.ts +389 -0
  6. package/dist/core/MlDsa44.d.ts.map +1 -0
  7. package/dist/core/MlDsa44.js +206 -0
  8. package/dist/core/MlDsa44.js.map +1 -0
  9. package/dist/core/internal/engine.d.ts +35 -1
  10. package/dist/core/internal/engine.d.ts.map +1 -1
  11. package/dist/core/internal/engine.js +2 -0
  12. package/dist/core/internal/engine.js.map +1 -1
  13. package/dist/core/internal/mlDsa44.d.ts +10 -0
  14. package/dist/core/internal/mlDsa44.d.ts.map +1 -0
  15. package/dist/core/internal/mlDsa44.js +41 -0
  16. package/dist/core/internal/mlDsa44.js.map +1 -0
  17. package/dist/index.d.ts +39 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +39 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/tempo/WithdrawalSenderTag.d.ts +36 -0
  22. package/dist/tempo/WithdrawalSenderTag.d.ts.map +1 -0
  23. package/dist/tempo/WithdrawalSenderTag.js +31 -0
  24. package/dist/tempo/WithdrawalSenderTag.js.map +1 -0
  25. package/dist/tempo/index.d.ts +23 -0
  26. package/dist/tempo/index.d.ts.map +1 -1
  27. package/dist/tempo/index.js +23 -0
  28. package/dist/tempo/index.js.map +1 -1
  29. package/dist/wasm/Engine.d.ts +5 -1
  30. package/dist/wasm/Engine.d.ts.map +1 -1
  31. package/dist/wasm/Engine.js +9 -1
  32. package/dist/wasm/Engine.js.map +1 -1
  33. package/dist/wasm/MlDsa44.d.ts +55 -0
  34. package/dist/wasm/MlDsa44.d.ts.map +1 -0
  35. package/dist/wasm/MlDsa44.js +143 -0
  36. package/dist/wasm/MlDsa44.js.map +1 -0
  37. package/dist/wasm/index.d.ts +23 -2
  38. package/dist/wasm/index.d.ts.map +1 -1
  39. package/dist/wasm/index.js +23 -2
  40. package/dist/wasm/index.js.map +1 -1
  41. package/dist/wasm/internal/mldsa44.d.ts +12 -0
  42. package/dist/wasm/internal/mldsa44.d.ts.map +1 -0
  43. package/dist/wasm/internal/mldsa44.js +5 -0
  44. package/dist/wasm/internal/mldsa44.js.map +1 -0
  45. package/dist/wasm/internal/mldsa44.wasm.d.ts +3 -0
  46. package/dist/wasm/internal/mldsa44.wasm.d.ts.map +1 -0
  47. package/dist/wasm/internal/mldsa44.wasm.js +10 -0
  48. package/dist/wasm/internal/mldsa44.wasm.js.map +1 -0
  49. package/dist/zod/TypedData.d.ts +2 -2
  50. package/package.json +19 -2
  51. package/src/core/Engine.ts +1 -0
  52. package/src/core/MlDsa44.ts +415 -0
  53. package/src/core/_test/Engine.test.ts +2 -2
  54. package/src/core/_test/MlDsa44.test-d.ts +56 -0
  55. package/src/core/_test/MlDsa44.test.ts +393 -0
  56. package/src/core/_test/index.test.ts +1 -0
  57. package/src/core/internal/engine.ts +49 -0
  58. package/src/core/internal/mlDsa44.ts +74 -0
  59. package/src/index.ts +41 -0
  60. package/src/tempo/WithdrawalSenderTag.test-d.ts +13 -0
  61. package/src/tempo/WithdrawalSenderTag.test.ts +22 -0
  62. package/src/tempo/WithdrawalSenderTag.ts +47 -0
  63. package/src/tempo/index.ts +24 -0
  64. package/src/version.ts +1 -1
  65. package/src/wasm/Engine.ts +19 -7
  66. package/src/wasm/MlDsa44.ts +190 -0
  67. package/src/wasm/_test/Engine.test-d.ts +2 -0
  68. package/src/wasm/_test/Engine.test.ts +16 -0
  69. package/src/wasm/_test/MlDsa44.test-d.ts +28 -0
  70. package/src/wasm/_test/MlDsa44.test.ts +192 -0
  71. package/src/wasm/index.ts +24 -2
  72. package/src/wasm/internal/mldsa44.ts +34 -0
  73. package/src/wasm/internal/mldsa44.wasm.ts +11 -0
  74. package/wasm/vendor/mldsa-native/LICENSE +286 -0
@@ -0,0 +1,415 @@
1
+ import { ml_dsa44 } from '@noble/post-quantum/ml-dsa.js'
2
+ import * as Bytes from './Bytes.js'
3
+ import * as Errors from './Errors.js'
4
+ import * as Hash from './Hash.js'
5
+ import * as Hex from './Hex.js'
6
+ import * as Entropy from './internal/entropy.js'
7
+ import * as engine from './internal/mlDsa44.js'
8
+
9
+ /** Re-export of noble/post-quantum ML-DSA-44 utilities. */
10
+ export const noble = ml_dsa44
11
+
12
+ /** Size of an ML-DSA-44 private key (seed) in bytes. */
13
+ export const privateKeySize = 32
14
+
15
+ /** Size of an ML-DSA-44 public key in bytes. */
16
+ export const publicKeySize = 1312
17
+
18
+ /** Size of an ML-DSA-44 signature in bytes. */
19
+ export const signatureSize = 2420
20
+
21
+ /**
22
+ * Creates a new ML-DSA-44 key pair consisting of a private key and its
23
+ * corresponding public key.
24
+ *
25
+ * The private key is the 32-byte seed (`ξ`) from FIPS 204 key generation —
26
+ * the canonical interchange form of an ML-DSA private key. The 1,312-byte
27
+ * public key is deterministically expanded from it.
28
+ *
29
+ * @example
30
+ * ```ts twoslash
31
+ * import { MlDsa44 } from 'ox'
32
+ *
33
+ * const { privateKey, publicKey } = MlDsa44.createKeyPair()
34
+ * ```
35
+ *
36
+ * @param options - The options to generate the key pair.
37
+ * @returns The generated key pair containing both private and public keys.
38
+ */
39
+ export function createKeyPair<as extends 'Hex' | 'Bytes' = 'Hex'>(
40
+ options: createKeyPair.Options<as> = {},
41
+ ): createKeyPair.ReturnType<as> {
42
+ const { as = 'Hex' } = options
43
+ const privateKey = randomPrivateKey({ as })
44
+ const publicKey = getPublicKey({ privateKey, as })
45
+
46
+ return {
47
+ privateKey: privateKey as never,
48
+ publicKey: publicKey as never,
49
+ }
50
+ }
51
+
52
+ export declare namespace createKeyPair {
53
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
54
+ /**
55
+ * Format of the returned private and public keys.
56
+ * @default 'Hex'
57
+ */
58
+ as?: as | 'Hex' | 'Bytes' | undefined
59
+ }
60
+
61
+ type ReturnType<as extends 'Hex' | 'Bytes'> = {
62
+ privateKey:
63
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
64
+ | (as extends 'Hex' ? Hex.Hex : never)
65
+ publicKey:
66
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
67
+ | (as extends 'Hex' ? Hex.Hex : never)
68
+ }
69
+
70
+ type ErrorType =
71
+ | randomPrivateKey.ErrorType
72
+ | getPublicKey.ErrorType
73
+ | Errors.GlobalErrorType
74
+ }
75
+
76
+ /**
77
+ * Derives an ML-DSA-44 private key from a 32-byte WebAuthn PRF output.
78
+ *
79
+ * The permanent derivation contract uses the PRF output as the HMAC-SHA256
80
+ * key. Its message is the UTF-8 bytes of `ox.mldsa44.fromPrf.v1` followed by
81
+ * a 32-bit big-endian counter set to zero.
82
+ *
83
+ * @example
84
+ * ```ts twoslash
85
+ * import { MlDsa44 } from 'ox'
86
+ *
87
+ * const privateKey = MlDsa44.fromPrf(
88
+ * '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'
89
+ * )
90
+ * ```
91
+ *
92
+ * @param value - A 32-byte WebAuthn PRF output.
93
+ * @param options - Options.
94
+ * @returns An ML-DSA-44 private key (32-byte seed).
95
+ */
96
+ export function fromPrf<as extends 'Hex' | 'Bytes' = 'Hex'>(
97
+ value: Hex.Hex | Bytes.Bytes,
98
+ options: fromPrf.Options<as> = {},
99
+ ): fromPrf.ReturnType<as> {
100
+ const { as = 'Hex' } = options
101
+ const bytes = Bytes.from(value)
102
+ if (bytes.length !== 32) throw new InvalidPrfSizeError({ size: bytes.length })
103
+
104
+ const privateKey = Hash.hmac256(
105
+ bytes,
106
+ Bytes.concat(fromPrfLabel, Bytes.fromNumber(0, { size: 4 })),
107
+ { as: 'Bytes' },
108
+ )
109
+ if (as === 'Hex') {
110
+ const value = Hex.fromBytes(privateKey)
111
+ privateKey.fill(0)
112
+ return value as never
113
+ }
114
+ return privateKey as never
115
+ }
116
+
117
+ export declare namespace fromPrf {
118
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
119
+ /**
120
+ * Format of the returned private key.
121
+ * @default 'Hex'
122
+ */
123
+ as?: as | 'Hex' | 'Bytes' | undefined
124
+ }
125
+
126
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
127
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
128
+ | (as extends 'Hex' ? Hex.Hex : never)
129
+
130
+ type ErrorType =
131
+ | Bytes.concat.ErrorType
132
+ | Bytes.from.ErrorType
133
+ | Bytes.fromNumber.ErrorType
134
+ | Hash.hmac256.ErrorType
135
+ | Hex.fromBytes.ErrorType
136
+ | InvalidPrfSizeError
137
+ | Errors.GlobalErrorType
138
+ }
139
+
140
+ /**
141
+ * Computes the ML-DSA-44 public key from a provided private key.
142
+ *
143
+ * @example
144
+ * ```ts twoslash
145
+ * import { MlDsa44 } from 'ox'
146
+ *
147
+ * const publicKey = MlDsa44.getPublicKey({
148
+ * privateKey: '0x...'
149
+ * })
150
+ * ```
151
+ *
152
+ * @param options - The options to compute the public key.
153
+ * @returns The computed 1,312-byte public key.
154
+ */
155
+ export function getPublicKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
156
+ options: getPublicKey.Options<as>,
157
+ ): getPublicKey.ReturnType<as> {
158
+ const { as = 'Hex', privateKey } = options
159
+ const privateKeyBytes = Bytes.from(privateKey)
160
+ const publicKeyBytes = engine.getPublicKey(privateKeyBytes)
161
+ if (as === 'Hex') return Hex.fromBytes(publicKeyBytes) as never
162
+ return publicKeyBytes as never
163
+ }
164
+
165
+ export declare namespace getPublicKey {
166
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
167
+ /**
168
+ * Format of the returned public key.
169
+ * @default 'Hex'
170
+ */
171
+ as?: as | 'Hex' | 'Bytes' | undefined
172
+ /**
173
+ * Private key (32-byte seed) to compute the public key from.
174
+ */
175
+ privateKey: Hex.Hex | Bytes.Bytes
176
+ }
177
+
178
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
179
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
180
+ | (as extends 'Hex' ? Hex.Hex : never)
181
+
182
+ type ErrorType =
183
+ | Bytes.from.ErrorType
184
+ | Hex.fromBytes.ErrorType
185
+ | Errors.GlobalErrorType
186
+ }
187
+
188
+ /**
189
+ * Generates a random ML-DSA-44 private key (32-byte seed).
190
+ *
191
+ * @example
192
+ * ```ts twoslash
193
+ * import { MlDsa44 } from 'ox'
194
+ *
195
+ * const privateKey = MlDsa44.randomPrivateKey()
196
+ * ```
197
+ *
198
+ * @param options - The options to generate the private key.
199
+ * @returns The generated private key.
200
+ */
201
+ export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
202
+ options: randomPrivateKey.Options<as> = {},
203
+ ): randomPrivateKey.ReturnType<as> {
204
+ const { as = 'Hex' } = options
205
+ const bytes = engine.randomSecretKey()
206
+ if (as === 'Hex') return Hex.fromBytes(bytes) as never
207
+ return bytes as never
208
+ }
209
+
210
+ export declare namespace randomPrivateKey {
211
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
212
+ /**
213
+ * Format of the returned private key.
214
+ * @default 'Hex'
215
+ */
216
+ as?: as | 'Hex' | 'Bytes' | undefined
217
+ }
218
+
219
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
220
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
221
+ | (as extends 'Hex' ? Hex.Hex : never)
222
+
223
+ type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
224
+ }
225
+
226
+ /**
227
+ * Signs the payload with the provided private key and returns an ML-DSA-44
228
+ * signature (2,420 bytes).
229
+ *
230
+ * Signing is deterministic by default. Set `extraEntropy` to `true` (or to 32
231
+ * bytes of entropy) for the hedged variant of FIPS 204, which protects against
232
+ * fault attacks and randomness-reuse pitfalls at the cost of reproducibility.
233
+ *
234
+ * @example
235
+ * ```ts twoslash
236
+ * import { MlDsa44 } from 'ox'
237
+ *
238
+ * const signature = MlDsa44.sign({
239
+ * // [!code focus]
240
+ * payload: '0xdeadbeef', // [!code focus]
241
+ * privateKey: '0x...' // [!code focus]
242
+ * }) // [!code focus]
243
+ * ```
244
+ *
245
+ * @param options - The signing options.
246
+ * @returns The ML-DSA-44 signature.
247
+ */
248
+ export function sign<as extends 'Hex' | 'Bytes' = 'Hex'>(
249
+ options: sign.Options<as>,
250
+ ): sign.ReturnType<as> {
251
+ const {
252
+ as = 'Hex',
253
+ extraEntropy = Entropy.extraEntropy,
254
+ payload,
255
+ privateKey,
256
+ } = options
257
+ const context = toContextBytes(options.context)
258
+ const signatureBytes = engine.sign(
259
+ Bytes.from(payload),
260
+ Bytes.from(privateKey),
261
+ {
262
+ context,
263
+ extraEntropy:
264
+ typeof extraEntropy === 'boolean'
265
+ ? extraEntropy
266
+ : Bytes.from(extraEntropy),
267
+ },
268
+ )
269
+ if (as === 'Hex') return Hex.fromBytes(signatureBytes) as never
270
+ return signatureBytes as never
271
+ }
272
+
273
+ export declare namespace sign {
274
+ type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
275
+ /**
276
+ * Format of the returned signature.
277
+ * @default 'Hex'
278
+ */
279
+ as?: as | 'Hex' | 'Bytes' | undefined
280
+ /**
281
+ * Context string for domain separation, at most 255 bytes.
282
+ * @default empty
283
+ */
284
+ context?: Hex.Hex | Bytes.Bytes | undefined
285
+ /**
286
+ * Extra entropy to add to the signing process. Setting to `true` enables
287
+ * hedged signing with 32 fresh random bytes; 32 bytes may be supplied
288
+ * directly instead.
289
+ * @default false
290
+ */
291
+ extraEntropy?: boolean | Hex.Hex | Bytes.Bytes | undefined
292
+ /**
293
+ * Payload to sign.
294
+ */
295
+ payload: Hex.Hex | Bytes.Bytes
296
+ /**
297
+ * ML-DSA-44 private key (32-byte seed).
298
+ */
299
+ privateKey: Hex.Hex | Bytes.Bytes
300
+ }
301
+
302
+ type ReturnType<as extends 'Hex' | 'Bytes'> =
303
+ | (as extends 'Bytes' ? Bytes.Bytes : never)
304
+ | (as extends 'Hex' ? Hex.Hex : never)
305
+
306
+ type ErrorType =
307
+ | Bytes.from.ErrorType
308
+ | Hex.fromBytes.ErrorType
309
+ | InvalidContextSizeError
310
+ | Errors.GlobalErrorType
311
+ }
312
+
313
+ /**
314
+ * Verifies a payload was signed by the provided public key.
315
+ *
316
+ * @example
317
+ * ```ts twoslash
318
+ * import { MlDsa44 } from 'ox'
319
+ *
320
+ * const { privateKey, publicKey } = MlDsa44.createKeyPair()
321
+ * const signature = MlDsa44.sign({
322
+ * payload: '0xdeadbeef',
323
+ * privateKey
324
+ * })
325
+ *
326
+ * const verified = MlDsa44.verify({
327
+ * // [!code focus]
328
+ * publicKey, // [!code focus]
329
+ * payload: '0xdeadbeef', // [!code focus]
330
+ * signature // [!code focus]
331
+ * }) // [!code focus]
332
+ * ```
333
+ *
334
+ * @param options - The verification options.
335
+ * @returns Whether the payload was signed by the provided public key.
336
+ */
337
+ export function verify(options: verify.Options): boolean {
338
+ const { payload, publicKey, signature } = options
339
+ const context = toContextBytes(options.context)
340
+ return engine.verify(
341
+ Bytes.from(signature),
342
+ Bytes.from(payload),
343
+ Bytes.from(publicKey),
344
+ { context },
345
+ )
346
+ }
347
+
348
+ export declare namespace verify {
349
+ type Options = {
350
+ /**
351
+ * Context string for domain separation, at most 255 bytes.
352
+ * @default empty
353
+ */
354
+ context?: Hex.Hex | Bytes.Bytes | undefined
355
+ /** Payload that was signed. */
356
+ payload: Hex.Hex | Bytes.Bytes
357
+ /** Public key that signed the payload. */
358
+ publicKey: Hex.Hex | Bytes.Bytes
359
+ /** Signature of the payload. */
360
+ signature: Hex.Hex | Bytes.Bytes
361
+ }
362
+
363
+ type ErrorType =
364
+ | Bytes.from.ErrorType
365
+ | InvalidContextSizeError
366
+ | Errors.GlobalErrorType
367
+ }
368
+
369
+ /** Thrown when a context string exceeds the 255-byte FIPS 204 limit. */
370
+ export class InvalidContextSizeError extends Errors.BaseError {
371
+ override readonly name = 'MlDsa44.InvalidContextSizeError'
372
+
373
+ constructor(options: InvalidContextSizeError.Options) {
374
+ super(`Context must be at most 255 bytes. Received ${options.size} bytes.`)
375
+ }
376
+ }
377
+
378
+ export declare namespace InvalidContextSizeError {
379
+ /** Options for {@link ox#MlDsa44.InvalidContextSizeError}. */
380
+ type Options = {
381
+ /** Received context size. */
382
+ size: number
383
+ }
384
+ }
385
+
386
+ /** Thrown when a WebAuthn PRF output is not 32 bytes. */
387
+ export class InvalidPrfSizeError extends Errors.BaseError {
388
+ override readonly name = 'MlDsa44.InvalidPrfSizeError'
389
+
390
+ constructor(options: InvalidPrfSizeError.Options) {
391
+ super(
392
+ `PRF output must be exactly 32 bytes. Received ${options.size} bytes.`,
393
+ )
394
+ }
395
+ }
396
+
397
+ export declare namespace InvalidPrfSizeError {
398
+ /** Options for {@link ox#MlDsa44.InvalidPrfSizeError}. */
399
+ type Options = {
400
+ /** Received PRF output size. */
401
+ size: number
402
+ }
403
+ }
404
+
405
+ function toContextBytes(
406
+ context: Hex.Hex | Bytes.Bytes | undefined,
407
+ ): Bytes.Bytes | undefined {
408
+ if (context === undefined) return undefined
409
+ const bytes = Bytes.from(context)
410
+ if (bytes.length > 255)
411
+ throw new InvalidContextSizeError({ size: bytes.length })
412
+ return bytes
413
+ }
414
+
415
+ const fromPrfLabel = Bytes.fromString('ox.mldsa44.fromPrf.v1')
@@ -255,7 +255,7 @@ describe('set', () => {
255
255
  `
256
256
  [Engine.UnknownSlotError: \`Keccak\` is not a valid engine slot.
257
257
 
258
- Valid slots: Bls, Ed25519, Hash, Keystore, Mnemonic, P256, Secp256k1, X25519]
258
+ Valid slots: Bls, Ed25519, Hash, Keystore, MlDsa44, Mnemonic, P256, Secp256k1, X25519]
259
259
  `,
260
260
  )
261
261
  })
@@ -336,7 +336,7 @@ describe('reset', () => {
336
336
  .toThrowErrorMatchingInlineSnapshot(`
337
337
  [Engine.UnknownSlotError: \`Hsah\` is not a valid engine slot.
338
338
 
339
- Valid slots: Bls, Ed25519, Hash, Keystore, Mnemonic, P256, Secp256k1, X25519]
339
+ Valid slots: Bls, Ed25519, Hash, Keystore, MlDsa44, Mnemonic, P256, Secp256k1, X25519]
340
340
  `)
341
341
 
342
342
  // The override the caller meant to remove is still installed, which is the
@@ -0,0 +1,56 @@
1
+ import { Bytes, Hex, MlDsa44 } from 'ox'
2
+ import { expectTypeOf, test } from 'vp/test'
3
+
4
+ test('createKeyPair', () => {
5
+ expectTypeOf(MlDsa44.createKeyPair()).toEqualTypeOf<{
6
+ privateKey: Hex.Hex
7
+ publicKey: Hex.Hex
8
+ }>()
9
+ expectTypeOf(MlDsa44.createKeyPair({ as: 'Bytes' })).toEqualTypeOf<{
10
+ privateKey: Bytes.Bytes
11
+ publicKey: Bytes.Bytes
12
+ }>()
13
+ })
14
+
15
+ test('fromPrf', () => {
16
+ const prf =
17
+ '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'
18
+
19
+ expectTypeOf(MlDsa44.fromPrf(prf)).toEqualTypeOf<Hex.Hex>()
20
+ expectTypeOf(MlDsa44.fromPrf(new Uint8Array(32))).toEqualTypeOf<Hex.Hex>()
21
+ expectTypeOf(MlDsa44.fromPrf(prf, { as: 'Hex' })).toEqualTypeOf<Hex.Hex>()
22
+ expectTypeOf(
23
+ MlDsa44.fromPrf(prf, { as: 'Bytes' }),
24
+ ).toEqualTypeOf<Bytes.Bytes>()
25
+ })
26
+
27
+ test('getPublicKey', () => {
28
+ expectTypeOf(
29
+ MlDsa44.getPublicKey({ privateKey: '0x' }),
30
+ ).toEqualTypeOf<Hex.Hex>()
31
+ expectTypeOf(
32
+ MlDsa44.getPublicKey({ privateKey: '0x', as: 'Bytes' }),
33
+ ).toEqualTypeOf<Bytes.Bytes>()
34
+ })
35
+
36
+ test('randomPrivateKey', () => {
37
+ expectTypeOf(MlDsa44.randomPrivateKey()).toEqualTypeOf<Hex.Hex>()
38
+ expectTypeOf(
39
+ MlDsa44.randomPrivateKey({ as: 'Bytes' }),
40
+ ).toEqualTypeOf<Bytes.Bytes>()
41
+ })
42
+
43
+ test('sign', () => {
44
+ expectTypeOf(
45
+ MlDsa44.sign({ payload: '0x', privateKey: '0x' }),
46
+ ).toEqualTypeOf<Hex.Hex>()
47
+ expectTypeOf(
48
+ MlDsa44.sign({ payload: '0x', privateKey: '0x', as: 'Bytes' }),
49
+ ).toEqualTypeOf<Bytes.Bytes>()
50
+ })
51
+
52
+ test('verify', () => {
53
+ expectTypeOf(
54
+ MlDsa44.verify({ payload: '0x', publicKey: '0x', signature: '0x' }),
55
+ ).toEqualTypeOf<boolean>()
56
+ })