@noble/post-quantum 0.6.0 → 0.7.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/README.md +106 -80
- package/_crystals.d.ts +23 -16
- package/_crystals.js +50 -12
- package/falcon.d.ts +7 -8
- package/falcon.js +109 -74
- package/hybrid.d.ts +21 -32
- package/hybrid.js +157 -78
- package/index.d.ts +0 -1
- package/index.js +8 -1
- package/ml-dsa.d.ts +35 -9
- package/ml-dsa.js +116 -43
- package/ml-kem.d.ts +46 -5
- package/ml-kem.js +175 -67
- package/package.json +10 -18
- package/slh-dsa.d.ts +44 -24
- package/slh-dsa.js +150 -84
- package/src/_crystals.ts +86 -35
- package/src/falcon.ts +230 -169
- package/src/hybrid.ts +243 -129
- package/src/index.ts +8 -0
- package/src/ml-dsa.ts +194 -87
- package/src/ml-kem.ts +283 -122
- package/src/slh-dsa.ts +310 -182
- package/src/utils.ts +244 -48
- package/utils.d.ts +99 -24
- package/utils.js +92 -24
- package/_crystals.d.ts.map +0 -1
- package/_crystals.js.map +0 -1
- package/falcon.d.ts.map +0 -1
- package/falcon.js.map +0 -1
- package/hybrid.d.ts.map +0 -1
- package/hybrid.js.map +0 -1
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/ml-dsa.d.ts.map +0 -1
- package/ml-dsa.js.map +0 -1
- package/ml-kem.d.ts.map +0 -1
- package/ml-kem.js.map +0 -1
- package/slh-dsa.d.ts.map +0 -1
- package/slh-dsa.js.map +0 -1
- package/utils.d.ts.map +0 -1
- package/utils.js.map +0 -1
package/src/utils.ts
CHANGED
|
@@ -8,10 +8,118 @@ import {
|
|
|
8
8
|
type TypedArray,
|
|
9
9
|
abytes,
|
|
10
10
|
abytes as abytes_,
|
|
11
|
+
ahash as ahash_,
|
|
12
|
+
anumber,
|
|
11
13
|
concatBytes,
|
|
14
|
+
isBytes,
|
|
12
15
|
isLE,
|
|
13
16
|
randomBytes as randb,
|
|
14
17
|
} from '@noble/hashes/utils.js';
|
|
18
|
+
/**
|
|
19
|
+
* Bytes API type helpers for old + new TypeScript.
|
|
20
|
+
*
|
|
21
|
+
* TS 5.6 has `Uint8Array`, while TS 5.9+ made it generic `Uint8Array<ArrayBuffer>`.
|
|
22
|
+
* We can't use specific return type, because TS 5.6 will error.
|
|
23
|
+
* We can't use generic return type, because most TS 5.9 software will expect specific type.
|
|
24
|
+
*
|
|
25
|
+
* Maps typed-array input leaves to broad forms.
|
|
26
|
+
* These are compatibility adapters, not ownership guarantees.
|
|
27
|
+
*
|
|
28
|
+
* - `TArg` keeps byte inputs broad.
|
|
29
|
+
* - `TRet` marks byte outputs for TS 5.6 and TS 5.9+ compatibility.
|
|
30
|
+
*/
|
|
31
|
+
export type TypedArg<T> = T extends BigInt64Array
|
|
32
|
+
? BigInt64Array
|
|
33
|
+
: T extends BigUint64Array
|
|
34
|
+
? BigUint64Array
|
|
35
|
+
: T extends Float32Array
|
|
36
|
+
? Float32Array
|
|
37
|
+
: T extends Float64Array
|
|
38
|
+
? Float64Array
|
|
39
|
+
: T extends Int16Array
|
|
40
|
+
? Int16Array
|
|
41
|
+
: T extends Int32Array
|
|
42
|
+
? Int32Array
|
|
43
|
+
: T extends Int8Array
|
|
44
|
+
? Int8Array
|
|
45
|
+
: T extends Uint16Array
|
|
46
|
+
? Uint16Array
|
|
47
|
+
: T extends Uint32Array
|
|
48
|
+
? Uint32Array
|
|
49
|
+
: T extends Uint8ClampedArray
|
|
50
|
+
? Uint8ClampedArray
|
|
51
|
+
: T extends Uint8Array
|
|
52
|
+
? Uint8Array
|
|
53
|
+
: never;
|
|
54
|
+
/** Maps typed-array output leaves to narrow TS-compatible forms. */
|
|
55
|
+
export type TypedRet<T> = T extends BigInt64Array
|
|
56
|
+
? ReturnType<typeof BigInt64Array.of>
|
|
57
|
+
: T extends BigUint64Array
|
|
58
|
+
? ReturnType<typeof BigUint64Array.of>
|
|
59
|
+
: T extends Float32Array
|
|
60
|
+
? ReturnType<typeof Float32Array.of>
|
|
61
|
+
: T extends Float64Array
|
|
62
|
+
? ReturnType<typeof Float64Array.of>
|
|
63
|
+
: T extends Int16Array
|
|
64
|
+
? ReturnType<typeof Int16Array.of>
|
|
65
|
+
: T extends Int32Array
|
|
66
|
+
? ReturnType<typeof Int32Array.of>
|
|
67
|
+
: T extends Int8Array
|
|
68
|
+
? ReturnType<typeof Int8Array.of>
|
|
69
|
+
: T extends Uint16Array
|
|
70
|
+
? ReturnType<typeof Uint16Array.of>
|
|
71
|
+
: T extends Uint32Array
|
|
72
|
+
? ReturnType<typeof Uint32Array.of>
|
|
73
|
+
: T extends Uint8ClampedArray
|
|
74
|
+
? ReturnType<typeof Uint8ClampedArray.of>
|
|
75
|
+
: T extends Uint8Array
|
|
76
|
+
? ReturnType<typeof Uint8Array.of>
|
|
77
|
+
: never;
|
|
78
|
+
/** Recursively adapts byte-carrying API input types. See {@link TypedArg}. */
|
|
79
|
+
export type TArg<T> =
|
|
80
|
+
| T
|
|
81
|
+
| ([TypedArg<T>] extends [never]
|
|
82
|
+
? T extends (...args: infer A) => infer R
|
|
83
|
+
? ((...args: { [K in keyof A]: TRet<A[K]> }) => TArg<R>) & {
|
|
84
|
+
[K in keyof T]: T[K] extends (...args: any) => any ? T[K] : TArg<T[K]>;
|
|
85
|
+
}
|
|
86
|
+
: T extends [infer A, ...infer R]
|
|
87
|
+
? [TArg<A>, ...{ [K in keyof R]: TArg<R[K]> }]
|
|
88
|
+
: T extends readonly [infer A, ...infer R]
|
|
89
|
+
? readonly [TArg<A>, ...{ [K in keyof R]: TArg<R[K]> }]
|
|
90
|
+
: T extends (infer A)[]
|
|
91
|
+
? TArg<A>[]
|
|
92
|
+
: T extends readonly (infer A)[]
|
|
93
|
+
? readonly TArg<A>[]
|
|
94
|
+
: T extends Promise<infer A>
|
|
95
|
+
? Promise<TArg<A>>
|
|
96
|
+
: T extends object
|
|
97
|
+
? { [K in keyof T]: TArg<T[K]> }
|
|
98
|
+
: T
|
|
99
|
+
: TypedArg<T>);
|
|
100
|
+
/** Recursively adapts byte-carrying API output types. See {@link TypedArg}. */
|
|
101
|
+
export type TRet<T> = T extends unknown
|
|
102
|
+
? T &
|
|
103
|
+
([TypedRet<T>] extends [never]
|
|
104
|
+
? T extends (...args: infer A) => infer R
|
|
105
|
+
? ((...args: { [K in keyof A]: TArg<A[K]> }) => TRet<R>) & {
|
|
106
|
+
[K in keyof T]: T[K] extends (...args: any) => any ? T[K] : TRet<T[K]>;
|
|
107
|
+
}
|
|
108
|
+
: T extends [infer A, ...infer R]
|
|
109
|
+
? [TRet<A>, ...{ [K in keyof R]: TRet<R[K]> }]
|
|
110
|
+
: T extends readonly [infer A, ...infer R]
|
|
111
|
+
? readonly [TRet<A>, ...{ [K in keyof R]: TRet<R[K]> }]
|
|
112
|
+
: T extends (infer A)[]
|
|
113
|
+
? TRet<A>[]
|
|
114
|
+
: T extends readonly (infer A)[]
|
|
115
|
+
? readonly TRet<A>[]
|
|
116
|
+
: T extends Promise<infer A>
|
|
117
|
+
? Promise<TRet<A>>
|
|
118
|
+
: T extends object
|
|
119
|
+
? { [K in keyof T]: TRet<T[K]> }
|
|
120
|
+
: T
|
|
121
|
+
: TypedRet<T>)
|
|
122
|
+
: never;
|
|
15
123
|
/**
|
|
16
124
|
* Asserts that a value is a byte array and optionally checks its length.
|
|
17
125
|
* Returns the original reference unchanged on success, and currently also accepts Node `Buffer`
|
|
@@ -43,6 +151,8 @@ export { concatBytesDoc as concatBytes };
|
|
|
43
151
|
* Requires `globalThis.crypto.getRandomValues` and throws if that API is unavailable.
|
|
44
152
|
* `bytesLength` is validated by the upstream helper as a non-negative integer before allocation,
|
|
45
153
|
* so negative and fractional values both throw instead of truncating through JS `ToIndex`.
|
|
154
|
+
* @param bytesLength - Number of random bytes to generate.
|
|
155
|
+
* @returns Fresh random bytes.
|
|
46
156
|
* @example
|
|
47
157
|
* Generate a fresh random seed.
|
|
48
158
|
* ```ts
|
|
@@ -51,9 +161,30 @@ export { concatBytesDoc as concatBytes };
|
|
|
51
161
|
*/
|
|
52
162
|
export const randomBytes: typeof randb = randb;
|
|
53
163
|
|
|
164
|
+
export function aarray<T>(
|
|
165
|
+
item: unknown,
|
|
166
|
+
title: string,
|
|
167
|
+
inner: (elm: T, title: string) => void = () => {}
|
|
168
|
+
): T[] {
|
|
169
|
+
if (!Array.isArray(item))
|
|
170
|
+
throw new TypeError(`"${title}" expected array, got type=${typeof item}`);
|
|
171
|
+
for (let i = 0; i < item.length; i++) inner(item[i], `${title}[${i}]`);
|
|
172
|
+
return item;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function aobject<T extends object>(value: unknown, title = 'object'): T {
|
|
176
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
177
|
+
throw new TypeError(
|
|
178
|
+
title === 'object'
|
|
179
|
+
? 'expected valid options object'
|
|
180
|
+
: `"${title}" expected object, got type=${typeof value}`
|
|
181
|
+
);
|
|
182
|
+
return value as T;
|
|
183
|
+
}
|
|
184
|
+
|
|
54
185
|
/**
|
|
55
186
|
* Compares two byte arrays in a length-constant way for equal lengths.
|
|
56
|
-
*
|
|
187
|
+
* Inputs are validated as byte arrays; unequal lengths return `false` immediately.
|
|
57
188
|
* @param a - First byte array.
|
|
58
189
|
* @param b - Second byte array.
|
|
59
190
|
* @returns Whether both arrays contain the same bytes.
|
|
@@ -63,7 +194,9 @@ export const randomBytes: typeof randb = randb;
|
|
|
63
194
|
* equalBytes(new Uint8Array([1]), new Uint8Array([1]));
|
|
64
195
|
* ```
|
|
65
196
|
*/
|
|
66
|
-
export function equalBytes(a: Uint8Array
|
|
197
|
+
export function equalBytes(a: TArg<Uint8Array>, b: TArg<Uint8Array>): boolean {
|
|
198
|
+
a = abytes(a);
|
|
199
|
+
b = abytes(b);
|
|
67
200
|
if (a.length !== b.length) return false;
|
|
68
201
|
let diff = 0;
|
|
69
202
|
for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
|
|
@@ -72,8 +205,7 @@ export function equalBytes(a: Uint8Array, b: Uint8Array): boolean {
|
|
|
72
205
|
|
|
73
206
|
/**
|
|
74
207
|
* Copies bytes into a fresh `Uint8Array`.
|
|
75
|
-
* Returns a detached plain `Uint8Array
|
|
76
|
-
* inputs because it delegates directly to `Uint8Array.from(...)`.
|
|
208
|
+
* Returns a detached plain `Uint8Array` after validating that the input is real bytes.
|
|
77
209
|
* @param bytes - Source bytes.
|
|
78
210
|
* @returns Copy of the input bytes.
|
|
79
211
|
* @example
|
|
@@ -82,8 +214,10 @@ export function equalBytes(a: Uint8Array, b: Uint8Array): boolean {
|
|
|
82
214
|
* copyBytes(new Uint8Array([1, 2]));
|
|
83
215
|
* ```
|
|
84
216
|
*/
|
|
85
|
-
export function copyBytes(bytes: Uint8Array): Uint8Array {
|
|
86
|
-
|
|
217
|
+
export function copyBytes(bytes: TArg<Uint8Array>): TRet<Uint8Array> {
|
|
218
|
+
// `Uint8Array.from(...)` would also accept arrays / other typed arrays. Keep this helper strict
|
|
219
|
+
// because callers use it at byte-validation boundaries before mutating the detached copy.
|
|
220
|
+
return Uint8Array.from(abytes(bytes)) as TRet<Uint8Array>;
|
|
87
221
|
}
|
|
88
222
|
|
|
89
223
|
/**
|
|
@@ -92,6 +226,11 @@ export function copyBytes(bytes: Uint8Array): Uint8Array {
|
|
|
92
226
|
* this boundary helper before aliasing them as host `Float64Array` lanes.
|
|
93
227
|
* @param arr - Byte buffer whose length is a multiple of 8.
|
|
94
228
|
* @returns The same buffer after in-place 64-bit lane byte swaps.
|
|
229
|
+
* @example
|
|
230
|
+
* Byte-swap one 64-bit lane in place.
|
|
231
|
+
* ```ts
|
|
232
|
+
* byteSwap64(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]));
|
|
233
|
+
* ```
|
|
95
234
|
*/
|
|
96
235
|
export function byteSwap64<T extends ArrayBufferView>(arr: T): T {
|
|
97
236
|
const bytes = new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
@@ -111,6 +250,18 @@ export function byteSwap64<T extends ArrayBufferView>(arr: T): T {
|
|
|
111
250
|
}
|
|
112
251
|
return arr;
|
|
113
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Byte-swaps 64-bit lanes on big-endian runtimes and returns the input unchanged on little-endian.
|
|
255
|
+
* This keeps Falcon's binary64 tables in canonical little-endian order before aliasing them as
|
|
256
|
+
* `Float64Array` lanes on the current host.
|
|
257
|
+
* @param arr - Buffer to pass through or swap in place.
|
|
258
|
+
* @returns The same buffer, normalized for Falcon's little-endian table layout.
|
|
259
|
+
* @example
|
|
260
|
+
* Normalize one host-endian buffer for Falcon's float tables.
|
|
261
|
+
* ```ts
|
|
262
|
+
* baswap64If(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]));
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
114
265
|
export const baswap64If: <T extends ArrayBufferView>(arr: T) => T = isLE
|
|
115
266
|
? (arr) => arr
|
|
116
267
|
: byteSwap64;
|
|
@@ -126,13 +277,16 @@ export type CryptoKeys = {
|
|
|
126
277
|
* @param seed - Optional seed bytes for deterministic key generation.
|
|
127
278
|
* @returns Fresh secret/public keypair.
|
|
128
279
|
*/
|
|
129
|
-
keygen: (seed?: Uint8Array) => {
|
|
280
|
+
keygen: (seed?: TArg<Uint8Array>) => {
|
|
281
|
+
secretKey: TRet<Uint8Array>;
|
|
282
|
+
publicKey: TRet<Uint8Array>;
|
|
283
|
+
};
|
|
130
284
|
/**
|
|
131
285
|
* Derive one public key from a secret key.
|
|
132
286
|
* @param secretKey - Secret key bytes.
|
|
133
287
|
* @returns Public key bytes.
|
|
134
288
|
*/
|
|
135
|
-
getPublicKey: (secretKey: Uint8Array) => Uint8Array
|
|
289
|
+
getPublicKey: (secretKey: TArg<Uint8Array>) => TRet<Uint8Array>;
|
|
136
290
|
};
|
|
137
291
|
|
|
138
292
|
/** Verification options shared by the signature APIs. */
|
|
@@ -159,8 +313,8 @@ export type SigOpts = VerOpts & {
|
|
|
159
313
|
*/
|
|
160
314
|
export function validateOpts(opts: object): void {
|
|
161
315
|
// Arrays silently passed here before, but these call sites expect named option-bag fields.
|
|
162
|
-
if (
|
|
163
|
-
|
|
316
|
+
if (isBytes(opts)) throw new TypeError('"opts" expected object, got Uint8Array');
|
|
317
|
+
aobject(opts, 'opts');
|
|
164
318
|
}
|
|
165
319
|
|
|
166
320
|
/**
|
|
@@ -175,7 +329,7 @@ export function validateOpts(opts: object): void {
|
|
|
175
329
|
* validateVerOpts({ context: new Uint8Array([1]) });
|
|
176
330
|
* ```
|
|
177
331
|
*/
|
|
178
|
-
export function validateVerOpts(opts: VerOpts): void {
|
|
332
|
+
export function validateVerOpts(opts: TArg<VerOpts>): void {
|
|
179
333
|
validateOpts(opts);
|
|
180
334
|
if (opts.context !== undefined) abytes(opts.context, undefined, 'opts.context');
|
|
181
335
|
}
|
|
@@ -192,7 +346,7 @@ export function validateVerOpts(opts: VerOpts): void {
|
|
|
192
346
|
* validateSigOpts({ extraEntropy: new Uint8Array([1]) });
|
|
193
347
|
* ```
|
|
194
348
|
*/
|
|
195
|
-
export function validateSigOpts(opts: SigOpts): void {
|
|
349
|
+
export function validateSigOpts(opts: TArg<SigOpts>): void {
|
|
196
350
|
validateVerOpts(opts);
|
|
197
351
|
if (opts.extraEntropy !== false && opts.extraEntropy !== undefined)
|
|
198
352
|
abytes(opts.extraEntropy, undefined, 'opts.extraEntropy');
|
|
@@ -209,7 +363,11 @@ export type Signer = CryptoKeys & {
|
|
|
209
363
|
* @param opts - Optional signing options.
|
|
210
364
|
* @returns Signature bytes.
|
|
211
365
|
*/
|
|
212
|
-
sign: (
|
|
366
|
+
sign: (
|
|
367
|
+
msg: TArg<Uint8Array>,
|
|
368
|
+
secretKey: TArg<Uint8Array>,
|
|
369
|
+
opts?: TArg<SigOpts>
|
|
370
|
+
) => TRet<Uint8Array>;
|
|
213
371
|
/**
|
|
214
372
|
* Verify one signature.
|
|
215
373
|
* @param sig - Signature bytes.
|
|
@@ -221,7 +379,12 @@ export type Signer = CryptoKeys & {
|
|
|
221
379
|
* a verification failure and return `false`.
|
|
222
380
|
* @throws On malformed API arguments or unsupported verification options.
|
|
223
381
|
*/
|
|
224
|
-
verify: (
|
|
382
|
+
verify: (
|
|
383
|
+
sig: TArg<Uint8Array>,
|
|
384
|
+
msg: TArg<Uint8Array>,
|
|
385
|
+
publicKey: TArg<Uint8Array>,
|
|
386
|
+
opts?: TArg<VerOpts>
|
|
387
|
+
) => boolean;
|
|
225
388
|
};
|
|
226
389
|
|
|
227
390
|
/** Generic key encapsulation mechanism interface. */
|
|
@@ -235,11 +398,11 @@ export type KEM = CryptoKeys & {
|
|
|
235
398
|
* @returns Ciphertext plus shared secret.
|
|
236
399
|
*/
|
|
237
400
|
encapsulate: (
|
|
238
|
-
publicKey: Uint8Array
|
|
239
|
-
msg?: Uint8Array
|
|
401
|
+
publicKey: TArg<Uint8Array>,
|
|
402
|
+
msg?: TArg<Uint8Array>
|
|
240
403
|
) => {
|
|
241
|
-
cipherText: Uint8Array
|
|
242
|
-
sharedSecret: Uint8Array
|
|
404
|
+
cipherText: TRet<Uint8Array>;
|
|
405
|
+
sharedSecret: TRet<Uint8Array>;
|
|
243
406
|
};
|
|
244
407
|
/**
|
|
245
408
|
* Recover the shared secret from a ciphertext and recipient secret key.
|
|
@@ -247,7 +410,7 @@ export type KEM = CryptoKeys & {
|
|
|
247
410
|
* @param secretKey - Recipient secret key bytes.
|
|
248
411
|
* @returns Decapsulated shared secret.
|
|
249
412
|
*/
|
|
250
|
-
decapsulate: (cipherText: Uint8Array
|
|
413
|
+
decapsulate: (cipherText: TArg<Uint8Array>, secretKey: TArg<Uint8Array>) => TRet<Uint8Array>;
|
|
251
414
|
};
|
|
252
415
|
|
|
253
416
|
/** Bidirectional encoder/decoder interface. */
|
|
@@ -308,8 +471,9 @@ type SplitOut<T extends (number | BytesCoderLen<any>)[]> = {
|
|
|
308
471
|
export function splitCoder<T extends (number | BytesCoderLen<any>)[]>(
|
|
309
472
|
label: string,
|
|
310
473
|
...lengths: T
|
|
311
|
-
): BytesCoder<SplitOut<T>> & { bytesLen: number } {
|
|
312
|
-
const getLength = (c: number | BytesCoderLen<any
|
|
474
|
+
): TRet<BytesCoder<SplitOut<T>> & { bytesLen: number }> {
|
|
475
|
+
const getLength = (c: TArg<number | BytesCoderLen<any>>) =>
|
|
476
|
+
typeof c === 'number' ? c : (c as BytesCoderLen<any>).bytesLen;
|
|
313
477
|
const bytesLen: number = lengths.reduce((sum: number, a) => sum + getLength(a), 0);
|
|
314
478
|
return {
|
|
315
479
|
bytesLen,
|
|
@@ -326,7 +490,7 @@ export function splitCoder<T extends (number | BytesCoderLen<any>)[]>(
|
|
|
326
490
|
}
|
|
327
491
|
return res;
|
|
328
492
|
},
|
|
329
|
-
decode: (buf: Uint8Array) => {
|
|
493
|
+
decode: (buf: TArg<Uint8Array>) => {
|
|
330
494
|
abytes_(buf, bytesLen, label);
|
|
331
495
|
const res = [];
|
|
332
496
|
for (const c of lengths) {
|
|
@@ -359,30 +523,32 @@ export function splitCoder<T extends (number | BytesCoderLen<any>)[]>(
|
|
|
359
523
|
* ).encode([1, 2]);
|
|
360
524
|
* ```
|
|
361
525
|
*/
|
|
362
|
-
export function vecCoder<T>(c: BytesCoderLen<T
|
|
363
|
-
const
|
|
526
|
+
export function vecCoder<T>(c: TArg<BytesCoderLen<T>>, vecLen: number): TRet<BytesCoderLen<T[]>> {
|
|
527
|
+
const coder = c as BytesCoderLen<T>;
|
|
528
|
+
const bytesLen = vecLen * coder.bytesLen;
|
|
364
529
|
return {
|
|
365
530
|
bytesLen,
|
|
366
|
-
encode: (u: T[]): Uint8Array => {
|
|
367
|
-
|
|
368
|
-
|
|
531
|
+
encode: (u: TArg<T[]>): TRet<Uint8Array> => {
|
|
532
|
+
const uArr = aarray<T>(u, 'u');
|
|
533
|
+
if (uArr.length !== vecLen)
|
|
534
|
+
throw new RangeError(`vecCoder.encode: wrong length=${uArr.length}. Expected: ${vecLen}`);
|
|
369
535
|
const res = new Uint8Array(bytesLen);
|
|
370
|
-
for (let i = 0, pos = 0; i <
|
|
371
|
-
const b =
|
|
536
|
+
for (let i = 0, pos = 0; i < uArr.length; i++) {
|
|
537
|
+
const b = coder.encode(uArr[i] as T);
|
|
372
538
|
res.set(b, pos);
|
|
373
539
|
b.fill(0); // clean
|
|
374
540
|
pos += b.length;
|
|
375
541
|
}
|
|
376
|
-
return res
|
|
542
|
+
return res as TRet<Uint8Array>;
|
|
377
543
|
},
|
|
378
|
-
decode: (a: Uint8Array): T[] => {
|
|
544
|
+
decode: (a: TArg<Uint8Array>): TRet<T[]> => {
|
|
379
545
|
abytes_(a, bytesLen);
|
|
380
546
|
const r: T[] = [];
|
|
381
|
-
for (let i = 0; i < a.length; i +=
|
|
382
|
-
r.push(
|
|
383
|
-
return r
|
|
547
|
+
for (let i = 0; i < a.length; i += coder.bytesLen)
|
|
548
|
+
r.push(coder.decode(a.subarray(i, i + coder.bytesLen)));
|
|
549
|
+
return r as TRet<T[]>;
|
|
384
550
|
},
|
|
385
|
-
};
|
|
551
|
+
} as any;
|
|
386
552
|
}
|
|
387
553
|
|
|
388
554
|
/**
|
|
@@ -407,6 +573,8 @@ export function cleanBytes(...list: (TypedArray | TypedArray[])[]): void {
|
|
|
407
573
|
* Creates a 32-bit mask with the lowest `bits` bits set.
|
|
408
574
|
* @param bits - Number of low bits to keep.
|
|
409
575
|
* @returns Bit mask with `bits` ones.
|
|
576
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
577
|
+
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
410
578
|
* @example
|
|
411
579
|
* Create a low-bit mask for packed-field operations.
|
|
412
580
|
* ```ts
|
|
@@ -414,14 +582,14 @@ export function cleanBytes(...list: (TypedArray | TypedArray[])[]): void {
|
|
|
414
582
|
* ```
|
|
415
583
|
*/
|
|
416
584
|
export function getMask(bits: number): number {
|
|
417
|
-
|
|
418
|
-
|
|
585
|
+
anumber(bits, 'bits');
|
|
586
|
+
if (bits > 32) throw new RangeError('"bits" expected <= 32, got ' + bits);
|
|
419
587
|
// JS shifts are modulo 32, so bit 32 needs an explicit full-width mask.
|
|
420
588
|
return bits === 32 ? 0xffffffff : ~(-1 << bits) >>> 0;
|
|
421
589
|
}
|
|
422
590
|
|
|
423
591
|
/** Shared empty byte array used as the default context. */
|
|
424
|
-
export const EMPTY: Uint8Array = /* @__PURE__ */ Uint8Array.of();
|
|
592
|
+
export const EMPTY: TRet<Uint8Array> = /* @__PURE__ */ Uint8Array.of();
|
|
425
593
|
|
|
426
594
|
/**
|
|
427
595
|
* Builds the domain-separated message payload for the pure sign/verify paths.
|
|
@@ -436,9 +604,9 @@ export const EMPTY: Uint8Array = /* @__PURE__ */ Uint8Array.of();
|
|
|
436
604
|
* const payload = getMessage(new Uint8Array([1, 2]));
|
|
437
605
|
* ```
|
|
438
606
|
*/
|
|
439
|
-
export function getMessage(msg: Uint8Array
|
|
440
|
-
abytes_(msg);
|
|
441
|
-
abytes_(ctx);
|
|
607
|
+
export function getMessage(msg: TArg<Uint8Array>, ctx: TArg<Uint8Array> = EMPTY): TRet<Uint8Array> {
|
|
608
|
+
abytes_(msg, undefined, 'msg');
|
|
609
|
+
abytes_(ctx, undefined, 'ctx');
|
|
442
610
|
if (ctx.length > 255) throw new RangeError('context should be 255 bytes or less');
|
|
443
611
|
return concatBytes(new Uint8Array([0, ctx.length]), ctx, msg);
|
|
444
612
|
}
|
|
@@ -467,8 +635,14 @@ const oidNistP = /* @__PURE__ */ Uint8Array.from([6, 9, 0x60, 0x86, 0x48, 1, 0x6
|
|
|
467
635
|
* ```
|
|
468
636
|
*/
|
|
469
637
|
export function checkHash(hash: CHash, requiredStrength: number = 0): void {
|
|
470
|
-
if (
|
|
471
|
-
throw new
|
|
638
|
+
if (typeof hash !== 'function' || typeof (hash as any).create !== 'function')
|
|
639
|
+
throw new TypeError('"hash" expected hash function, got type=' + typeof hash);
|
|
640
|
+
ahash_(hash);
|
|
641
|
+
anumber(requiredStrength, 'requiredStrength');
|
|
642
|
+
const oid = hash.oid as unknown as TArg<Uint8Array>;
|
|
643
|
+
abytes_(oid, undefined, 'hash.oid');
|
|
644
|
+
if (!equalBytes(oid.subarray(0, 10), oidNistP))
|
|
645
|
+
throw new Error('"hash.oid" is invalid: expected NIST hash');
|
|
472
646
|
// FIPS 204 / FIPS 205 require both collision and second-preimage strength; for approved NIST
|
|
473
647
|
// hashes/XOFs under this OID subtree, the collision bound from the configured digest length is
|
|
474
648
|
// the tighter runtime check, so enforce that lower bound here.
|
|
@@ -503,12 +677,34 @@ export function checkHash(hash: CHash, requiredStrength: number = 0): void {
|
|
|
503
677
|
*/
|
|
504
678
|
export function getMessagePrehash(
|
|
505
679
|
hash: CHash,
|
|
506
|
-
msg: Uint8Array
|
|
507
|
-
ctx: Uint8Array = EMPTY
|
|
508
|
-
): Uint8Array {
|
|
509
|
-
|
|
510
|
-
abytes_(
|
|
680
|
+
msg: TArg<Uint8Array>,
|
|
681
|
+
ctx: TArg<Uint8Array> = EMPTY
|
|
682
|
+
): TRet<Uint8Array> {
|
|
683
|
+
checkHash(hash);
|
|
684
|
+
abytes_(msg, undefined, 'msg');
|
|
685
|
+
abytes_(ctx, undefined, 'ctx');
|
|
511
686
|
if (ctx.length > 255) throw new RangeError('context should be 255 bytes or less');
|
|
512
687
|
const hashed = hash(msg);
|
|
513
688
|
return concatBytes(new Uint8Array([1, ctx.length]), ctx, hash.oid!, hashed);
|
|
514
689
|
}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Asserts something is a string.
|
|
693
|
+
* @param value - Value to validate.
|
|
694
|
+
* @param title - Label included in thrown errors.
|
|
695
|
+
* @returns The validated string.
|
|
696
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
697
|
+
* @example
|
|
698
|
+
* Validate a label string.
|
|
699
|
+
*
|
|
700
|
+
* ```ts
|
|
701
|
+
* astring('example', 'label');
|
|
702
|
+
* ```
|
|
703
|
+
*/
|
|
704
|
+
export function astring(value: unknown, title: string = ''): string {
|
|
705
|
+
if (typeof value !== 'string') {
|
|
706
|
+
const prefix = title && `"${title}" `;
|
|
707
|
+
throw new TypeError(prefix + 'expected string, got type=' + typeof value);
|
|
708
|
+
}
|
|
709
|
+
return value;
|
|
710
|
+
}
|