@noble/post-quantum 0.6.0 → 0.6.1
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 +45 -32
- package/_crystals.d.ts +17 -15
- package/_crystals.d.ts.map +1 -1
- package/_crystals.js +13 -3
- package/_crystals.js.map +1 -1
- package/falcon.d.ts +7 -7
- package/falcon.d.ts.map +1 -1
- package/falcon.js +27 -20
- package/falcon.js.map +1 -1
- package/hybrid.d.ts +23 -23
- package/hybrid.d.ts.map +1 -1
- package/hybrid.js +37 -28
- package/hybrid.js.map +1 -1
- package/index.js +8 -0
- package/index.js.map +1 -1
- package/ml-dsa.d.ts +7 -7
- package/ml-dsa.d.ts.map +1 -1
- package/ml-dsa.js +54 -28
- package/ml-dsa.js.map +1 -1
- package/ml-kem.d.ts +4 -4
- package/ml-kem.d.ts.map +1 -1
- package/ml-kem.js +43 -26
- package/ml-kem.js.map +1 -1
- package/package.json +5 -5
- package/slh-dsa.d.ts +21 -21
- package/slh-dsa.d.ts.map +1 -1
- package/slh-dsa.js +57 -35
- package/slh-dsa.js.map +1 -1
- package/src/_crystals.ts +44 -27
- package/src/falcon.ts +150 -117
- package/src/hybrid.ts +145 -96
- package/src/index.ts +8 -0
- package/src/ml-dsa.ts +124 -69
- package/src/ml-kem.ts +114 -85
- package/src/slh-dsa.ts +211 -132
- package/src/utils.ts +174 -34
- package/utils.d.ts +81 -22
- package/utils.d.ts.map +1 -1
- package/utils.js +30 -8
- package/utils.js.map +1 -1
package/src/falcon.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from '@noble/hashes/utils.js';
|
|
25
25
|
import { genCrystals, type TypedCons } from './_crystals.ts';
|
|
26
26
|
import {
|
|
27
|
+
baswap64If,
|
|
27
28
|
type BytesCoderLen,
|
|
28
29
|
cleanBytes,
|
|
29
30
|
type Coder,
|
|
@@ -31,8 +32,9 @@ import {
|
|
|
31
32
|
getMask,
|
|
32
33
|
type Signer,
|
|
33
34
|
type SigOpts,
|
|
34
|
-
baswap64If,
|
|
35
35
|
splitCoder,
|
|
36
|
+
type TArg,
|
|
37
|
+
type TRet,
|
|
36
38
|
validateSigOpts,
|
|
37
39
|
validateVerOpts,
|
|
38
40
|
type VerOpts,
|
|
@@ -121,12 +123,12 @@ const bitsCoderMSB = <T extends TypedArray>(
|
|
|
121
123
|
N: number,
|
|
122
124
|
d: number,
|
|
123
125
|
c: Coder<number, number>
|
|
124
|
-
): BytesCoderLen<T
|
|
126
|
+
): TRet<BytesCoderLen<T>> => {
|
|
125
127
|
const mask = getMask(d);
|
|
126
128
|
const bytesLen = d * (N / 8);
|
|
127
129
|
return {
|
|
128
130
|
bytesLen,
|
|
129
|
-
encode: (poly: T): Uint8Array => {
|
|
131
|
+
encode: (poly: TArg<T>): TRet<Uint8Array> => {
|
|
130
132
|
if (poly.length !== N) throw new Error(`wrong length: expected ${N}, got ${poly.length}`);
|
|
131
133
|
const r = new Uint8Array(bytesLen);
|
|
132
134
|
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) {
|
|
@@ -134,38 +136,39 @@ const bitsCoderMSB = <T extends TypedArray>(
|
|
|
134
136
|
bufLen += d;
|
|
135
137
|
for (; bufLen >= 8; bufLen -= 8) r[pos++] = (buf >>> (bufLen - 8)) & 0xff;
|
|
136
138
|
}
|
|
137
|
-
return r
|
|
139
|
+
return r as TRet<Uint8Array>;
|
|
138
140
|
},
|
|
139
|
-
decode: (bytes: Uint8Array): T => {
|
|
141
|
+
decode: (bytes: TArg<Uint8Array>): TRet<T> => {
|
|
140
142
|
const r = newPoly(N);
|
|
141
143
|
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) {
|
|
142
144
|
buf = (buf << 8) | bytes[i];
|
|
143
145
|
bufLen += 8;
|
|
144
146
|
for (; bufLen >= d; bufLen -= d) r[pos++] = c.decode((buf >>> (bufLen - d)) & mask);
|
|
145
147
|
}
|
|
146
|
-
return r
|
|
148
|
+
return r as TRet<T>;
|
|
147
149
|
},
|
|
148
|
-
}
|
|
150
|
+
} as TRet<BytesCoderLen<T>>;
|
|
149
151
|
};
|
|
150
152
|
// Adds a single leading tag byte. Exact body validation is delegated to `restCoder.decode()`.
|
|
151
153
|
// encode() zeroizes the temporary encoded body after copying, so wrapped encoders must return
|
|
152
154
|
// owned scratch bytes rather than caller-owned buffers.
|
|
153
|
-
const headerCoder = <T>(tag: number, restCoder: BytesCoderLen<T
|
|
155
|
+
const headerCoder = <T>(tag: number, restCoder: TArg<BytesCoderLen<T>>): TRet<BytesCoderLen<T>> => {
|
|
156
|
+
const coder = restCoder as BytesCoderLen<T>;
|
|
154
157
|
return {
|
|
155
|
-
bytesLen: 1 +
|
|
156
|
-
encode(value: T): Uint8Array {
|
|
157
|
-
const body =
|
|
158
|
+
bytesLen: 1 + coder.bytesLen,
|
|
159
|
+
encode(value: TArg<T>): TRet<Uint8Array> {
|
|
160
|
+
const body = coder.encode(value as T);
|
|
158
161
|
const out = new Uint8Array(1 + body.length);
|
|
159
162
|
out[0] = tag;
|
|
160
163
|
out.set(body, 1);
|
|
161
164
|
cleanBytes(body);
|
|
162
|
-
return out
|
|
165
|
+
return out as TRet<Uint8Array>;
|
|
163
166
|
},
|
|
164
|
-
decode(data: Uint8Array): T {
|
|
167
|
+
decode(data: TArg<Uint8Array>): TRet<T> {
|
|
165
168
|
if (data[0] !== tag) throw new Error(`wrong tag: expected ${tag}, got 0x${data[0]}`);
|
|
166
|
-
return
|
|
169
|
+
return coder.decode(data.subarray(1)) as TRet<T>;
|
|
167
170
|
},
|
|
168
|
-
}
|
|
171
|
+
} as TRet<BytesCoderLen<T>>;
|
|
169
172
|
};
|
|
170
173
|
|
|
171
174
|
// Fun, but overengineered. Hoping FIPS would fix this.
|
|
@@ -176,7 +179,7 @@ const headerCoder = <T>(tag: number, restCoder: BytesCoderLen<T>): BytesCoderLen
|
|
|
176
179
|
const compCoder = (n: number) => {
|
|
177
180
|
const LIMIT = 2047;
|
|
178
181
|
return {
|
|
179
|
-
encode(data: Int16Array): Uint8Array {
|
|
182
|
+
encode(data: TArg<Int16Array>): TRet<Uint8Array> {
|
|
180
183
|
// Algorithm 17: Compress(s, slen) (Page 47)
|
|
181
184
|
// Require: A polynomial s = Σ sᵢxⁱ ∈ Z[x] of degree < n, a string bitlength slen
|
|
182
185
|
// Ensure: A compressed representation str of s of slen bits, or ⊥
|
|
@@ -216,9 +219,9 @@ const compCoder = (n: number) => {
|
|
|
216
219
|
writeBits((v >>> 7) + 1, 1); // high (unary)
|
|
217
220
|
}
|
|
218
221
|
if (bufLen > 0) res.push((buf << (8 - bufLen)) & 0xff);
|
|
219
|
-
return new Uint8Array(res)
|
|
222
|
+
return new Uint8Array(res) as TRet<Uint8Array>;
|
|
220
223
|
},
|
|
221
|
-
decode(data: Uint8Array): Int16Array {
|
|
224
|
+
decode(data: TArg<Uint8Array>): TRet<Int16Array> {
|
|
222
225
|
// Algorithm 18: Decompress(str, slen), (Page 48)
|
|
223
226
|
// Require: A bitstring str = (str[i])_{i=0,...,slen-1}, a bitlength slen
|
|
224
227
|
// Ensure: A polynomial s = Σ sᵢxⁱ ∈ Z[x], or ⊥
|
|
@@ -260,7 +263,7 @@ const compCoder = (n: number) => {
|
|
|
260
263
|
res[resPos] = sign ? -v : v;
|
|
261
264
|
}
|
|
262
265
|
if (buf) throw new Error('non-empty accumulator');
|
|
263
|
-
return res
|
|
266
|
+
return res as TRet<Int16Array>;
|
|
264
267
|
},
|
|
265
268
|
};
|
|
266
269
|
};
|
|
@@ -268,12 +271,12 @@ const compCoder = (n: number) => {
|
|
|
268
271
|
// Falcon padded-signature helper. encode() assumes `data.length <= len`; decode() strips trailing
|
|
269
272
|
// zero padding and returns a subarray view, so it is not a generic byte-string codec.
|
|
270
273
|
const pad = (len: number) => ({
|
|
271
|
-
encode(data: Uint8Array) {
|
|
274
|
+
encode(data: TArg<Uint8Array>) {
|
|
272
275
|
const res = new Uint8Array(len);
|
|
273
276
|
res.set(data);
|
|
274
277
|
return res;
|
|
275
278
|
},
|
|
276
|
-
decode(data: Uint8Array) {
|
|
279
|
+
decode(data: TArg<Uint8Array>) {
|
|
277
280
|
let end = data.length;
|
|
278
281
|
while (end > 0 && data[end - 1] === 0) end--;
|
|
279
282
|
return data.subarray(0, end);
|
|
@@ -391,22 +394,22 @@ const ComplexArrInterleaved = {
|
|
|
391
394
|
},
|
|
392
395
|
};
|
|
393
396
|
// Alias a Float64Array as bytes for the root-table hash pin; not a portable serialization.
|
|
394
|
-
const u8f = (arr: Float64Array): Uint8Array =>
|
|
395
|
-
new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength)
|
|
397
|
+
const u8f = (arr: TArg<Float64Array>): TRet<Uint8Array> =>
|
|
398
|
+
new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength) as TRet<Uint8Array>;
|
|
396
399
|
|
|
397
400
|
// Alias bytes as Float64Array lanes. Falcon's exact binary64 tables are stored as little-endian
|
|
398
401
|
// payload bytes, so BE runtimes must decode lane-by-lane instead of aliasing host-endian floats.
|
|
399
402
|
// Copy/truncate to whole 8-byte lanes first
|
|
400
403
|
// so BE byte swaps cannot mutate caller-owned bytes
|
|
401
404
|
// or read a partial float.
|
|
402
|
-
const f64a = (arr: Uint8Array): Float64Array =>
|
|
405
|
+
const f64a = (arr: TArg<Uint8Array>): TRet<Float64Array> =>
|
|
403
406
|
new Float64Array(
|
|
404
407
|
baswap64If(Uint8Array.from(arr.subarray(0, Math.floor(arr.byteLength / 8) * 8))).buffer
|
|
405
|
-
)
|
|
408
|
+
) as TRet<Float64Array>;
|
|
406
409
|
|
|
407
410
|
// Exact big-endian binary64 hex helper for constants. Only decode() is currently used; malformed
|
|
408
411
|
// inputs fail through lower-level hex / DataView checks instead of an explicit wrapper guard.
|
|
409
|
-
const Float = {
|
|
412
|
+
const Float = /* @__PURE__ */ Object.freeze({
|
|
410
413
|
encode(n: number): string {
|
|
411
414
|
const bytes = new Uint8Array(8);
|
|
412
415
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
@@ -418,7 +421,7 @@ const Float = {
|
|
|
418
421
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
419
422
|
return view.getFloat64(0, false);
|
|
420
423
|
},
|
|
421
|
-
};
|
|
424
|
+
});
|
|
422
425
|
// Decode a 64-bit bigint bit pattern into the exact binary64 value.
|
|
423
426
|
const f64b = (n: bigint): number => Float.decode(numberToHexUnpadded(n));
|
|
424
427
|
|
|
@@ -426,8 +429,6 @@ const f64b = (n: bigint): number => Float.decode(numberToHexUnpadded(n));
|
|
|
426
429
|
type SignatureRaw = { msg: Uint8Array; nonce: Uint8Array; s2: Uint8Array };
|
|
427
430
|
type BPoly = bigint[];
|
|
428
431
|
type FPoly = Float64Array;
|
|
429
|
-
// Keep these non-generic to match the rest of noble;
|
|
430
|
-
// newer typed-array defs get handled at call sites.
|
|
431
432
|
type SPoly = Int8Array; // Small poly (f/g/F/G)
|
|
432
433
|
type IPoly = Uint16Array; // Integer poly mod Q
|
|
433
434
|
|
|
@@ -510,7 +511,7 @@ const gauss_1024_12289 = [
|
|
|
510
511
|
|
|
511
512
|
// Exact binary64 1/sigma payloads from round-3 fpr.h. Nearby decimal spellings round 1 ULP low in
|
|
512
513
|
// JS, so keep these as decoded bit patterns and recheck the raw payloads after edits.
|
|
513
|
-
const INV_SIGMA = [
|
|
514
|
+
const INV_SIGMA = /* @__PURE__ */ Object.freeze([
|
|
514
515
|
0.0, // unused
|
|
515
516
|
f64b(BigInt('4574611497772390042')),
|
|
516
517
|
f64b(BigInt('4574501679055810265')),
|
|
@@ -522,12 +523,12 @@ const INV_SIGMA = [
|
|
|
522
523
|
f64b(BigInt('4573721358406441454')),
|
|
523
524
|
f64b(BigInt('4573606369665796042')),
|
|
524
525
|
f64b(BigInt('4573496814039276259')),
|
|
525
|
-
];
|
|
526
|
+
]);
|
|
526
527
|
|
|
527
528
|
// Exact binary64 sigma_min constants from round-3 fpr.h indexed by logn; despite one PQClean
|
|
528
529
|
// summary comment, these are sigma_min itself, not 1/sigma_min, which is why this table stays
|
|
529
530
|
// separate from INV_SIGMA.
|
|
530
|
-
const SIGMA_MIN = [
|
|
531
|
+
const SIGMA_MIN = /* @__PURE__ */ Object.freeze([
|
|
531
532
|
0.0, // unused
|
|
532
533
|
f64b(BigInt('4607707126469777035')),
|
|
533
534
|
f64b(BigInt('4607777455861499430')),
|
|
@@ -539,7 +540,7 @@ const SIGMA_MIN = [
|
|
|
539
540
|
f64b(BigInt('4608340089478362016')),
|
|
540
541
|
f64b(BigInt('4608433670533905013')),
|
|
541
542
|
f64b(BigInt('4608525754002622308')),
|
|
542
|
-
];
|
|
543
|
+
]);
|
|
543
544
|
|
|
544
545
|
// Falcon Table 3.1 RCDT values for chi, split into 24-bit limbs; storage is [high, mid, low],
|
|
545
546
|
// so gaussian0() intentionally compares them against v0, v1, v2 in reverse order. The final
|
|
@@ -1018,19 +1019,19 @@ function getIntPoly(logn: number) {
|
|
|
1018
1019
|
});
|
|
1019
1020
|
// Keep Falcon source compatible with older TS parsers: avoid spelling newer
|
|
1020
1021
|
// `Uint16Array<ArrayBuffer>` syntax directly and cast the callee side at the boundary.
|
|
1021
|
-
const ntt = (r: IPoly): IPoly => (NTT.encode as any)(r);
|
|
1022
|
-
const intt = (r: IPoly): IPoly => (NTT.decode as any)(r);
|
|
1022
|
+
const ntt = (r: TArg<IPoly>): TRet<IPoly> => (NTT.encode as any)(r);
|
|
1023
|
+
const intt = (r: TArg<IPoly>): TRet<IPoly> => (NTT.decode as any)(r);
|
|
1023
1024
|
// Falcon integer helpers mutate their first argument in place; div() also performs intt()
|
|
1024
1025
|
// before returning, so callers must treat these as owned-temporary transforms, not pure helpers.
|
|
1025
1026
|
// Centered representatives are in [-6144, 6144] for odd q = 12289,
|
|
1026
1027
|
// not a generic [-q/2, q/2] range.
|
|
1027
1028
|
const signedCoder = {
|
|
1028
|
-
encode: (p: IPoly) => Int16Array.from(p, (x) => smod(x)),
|
|
1029
|
-
decode: (p: SPoly | Int16Array) => Uint16Array.from(p, (x) => mod(x)),
|
|
1029
|
+
encode: (p: TArg<IPoly>) => Int16Array.from(p, (x) => smod(x)),
|
|
1030
|
+
decode: (p: TArg<SPoly | Int16Array>) => Uint16Array.from(p, (x) => mod(x)),
|
|
1030
1031
|
};
|
|
1031
1032
|
const intPoly = {
|
|
1032
1033
|
create: newPoly,
|
|
1033
|
-
smallSqnorm(f: SPoly) {
|
|
1034
|
+
smallSqnorm(f: TArg<SPoly>) {
|
|
1034
1035
|
let s = 0;
|
|
1035
1036
|
let ng = 0;
|
|
1036
1037
|
for (let u = 0; u < n; u++) {
|
|
@@ -1040,7 +1041,7 @@ function getIntPoly(logn: number) {
|
|
|
1040
1041
|
}
|
|
1041
1042
|
return (s | -(ng >>> 31)) >>> 0;
|
|
1042
1043
|
},
|
|
1043
|
-
isShort(s1: Int16Array
|
|
1044
|
+
isShort(s1: TArg<Int16Array>, s2: TArg<Int16Array>) {
|
|
1044
1045
|
let s = 0 >>> 0;
|
|
1045
1046
|
let ng = 0 >>> 0;
|
|
1046
1047
|
for (let u = 0; u < n; u++) {
|
|
@@ -1054,24 +1055,24 @@ function getIntPoly(logn: number) {
|
|
|
1054
1055
|
if (ng & 0x80000000) s = 0xffffffff;
|
|
1055
1056
|
return s <= L2BOUND[logn];
|
|
1056
1057
|
},
|
|
1057
|
-
sub(a: IPoly
|
|
1058
|
+
sub(a: TArg<IPoly>, b: TArg<IPoly>): TRet<IPoly> {
|
|
1058
1059
|
for (let i = 0; i < n; i++) a[i] = mod(a[i] - b[i]);
|
|
1059
|
-
return a
|
|
1060
|
+
return a as TRet<IPoly>;
|
|
1060
1061
|
},
|
|
1061
1062
|
ntt,
|
|
1062
1063
|
intt,
|
|
1063
|
-
toMontgomery(d: IPoly): IPoly {
|
|
1064
|
+
toMontgomery(d: TArg<IPoly>): TRet<IPoly> {
|
|
1064
1065
|
for (let i = 0; i < n; i++) d[i] = intField.mul(d[i], R2);
|
|
1065
|
-
return d
|
|
1066
|
+
return d as TRet<IPoly>;
|
|
1066
1067
|
},
|
|
1067
|
-
mul(f: IPoly
|
|
1068
|
+
mul(f: TArg<IPoly>, d: TArg<IPoly>): TRet<IPoly> {
|
|
1068
1069
|
for (let i = 0; i < n; i++) f[i] = intField.mul(f[i], d[i]);
|
|
1069
|
-
return f
|
|
1070
|
+
return f as TRet<IPoly>;
|
|
1070
1071
|
},
|
|
1071
|
-
div(f: IPoly
|
|
1072
|
+
div(f: TArg<IPoly>, d: TArg<IPoly>): TRet<IPoly> {
|
|
1072
1073
|
for (let i = 0; i < n; i++) f[i] = intField.div(f[i], d[i]);
|
|
1073
1074
|
this.intt(f);
|
|
1074
|
-
return f
|
|
1075
|
+
return f as TRet<IPoly>;
|
|
1075
1076
|
},
|
|
1076
1077
|
};
|
|
1077
1078
|
return { newPoly, intPoly, signedCoder };
|
|
@@ -1127,19 +1128,19 @@ function getFloatPoly(logn: number) {
|
|
|
1127
1128
|
const fftOpts = { N: N_COMPLEX, invertButterflies: true, skipStages: 0, brp: false };
|
|
1128
1129
|
const inv = 1.0 / N_COMPLEX;
|
|
1129
1130
|
return {
|
|
1130
|
-
to: (f: FPoly) => ComplexArr.decode(Array.from(f)),
|
|
1131
|
-
from: (f: CPoly): FPoly => new Float64Array(ComplexArr.encode(f))
|
|
1131
|
+
to: (f: TArg<FPoly>) => ComplexArr.decode(Array.from(f)),
|
|
1132
|
+
from: (f: CPoly): TRet<FPoly> => new Float64Array(ComplexArr.encode(f)) as TRet<FPoly>,
|
|
1132
1133
|
// Runtime callers also pass HashToPoint's Uint16Array output here;
|
|
1133
1134
|
// the implementation only needs a numeric typed-array shape,
|
|
1134
1135
|
// even though the local type is narrower.
|
|
1135
|
-
convSmall: (f: SPoly): CPoly => ComplexArr.decode(Array.from(f)),
|
|
1136
|
+
convSmall: (f: TArg<SPoly>): CPoly => ComplexArr.decode(Array.from(f)),
|
|
1136
1137
|
add: (a: CPoly, b: CPoly): CPoly => a.map((i, j) => fComplex.add(i, b[j])),
|
|
1137
1138
|
sub: (a: CPoly, b: CPoly): CPoly => a.map((i, j) => fComplex.sub(i, b[j])),
|
|
1138
1139
|
neg: (a: CPoly): CPoly => a.map((i) => fComplex.neg(i)),
|
|
1139
1140
|
mul: (a: CPoly, b: CPoly): CPoly => a.map((i, j) => fComplex.mul(i, b[j])),
|
|
1140
1141
|
conj: (a: CPoly): CPoly => a.map((i) => fComplex.conj(i)),
|
|
1141
1142
|
mulConst: (a: CPoly, x: number): CPoly => a.map((i) => fComplex.scale(i, x)),
|
|
1142
|
-
scaleNorm: (a: CPoly, b: FPoly): CPoly => a.map((i, j) => fComplex.scale(i, b[j])),
|
|
1143
|
+
scaleNorm: (a: CPoly, b: TArg<FPoly>): CPoly => a.map((i, j) => fComplex.scale(i, b[j])),
|
|
1143
1144
|
invNorm: (a: CPoly, b: CPoly) =>
|
|
1144
1145
|
new Float64Array(a.map((i, j) => 1.0 / fComplex.magSqSum(i, b[j]))),
|
|
1145
1146
|
FFT: (f: CPoly): CPoly =>
|
|
@@ -1199,7 +1200,8 @@ type FalconOpts = {
|
|
|
1199
1200
|
maxS2Len: number;
|
|
1200
1201
|
};
|
|
1201
1202
|
|
|
1202
|
-
type
|
|
1203
|
+
type FalconRandom = (bytesLength?: number) => TRet<Uint8Array>;
|
|
1204
|
+
type FalconSigOpts = SigOpts & { random?: FalconRandom };
|
|
1203
1205
|
/** Falcon attached-signature API. */
|
|
1204
1206
|
export type FalconAttached = CryptoKeys & {
|
|
1205
1207
|
/** Key lengths plus the 48-byte sampler-seed hook for signing. */
|
|
@@ -1227,7 +1229,7 @@ export type Falcon = Signer & {
|
|
|
1227
1229
|
attached: FalconAttached;
|
|
1228
1230
|
};
|
|
1229
1231
|
|
|
1230
|
-
function genFalcon(opts: FalconOpts): Falcon {
|
|
1232
|
+
function genFalcon(opts: FalconOpts): TRet<Falcon> {
|
|
1231
1233
|
const { N } = opts;
|
|
1232
1234
|
const logn = Math.log2(N);
|
|
1233
1235
|
const id = <T>(n: T): T => n;
|
|
@@ -1544,14 +1546,14 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1544
1546
|
}) as BytesCoderLen<IPoly>;
|
|
1545
1547
|
return {
|
|
1546
1548
|
bytesLen: coder.bytesLen,
|
|
1547
|
-
encode(poly: Uint16Array) {
|
|
1549
|
+
encode(poly: TArg<Uint16Array>) {
|
|
1548
1550
|
// Keep these raw checks in sync with Q:
|
|
1549
1551
|
// Falcon public-key coefficients must stay in [0, q - 1].
|
|
1550
1552
|
for (let i = 0; i < poly.length; i++)
|
|
1551
1553
|
if (poly[i] >= 12289) throw new Error('public key coeff out of range');
|
|
1552
1554
|
return coder.encode(poly);
|
|
1553
1555
|
},
|
|
1554
|
-
decode(bytes: Uint8Array) {
|
|
1556
|
+
decode(bytes: TArg<Uint8Array>) {
|
|
1555
1557
|
// Round-3 Falcon requires exact body length here;
|
|
1556
1558
|
// otherwise truncated keys decode as zero-padded
|
|
1557
1559
|
// and overlong keys silently ignore the tail in this generic bit decoder.
|
|
@@ -1577,7 +1579,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1577
1579
|
}) as BytesCoderLen<SPoly>;
|
|
1578
1580
|
return {
|
|
1579
1581
|
bytesLen: coder.bytesLen,
|
|
1580
|
-
encode(poly: Int8Array) {
|
|
1582
|
+
encode(poly: TArg<Int8Array>) {
|
|
1581
1583
|
// Secret-key trim encodings keep a symmetric signed range and reserve the most-negative
|
|
1582
1584
|
// value as a non-canonical sentinel,
|
|
1583
1585
|
// so encode() and decode() intentionally use different bounds.
|
|
@@ -1587,7 +1589,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1587
1589
|
if (poly[i] < min || poly[i] > max) throw new Error('private key coeff out of range');
|
|
1588
1590
|
return coder.encode(poly);
|
|
1589
1591
|
},
|
|
1590
|
-
decode(bytes: Uint8Array) {
|
|
1592
|
+
decode(bytes: TArg<Uint8Array>) {
|
|
1591
1593
|
const poly = coder.decode(bytes);
|
|
1592
1594
|
const min = -(1 << (bits - 1));
|
|
1593
1595
|
for (let i = 0; i < poly.length; i++)
|
|
@@ -1606,7 +1608,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1606
1608
|
splitCoder('falcon.secretKey', fgCoder, fgCoder, FGCoder)
|
|
1607
1609
|
) as BytesCoderLen<[Int8Array, Int8Array, Int8Array]>;
|
|
1608
1610
|
const publicKeyCoder = headerCoder(0x00 + logn, modqCoder()) as BytesCoderLen<Uint16Array>;
|
|
1609
|
-
const decodePaddedSig = (s2: Uint8Array) => {
|
|
1611
|
+
const decodePaddedSig = (s2: TArg<Uint8Array>) => {
|
|
1610
1612
|
// The fixed padded form accepts only a canonical compressed payload
|
|
1611
1613
|
// followed by an all-zero tail.
|
|
1612
1614
|
const normalized = compCoder(N).encode(compCoder(N).decode(s2));
|
|
@@ -1614,7 +1616,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1614
1616
|
if (s2[i] !== 0) throw new Error('non-zero padding');
|
|
1615
1617
|
return normalized;
|
|
1616
1618
|
};
|
|
1617
|
-
const decodeUnpaddedSig = (s2: Uint8Array) => {
|
|
1619
|
+
const decodeUnpaddedSig = (s2: TArg<Uint8Array>) => {
|
|
1618
1620
|
// Unpadded attached and detached signatures require the compressed payload to use its exact
|
|
1619
1621
|
// canonical bitlength. Appending a zero tail and adjusting the outer container length must
|
|
1620
1622
|
// still be rejected.
|
|
@@ -1628,7 +1630,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1628
1630
|
const SignatureCoderBasic = (logn: number) => {
|
|
1629
1631
|
const TYPE_BYTE = 0x20 + logn;
|
|
1630
1632
|
return {
|
|
1631
|
-
encode({ msg, nonce, s2 }: SignatureRaw): Uint8Array {
|
|
1633
|
+
encode({ msg, nonce, s2 }: TArg<SignatureRaw>): TRet<Uint8Array> {
|
|
1632
1634
|
let compressed: Uint8Array = s2;
|
|
1633
1635
|
const payloadLen = 1 + compressed.length;
|
|
1634
1636
|
const totalLen = 2 + NONCELEN + msg.length + payloadLen;
|
|
@@ -1642,9 +1644,9 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1642
1644
|
i += msg.length;
|
|
1643
1645
|
out[i++] = TYPE_BYTE;
|
|
1644
1646
|
out.set(compressed, i);
|
|
1645
|
-
return out
|
|
1647
|
+
return out as TRet<Uint8Array>;
|
|
1646
1648
|
},
|
|
1647
|
-
decode(data: Uint8Array): SignatureRaw {
|
|
1649
|
+
decode(data: TArg<Uint8Array>): TRet<SignatureRaw> {
|
|
1648
1650
|
if (!data || data.length < NONCELEN + 3) throw new Error('signature coder: wrong length');
|
|
1649
1651
|
const len = (data[0] << 8) | data[1];
|
|
1650
1652
|
const s2Len = len - 1;
|
|
@@ -1656,50 +1658,50 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1656
1658
|
const msg = data.subarray(2 + NONCELEN, 2 + NONCELEN + msgLen);
|
|
1657
1659
|
const s2 = decodeUnpaddedSig(data.subarray(2 + NONCELEN + msgLen + 1));
|
|
1658
1660
|
if (s2.length !== s2Len) throw new Error('signature coder: wrong s2 length');
|
|
1659
|
-
return { msg, nonce, s2 }
|
|
1661
|
+
return { msg, nonce, s2 } as TRet<SignatureRaw>;
|
|
1660
1662
|
},
|
|
1661
1663
|
};
|
|
1662
1664
|
};
|
|
1663
1665
|
const SignatureCoderPadded = (logn: number) => {
|
|
1664
1666
|
const sigLen = opts.paddedLen;
|
|
1665
1667
|
return {
|
|
1666
|
-
encode({ msg, nonce, s2 }: SignatureRaw): Uint8Array {
|
|
1668
|
+
encode({ msg, nonce, s2 }: TArg<SignatureRaw>): TRet<Uint8Array> {
|
|
1667
1669
|
return headerCoder(
|
|
1668
1670
|
0x30 + logn,
|
|
1669
1671
|
splitCoder('falcon.signature', NONCELEN, sigLen, msg.length)
|
|
1670
1672
|
).encode([nonce, pad(sigLen).encode(s2), msg]);
|
|
1671
1673
|
},
|
|
1672
|
-
decode(data: Uint8Array): SignatureRaw {
|
|
1674
|
+
decode(data: TArg<Uint8Array>): TRet<SignatureRaw> {
|
|
1673
1675
|
const msgLen = data.length - NONCELEN - sigLen - 1;
|
|
1674
1676
|
const [nonce, s2, msg] = headerCoder(
|
|
1675
1677
|
0x30 + logn,
|
|
1676
1678
|
splitCoder('falcon.signature', NONCELEN, sigLen, msgLen)
|
|
1677
1679
|
).decode(data);
|
|
1678
|
-
return { nonce, s2: decodeSig(s2), msg }
|
|
1680
|
+
return { nonce, s2: decodeSig(s2), msg } as TRet<SignatureRaw>;
|
|
1679
1681
|
},
|
|
1680
1682
|
};
|
|
1681
1683
|
};
|
|
1682
1684
|
// [ 1B header ] [ 40B nonce ] [ compressed_sig ]
|
|
1683
1685
|
const SignatureCoderDetached = (logn: number) => {
|
|
1684
1686
|
const sigLen = opts.padded ? opts.sigLen - 1 - NONCELEN : opts.detachedLen;
|
|
1685
|
-
const getSigLen = (s2: Uint8Array) => (opts.padded ? sigLen : s2.length);
|
|
1687
|
+
const getSigLen = (s2: TArg<Uint8Array>) => (opts.padded ? sigLen : s2.length);
|
|
1686
1688
|
return {
|
|
1687
|
-
encode({ nonce, s2 }: { nonce: Uint8Array; s2: Uint8Array }): Uint8Array {
|
|
1689
|
+
encode({ nonce, s2 }: TArg<{ nonce: Uint8Array; s2: Uint8Array }>): TRet<Uint8Array> {
|
|
1688
1690
|
return headerCoder(
|
|
1689
1691
|
0x30 + logn,
|
|
1690
1692
|
splitCoder('falcon.detachedSignature', NONCELEN, getSigLen(s2))
|
|
1691
1693
|
).encode([nonce, opts.padded ? pad(sigLen).encode(s2) : s2]);
|
|
1692
1694
|
},
|
|
1693
|
-
decode(data: Uint8Array): {
|
|
1695
|
+
decode(data: TArg<Uint8Array>): TRet<{
|
|
1694
1696
|
nonce: Uint8Array;
|
|
1695
1697
|
s2: Uint8Array;
|
|
1696
|
-
} {
|
|
1698
|
+
}> {
|
|
1697
1699
|
const [nonce, raw] = headerCoder(
|
|
1698
1700
|
0x30 + logn,
|
|
1699
1701
|
splitCoder('falcon.detachedSignature', NONCELEN, data.length - NONCELEN - 1)
|
|
1700
1702
|
).decode(data);
|
|
1701
1703
|
const s2 = decodeSig(raw);
|
|
1702
|
-
return { nonce, s2 };
|
|
1704
|
+
return { nonce, s2 } as TRet<{ nonce: Uint8Array; s2: Uint8Array }>;
|
|
1703
1705
|
},
|
|
1704
1706
|
};
|
|
1705
1707
|
};
|
|
@@ -1708,13 +1710,13 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1708
1710
|
// otherwise malformed secret keys leak a raw arithmetic error.
|
|
1709
1711
|
// Returns NTT(f) after the nonzero-lane check;
|
|
1710
1712
|
// callers still apply f^{-1} via coefficient-wise division.
|
|
1711
|
-
const invertF = (f: SPoly) => {
|
|
1713
|
+
const invertF = (f: TArg<SPoly>) => {
|
|
1712
1714
|
const tt = intPoly.ntt(signedCoder.decode(f));
|
|
1713
1715
|
for (let u = 0; u < N; u++)
|
|
1714
1716
|
if (tt[u] === 0) throw new Error('invalid secretKey: non-invertible f');
|
|
1715
1717
|
return tt;
|
|
1716
1718
|
};
|
|
1717
|
-
function computePublic(f: SPoly
|
|
1719
|
+
function computePublic(f: TArg<SPoly>, g: TArg<SPoly>) {
|
|
1718
1720
|
const tt = invertF(f);
|
|
1719
1721
|
const h = intPoly.ntt(signedCoder.decode(g));
|
|
1720
1722
|
// intPoly.div() returns to coefficient form via intt(), so public keys are encoded from the
|
|
@@ -1725,7 +1727,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1725
1727
|
}
|
|
1726
1728
|
// Reconstruct the omitted secret-key limb G as g*F/f mod q, then mirror round-3 Falcon's centered
|
|
1727
1729
|
// reduction and small-coefficient check before using the completed basis for signing.
|
|
1728
|
-
function completePrivate(f: SPoly
|
|
1730
|
+
function completePrivate(f: TArg<SPoly>, g: TArg<SPoly>, F: TArg<SPoly>) {
|
|
1729
1731
|
let t1 = intPoly.toMontgomery(intPoly.ntt(signedCoder.decode(g)));
|
|
1730
1732
|
const t2 = intPoly.ntt(signedCoder.decode(F));
|
|
1731
1733
|
const tt = invertF(f);
|
|
@@ -1747,7 +1749,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1747
1749
|
cleanBytes(t1, t2, tt);
|
|
1748
1750
|
return G;
|
|
1749
1751
|
}
|
|
1750
|
-
function HashToPoint(nonce: Uint8Array
|
|
1752
|
+
function HashToPoint(nonce: TArg<Uint8Array>, msg: TArg<Uint8Array>): TRet<IPoly> {
|
|
1751
1753
|
// Algorithm 3: HashToPoint(str, q, n)
|
|
1752
1754
|
// (Page 31)
|
|
1753
1755
|
// Require: A string str, a modulus q ≤ 2¹⁶, a degree n ∈ N*
|
|
@@ -1772,7 +1774,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
1772
1774
|
let w = (tmp[0] << 8) | tmp[1];
|
|
1773
1775
|
if (w < kQ) c[i++] = w % Q; // 8: cᵢ ← t mod q
|
|
1774
1776
|
}
|
|
1775
|
-
return c
|
|
1777
|
+
return c as TRet<IPoly>;
|
|
1776
1778
|
}
|
|
1777
1779
|
// This is basically one sampling routine,
|
|
1778
1780
|
// but it carries a lot of internal state and gets complex quickly.
|
|
@@ -2154,7 +2156,12 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
2154
2156
|
}
|
|
2155
2157
|
}
|
|
2156
2158
|
|
|
2157
|
-
const signRaw = (
|
|
2159
|
+
const signRaw = (
|
|
2160
|
+
sk: TArg<Uint8Array>,
|
|
2161
|
+
msg: TArg<Uint8Array>,
|
|
2162
|
+
maxLen: number,
|
|
2163
|
+
rnd: TArg<FalconRandom> = randomBytes
|
|
2164
|
+
): TRet<SignatureRaw> => {
|
|
2158
2165
|
// Algorithm 10: Sign(m, sk, [β²]), (Page 39)
|
|
2159
2166
|
// Require: A message m, a secret key sk, a bound [β²]
|
|
2160
2167
|
// Ensure: A signature sig of m
|
|
@@ -2226,7 +2233,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
2226
2233
|
cleanBytes(s2comp);
|
|
2227
2234
|
continue;
|
|
2228
2235
|
}
|
|
2229
|
-
return { s2: s2comp, nonce, msg }
|
|
2236
|
+
return { s2: s2comp, nonce, msg } as TRet<SignatureRaw>;
|
|
2230
2237
|
}
|
|
2231
2238
|
} finally {
|
|
2232
2239
|
cleanBytes(s2);
|
|
@@ -2244,7 +2251,12 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
2244
2251
|
|
|
2245
2252
|
// Raw helper: malformed encodings or wrong lengths still throw here; the public verify()/open()
|
|
2246
2253
|
// wrappers decide whether to translate those failures into false or an exception.
|
|
2247
|
-
const verifyRaw = (
|
|
2254
|
+
const verifyRaw = (
|
|
2255
|
+
pk: TArg<Uint8Array>,
|
|
2256
|
+
s2comp: TArg<Uint8Array>,
|
|
2257
|
+
nonce: TArg<Uint8Array>,
|
|
2258
|
+
msg: TArg<Uint8Array>
|
|
2259
|
+
) => {
|
|
2248
2260
|
// Algorithm 16: Verify(m, sig, pk, [β²])
|
|
2249
2261
|
// (Page 45)
|
|
2250
2262
|
// Require: A message m, a signature sig = (r, s), a public key pk = h ∈ Zq[x]/(φ), a bound [β²]
|
|
@@ -2266,34 +2278,42 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
2266
2278
|
return intPoly.isShort(signedCoder.encode(s1), s2); // 6: if ||(s₁, s₂)||² < [β²] then
|
|
2267
2279
|
};
|
|
2268
2280
|
|
|
2269
|
-
const info = { type: 'falcon' };
|
|
2270
|
-
const keyLengths = {
|
|
2281
|
+
const info = Object.freeze({ type: 'falcon' });
|
|
2282
|
+
const keyLengths = Object.freeze({
|
|
2271
2283
|
seed: 48,
|
|
2272
2284
|
publicKey: publicKeyCoder.bytesLen,
|
|
2273
2285
|
secretKey: secretKeyCoder.bytesLen,
|
|
2274
|
-
};
|
|
2286
|
+
});
|
|
2275
2287
|
// Noble exposes a 48-byte sampler-seed hook,
|
|
2276
2288
|
// but Falcon still samples/encodes a separate 40-byte nonce per signature.
|
|
2277
|
-
const getRnd = (opts: FalconSigOpts = {}) => {
|
|
2289
|
+
const getRnd = (opts: TArg<FalconSigOpts> = {}): TRet<FalconRandom> => {
|
|
2278
2290
|
validateSigOpts(opts);
|
|
2279
2291
|
if (opts.context !== undefined) throw new Error('context is not supported');
|
|
2280
|
-
if (opts.random !== undefined) return opts.random
|
|
2292
|
+
if (opts.random !== undefined) return opts.random as TRet<FalconRandom>;
|
|
2281
2293
|
if (opts.extraEntropy === undefined) return randomBytes;
|
|
2282
2294
|
const seed = opts.extraEntropy === false ? new Uint8Array(48) : opts.extraEntropy;
|
|
2283
2295
|
abytes(seed, 48, 'opts.extraEntropy');
|
|
2284
2296
|
const drbg = rngAesCtrDrbg256(seed);
|
|
2285
|
-
return (len = 0) => drbg.randomBytes(len)
|
|
2297
|
+
return (len = 0) => drbg.randomBytes(len) as TRet<Uint8Array>;
|
|
2286
2298
|
};
|
|
2287
|
-
const checkVerOpts = (opts: VerOpts = {}) => {
|
|
2299
|
+
const checkVerOpts = (opts: TArg<VerOpts> = {}) => {
|
|
2288
2300
|
validateVerOpts(opts);
|
|
2289
2301
|
if (opts.context !== undefined) throw new Error('context is not supported');
|
|
2290
2302
|
};
|
|
2291
|
-
const tests = {
|
|
2303
|
+
const tests = Object.freeze({
|
|
2304
|
+
publicKeyCoder: Object.freeze(publicKeyCoder),
|
|
2305
|
+
privateKeyCoder: Object.freeze(secretKeyCoder),
|
|
2306
|
+
maxS2Len: opts.maxS2Len,
|
|
2307
|
+
});
|
|
2292
2308
|
// `signRand` documents only the sampler-seed input length;
|
|
2293
2309
|
// detached/attached signatures still include their own 40-byte nonce.
|
|
2294
|
-
const attachedLengths = { ...keyLengths, signRand: 48 };
|
|
2295
|
-
const lengths = opts.padded
|
|
2296
|
-
|
|
2310
|
+
const attachedLengths = Object.freeze({ ...keyLengths, signRand: 48 });
|
|
2311
|
+
const lengths = opts.padded
|
|
2312
|
+
? Object.freeze({ ...attachedLengths, signature: opts.sigLen })
|
|
2313
|
+
: attachedLengths;
|
|
2314
|
+
const keygen = (
|
|
2315
|
+
seed?: TArg<Uint8Array>
|
|
2316
|
+
): TRet<{ publicKey: Uint8Array; secretKey: Uint8Array }> => {
|
|
2297
2317
|
const randSeed = seed === undefined;
|
|
2298
2318
|
if (randSeed) seed = randomBytes(48);
|
|
2299
2319
|
abytes(seed!, 48, 'seed');
|
|
@@ -2302,20 +2322,27 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
2302
2322
|
const pk = publicKeyCoder.encode(pub);
|
|
2303
2323
|
if (randSeed) cleanBytes(seed!);
|
|
2304
2324
|
cleanBytes(f, g, F, _G);
|
|
2305
|
-
return { publicKey: pk, secretKey: sk }
|
|
2325
|
+
return { publicKey: pk, secretKey: sk } as TRet<{
|
|
2326
|
+
publicKey: Uint8Array;
|
|
2327
|
+
secretKey: Uint8Array;
|
|
2328
|
+
}>;
|
|
2306
2329
|
};
|
|
2307
|
-
const getPublicKey = (sk: Uint8Array) => {
|
|
2330
|
+
const getPublicKey = (sk: TArg<Uint8Array>): TRet<Uint8Array> => {
|
|
2308
2331
|
const [f, g, F] = secretKeyCoder.decode(sk);
|
|
2309
2332
|
try {
|
|
2310
2333
|
const h = computePublic(f, g);
|
|
2311
2334
|
cleanBytes(f, g, F);
|
|
2312
|
-
return publicKeyCoder.encode(h)
|
|
2335
|
+
return publicKeyCoder.encode(h) as TRet<Uint8Array>;
|
|
2313
2336
|
} catch (e) {
|
|
2314
2337
|
cleanBytes(f, g, F);
|
|
2315
2338
|
throw e;
|
|
2316
2339
|
}
|
|
2317
2340
|
};
|
|
2318
|
-
const sign = (
|
|
2341
|
+
const sign = (
|
|
2342
|
+
msg: TArg<Uint8Array>,
|
|
2343
|
+
sk: TArg<Uint8Array>,
|
|
2344
|
+
sigOpts: TArg<FalconSigOpts> = {}
|
|
2345
|
+
): TRet<Uint8Array> => {
|
|
2319
2346
|
const { s2, nonce } = signRaw(sk, msg, opts.maxS2Len, getRnd(sigOpts));
|
|
2320
2347
|
return SignatureCoderDetached(logn).encode({ nonce, s2 });
|
|
2321
2348
|
};
|
|
@@ -2324,7 +2351,12 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
2324
2351
|
* and well-formed signatures that do not validate. Throws on malformed API argument types or
|
|
2325
2352
|
* unsupported verification options.
|
|
2326
2353
|
*/
|
|
2327
|
-
const verify = (
|
|
2354
|
+
const verify = (
|
|
2355
|
+
sig: TArg<Uint8Array>,
|
|
2356
|
+
msg: TArg<Uint8Array>,
|
|
2357
|
+
pk: TArg<Uint8Array>,
|
|
2358
|
+
verOpts: TArg<VerOpts> = {}
|
|
2359
|
+
) => {
|
|
2328
2360
|
checkVerOpts(verOpts);
|
|
2329
2361
|
abytes(sig);
|
|
2330
2362
|
abytes(msg);
|
|
@@ -2336,16 +2368,16 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
2336
2368
|
return false;
|
|
2337
2369
|
}
|
|
2338
2370
|
};
|
|
2339
|
-
const attached: FalconAttached = {
|
|
2371
|
+
const attached: TRet<FalconAttached> = Object.freeze({
|
|
2340
2372
|
info,
|
|
2341
2373
|
lengths: attachedLengths,
|
|
2342
2374
|
keygen,
|
|
2343
2375
|
getPublicKey,
|
|
2344
|
-
seal(msg: Uint8Array
|
|
2376
|
+
seal(msg: TArg<Uint8Array>, sk: TArg<Uint8Array>, sigOpts: TArg<FalconSigOpts> = {}) {
|
|
2345
2377
|
const { s2, nonce } = signRaw(sk, msg, opts.maxS2Len, getRnd(sigOpts));
|
|
2346
2378
|
return SignatureCoder.encode({ msg, nonce, s2 });
|
|
2347
2379
|
},
|
|
2348
|
-
open(sig: Uint8Array
|
|
2380
|
+
open(sig: TArg<Uint8Array>, pk: TArg<Uint8Array>, verOpts: TArg<VerOpts> = {}) {
|
|
2349
2381
|
checkVerOpts(verOpts);
|
|
2350
2382
|
const { s2, nonce, msg } = SignatureCoder.decode(sig);
|
|
2351
2383
|
// Zero-copy API: returned message aliases the caller-provided signature buffer.
|
|
@@ -2353,7 +2385,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
2353
2385
|
if (verifyRaw(pk, s2, nonce, msg)) return msg;
|
|
2354
2386
|
throw new Error('invalid signature');
|
|
2355
2387
|
},
|
|
2356
|
-
};
|
|
2388
|
+
});
|
|
2357
2389
|
const res = {
|
|
2358
2390
|
info,
|
|
2359
2391
|
lengths,
|
|
@@ -2364,7 +2396,7 @@ function genFalcon(opts: FalconOpts): Falcon {
|
|
|
2364
2396
|
verify,
|
|
2365
2397
|
};
|
|
2366
2398
|
(res as any).__test = tests;
|
|
2367
|
-
return res;
|
|
2399
|
+
return Object.freeze(res);
|
|
2368
2400
|
}
|
|
2369
2401
|
|
|
2370
2402
|
const falcon512opts = {
|
|
@@ -2389,7 +2421,7 @@ const falcon512opts = {
|
|
|
2389
2421
|
* falcon512.verify(sig, msg, publicKey);
|
|
2390
2422
|
* ```
|
|
2391
2423
|
*/
|
|
2392
|
-
export const falcon512: Falcon = /* @__PURE__ */ (() =>
|
|
2424
|
+
export const falcon512: TRet<Falcon> = /* @__PURE__ */ (() =>
|
|
2393
2425
|
genFalcon({ ...falcon512opts, maxS2Len: 711 }))();
|
|
2394
2426
|
/**
|
|
2395
2427
|
* Falcon-512 padded detached-signature API with the attached helper exposed as `.attached`.
|
|
@@ -2402,7 +2434,7 @@ export const falcon512: Falcon = /* @__PURE__ */ (() =>
|
|
|
2402
2434
|
* falcon512padded.verify(sig, msg, publicKey);
|
|
2403
2435
|
* ```
|
|
2404
2436
|
*/
|
|
2405
|
-
export const falcon512padded: Falcon = /* @__PURE__ */ (() =>
|
|
2437
|
+
export const falcon512padded: TRet<Falcon> = /* @__PURE__ */ (() =>
|
|
2406
2438
|
genFalcon({
|
|
2407
2439
|
...falcon512opts,
|
|
2408
2440
|
padded: true,
|
|
@@ -2431,7 +2463,7 @@ const falcon1024opts = {
|
|
|
2431
2463
|
* falcon1024.verify(sig, msg, publicKey);
|
|
2432
2464
|
* ```
|
|
2433
2465
|
*/
|
|
2434
|
-
export const falcon1024: Falcon = /* @__PURE__ */ (() =>
|
|
2466
|
+
export const falcon1024: TRet<Falcon> = /* @__PURE__ */ (() =>
|
|
2435
2467
|
genFalcon({
|
|
2436
2468
|
...falcon1024opts,
|
|
2437
2469
|
maxS2Len: 1421,
|
|
@@ -2447,7 +2479,7 @@ export const falcon1024: Falcon = /* @__PURE__ */ (() =>
|
|
|
2447
2479
|
* falcon1024padded.verify(sig, msg, publicKey);
|
|
2448
2480
|
* ```
|
|
2449
2481
|
*/
|
|
2450
|
-
export const falcon1024padded: Falcon = /* @__PURE__ */ (() =>
|
|
2482
|
+
export const falcon1024padded: TRet<Falcon> = /* @__PURE__ */ (() =>
|
|
2451
2483
|
genFalcon({
|
|
2452
2484
|
...falcon1024opts,
|
|
2453
2485
|
padded: true,
|
|
@@ -2455,16 +2487,17 @@ export const falcon1024padded: Falcon = /* @__PURE__ */ (() =>
|
|
|
2455
2487
|
}))();
|
|
2456
2488
|
|
|
2457
2489
|
// NOTE: for tests only, don't use
|
|
2458
|
-
export const __tests: any = /* @__PURE__ */ (() =>
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2490
|
+
export const __tests: any = /* @__PURE__ */ (() =>
|
|
2491
|
+
Object.freeze({
|
|
2492
|
+
BNORM_MAX,
|
|
2493
|
+
COMPLEX_ROOTS,
|
|
2494
|
+
Float,
|
|
2495
|
+
INV_SIGMA,
|
|
2496
|
+
SIGMA_MIN,
|
|
2497
|
+
getFloatPoly,
|
|
2498
|
+
cleanCPoly,
|
|
2499
|
+
falcon512: (falcon512 as any).__test,
|
|
2500
|
+
falcon512padded: (falcon512padded as any).__test,
|
|
2501
|
+
falcon1024: (falcon1024 as any).__test,
|
|
2502
|
+
falcon1024padded: (falcon1024padded as any).__test,
|
|
2503
|
+
}))();
|