Skip to content

Add an end-to-end runner test for ckks.relinearize. Part of #3022. - #3598

Merged
copybara-service[bot] merged 1 commit into
google:mainfrom
Heath4:relinearize-e2e-test
Nov 5, 2026
Merged

copybara-service[bot] merged 1 commit into
google:mainfrom
Heath4:relinearize-e2e-test

Conversation

@Heath4

@Heath4 Heath4 commented Nov 3, 2026

Copy link
Copy Markdown

Contributes to #3022
Adds a runner test that compiles ckks.relinearize to machine code and checks the math on real parameters (N=1024, two ~40-bit Q primes, one P prime).

How it works:

  • A python script generates a secret key, a 3-part ciphertext, a relinearization key, and the expected result c0 + c1*s + c2*s^2, using a seed. Bazel writes these to a header at build time.
  • The C++ test runs the compiled relinearize, computes d0 + d1*s, and checks that it is within a noise bound of the python's output.

How I checked it:

  • Max noise is 101 (measured seperately) against bound of 7568 (derived from relin noise bounds * 2 for safety).
  • Doing some negative-testing by modifying relinearize causes test fail due to high noise (removing P^-1 scaling from mod-down causes noise explosion).

Questions/Concerns:

  • --convert-polynomial-mul-to-ntt makes the relinearization key argument eval-form, so the test converts the key using a small helper, key_to_ntt.mlir. Is passing the key in NTT form the intended convention?
  • Keys come from the Python script rather than keygen HEIR ops. Is that acceptable for this test?

This does not cover ckks.mul, so it does not close #3022. Just want to get this sanity-checked first. Also this does not cover key-switching with multiple P limbs.

Code co-authored by Claude Opus 5.5

@AdrianHeath988

Copy link
Copy Markdown
Contributor

Whoops: this is me (Heath4 is my other account), opened from it by mistake. Can re-make it, or discuss here :)

@j2kun

j2kun commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

--convert-polynomial-mul-to-ntt makes the relinearization key argument eval-form, so the test converts the key using a small helper, key_to_ntt.mlir. Is passing the key in NTT form the intended convention?

Perhaps @crockeea has an opinion on this? I don't see a problem with the relin key being passed in NTT form, though in the future we should ensure the client code HEIR generates keeps its key material form in sync with changes to the function argument. For other function arguments that flow between client helpers and the main function, HEIR puts an attribute on the function argument that allows you to connect them properly, so this shouldn't be hard. However, I think for key material we just haven't gotten around to implementing this. I will open an issue for it maybe.

Keys come from the Python script rather than keygen HEIR ops. Is that acceptable for this test?

I was looking into this and it seems we don't properly support CKKS keygen/encrypt/decrypt yet. So doing it in the test harness is the only way we could submit this until those extra features are added. I started looking at this with #3597 while I was combing through old issues, and that PR makes it explicit that CKKS encrypt/decrypt is not supported.

Ideally we have it using HEIR ops for keygen and encrypt/decrypt. However, I think there is still some nontrivial work to accomplish that (e.g., lowering the random number generation ops to a secure implementation), so I'm happy to submit this approach in the mean time and refactor it later.

@crockeea

crockeea commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Is passing the key in NTT form the intended convention?

Jeremy has it spot-on. In general, the coeff/eval form of any arguments should be determined by the PolyMulToNTT solver.

@j2kun

j2kun commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

I filed #3600 for the key material tracking issue. I will submit a review of the PR itself shortly.

@j2kun j2kun left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Just one small nit

llvm_runner_test(
name = "relinearize",
heir_opt_flags = [
"--ckks-decompose-relinearize",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please replace this with a new pipeline in lib/Pipelines/ArithmeticPipelineRegistration.h (maybe called ckks-to-polynomial) that has all these steps: ckks-decompose-relinearize through rns-lower-convert-basis. That will ensure future work that modifies this pipeline will be reflected in this test.

@AdrianHeath988

AdrianHeath988 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

I attempted to add the pipeline (though I am unfamiliar with the process and Claude hand-held me), furthermore, perhaps using the python-test format for semantic checks will be useful now but please ping me when CKKS keygen/encrypt/decrypt land and I will deprecate the python tests and replace them with native HEIR ops.

// FHE.
void linalgPreprocessingBuilder(OpPassManager& manager);

// Lowers CKKS ops (like relin) to the polynomial dialect

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Lowers CKKS ops (like relin) to the polynomial dialect
// Lowers CKKS to the polynomial arithmetic

@j2kun j2kun left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! one last, nit then please squash and we can get it in

@Heath4
Heath4 force-pushed the relinearize-e2e-test branch from 841d852 to 548ca84 Compare November 5, 2026 18:37
@AdrianHeath988

Copy link
Copy Markdown
Contributor

Done, should be good now, I'll try to add the mul test to close #3022 after this, though I may be a bit busy until the 12th.

@j2kun

j2kun commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

No worries! Thank you for the contributions.

@j2kun j2kun added the pull_ready Indicates whether a PR is ready to pull. The copybara worker will import for internal testing label Nov 5, 2026
@copybara-service
copybara-service Bot merged commit 65fb031 into google:main Nov 5, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pull_ready Indicates whether a PR is ready to pull. The copybara worker will import for internal testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an end-to-end correctness test for ckks.relinearize

4 participants