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.
- package/CHANGELOG.md +12 -0
- package/dist/core/Engine.d.ts +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/MlDsa44.d.ts +389 -0
- package/dist/core/MlDsa44.d.ts.map +1 -0
- package/dist/core/MlDsa44.js +206 -0
- package/dist/core/MlDsa44.js.map +1 -0
- package/dist/core/internal/engine.d.ts +35 -1
- package/dist/core/internal/engine.d.ts.map +1 -1
- package/dist/core/internal/engine.js +2 -0
- package/dist/core/internal/engine.js.map +1 -1
- package/dist/core/internal/mlDsa44.d.ts +10 -0
- package/dist/core/internal/mlDsa44.d.ts.map +1 -0
- package/dist/core/internal/mlDsa44.js +41 -0
- package/dist/core/internal/mlDsa44.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -1
- package/dist/tempo/WithdrawalSenderTag.d.ts +36 -0
- package/dist/tempo/WithdrawalSenderTag.d.ts.map +1 -0
- package/dist/tempo/WithdrawalSenderTag.js +31 -0
- package/dist/tempo/WithdrawalSenderTag.js.map +1 -0
- package/dist/tempo/index.d.ts +23 -0
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +23 -0
- package/dist/tempo/index.js.map +1 -1
- package/dist/wasm/Engine.d.ts +5 -1
- package/dist/wasm/Engine.d.ts.map +1 -1
- package/dist/wasm/Engine.js +9 -1
- package/dist/wasm/Engine.js.map +1 -1
- package/dist/wasm/MlDsa44.d.ts +55 -0
- package/dist/wasm/MlDsa44.d.ts.map +1 -0
- package/dist/wasm/MlDsa44.js +143 -0
- package/dist/wasm/MlDsa44.js.map +1 -0
- package/dist/wasm/index.d.ts +23 -2
- package/dist/wasm/index.d.ts.map +1 -1
- package/dist/wasm/index.js +23 -2
- package/dist/wasm/index.js.map +1 -1
- package/dist/wasm/internal/mldsa44.d.ts +12 -0
- package/dist/wasm/internal/mldsa44.d.ts.map +1 -0
- package/dist/wasm/internal/mldsa44.js +5 -0
- package/dist/wasm/internal/mldsa44.js.map +1 -0
- package/dist/wasm/internal/mldsa44.wasm.d.ts +3 -0
- package/dist/wasm/internal/mldsa44.wasm.d.ts.map +1 -0
- package/dist/wasm/internal/mldsa44.wasm.js +10 -0
- package/dist/wasm/internal/mldsa44.wasm.js.map +1 -0
- package/dist/zod/TypedData.d.ts +2 -2
- package/package.json +19 -2
- package/src/core/Engine.ts +1 -0
- package/src/core/MlDsa44.ts +415 -0
- package/src/core/_test/Engine.test.ts +2 -2
- package/src/core/_test/MlDsa44.test-d.ts +56 -0
- package/src/core/_test/MlDsa44.test.ts +393 -0
- package/src/core/_test/index.test.ts +1 -0
- package/src/core/internal/engine.ts +49 -0
- package/src/core/internal/mlDsa44.ts +74 -0
- package/src/index.ts +41 -0
- package/src/tempo/WithdrawalSenderTag.test-d.ts +13 -0
- package/src/tempo/WithdrawalSenderTag.test.ts +22 -0
- package/src/tempo/WithdrawalSenderTag.ts +47 -0
- package/src/tempo/index.ts +24 -0
- package/src/version.ts +1 -1
- package/src/wasm/Engine.ts +19 -7
- package/src/wasm/MlDsa44.ts +190 -0
- package/src/wasm/_test/Engine.test-d.ts +2 -0
- package/src/wasm/_test/Engine.test.ts +16 -0
- package/src/wasm/_test/MlDsa44.test-d.ts +28 -0
- package/src/wasm/_test/MlDsa44.test.ts +192 -0
- package/src/wasm/index.ts +24 -2
- package/src/wasm/internal/mldsa44.ts +34 -0
- package/src/wasm/internal/mldsa44.wasm.ts +11 -0
- 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
|
+
})
|