@atlasauth/pca-fndsa 0.0.0-stage → 0.1.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/dist/index.d.ts +221 -0
- package/dist/index.js +411 -0
- package/dist/index.js.map +1 -0
- package/package.json +30 -3
- package/README.md +0 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @atlasauth/pca-fndsa — FN-DSA / Falcon (FIPS 206 draft) for PCA's crypto-agility seam.
|
|
3
|
+
*
|
|
4
|
+
* FN-DSA (standardization name for Falcon) is a LATTICE signature over NTRU whose selling point is
|
|
5
|
+
* COMPACTNESS: its public keys and signatures are far smaller than ML-DSA's at the same security
|
|
6
|
+
* category (Falcon-512 ≈ Category 1, Falcon-1024 ≈ Category 5). That makes it the suite to reach for
|
|
7
|
+
* on bandwidth-bound or storage-bound surfaces — exactly the places ML-DSA-65's 1952 B key / 3309 B
|
|
8
|
+
* signature hurt.
|
|
9
|
+
*
|
|
10
|
+
* WHY A PLUGGABLE BACKEND (the honest part):
|
|
11
|
+
* Falcon signing needs discrete-Gaussian sampling over a lattice and an FFT/NTT in a regime that the
|
|
12
|
+
* reference implementation runs in floating point. A CONSTANT-TIME, correct, interoperable Falcon
|
|
13
|
+
* CANNOT be safely hand-rolled in TypeScript: a float-based sampler leaks the secret via timing, and a
|
|
14
|
+
* naive integer reimplementation is a research project, not a package. Shipping a "pure-TS Falcon"
|
|
15
|
+
* here would be worse than shipping nothing — it would look done while being unsafe. So this package
|
|
16
|
+
* does the one honest thing: it REGISTERS the FN-DSA suites in PCA's wire + agility framing and routes
|
|
17
|
+
* the heavy math to a PLUGGABLE, VETTED backend (a wasm build of the FIPS-206 reference, or a vetted
|
|
18
|
+
* native lib). The wire format, the suite ids, the byte-length enforcement, the PCA leaf framing and
|
|
19
|
+
* the hybrid composition are all REAL and fully tested here (against a deterministic KAT mock); only
|
|
20
|
+
* the Gaussian-sampling arithmetic is delegated. Drop in a real backend via {@link setFalconBackend}
|
|
21
|
+
* and nothing else in PCA changes.
|
|
22
|
+
*
|
|
23
|
+
* This mirrors the conventions of `@atlasauth/pca`'s `pq.ts` suite registry (SigAlg / SIG_SUITES /
|
|
24
|
+
* signWithSuite / verifyWithSuite) so FN-DSA slots in as a PEER suite family: same `sig` / `alg` /
|
|
25
|
+
* `pq_pk` / `pq_sig` wire fields, same fail-closed hybrid rule, same per-suite exact-length enforcement.
|
|
26
|
+
* It lives in its own package (not in `pq.ts`) precisely because its primitive is pluggable, not bundled.
|
|
27
|
+
*/
|
|
28
|
+
import { type PCActn, type PCActnBody } from '@atlasauth/pca';
|
|
29
|
+
/** FN-DSA-512 (Falcon-512, ~Category 1) public-key size, in bytes. */
|
|
30
|
+
export declare const FN_DSA_512_PUBLIC_KEY_BYTES = 897;
|
|
31
|
+
/** FN-DSA-512 padded (FIPS-206 fixed-length) signature size, in bytes. The compressed form averages smaller. */
|
|
32
|
+
export declare const FN_DSA_512_SIGNATURE_BYTES = 666;
|
|
33
|
+
/** FN-DSA-1024 (Falcon-1024, ~Category 5) public-key size, in bytes. */
|
|
34
|
+
export declare const FN_DSA_1024_PUBLIC_KEY_BYTES = 1793;
|
|
35
|
+
/** FN-DSA-1024 padded (FIPS-206 fixed-length) signature size, in bytes. The compressed form averages smaller. */
|
|
36
|
+
export declare const FN_DSA_1024_SIGNATURE_BYTES = 1280;
|
|
37
|
+
/** The two pure FN-DSA parameter sets (the backend's "variant"). */
|
|
38
|
+
export type FnDsaVariant = 'fn-dsa-512' | 'fn-dsa-1024';
|
|
39
|
+
/**
|
|
40
|
+
* The FN-DSA suite ids registered in PCA's agility seam. The pure suites carry the FN-DSA signature in
|
|
41
|
+
* the primary `sig` field; the `hybrid-ed25519-fn-dsa-*` suites carry an Ed25519 signature in `sig` and
|
|
42
|
+
* the FN-DSA signature in `pq_sig` — classical + lattice defense-in-depth, requiring BOTH to verify.
|
|
43
|
+
*/
|
|
44
|
+
export type FnDsaSigAlg = 'fn-dsa-512' | 'fn-dsa-1024' | 'hybrid-ed25519-fn-dsa-512' | 'hybrid-ed25519-fn-dsa-1024';
|
|
45
|
+
/** A single FN-DSA suite's wire contract — the FN-DSA parallel of pq.ts's {@link SigSuite}. */
|
|
46
|
+
export interface FnDsaSuite {
|
|
47
|
+
alg: FnDsaSigAlg;
|
|
48
|
+
/** The pure FN-DSA parameter set the suite uses (which `pq_pk` / FN-DSA `sig` lengths apply). */
|
|
49
|
+
variant: FnDsaVariant;
|
|
50
|
+
/** Suite carries an Ed25519 component (in `sig`, under the leaf holder key). */
|
|
51
|
+
hasEd25519: boolean;
|
|
52
|
+
/** Decoded byte length REQUIRED in the primary `sig` field (Ed25519 64 for hybrid; the FN-DSA sig for pure). */
|
|
53
|
+
sigBytes: number;
|
|
54
|
+
/** A `pq_pk` (FN-DSA public key) field is REQUIRED (always true for FN-DSA suites). */
|
|
55
|
+
needsPqPk: boolean;
|
|
56
|
+
/** Decoded byte length REQUIRED in `pq_pk`. */
|
|
57
|
+
pqPkBytes: number;
|
|
58
|
+
/** A `pq_sig` field is REQUIRED — i.e. the FN-DSA sig is separate from `sig` (hybrid only). */
|
|
59
|
+
needsPqSig: boolean;
|
|
60
|
+
/** Decoded byte length REQUIRED in `pq_sig` when `needsPqSig`; `0` when unused. */
|
|
61
|
+
pqSigBytes: number;
|
|
62
|
+
/** The FN-DSA signature length for this suite's variant (== sigBytes for pure, == pqSigBytes for hybrid). */
|
|
63
|
+
fnSigBytes: number;
|
|
64
|
+
}
|
|
65
|
+
/** The closed FN-DSA suite registry (the FN-DSA parallel of pq.ts's SIG_SUITES). */
|
|
66
|
+
export declare const FN_DSA_SUITES: Readonly<Record<FnDsaSigAlg, Readonly<FnDsaSuite>>>;
|
|
67
|
+
export declare function isKnownFnDsaAlg(x: unknown): x is FnDsaSigAlg;
|
|
68
|
+
/** Resolve an FN-DSA suite by id; `null` (FAIL-CLOSED) for an unknown name or non-string. */
|
|
69
|
+
export declare function resolveFnDsaAlg(alg: unknown): Readonly<FnDsaSuite> | null;
|
|
70
|
+
/** Is `v` one of the two pure FN-DSA parameter sets? */
|
|
71
|
+
export declare function isFnDsaVariant(v: unknown): v is FnDsaVariant;
|
|
72
|
+
/** An FN-DSA key pair as raw bytes (the wire/PKI boundary). */
|
|
73
|
+
export interface FalconKeyPair {
|
|
74
|
+
/** FN-DSA public key (897 B for 512, 1793 B for 1024). */
|
|
75
|
+
pk: Uint8Array;
|
|
76
|
+
/** FN-DSA secret key (backend-defined encoding). */
|
|
77
|
+
sk: Uint8Array;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The vetted FN-DSA primitive, supplied by a real backend (wasm build of the FIPS-206 reference, or a
|
|
81
|
+
* vetted native lib). `verify` is mandatory (verification is the hot path and is safe to run anywhere);
|
|
82
|
+
* `sign` and `keygen` are OPTIONAL because many deployments only ever VERIFY FN-DSA signatures (signing,
|
|
83
|
+
* with its constant-time Gaussian sampler, lives next to the secret key and may be absent client-side).
|
|
84
|
+
*
|
|
85
|
+
* All byte arguments are the padded FIPS-206 encodings; a backend that works in the compressed form MUST
|
|
86
|
+
* pad to the fixed sizes before returning from `sign` and accept the padded form in `verify`.
|
|
87
|
+
*/
|
|
88
|
+
export interface FalconBackend {
|
|
89
|
+
/** Verify `signature` over `message` under `pubkey`. MUST NOT throw on a bad signature — return false. */
|
|
90
|
+
verify(pubkey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean;
|
|
91
|
+
/** Sign `message` under `secretkey`, returning the padded FIPS-206 signature. Optional. */
|
|
92
|
+
sign?(secretkey: Uint8Array, message: Uint8Array): Uint8Array;
|
|
93
|
+
/** Generate a fresh FN-DSA key pair. Optional. */
|
|
94
|
+
keygen?(): FalconKeyPair;
|
|
95
|
+
}
|
|
96
|
+
/** The clear error the default (unregistered) backend raises so misuse FAILS LOUD, not silently. */
|
|
97
|
+
export declare const NO_FN_DSA_BACKEND_MESSAGE = "no FN-DSA backend registered \u2014 install @atlasauth/pca-fndsa-node or supply a wasm backend via setFalconBackend()";
|
|
98
|
+
/** Install the FN-DSA backend that performs the actual Falcon math. */
|
|
99
|
+
export declare function setFalconBackend(backend: FalconBackend): void;
|
|
100
|
+
/** The currently installed FN-DSA backend (the default throws {@link NO_FN_DSA_BACKEND_MESSAGE}). */
|
|
101
|
+
export declare function getFalconBackend(): FalconBackend;
|
|
102
|
+
/** Restore the default (throwing) backend — mainly for tests and teardown. */
|
|
103
|
+
export declare function resetFalconBackend(): void;
|
|
104
|
+
/**
|
|
105
|
+
* FN-DSA sign over raw bytes, delegating to the registered backend AFTER enforcing the suite's key/sig
|
|
106
|
+
* framing. THROWS (fail-loud) when no backend is registered, when the backend is verify-only (no `sign`),
|
|
107
|
+
* or when the backend returns a signature of the wrong padded length. `sk` must be a non-empty Uint8Array
|
|
108
|
+
* (its exact encoding is backend-defined, so its length is not pinned here).
|
|
109
|
+
*/
|
|
110
|
+
export declare function fndsaSign(variant: FnDsaVariant, sk: Uint8Array, msg: Uint8Array): Uint8Array;
|
|
111
|
+
/**
|
|
112
|
+
* FN-DSA verify over raw bytes. The suite's key + signature LENGTHS are enforced HERE, BEFORE the backend
|
|
113
|
+
* is ever called, so a wrong-length public key or signature is rejected (false) without reaching the
|
|
114
|
+
* primitive. A registered backend that itself throws is NOT swallowed (fail-loud) — but a wrong-length
|
|
115
|
+
* input, and the clear "no backend" error, surface as described: length guard returns false; the default
|
|
116
|
+
* backend throws {@link NO_FN_DSA_BACKEND_MESSAGE} once the length guard has passed.
|
|
117
|
+
*/
|
|
118
|
+
export declare function fndsaVerify(variant: FnDsaVariant, pk: Uint8Array, msg: Uint8Array, sig: Uint8Array): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* The wire fields an FN-DSA-signed PCA surface carries — structurally the SAME shape pq.ts emits from
|
|
121
|
+
* {@link signSuiteArtifact} (`sig` always; `alg` + `pq_pk` for every FN-DSA suite; `pq_sig` for hybrid).
|
|
122
|
+
* The caller spreads these onto the artifact it transports alongside the PCActn, exactly as the core
|
|
123
|
+
* suite fields ride on a PCActn. (FN-DSA is not yet a member of pq.ts's `SigAlg` union — admitting it
|
|
124
|
+
* there is the mechanical follow pq.ts describes for SLH-DSA — so these fields travel as a parallel,
|
|
125
|
+
* byte-compatible frame rather than being typed onto the PCActn object.)
|
|
126
|
+
*/
|
|
127
|
+
export interface FnDsaArtifactFields {
|
|
128
|
+
/** b64u — the FN-DSA signature for a pure suite; the Ed25519 signature for a hybrid suite. */
|
|
129
|
+
sig: string;
|
|
130
|
+
/** The FN-DSA suite id (SIGNED into the leaf message, so a downgrade/key-swap invalidates the signature). */
|
|
131
|
+
alg: FnDsaSigAlg;
|
|
132
|
+
/** b64u FN-DSA public key (SIGNED into the leaf message). */
|
|
133
|
+
pq_pk: string;
|
|
134
|
+
/** b64u FN-DSA signature — hybrid suites only. */
|
|
135
|
+
pq_sig?: string;
|
|
136
|
+
}
|
|
137
|
+
/** The domain separator for the FN-DSA leaf/hop binding suffix. */
|
|
138
|
+
export declare const FN_DSA_LEAF_DOMAIN = "atlas-pca/fn-dsa/leaf/v1\0";
|
|
139
|
+
/**
|
|
140
|
+
* The exact bytes an FN-DSA leaf/hop signature covers:
|
|
141
|
+
*
|
|
142
|
+
* thresholdMessage(leaf) ‖ FN_DSA_LEAF_DOMAIN ‖ utf8(alg) ‖ 0x00 ‖ utf8(pq_pk b64u)
|
|
143
|
+
*
|
|
144
|
+
* The leading `thresholdMessage(leaf)` is the IDENTICAL canonical message pq.ts's core leaf signs, so an
|
|
145
|
+
* FN-DSA signature commits to the whole action. The domain-separated suffix additively BINDS `alg` and
|
|
146
|
+
* `pq_pk` into the signed bytes — the same downgrade/key-swap protection pq.ts gets by folding `alg` /
|
|
147
|
+
* `pq_pk` into the canonical body via `bindSuiteFields`, achieved here without mutating the PCActn's typed
|
|
148
|
+
* shape (FN-DSA is not yet in the `SigAlg` union). In a hybrid both the Ed25519 and FN-DSA halves sign
|
|
149
|
+
* these same bytes, so each commits to the suite + PQ key.
|
|
150
|
+
*/
|
|
151
|
+
export declare function fndsaLeafMessage(leaf: PCActn | PCActnBody, alg: FnDsaSigAlg, pqPkB64u: string): Uint8Array;
|
|
152
|
+
/** Inputs to {@link signPcaWithFndsa}. */
|
|
153
|
+
export interface SignPcaWithFndsaInput {
|
|
154
|
+
/** The FN-DSA suite id. */
|
|
155
|
+
alg: FnDsaSigAlg;
|
|
156
|
+
/** The PCActn (or its body) whose leaf is being signed — its {@link thresholdMessage} is the base. */
|
|
157
|
+
leaf: PCActn | PCActnBody;
|
|
158
|
+
/** The FN-DSA key pair (its `pk` becomes `pq_pk`; its `sk` signs). */
|
|
159
|
+
fnDsa: FalconKeyPair;
|
|
160
|
+
/** Ed25519 leaf-holder secret key — REQUIRED for a `hybrid-*` suite, ignored for a pure suite. */
|
|
161
|
+
edSecret?: Uint8Array;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Produce an FN-DSA leaf (or capability-hop) signature for a PCActn, returning the wire fields the
|
|
165
|
+
* surface carries. Pure FN-DSA: `sig` = FN-DSA signature, `pq_pk` = FN-DSA key. Hybrid: `sig` = Ed25519
|
|
166
|
+
* signature, `pq_sig` = FN-DSA signature, `pq_pk` = FN-DSA key — both over the SAME leaf message, for
|
|
167
|
+
* classical + lattice DEFENSE-IN-DEPTH (a forger must break Ed25519 AND Falcon). THROWS fail-closed on an
|
|
168
|
+
* unknown suite, a wrong-length FN-DSA key, a hybrid suite with no `edSecret`, or a missing/limited backend.
|
|
169
|
+
*/
|
|
170
|
+
export declare function signPcaWithFndsa(input: SignPcaWithFndsaInput): FnDsaArtifactFields;
|
|
171
|
+
/** Inputs to {@link verifyPcaFndsa}. The signature fields are UNTRUSTED (every one optional/`unknown`). */
|
|
172
|
+
export interface VerifyPcaFndsaInput {
|
|
173
|
+
/** The FN-DSA suite id from the wire (validated; an unknown value fails closed). */
|
|
174
|
+
alg: unknown;
|
|
175
|
+
/** The PCActn (or body) whose leaf is being verified — its {@link thresholdMessage} is recomputed. */
|
|
176
|
+
leaf: PCActn | PCActnBody;
|
|
177
|
+
/** The Ed25519 leaf-holder public key (b64u) — REQUIRED for a hybrid suite. */
|
|
178
|
+
holder?: unknown;
|
|
179
|
+
/** The FN-DSA public key (b64u) as carried in the surface's `pq_pk`. */
|
|
180
|
+
pq_pk?: unknown;
|
|
181
|
+
/** The primary signature (b64u): FN-DSA sig for a pure suite, Ed25519 sig for a hybrid suite. */
|
|
182
|
+
sig?: unknown;
|
|
183
|
+
/** The FN-DSA signature (b64u) — hybrid suites only. */
|
|
184
|
+
pq_sig?: unknown;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Verify an FN-DSA leaf/hop signature over a PCActn. FAIL-CLOSED and never throws for ordinary wire
|
|
188
|
+
* faults: an unknown `alg`, a wrong-length/absent key or signature, a tampered action (its
|
|
189
|
+
* {@link thresholdMessage} changes), or a suite/key downgrade (the binding suffix changes) all return
|
|
190
|
+
* false. Hybrid requires BOTH the Ed25519 half AND the FN-DSA half. (A registered backend that itself
|
|
191
|
+
* throws is not caught — that is a backend bug, which should be loud.)
|
|
192
|
+
*/
|
|
193
|
+
export declare function verifyPcaFndsa(input: VerifyPcaFndsaInput): boolean;
|
|
194
|
+
/** A known-answer vector: the backend must map `(pk, msg)` to `sig`. */
|
|
195
|
+
export interface FalconKat {
|
|
196
|
+
pk: Uint8Array;
|
|
197
|
+
msg: Uint8Array;
|
|
198
|
+
sig: Uint8Array;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Deterministic SHA-256 counter-mode stretch of `seed` to exactly `outLen` bytes. This is the mock/KAT
|
|
202
|
+
* key-derivation and signature-derivation function — NOT Falcon. It exists only so the wire framing and
|
|
203
|
+
* length enforcement are testable with reproducible, fixed-length byte strings.
|
|
204
|
+
*/
|
|
205
|
+
export declare function hashKat(seed: Uint8Array, outLen: number): Uint8Array;
|
|
206
|
+
/**
|
|
207
|
+
* Deterministically mint a MOCK FN-DSA key pair for a variant (NOT real Falcon keys). The secret key is
|
|
208
|
+
* `MOCK_SK_TAG ‖ pk` so the mock backend's `sign` can recover the public key from it; the public key is a
|
|
209
|
+
* reproducible stretch of `seed` to the variant's exact length, so a given `seed` always yields the same
|
|
210
|
+
* pair (handy for stable KAT fixtures).
|
|
211
|
+
*/
|
|
212
|
+
export declare function mockKeypair(variant: FnDsaVariant, seed?: Uint8Array | string): FalconKeyPair;
|
|
213
|
+
/**
|
|
214
|
+
* Install a DETERMINISTIC mock FN-DSA backend (and return it) so the wire format, PCA integration and
|
|
215
|
+
* length enforcement can be tested WITHOUT the real Falcon math. The backend is keyed by `(pk, msg) -> sig`:
|
|
216
|
+
* - any explicit `vectors` take precedence (drop in real FIPS-206 known-answer vectors here);
|
|
217
|
+
* - otherwise `(pk, msg)` maps to a reproducible {@link deriveMockSig}, so sign/verify round-trip.
|
|
218
|
+
* `keygen()` returns an `fn-dsa-512` {@link mockKeypair} by default; use {@link mockKeypair} directly for a
|
|
219
|
+
* specific variant. This is a TEST double — never register it in production (register a vetted backend).
|
|
220
|
+
*/
|
|
221
|
+
export declare function registerTestBackend(vectors?: readonly FalconKat[]): FalconBackend;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @atlasauth/pca-fndsa — FN-DSA / Falcon (FIPS 206 draft) for PCA's crypto-agility seam.
|
|
4
|
+
*
|
|
5
|
+
* FN-DSA (standardization name for Falcon) is a LATTICE signature over NTRU whose selling point is
|
|
6
|
+
* COMPACTNESS: its public keys and signatures are far smaller than ML-DSA's at the same security
|
|
7
|
+
* category (Falcon-512 ≈ Category 1, Falcon-1024 ≈ Category 5). That makes it the suite to reach for
|
|
8
|
+
* on bandwidth-bound or storage-bound surfaces — exactly the places ML-DSA-65's 1952 B key / 3309 B
|
|
9
|
+
* signature hurt.
|
|
10
|
+
*
|
|
11
|
+
* WHY A PLUGGABLE BACKEND (the honest part):
|
|
12
|
+
* Falcon signing needs discrete-Gaussian sampling over a lattice and an FFT/NTT in a regime that the
|
|
13
|
+
* reference implementation runs in floating point. A CONSTANT-TIME, correct, interoperable Falcon
|
|
14
|
+
* CANNOT be safely hand-rolled in TypeScript: a float-based sampler leaks the secret via timing, and a
|
|
15
|
+
* naive integer reimplementation is a research project, not a package. Shipping a "pure-TS Falcon"
|
|
16
|
+
* here would be worse than shipping nothing — it would look done while being unsafe. So this package
|
|
17
|
+
* does the one honest thing: it REGISTERS the FN-DSA suites in PCA's wire + agility framing and routes
|
|
18
|
+
* the heavy math to a PLUGGABLE, VETTED backend (a wasm build of the FIPS-206 reference, or a vetted
|
|
19
|
+
* native lib). The wire format, the suite ids, the byte-length enforcement, the PCA leaf framing and
|
|
20
|
+
* the hybrid composition are all REAL and fully tested here (against a deterministic KAT mock); only
|
|
21
|
+
* the Gaussian-sampling arithmetic is delegated. Drop in a real backend via {@link setFalconBackend}
|
|
22
|
+
* and nothing else in PCA changes.
|
|
23
|
+
*
|
|
24
|
+
* This mirrors the conventions of `@atlasauth/pca`'s `pq.ts` suite registry (SigAlg / SIG_SUITES /
|
|
25
|
+
* signWithSuite / verifyWithSuite) so FN-DSA slots in as a PEER suite family: same `sig` / `alg` /
|
|
26
|
+
* `pq_pk` / `pq_sig` wire fields, same fail-closed hybrid rule, same per-suite exact-length enforcement.
|
|
27
|
+
* It lives in its own package (not in `pq.ts`) precisely because its primitive is pluggable, not bundled.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.FN_DSA_LEAF_DOMAIN = exports.NO_FN_DSA_BACKEND_MESSAGE = exports.FN_DSA_SUITES = exports.FN_DSA_1024_SIGNATURE_BYTES = exports.FN_DSA_1024_PUBLIC_KEY_BYTES = exports.FN_DSA_512_SIGNATURE_BYTES = exports.FN_DSA_512_PUBLIC_KEY_BYTES = void 0;
|
|
31
|
+
exports.isKnownFnDsaAlg = isKnownFnDsaAlg;
|
|
32
|
+
exports.resolveFnDsaAlg = resolveFnDsaAlg;
|
|
33
|
+
exports.isFnDsaVariant = isFnDsaVariant;
|
|
34
|
+
exports.setFalconBackend = setFalconBackend;
|
|
35
|
+
exports.getFalconBackend = getFalconBackend;
|
|
36
|
+
exports.resetFalconBackend = resetFalconBackend;
|
|
37
|
+
exports.fndsaSign = fndsaSign;
|
|
38
|
+
exports.fndsaVerify = fndsaVerify;
|
|
39
|
+
exports.fndsaLeafMessage = fndsaLeafMessage;
|
|
40
|
+
exports.signPcaWithFndsa = signPcaWithFndsa;
|
|
41
|
+
exports.verifyPcaFndsa = verifyPcaFndsa;
|
|
42
|
+
exports.hashKat = hashKat;
|
|
43
|
+
exports.mockKeypair = mockKeypair;
|
|
44
|
+
exports.registerTestBackend = registerTestBackend;
|
|
45
|
+
const pca_1 = require("@atlasauth/pca");
|
|
46
|
+
// ---------------------------------------------------------------------------------------------------
|
|
47
|
+
// FIPS-206 (FN-DSA / Falcon) encoded sizes
|
|
48
|
+
// ---------------------------------------------------------------------------------------------------
|
|
49
|
+
//
|
|
50
|
+
// FN-DSA public keys are a fixed size. Falcon SIGNATURES are natively VARIABLE-LENGTH (the signature's
|
|
51
|
+
// short vector is range/Huffman-"compressed", so the exact byte count depends on the sampled vector).
|
|
52
|
+
// FIPS 206 pins a FIXED "padded" signature encoding per parameter set — the sizes below — so a signature
|
|
53
|
+
// always occupies a constant number of bytes on the wire. PCA uses the PADDED encoding exclusively: it
|
|
54
|
+
// gives deterministic framing and a single exact length to enforce, matching how pq.ts enforces ML-DSA /
|
|
55
|
+
// SLH-DSA lengths. (A backend that produces the compressed variable-length form MUST pad it to these
|
|
56
|
+
// sizes before returning — the standard "sig" vs "sig (padded)" distinction in the reference code.)
|
|
57
|
+
/** FN-DSA-512 (Falcon-512, ~Category 1) public-key size, in bytes. */
|
|
58
|
+
exports.FN_DSA_512_PUBLIC_KEY_BYTES = 897;
|
|
59
|
+
/** FN-DSA-512 padded (FIPS-206 fixed-length) signature size, in bytes. The compressed form averages smaller. */
|
|
60
|
+
exports.FN_DSA_512_SIGNATURE_BYTES = 666;
|
|
61
|
+
/** FN-DSA-1024 (Falcon-1024, ~Category 5) public-key size, in bytes. */
|
|
62
|
+
exports.FN_DSA_1024_PUBLIC_KEY_BYTES = 1793;
|
|
63
|
+
/** FN-DSA-1024 padded (FIPS-206 fixed-length) signature size, in bytes. The compressed form averages smaller. */
|
|
64
|
+
exports.FN_DSA_1024_SIGNATURE_BYTES = 1280;
|
|
65
|
+
const VARIANT_PK_BYTES = Object.freeze({
|
|
66
|
+
'fn-dsa-512': exports.FN_DSA_512_PUBLIC_KEY_BYTES,
|
|
67
|
+
'fn-dsa-1024': exports.FN_DSA_1024_PUBLIC_KEY_BYTES,
|
|
68
|
+
});
|
|
69
|
+
const VARIANT_SIG_BYTES = Object.freeze({
|
|
70
|
+
'fn-dsa-512': exports.FN_DSA_512_SIGNATURE_BYTES,
|
|
71
|
+
'fn-dsa-1024': exports.FN_DSA_1024_SIGNATURE_BYTES,
|
|
72
|
+
});
|
|
73
|
+
/** The closed FN-DSA suite registry (the FN-DSA parallel of pq.ts's SIG_SUITES). */
|
|
74
|
+
exports.FN_DSA_SUITES = Object.freeze({
|
|
75
|
+
'fn-dsa-512': {
|
|
76
|
+
alg: 'fn-dsa-512', variant: 'fn-dsa-512', hasEd25519: false,
|
|
77
|
+
sigBytes: exports.FN_DSA_512_SIGNATURE_BYTES, needsPqPk: true, pqPkBytes: exports.FN_DSA_512_PUBLIC_KEY_BYTES,
|
|
78
|
+
needsPqSig: false, pqSigBytes: 0, fnSigBytes: exports.FN_DSA_512_SIGNATURE_BYTES,
|
|
79
|
+
},
|
|
80
|
+
'fn-dsa-1024': {
|
|
81
|
+
alg: 'fn-dsa-1024', variant: 'fn-dsa-1024', hasEd25519: false,
|
|
82
|
+
sigBytes: exports.FN_DSA_1024_SIGNATURE_BYTES, needsPqPk: true, pqPkBytes: exports.FN_DSA_1024_PUBLIC_KEY_BYTES,
|
|
83
|
+
needsPqSig: false, pqSigBytes: 0, fnSigBytes: exports.FN_DSA_1024_SIGNATURE_BYTES,
|
|
84
|
+
},
|
|
85
|
+
'hybrid-ed25519-fn-dsa-512': {
|
|
86
|
+
alg: 'hybrid-ed25519-fn-dsa-512', variant: 'fn-dsa-512', hasEd25519: true,
|
|
87
|
+
sigBytes: pca_1.ED25519_SIGNATURE_BYTES, needsPqPk: true, pqPkBytes: exports.FN_DSA_512_PUBLIC_KEY_BYTES,
|
|
88
|
+
needsPqSig: true, pqSigBytes: exports.FN_DSA_512_SIGNATURE_BYTES, fnSigBytes: exports.FN_DSA_512_SIGNATURE_BYTES,
|
|
89
|
+
},
|
|
90
|
+
'hybrid-ed25519-fn-dsa-1024': {
|
|
91
|
+
alg: 'hybrid-ed25519-fn-dsa-1024', variant: 'fn-dsa-1024', hasEd25519: true,
|
|
92
|
+
sigBytes: pca_1.ED25519_SIGNATURE_BYTES, needsPqPk: true, pqPkBytes: exports.FN_DSA_1024_PUBLIC_KEY_BYTES,
|
|
93
|
+
needsPqSig: true, pqSigBytes: exports.FN_DSA_1024_SIGNATURE_BYTES, fnSigBytes: exports.FN_DSA_1024_SIGNATURE_BYTES,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
function isKnownFnDsaAlg(x) {
|
|
97
|
+
return typeof x === 'string' && Object.prototype.hasOwnProperty.call(exports.FN_DSA_SUITES, x);
|
|
98
|
+
}
|
|
99
|
+
/** Resolve an FN-DSA suite by id; `null` (FAIL-CLOSED) for an unknown name or non-string. */
|
|
100
|
+
function resolveFnDsaAlg(alg) {
|
|
101
|
+
if (isKnownFnDsaAlg(alg))
|
|
102
|
+
return exports.FN_DSA_SUITES[alg];
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
/** Is `v` one of the two pure FN-DSA parameter sets? */
|
|
106
|
+
function isFnDsaVariant(v) {
|
|
107
|
+
return v === 'fn-dsa-512' || v === 'fn-dsa-1024';
|
|
108
|
+
}
|
|
109
|
+
/** The clear error the default (unregistered) backend raises so misuse FAILS LOUD, not silently. */
|
|
110
|
+
exports.NO_FN_DSA_BACKEND_MESSAGE = 'no FN-DSA backend registered — install @atlasauth/pca-fndsa-node or supply a wasm backend via setFalconBackend()';
|
|
111
|
+
const DEFAULT_BACKEND = Object.freeze({
|
|
112
|
+
verify() {
|
|
113
|
+
throw new Error(exports.NO_FN_DSA_BACKEND_MESSAGE);
|
|
114
|
+
},
|
|
115
|
+
sign() {
|
|
116
|
+
throw new Error(exports.NO_FN_DSA_BACKEND_MESSAGE);
|
|
117
|
+
},
|
|
118
|
+
keygen() {
|
|
119
|
+
throw new Error(exports.NO_FN_DSA_BACKEND_MESSAGE);
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
let currentBackend = DEFAULT_BACKEND;
|
|
123
|
+
/** Install the FN-DSA backend that performs the actual Falcon math. */
|
|
124
|
+
function setFalconBackend(backend) {
|
|
125
|
+
currentBackend = backend;
|
|
126
|
+
}
|
|
127
|
+
/** The currently installed FN-DSA backend (the default throws {@link NO_FN_DSA_BACKEND_MESSAGE}). */
|
|
128
|
+
function getFalconBackend() {
|
|
129
|
+
return currentBackend;
|
|
130
|
+
}
|
|
131
|
+
/** Restore the default (throwing) backend — mainly for tests and teardown. */
|
|
132
|
+
function resetFalconBackend() {
|
|
133
|
+
currentBackend = DEFAULT_BACKEND;
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------------------------------------------
|
|
136
|
+
// Primitive-level wrappers (raw bytes) — mirror pq.ts's mlDsa65Sign / mlDsa65Verify
|
|
137
|
+
// ---------------------------------------------------------------------------------------------------
|
|
138
|
+
/**
|
|
139
|
+
* FN-DSA sign over raw bytes, delegating to the registered backend AFTER enforcing the suite's key/sig
|
|
140
|
+
* framing. THROWS (fail-loud) when no backend is registered, when the backend is verify-only (no `sign`),
|
|
141
|
+
* or when the backend returns a signature of the wrong padded length. `sk` must be a non-empty Uint8Array
|
|
142
|
+
* (its exact encoding is backend-defined, so its length is not pinned here).
|
|
143
|
+
*/
|
|
144
|
+
function fndsaSign(variant, sk, msg) {
|
|
145
|
+
if (!isFnDsaVariant(variant))
|
|
146
|
+
throw new RangeError(`fndsaSign: unknown FN-DSA variant '${String(variant)}'`);
|
|
147
|
+
if (!(sk instanceof Uint8Array) || sk.length === 0)
|
|
148
|
+
throw new TypeError('fndsaSign: secret key must be a non-empty Uint8Array');
|
|
149
|
+
if (!(msg instanceof Uint8Array))
|
|
150
|
+
throw new TypeError('fndsaSign: message must be a Uint8Array');
|
|
151
|
+
const backend = currentBackend;
|
|
152
|
+
if (typeof backend.sign !== 'function')
|
|
153
|
+
throw new Error('fndsaSign: FN-DSA backend is verify-only (no sign())');
|
|
154
|
+
const sig = backend.sign(sk, msg);
|
|
155
|
+
const expected = VARIANT_SIG_BYTES[variant];
|
|
156
|
+
if (!(sig instanceof Uint8Array) || sig.length !== expected) {
|
|
157
|
+
throw new Error(`fndsaSign: FN-DSA backend returned a ${sig instanceof Uint8Array ? String(sig.length) : 'non-byte'} signature; expected padded ${expected} bytes for '${variant}'`);
|
|
158
|
+
}
|
|
159
|
+
return sig;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* FN-DSA verify over raw bytes. The suite's key + signature LENGTHS are enforced HERE, BEFORE the backend
|
|
163
|
+
* is ever called, so a wrong-length public key or signature is rejected (false) without reaching the
|
|
164
|
+
* primitive. A registered backend that itself throws is NOT swallowed (fail-loud) — but a wrong-length
|
|
165
|
+
* input, and the clear "no backend" error, surface as described: length guard returns false; the default
|
|
166
|
+
* backend throws {@link NO_FN_DSA_BACKEND_MESSAGE} once the length guard has passed.
|
|
167
|
+
*/
|
|
168
|
+
function fndsaVerify(variant, pk, msg, sig) {
|
|
169
|
+
if (!isFnDsaVariant(variant))
|
|
170
|
+
return false;
|
|
171
|
+
if (!(pk instanceof Uint8Array) || pk.length !== VARIANT_PK_BYTES[variant])
|
|
172
|
+
return false;
|
|
173
|
+
if (!(sig instanceof Uint8Array) || sig.length !== VARIANT_SIG_BYTES[variant])
|
|
174
|
+
return false;
|
|
175
|
+
if (!(msg instanceof Uint8Array))
|
|
176
|
+
return false;
|
|
177
|
+
return currentBackend.verify(pk, msg, sig);
|
|
178
|
+
}
|
|
179
|
+
/** The domain separator for the FN-DSA leaf/hop binding suffix. */
|
|
180
|
+
exports.FN_DSA_LEAF_DOMAIN = 'atlas-pca/fn-dsa/leaf/v1\0';
|
|
181
|
+
/**
|
|
182
|
+
* The exact bytes an FN-DSA leaf/hop signature covers:
|
|
183
|
+
*
|
|
184
|
+
* thresholdMessage(leaf) ‖ FN_DSA_LEAF_DOMAIN ‖ utf8(alg) ‖ 0x00 ‖ utf8(pq_pk b64u)
|
|
185
|
+
*
|
|
186
|
+
* The leading `thresholdMessage(leaf)` is the IDENTICAL canonical message pq.ts's core leaf signs, so an
|
|
187
|
+
* FN-DSA signature commits to the whole action. The domain-separated suffix additively BINDS `alg` and
|
|
188
|
+
* `pq_pk` into the signed bytes — the same downgrade/key-swap protection pq.ts gets by folding `alg` /
|
|
189
|
+
* `pq_pk` into the canonical body via `bindSuiteFields`, achieved here without mutating the PCActn's typed
|
|
190
|
+
* shape (FN-DSA is not yet in the `SigAlg` union). In a hybrid both the Ed25519 and FN-DSA halves sign
|
|
191
|
+
* these same bytes, so each commits to the suite + PQ key.
|
|
192
|
+
*/
|
|
193
|
+
function fndsaLeafMessage(leaf, alg, pqPkB64u) {
|
|
194
|
+
const base = (0, pca_1.thresholdMessage)(leaf);
|
|
195
|
+
const suffix = (0, pca_1.utf8)(exports.FN_DSA_LEAF_DOMAIN);
|
|
196
|
+
const algBytes = (0, pca_1.utf8)(alg);
|
|
197
|
+
const pkBytes = (0, pca_1.utf8)(pqPkB64u);
|
|
198
|
+
const out = new Uint8Array(base.length + suffix.length + algBytes.length + 1 + pkBytes.length);
|
|
199
|
+
let off = 0;
|
|
200
|
+
out.set(base, off);
|
|
201
|
+
off += base.length;
|
|
202
|
+
out.set(suffix, off);
|
|
203
|
+
off += suffix.length;
|
|
204
|
+
out.set(algBytes, off);
|
|
205
|
+
off += algBytes.length;
|
|
206
|
+
out[off] = 0;
|
|
207
|
+
off += 1;
|
|
208
|
+
out.set(pkBytes, off);
|
|
209
|
+
return out;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Produce an FN-DSA leaf (or capability-hop) signature for a PCActn, returning the wire fields the
|
|
213
|
+
* surface carries. Pure FN-DSA: `sig` = FN-DSA signature, `pq_pk` = FN-DSA key. Hybrid: `sig` = Ed25519
|
|
214
|
+
* signature, `pq_sig` = FN-DSA signature, `pq_pk` = FN-DSA key — both over the SAME leaf message, for
|
|
215
|
+
* classical + lattice DEFENSE-IN-DEPTH (a forger must break Ed25519 AND Falcon). THROWS fail-closed on an
|
|
216
|
+
* unknown suite, a wrong-length FN-DSA key, a hybrid suite with no `edSecret`, or a missing/limited backend.
|
|
217
|
+
*/
|
|
218
|
+
function signPcaWithFndsa(input) {
|
|
219
|
+
const suite = resolveFnDsaAlg(input.alg);
|
|
220
|
+
if (suite === null)
|
|
221
|
+
throw new RangeError(`signPcaWithFndsa: unknown FN-DSA alg '${String(input.alg)}'`);
|
|
222
|
+
if (!(input.fnDsa?.pk instanceof Uint8Array) || input.fnDsa.pk.length !== suite.pqPkBytes) {
|
|
223
|
+
throw new TypeError(`signPcaWithFndsa: '${suite.alg}' requires a ${suite.pqPkBytes}-byte FN-DSA public key`);
|
|
224
|
+
}
|
|
225
|
+
if (!(input.fnDsa.sk instanceof Uint8Array) || input.fnDsa.sk.length === 0) {
|
|
226
|
+
throw new TypeError(`signPcaWithFndsa: '${suite.alg}' requires FN-DSA secret-key material`);
|
|
227
|
+
}
|
|
228
|
+
const pqPkB64u = (0, pca_1.b64u)(input.fnDsa.pk);
|
|
229
|
+
const msg = fndsaLeafMessage(input.leaf, suite.alg, pqPkB64u);
|
|
230
|
+
const fnSig = fndsaSign(suite.variant, input.fnDsa.sk, msg);
|
|
231
|
+
if (!suite.hasEd25519) {
|
|
232
|
+
// Pure FN-DSA: the FN-DSA signature IS the primary `sig`.
|
|
233
|
+
return { sig: (0, pca_1.b64u)(fnSig), alg: suite.alg, pq_pk: pqPkB64u };
|
|
234
|
+
}
|
|
235
|
+
// Hybrid ed25519 + fn-dsa: `sig` = Ed25519 over `msg`, `pq_sig` = FN-DSA over `msg`.
|
|
236
|
+
if (!(input.edSecret instanceof Uint8Array)) {
|
|
237
|
+
throw new TypeError(`signPcaWithFndsa: '${suite.alg}' requires edSecret (Ed25519 leaf-holder secret key)`);
|
|
238
|
+
}
|
|
239
|
+
return { sig: (0, pca_1.b64u)((0, pca_1.sign)(input.edSecret, msg)), alg: suite.alg, pq_pk: pqPkB64u, pq_sig: (0, pca_1.b64u)(fnSig) };
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Verify an FN-DSA leaf/hop signature over a PCActn. FAIL-CLOSED and never throws for ordinary wire
|
|
243
|
+
* faults: an unknown `alg`, a wrong-length/absent key or signature, a tampered action (its
|
|
244
|
+
* {@link thresholdMessage} changes), or a suite/key downgrade (the binding suffix changes) all return
|
|
245
|
+
* false. Hybrid requires BOTH the Ed25519 half AND the FN-DSA half. (A registered backend that itself
|
|
246
|
+
* throws is not caught — that is a backend bug, which should be loud.)
|
|
247
|
+
*/
|
|
248
|
+
function verifyPcaFndsa(input) {
|
|
249
|
+
const suite = resolveFnDsaAlg(input.alg);
|
|
250
|
+
if (suite === null)
|
|
251
|
+
return false; // unknown alg => fail-closed
|
|
252
|
+
if (typeof input.pq_pk !== 'string')
|
|
253
|
+
return false;
|
|
254
|
+
const pk = (0, pca_1.decodeB64uStrict)(input.pq_pk, suite.pqPkBytes);
|
|
255
|
+
if (pk === null)
|
|
256
|
+
return false; // wrong-length / non-canonical FN-DSA key — rejected before the backend
|
|
257
|
+
const msg = fndsaLeafMessage(input.leaf, suite.alg, input.pq_pk);
|
|
258
|
+
if (!suite.hasEd25519) {
|
|
259
|
+
// Pure FN-DSA: `sig` holds the FN-DSA signature.
|
|
260
|
+
if (typeof input.sig !== 'string')
|
|
261
|
+
return false;
|
|
262
|
+
const fnSig = (0, pca_1.decodeB64uStrict)(input.sig, suite.sigBytes);
|
|
263
|
+
if (fnSig === null)
|
|
264
|
+
return false; // wrong-length FN-DSA sig — rejected before the backend
|
|
265
|
+
return fndsaVerify(suite.variant, pk, msg, fnSig);
|
|
266
|
+
}
|
|
267
|
+
// Hybrid: Ed25519 `sig` under `holder` AND FN-DSA `pq_sig` under `pq_pk`, both over `msg`.
|
|
268
|
+
if (typeof input.holder !== 'string' || typeof input.sig !== 'string')
|
|
269
|
+
return false;
|
|
270
|
+
const edSig = (0, pca_1.decodeB64uStrict)(input.sig, suite.sigBytes); // enforce 64-byte Ed25519 sig
|
|
271
|
+
if (edSig === null)
|
|
272
|
+
return false;
|
|
273
|
+
const edOk = (0, pca_1.verifyB64u)(input.holder, msg, input.sig);
|
|
274
|
+
if (typeof input.pq_sig !== 'string')
|
|
275
|
+
return false;
|
|
276
|
+
const fnSig = (0, pca_1.decodeB64uStrict)(input.pq_sig, suite.pqSigBytes);
|
|
277
|
+
if (fnSig === null)
|
|
278
|
+
return false;
|
|
279
|
+
const pqOk = fndsaVerify(suite.variant, pk, msg, fnSig);
|
|
280
|
+
return edOk && pqOk; // fail-closed: BOTH required
|
|
281
|
+
}
|
|
282
|
+
/** Tag prefixed to a MOCK secret key so the mock can recover the public key from it (mock-only encoding). */
|
|
283
|
+
const MOCK_SK_TAG = (0, pca_1.utf8)('atlas-pca/fn-dsa/mock-sk/v1\0');
|
|
284
|
+
function concatBytes(...parts) {
|
|
285
|
+
let total = 0;
|
|
286
|
+
for (const p of parts)
|
|
287
|
+
total += p.length;
|
|
288
|
+
const out = new Uint8Array(total);
|
|
289
|
+
let off = 0;
|
|
290
|
+
for (const p of parts) {
|
|
291
|
+
out.set(p, off);
|
|
292
|
+
off += p.length;
|
|
293
|
+
}
|
|
294
|
+
return out;
|
|
295
|
+
}
|
|
296
|
+
function u32be(n) {
|
|
297
|
+
const b = new Uint8Array(4);
|
|
298
|
+
b[0] = (n >>> 24) & 0xff;
|
|
299
|
+
b[1] = (n >>> 16) & 0xff;
|
|
300
|
+
b[2] = (n >>> 8) & 0xff;
|
|
301
|
+
b[3] = n & 0xff;
|
|
302
|
+
return b;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Deterministic SHA-256 counter-mode stretch of `seed` to exactly `outLen` bytes. This is the mock/KAT
|
|
306
|
+
* key-derivation and signature-derivation function — NOT Falcon. It exists only so the wire framing and
|
|
307
|
+
* length enforcement are testable with reproducible, fixed-length byte strings.
|
|
308
|
+
*/
|
|
309
|
+
function hashKat(seed, outLen) {
|
|
310
|
+
const out = new Uint8Array(outLen);
|
|
311
|
+
let off = 0;
|
|
312
|
+
let counter = 0;
|
|
313
|
+
while (off < outLen) {
|
|
314
|
+
const block = (0, pca_1.sha256)(concatBytes(seed, u32be(counter)));
|
|
315
|
+
const take = Math.min(block.length, outLen - off);
|
|
316
|
+
out.set(block.subarray(0, take), off);
|
|
317
|
+
off += take;
|
|
318
|
+
counter += 1;
|
|
319
|
+
}
|
|
320
|
+
return out;
|
|
321
|
+
}
|
|
322
|
+
function sigLenForPk(pkLen) {
|
|
323
|
+
if (pkLen === exports.FN_DSA_512_PUBLIC_KEY_BYTES)
|
|
324
|
+
return exports.FN_DSA_512_SIGNATURE_BYTES;
|
|
325
|
+
if (pkLen === exports.FN_DSA_1024_PUBLIC_KEY_BYTES)
|
|
326
|
+
return exports.FN_DSA_1024_SIGNATURE_BYTES;
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
/** The mock's deterministic `(pk, msg) -> sig` derivation, padded to the variant's fixed length. */
|
|
330
|
+
function deriveMockSig(pk, msg) {
|
|
331
|
+
const sigLen = sigLenForPk(pk.length);
|
|
332
|
+
if (sigLen === null)
|
|
333
|
+
return null;
|
|
334
|
+
return hashKat(concatBytes((0, pca_1.utf8)('fn-dsa/mock-sig/v1\0'), pk, msg), sigLen);
|
|
335
|
+
}
|
|
336
|
+
function katKey(pk, msg) {
|
|
337
|
+
return `${(0, pca_1.b64u)(pk)}|${(0, pca_1.b64u)(msg)}`;
|
|
338
|
+
}
|
|
339
|
+
/** Constant-time byte-equality (no early return on the first differing byte). */
|
|
340
|
+
function timingSafeEqual(a, b) {
|
|
341
|
+
if (a.length !== b.length)
|
|
342
|
+
return false;
|
|
343
|
+
let diff = 0;
|
|
344
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
345
|
+
diff |= (a[i] ?? 0) ^ (b[i] ?? 0);
|
|
346
|
+
}
|
|
347
|
+
return diff === 0;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Deterministically mint a MOCK FN-DSA key pair for a variant (NOT real Falcon keys). The secret key is
|
|
351
|
+
* `MOCK_SK_TAG ‖ pk` so the mock backend's `sign` can recover the public key from it; the public key is a
|
|
352
|
+
* reproducible stretch of `seed` to the variant's exact length, so a given `seed` always yields the same
|
|
353
|
+
* pair (handy for stable KAT fixtures).
|
|
354
|
+
*/
|
|
355
|
+
function mockKeypair(variant, seed = 'default') {
|
|
356
|
+
if (!isFnDsaVariant(variant))
|
|
357
|
+
throw new RangeError(`mockKeypair: unknown FN-DSA variant '${String(variant)}'`);
|
|
358
|
+
const seedBytes = typeof seed === 'string' ? (0, pca_1.utf8)(`${variant}/${seed}`) : concatBytes((0, pca_1.utf8)(`${variant}/`), seed);
|
|
359
|
+
const pk = hashKat(seedBytes, VARIANT_PK_BYTES[variant]);
|
|
360
|
+
const sk = concatBytes(MOCK_SK_TAG, pk);
|
|
361
|
+
return { pk, sk };
|
|
362
|
+
}
|
|
363
|
+
function pkFromMockSk(sk) {
|
|
364
|
+
if (sk.length <= MOCK_SK_TAG.length)
|
|
365
|
+
return null;
|
|
366
|
+
if (!timingSafeEqual(sk.subarray(0, MOCK_SK_TAG.length), MOCK_SK_TAG))
|
|
367
|
+
return null;
|
|
368
|
+
return sk.subarray(MOCK_SK_TAG.length);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Install a DETERMINISTIC mock FN-DSA backend (and return it) so the wire format, PCA integration and
|
|
372
|
+
* length enforcement can be tested WITHOUT the real Falcon math. The backend is keyed by `(pk, msg) -> sig`:
|
|
373
|
+
* - any explicit `vectors` take precedence (drop in real FIPS-206 known-answer vectors here);
|
|
374
|
+
* - otherwise `(pk, msg)` maps to a reproducible {@link deriveMockSig}, so sign/verify round-trip.
|
|
375
|
+
* `keygen()` returns an `fn-dsa-512` {@link mockKeypair} by default; use {@link mockKeypair} directly for a
|
|
376
|
+
* specific variant. This is a TEST double — never register it in production (register a vetted backend).
|
|
377
|
+
*/
|
|
378
|
+
function registerTestBackend(vectors) {
|
|
379
|
+
const table = new Map();
|
|
380
|
+
if (vectors) {
|
|
381
|
+
for (const v of vectors)
|
|
382
|
+
table.set(katKey(v.pk, v.msg), v.sig);
|
|
383
|
+
}
|
|
384
|
+
const backend = {
|
|
385
|
+
verify(pk, msg, sig) {
|
|
386
|
+
const fromTable = table.get(katKey(pk, msg));
|
|
387
|
+
const expected = fromTable ?? deriveMockSig(pk, msg);
|
|
388
|
+
if (expected === null)
|
|
389
|
+
return false;
|
|
390
|
+
return timingSafeEqual(sig, expected);
|
|
391
|
+
},
|
|
392
|
+
sign(sk, msg) {
|
|
393
|
+
const pk = pkFromMockSk(sk);
|
|
394
|
+
if (pk === null)
|
|
395
|
+
throw new Error('mock FN-DSA backend: secret key was not minted by mockKeypair()');
|
|
396
|
+
const fromTable = table.get(katKey(pk, msg));
|
|
397
|
+
if (fromTable)
|
|
398
|
+
return fromTable;
|
|
399
|
+
const derived = deriveMockSig(pk, msg);
|
|
400
|
+
if (derived === null)
|
|
401
|
+
throw new Error('mock FN-DSA backend: public key length matches no FN-DSA variant');
|
|
402
|
+
return derived;
|
|
403
|
+
},
|
|
404
|
+
keygen() {
|
|
405
|
+
return mockKeypair('fn-dsa-512');
|
|
406
|
+
},
|
|
407
|
+
};
|
|
408
|
+
setFalconBackend(backend);
|
|
409
|
+
return backend;
|
|
410
|
+
}
|
|
411
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlasauth/pca-fndsa",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "FN-DSA / Falcon (FIPS 206 draft) suite for PCA: register the compact PQ signature suite in the crypto-agility seam with a pluggable, vetted verify backend (a constant-time Falcon is not safely hand-rolled in TS) — wire format, suite ids, and KAT-driven integration tests.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@atlasauth/pca": "0.1.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.6.3",
|
|
19
|
+
"vitest": "^2.1.4"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc -p tsconfig.build.json",
|
|
30
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
31
|
+
"test": "vitest run"
|
|
32
|
+
}
|
|
6
33
|
}
|
package/README.md
DELETED