Skip to content

Throw when an operand cannot be adjusted to the ciphertext instead of silently skipping the operation - #36

Open
seyfal wants to merge 2 commits into
CAPS-UMU:mainfrom
seyfal:fix/plaintext-adjust-failure-throws
Open

seyfal wants to merge 2 commits into
CAPS-UMU:mainfrom
seyfal:fix/plaintext-adjust-failure-throws

Conversation

@seyfal

@seyfal seyfal commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Ciphertext::multPt (and addPt, subPt, add, sub, mult) adjust the operand's level and scaling degree to the ciphertext's when they differ. When the adjustment fails, for example because the plaintext was encoded with fewer RNS limbs than the ciphertext has, the code reaches assert(false) and returns. In a Release build the assert is compiled out, so the multiplication is silently skipped and the caller receives the unmodified ciphertext. We chased this for a while as "multPt does nothing above level 16": the boundary was simply where our plaintexts had fewer limbs than the ciphertext.

This PR replaces the six assert(false) sites with a std::runtime_error that names the operation, both (level, NoiseLevel) pairs and what the operand needs. It also fixes subPt's adjust path, which called addPt on the adjusted plaintext and therefore computed ct + pt instead of ct - pt whenever the levels differed (already fixed on OpenFHECompatTests; included here for main). Nothing changes for operands that adjust successfully.

Tested on v2.1.3 (786c760), CUDA 13.0, H200 with N=2^16 / depth 25 / FLEXIBLEAUTO and a depth-12 variant: a plaintext encoded at the same level or at full level multiplies correctly at every ciphertext level (max error ~2e-10, unchanged); a plaintext with fewer limbs than the ciphertext used to return the input unchanged and now throws, leaving the ciphertext untouched; subPt with a full-level plaintext now gives ct - pt (before: ct + pt). A stand-alone single-file repro is available if useful.

The commit also applies cleanly on OpenFHECompatTests.

Update: a second commit adds the same check before the kernels in addPt, subPt and multPt for the paths where no adjustment step runs (FIXEDMANUAL, ignore_scale). There a plaintext with fewer limbs than the ciphertext was read past its end (illegal memory access); it now throws the same exception. The FIXEDMANUAL top-limb bug found alongside is #39.

Fable 5.1 on behalf of Seyfal

seyfal and others added 2 commits September 5, 2026 05:54
…of silently skipping the operation

addPt, subPt, multPt, add, sub and mult adjust the operand's level and
scaling degree to the ciphertext's when they differ. When that adjustment
fails (for example a plaintext encoded with fewer RNS limbs than the
ciphertext, or a NoiseLevel-2 plaintext at the ciphertext's level) the code
hit assert(false) and returned, leaving the ciphertext unmodified. In
Release builds the assert is compiled out, so the operation is silently
skipped and the caller gets the un-multiplied (un-added) ciphertext back.

Report the failure with std::runtime_error naming the operation, both
(level, NoiseLevel) pairs and what the operand needs. Also fix subPt's
adjust path, which called addPt on the adjusted plaintext and therefore
computed ct + pt instead of ct - pt whenever the levels differed. Valid
operands are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tment step runs

Under FIXEDMANUAL (and with ignore_scale) the level-adjustment branch is
skipped, so a plaintext with fewer RNS limbs than the ciphertext reached
the kernels and was read past its end (illegal memory access). Check the
limb count before the kernels and throw the same exception as the
adjustment failure.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant