Reportskem-40 · Constant-time review

YuanYang.KEM (kem-40)

CandidateYuanYang.KEM
FamilyLattice (NTRU)
ArchiveYuanYang.KEM.zip (SHA-256: fe1bf3d78272bb79048e7d456819160324c6140206798cb77a22c2babcfdcf4a)

kem-40-1: Encryption discards the specified error polynomial

SeverityMedium
Scopeimplementation
StatusConfirmed
AffectedReference implementation, all three parameter sets
DiscoveryTrivial
ExploitationSecurity-proof gap; no complete attack demonstrated
CreditYijian Liu (archive sender Yijian_Liu)
Date2026-09-22

Original source: NGCC PKC Forum report

Algorithm 3 specifies c_bar = h*s + e + m*p^-1 mod q, and the IND-CPA proof invokes decisional Ring-LWE for (h, h*s+e). Every submitted yy_encrypt samples both s and e, but computes the ciphertext from h*s and the encoded message without ever reading e again.

This confirms Yijian Liu's mailing-list report. The shipped ciphertext distribution is not the distribution analyzed by the proof or the failure calculation. Omitting e is not by itself a demonstrated message-recovery attack—classical NTRU encryption can use a single ephemeral short polynomial—but the submitted implementation cannot claim the stated Ring-LWE reduction without a new analysis.

Reproducing

Commands below run in a checkout of the ngcc-harness repository with the candidate built (see its README).

python3 kem-40/reproduce_unused_error.py

The static witness checks all three independent implementation copies and fails unless e is sampled and then absent from the remainder of yy_encrypt.

kem-40-2: Decapsulation addresses a private array with a secret-derived index

SeverityMedium
Scopeside-channel
StatusProbable
AffectedReference decapsulation, all three parameter sets
DiscoveryTrivial
ExploitationLocal cache/address-trace leak of an internal decryption value; no key recovery demonstrated
CreditMarkku-Juhani O. Saarinen markku-juhani.saarinen@tuni.fi, with AI assistance
Date2026-09-23

During decapsulation, yy_decrypt_ciphertext computes hamming and overflow from the ciphertext multiplied by the private key (kem.c:181-220). It then reads the private inverse polynomial at sk->finvint[(i-overflow+h)%h] for each i (kem.c:224). The address pattern rotates with the secret-derived overflow, creating a cache/address side channel even though the surrounding loops have fixed bounds. No full secret-key or shared-secret recovery is claimed; see constant_time.md.

Reproducing

Commands below run in a checkout of the ngcc-harness repository with the candidate built (see its README).

The same source path occurs in yuanyang-512, yuanyang-1024, and yuanyang-2048 reference kem.c files. Inspect lines 181–224 and the call from yy_decapsulate_API at line 249. This is a source/dataflow witness; a measured cache attack remains open.