Non-canonical ciphertext byte encodings decapsulate to the challenge key
Minor break · Demonstrated · Cause: specification text
Property: IND-CCA security
Cost against claim: one decapsulation query wins IND-CCA2 with the challenge key, no secret key or plaintext recovery
Because the byte width used to encode each ring coefficient exceeds log2(q), every coefficient below a small threshold has two distinct byte encodings of the same ring element, and the decapsulation algorithm accepts either one and returns the same key. An attacker who takes a challenge ciphertext, re-encodes one such coefficient, and submits the result to the decapsulation oracle recovers the challenge key in a single query, winning the designers' own IND-CCA2 game.
| Parameter set | Claim | Attack cost | Verdict |
|---|---|---|---|
| all OAEP-NTRU sets | IND-CCA2 up to 280 chosen ciphertext decapsulations | 1 decapsulation query | Minor break |
What causes it
DecodePoly (Algorithm 12 for 13-bit fields, Algorithm 14 for 15-bit fields, pp. 11 and 13) reads raw bytes into coefficients with no reduction or range check, so a byte string encoding v and one encoding v+q decode to the same element of Z_q; EncodePoly (Algorithm 11/13) only ever emits fields below q, so any adversarial re-encoding above q is new to the oracle. Decap (Algorithm 3, p. 7) reads the ciphertext bytes once through DecodePoly, performs no re-encryption and no ciphertext comparison, and rejects only when the tag sigma differs from the challenge's; the designers' own game (Figure 7, p. 26) likewise refuses only ct = ct*. Table 1 (p. 15) gives q = 7129/17497/28513 against byte widths of 13/15/15 bits, so a fraction 0.149/0.873/0.149 of coefficients admit a second encoding.
Evidence
The re-encoded ciphertext was submitted to the unmodified reference, optimized (AVX2) and additional implementations of all three parameter sets against the 10 official KAT ciphertexts of each, using a byte-level codec written independently from Algorithms 11 to 14 (not the original attacker's codec). Re-encoding the smallest, largest or a random aliasable coefficient succeeded on 10 of 10 official vectors in all 9 builds. Re-encoding every aliasable coefficient at once succeeded in the reference and additional builds (10/10 for 648 and 2592, 2/10 for 1296) but not in the AVX2-optimized 1296 build (0/10), whose 16-bit arithmetic rejects fields near 215; single-coefficient re-encoding still succeeds there in 9,649 of 11,220 cases (86 percent, every alias with v+q under 23,223 accepted). A second PQC-X member re-ran the original attacker's malleation and decapsulation scripts, got byte-identical logs, then independently confirmed the codec and the byte counts from a fresh, unmodified build.
Cause in the specification, traced to the specification text.
Limits
Benign malleability only: it gives no secret-key or plaintext recovery by itself. The spec-level count of about 297/21131/2387 simultaneous re-encodings per ciphertext holds for the specification and for 8 of the 9 builds; the AVX2-optimized 1296 build only reliably accepts single-coefficient re-encoding, already enough for the break.
Credit
Found by PQC-X.