Design
ctl-1
A 256-bit key-generation seed determines the whole CTL-512 key pair
Minor break · Argued · Cause: parameter size
Property: key recovery
Cost against claim: seed search 2256 classical, 2128 quantum against 2512 / 2256
Key generation draws one 32-byte seed, and everything else in the key pair is a deterministic function of it: the polynomials f and g, from which F, G, the decoding polynomial w and the public key h follow, and the backup value r used when a decryption fails; the short private-key format stores only the seed and F. There are therefore at most 2256 possible CTL-512 key pairs, and an attacker who runs the specified key generation on candidate seeds until h matches the target recovers the private key in at most 2256 trials classically, or 2128 Grover iterations, where level 512 requires 2512 and 2256. The bound does not depend on the lattice parameters.
| Parameter set | Claim | Attack cost | Verdict |
|---|
| CTL-512 | 512 classical, 256 quantum | 2256 key-generation trials classical (each about 220 to 233 operations); 2128 Grover iterations, about 2161 gates | Minor break |
| CTL-256 | 256 classical, 128 quantum | 2256 classical; 2128 quantum (no margin) | Holds |
What causes it
Section 3.5.4 builds the private key around one 32-byte key-generation seed from which f, g and r are regenerated deterministically, and Algorithm 1 draws no other randomness. The same seed length serves at all three levels: it matches the level-256 requirement exactly and falls 256 bits short of the level-512 one.
Evidence
PQC-X traced the seed length in the specification (section 3.5.4) and in the reference code (a 32-byte seed field in the key structure; key generation requests 32 bytes from the random source and expands them). A second member of PQC-X rebuilt the unmodified CTL-512 reference code, reproduced its official test-vector file byte for byte, counted the bytes drawn from the random source during one key generation (exactly 32, in one request), and checked that the code's own key generation, given only the 32 seed bytes stored in the private key, regenerates f and g and returns the public key of each of the 10 official test-vector key pairs (10 of 10). The search itself was not run.
Cause in the specification, traced to the specification text.
Limits
Far out of reach (2256 trials) and removed by a longer seed at level 512. CTL-128 is unaffected; CTL-256 lands exactly on its requirement, with no margin.
Designers' response
The designers acknowledged the finding on the PKC forum (2026-09-23): the 32-byte seed caps CTL-512 at 2256 public keys, and a revised version is to use a 64-byte seed with a matching expansion and private-key encoding, after a review of the whole entropy path. PQC-X has not checked it.
What PQC-X adds
The quantum cost of the search (2128 iterations: about 2161 gates with no depth limit, about 2213 under a 296 depth limit, both below the 2256 required), and a check on the reference code that the 32 stored seed bytes regenerate the public key of every official test-vector key pair.
Credit
First public report: M.-J. Saarinen (ngcc.dev kem-12-1, 2026-09-21). Found independently by PQC-X.
ctl-2
Decryption failures are 51 to 246 bits more likely than claimed
Holds · Argued · Cause: parameter size
Property: correctness (decryption-failure rate); no claimed or required property shown to fall
Cost against claim: failure rate 2-145 / 2-145 / 2-180 against the claimed 2-196 / 2-308 / 2-426.1; no failure within 280 queries
The designers compute their decryption-failure rates with secret polynomials f and g of standard deviation σ_f = 0.48 / 0.47 / 0.64 (Table 1), but the sampler of Algorithm 7 produces coefficients of standard deviation 0.58 / 0.69 / 0.97 at CTL-128 / 256 / 512, as the official keys show. With the real keys, the probability that a ciphertext fails to decrypt (the first of the two failure conditions, computed exactly under the designers' own independence heuristic) is 2-145 / 2-145 / 2-180 for the worst official key, against the claimed 2-196 / 2-308 / 2-426.1. No failure is expected within the 280 decapsulation queries the call allows, so the IND-CCA claim stands, with 51 / 163 / 246 bits less margin than stated.
| Parameter set | Claim | Attack cost | Verdict |
|---|
| CTL-128 | decryption failure 2-196 | 2-145 for the worst official key; no failure expected within 280 queries | Holds |
| CTL-256 | decryption failure 2-308 | 2-145 for the worst official key; no failure expected within 280 queries | Holds |
| CTL-512 | decryption failure 2-426.1 | 2-180 for the worst official key (about 2-137 per query with the largest admissible noise); no failure expected within 280 queries | Holds |
What causes it
Section 6.3 and Table 1 model f and g as discrete Gaussians of parameter σ_f, but Algorithm 7 (Sampler_fg) takes no σ_f: it samples (f, g) on an annulus whose radii depend on α and q only. The expected norm this annulus gives, with Table 1's α, corresponds to σ = 0.58 / 0.69 / 1.00, which matches the measured keys: the larger secrets are a property of the specified sampler, not of the code. The designers' formula with their σ_f reproduces their three claimed rates exactly.
Evidence
PQC-X decoded the private keys of the official test vectors (10 per set), measured the standard deviation of the coefficients of f and g, and computed the failure probability of the first condition for each key by exact convolution. A second member of PQC-X wrote an independent key parser (checked with the identity gF − fG = q on all 30 keys), re-measured σ (0.584 / 0.689 / 0.968, pooled over the 10 keys of each set), recomputed the exact per-key probabilities with another method (agreement to 0.01 bit: worst key 2-144.9 / 2-144.9 / 2-180.2, best key 2-153.6 / 2-152.6 / 2-193.1), reproduced the claimed rates from the designers' formula with Table 1's σ_f, and re-ran the first script with identical output. The second failure condition stays below 2-196 at every level.
Cause in the specification, traced to the specification text.
Limits
Choosing the ciphertexts gains little: the specified encryption caps the norm of the noise at about 1.08 times its mean and decapsulation re-encrypts, so no ciphertext with larger noise is accepted; that leaves at most about 2-137 per query at CTL-512 and nothing to gain at CTL-128, where the error norm is constant. With 280 queries no failure is expected. The larger secrets do not weaken the lattice problems: with the measured σ, recovering a CTL-512 key costs at least 2538 in core-SVP and about 2550 to 2559 in the MATZOV model, so the designers' key-recovery estimates, computed with σ_f = 0.64, understate the real cost.
Credit
Found by PQC-X.
Implementation
Bugs in the submitted code; the specification is sound on these points.
ctl-i1
The submitted CTL-512 code uses a 384-bit message and returns a 384-bit shared key where the specification fixes 512 bits
Minor break · Argued · Cause: code
Property: message recovery
Cost against claim: message recovery 2384 classical, 2192 quantum against 2512 / 2256; a 384-bit shared key where 512 bits are required
Scope: Users of the submitted CTL-512 code and of its test vectors; an implementation written from the specification (a 64-byte c2, a 512-bit message) is not affected.
The CTL-512 reference code draws a 48-byte message m, masks it into a 48-byte c2 and returns the 48-byte shared key K = Hash_k(m), where the specification fixes c2 at 64 bytes (a 512-bit m) and the call requires a shared key of at least 512 bits at this level. The ciphertext is a deterministic function of the public key and m, and K depends on m alone, so an attacker who guesses m confirms it by re-encryption and obtains K: 2384 trials classically and 2192 Grover iterations, against the 2512 and 2256 the level requires. The official test vectors carry the same 48-byte lengths.
| Parameter set | Claim | Attack cost | Verdict |
|---|
| CTL-512 | 512 classical, 256 quantum; a shared key of at least 512 bits | 2384 encapsulation trials classical; 2192 Grover iterations (about 2217 gates); the shared key has 384 bits | Minor break |
What causes it
The code sets the level constant of CTL-512 to 48 bytes (LVLBYTES in api_3329_2048.c; a 48-byte c2 field in ctl.h; a 48-byte shared key in KEM_AlgorithmInstance.c), and the test vectors follow it (SS_Len = 48, CT_Len = 2353), while section 3.5.3 and Table 3 assign 64 bytes to c2 and 2305 bytes to the ciphertext, and Algorithm 3 makes the message as long as c2. The code's c1 encoding also departs from the specification (2304 bytes at 9 bits per coefficient against 2240), with no security consequence. The specification is sound on this point.
Evidence
PQC-X read the lengths in the CTL-512 code and test vectors against the specification. A second member of PQC-X, on a fresh build of the unmodified reference code, reproduced the official test-vector file byte for byte, counted the bytes drawn from the random source during one encapsulation (exactly 48, the message), and checked that the same message under the same public key gives the same ciphertext and shared key (a guessed message is confirmed by re-encryption), that the same message under a different public key gives the same shared key (the key depends on the message alone), and that decapsulation returns that key. The search itself was not run.
Cause in the submitted code; the specification is not affected.
Limits
Out of reach (2384 trials). The quantum figure depends on the cost model: 2192 iterations are about 2217 gates with no depth limit, below 2256, but about 2328 under a 296 depth limit. CTL-128 and CTL-256 use the lengths the specification fixes.
Designers' response
The designers acknowledged on the PKC forum (2026-09-23) the inconsistency between the 48-byte shared key and c2 of the implementation and the 64-byte c2 of the specification, to be made consistent in a revised version with new test vectors. PQC-X has not checked it.
What PQC-X adds
The cost of the message recovery this length allows (2384 classical, 2192 Grover iterations, both below the level-512 requirement), checked on the reference code: the ciphertext is deterministic in the public key and the message, and the shared key depends on the message alone.
Credit
First public report: M.-J. Saarinen (ngcc.dev kem-12-2, 2026-09-21). Found independently by PQC-X.