Repository navigation
292 update the repository for v1.6.1 - #293
Merged
Merged
Conversation
- Port the missing PKE and BinFHE examples and expose the APIs they need, including functional bootstrapping, BinFHE public-key support, and serialization. - Move the functional-bootstrapping bindings into fbt.cpp and extend the example tests to check the complete v1.6 inventory.
The binfhe examples keep their cryptocontexts and bootstrapping keys in module-level globals (1-2.5 GB each), so running all of them in one pytest process accumulates tens of GB and gets pytest killed on the runner. Running every example in its own interpreter returns the memory to the OS after each test.
The examples added for 1.6.0 hard-coded FLEXIBLEAUTO scaling, which 128-bit CKKS rejects. Pick FIXEDAUTO and matching modulus sizes when get_native_int() is 128, the same way the older examples do, and skip the composite scaling and functional bootstrapping examples on 128-bit builds since those techniques only exist for 64-bit.
…S class to Python
- Fix bind_eval_multinplace_scalar_overloads, which registered EvalAddInPlace instead of EvalMultInPlace. The scalar EvalAddInPlace overloads are bound elsewhere, so nothing is lost. - Bind PrivateKey(cryptoContext). RecoverSharedKey() dereferences sk->GetCryptoContext(), so a default-constructed key crashed it. - Add CryptoContext.GetElementParams(), needed to call GetPlaintextForDecrypt(). - Add the CryptoContext overloads of SerializeEvalSumKey and check is_open(), so an unusable path returns False instead of a cereal error. - Add tests/test_api_coverage.py, which checks decrypted values rather than method presence.
Bind missing BinFHE APIs, plus LWESwitchingKey which KeySwitchGen returns and SwitchCTtoqn consumes. - Drop the LWEPrivateKey default constructor. BinFHEContext only checks for a null key, so an empty one segfaulted BTKeyGen, PubKeyGen and KeySwitchGen. Keys come from KeyGen(), KeyGenN() or deserialization. - Move the integer conversions into integer_conversions.h, replacing the copies in bindings.cpp, binfhe_bindings.cpp and fbt.cpp. - Widen LWECiphertext.GetModulus(), which truncated for NATIVE_INT=128. - Add tests/test_binfhe_api_coverage.py.
- Add docstrings for the 79 bindings added by the two API-coverage commits, taken from the doxygen comments in openfhe-development. - Move the remaining docstrings out of the .cpp files into *_docs.h. fbt.cpp gets its own header, since these hold external-linkage globals. - Fix stale parameter names (keyId -> keyTag, i -> index and others), and add or drop the :param: and :return: entries that no longer matched. - Indent the 20 docstrings that were flush left.
Contributor
|
@dsuponitskiy Update README.md for openfhe-python to list the same examples as in the README.md for openfhe-development |
yspolyakov
reviewed
Oct 15, 2026
…n README - Fix MakeCoefPackedPlaintext kwarg bound as "noiseScaleDeg " (trailing space) - Return false early when EvalMultKey/EvalAutomorphismKey files cannot be opened - Make the GenerateLUTviaFunction callback exception-safe via thread_local + guard - Remove BinFHE bindings that could never be called (cereal save/load, getters returning unregistered types) and the unused PKE serialization wrappers/header - Replace manual enum re-export blocks with py::enum_::export_values() - Add missing py::arg names (CCParams/SchSwchParams setters, keys, plaintext, ciphertext) - Select Python before pybind11 in CMake and install to sysconfig platlib - Add regression tests; list all 59 examples in the README with fixed links
- Reject negative, oversized, and bool Python ints in PyIntToInteger - Fix and enable simple_bootstrap_stc_example() - Remove the unsafe default LWEPublicKey constructor - Check is_open() in the EvalMultKey/EvalAutomorphismKey/EvalBootstrapKey serializers - Correct BinFHE docstrings and add a timeout to the example runner
- Reject None CryptoContext in ConvertRLWEToCKKS and SchemeSwitchingDataSerializer, with tests covering all three serializer arguments passed as None - Add regression tests for unwritable key-serialization paths - Use tmp_path-based unusable paths; make the eval-sum round trip able to fail - Gate slow examples with the long marker; FE example behind RUN_HIGH_MEMORY_EXAMPLES - Automate the nested LUT callback test
… decimal round trip, improving conversion performance.
- New CI workflow reusing the Manual pipeline, pinned to OpenFHE v1.6.1; triggers stay commented out, with the PR-checkout and runner-policy preconditions documented in the file - Inject openfhe.__version__ from CMake and re-export it from the package, since the star import skips underscore names - Pin the version test to CMakeLists.txt as the single source of truth - Derive the Sphinx release from the module; refresh the copyright - Document LWESwitchingKey and the BinFHE deserialization functions
- Replace all empty py::doc("") placeholders; commuted subtraction overloads get direction-correct text
- Document CCParams, SchSwchParams, Ciphertext, and BinFHE context methods, noting that SchSwchParams getters require
an object populated from a CKKS cryptocontext and that GetElements/GetElementsMutable return copies, not views
- Use the plain TOY context in the LUT callback tests: the large-precision overload needs primes wider than
NATIVE_SIZE=32 supports
The test used the hardcoded value 3*10**19, which overflows a 64-bit NativeInteger but is representable on NATIVE_SIZE=128, so no OverflowError was raised and the CI job failed. Derive the overflow probes from the configured native size instead: native_max + 1 and native_max * 10. The conversion guard itself was correct.
All 661 public APIs in the openfhe module now carry a docstring (verified at runtime). Adds docstrings/serialization_docs.h for the (de)serialization functions, inline py::doc() for the CryptoContext getters/setters, key, Plaintext, Ciphertext and BinFHE/LWE methods and free functions, and class docstrings for every exposed class.
- Reject None/empty arguments in the SchemeletRLWEMP entry points instead of segfaulting, and add a regression test for every guard - Fix the GetPublicKey docstring: only BTKeyGen(PUB_ENCRYPT) stores the key - Raise OverflowError for oversized ints on both math backends, and static_assert that the overflow check cannot silently switch off - Add a README section on the v1.6 breaking changes (FHECKKSRNS and the removed BinFHEContext attributes) - Install only the extension module (no stray __init__.py) and update the README install notes
openfhe-python-packager composes the pip wheel as an openfhe/ package from the install tree; without __init__.py setuptools packages nothing, the wheel ships empty, and import openfhe fails in CI.
Attach py::call_guard<py::gil_scoped_release> (the shared release_gil constant in bindings.h) to the PKE bindings whose C++ bodies never touch Python objects: the EvalAdd/Sub/Mult families, rotations and key switching, Encrypt/Decrypt, the Make*Plaintext encoders, key generation, multiparty decryption, bootstrapping, scheme switching, and polynomial/ Chebyshev evaluation, plus every (de)serialization entry point. Wrappers that must touch Python objects mid-body (the py::bytes serialization wrappers, EvalMultNoCheck's py::int_ conversion) release the GIL around their pure-C++ section instead. Also drop a dead local in the EvalAutomorphismKey string deserializer. Python threads can now run OpenFHE work in parallel instead of serializing on the GIL; callers that previously needed process pools (paying per-worker context/key re-deserialization and ciphertext IPC round trips) can share one in-memory CryptoContext across a thread pool. Measured on 4 threads with OMP_NUM_THREADS=1 at ring dimension 16384: EvalMult 2.35x, EvalAtIndex 2.80x, MakeCKKSPackedPlaintext 3.11x, ciphertext deserialization 4.80x. The thread-safety contract is unchanged from the C++ API but is now observable from Python and documented in bindings.h: the static evaluation-key maps are unsynchronized, so keys must not be generated, inserted, or deserialized while another thread evaluates. The BinFHE and FBT bindings are not yet covered and are left for a follow-up.
Deserialize the py::bytes wrappers straight from the bytes object's internal buffer through a non-owning streambuf, instead of copying the payload into a std::string and again into an istringstream; the GIL is released once the buffer is borrowed. Serialize into a single owned std::string through an appending streambuf, instead of copying out of a stringbuf; the only remaining copy in either direction is into the returned py::bytes. The JSON/string wrappers use the same streambufs, dropping their stringstream copies. Transient memory per call falls from roughly three times the payload to one, and at 1 MB ciphertexts (ring dimension 16384) serialization runs 3.5x faster and deserialization 1.65x faster single-threaded.
Declare the module's runtime dependencies in requirements.txt, which openfhe-python-packager reads into the wheel's install_requires, and import numpy eagerly at module load so a missing install fails with a message naming the fix instead of a lazy mid-computation error. With numpy guaranteed, the numpy bindings are registered unconditionally. The README documents pip install -r requirements.txt in the source and conda build flows and in the test instructions. Add numpy fast paths for encode/decode and fix overload dispatch
EvalFastRotationPrecompute now moves the decomposition into the carrier ciphertext, and EvalFastRotation/EvalFastRotationExt pass the C++ API an aliasing shared_ptr into the carrier's elements instead of deep-copying the full decomposition on every rotation call. Hoisted rotations run ~1.8x faster than repeated EvalRotate (8 rotations, ring dim 16384). Also accept signed rotation offsets like EvalRotate does (the uint32_t binding rejected them), add the GIL release EvalFastRotationExt was missing, and add a fast-vs-plain regression test with a reused precompute.
pascoec
approved these changes
Oct 20, 2026
dsuponitskiy
added a commit
that referenced
this pull request
Oct 27, 2026
* 289 return a vector of rotation indices (#291) * Expose automorphism key indices as a Python list - Add GetExistingEvalAutomorphismKeyIndices to query generated keys by tag. - Document its behavior, demonstrate bootstrapping key counts, and add tests for rotation and bootstrapping keys. * Fix automorphism index bindings to accept signed rotation offsets - Accept signed 32-bit offsets in FindAutomorphismIndex and FindAutomorphismIndices, converting them to the C++ API's unsigned form. - Update docstrings and add CKKS coverage for negative offsets, empty lists, and out-of-range inputs. --------- Co-authored-by: Dmitriy Suponitskiy <dsuponitskiy@dualitytech.com> * 292 update the repository for v1.6.1 (#293) * Add Python bindings and examples for OpenFHE 1.6 - Port the missing PKE and BinFHE examples and expose the APIs they need, including functional bootstrapping, BinFHE public-key support, and serialization. - Move the functional-bootstrapping bindings into fbt.cpp and extend the example tests to check the complete v1.6 inventory. * Fix plaintext modulus value in depth-bgvrns.py * Run each example test in a subprocess to avoid "out of memory" error The binfhe examples keep their cryptocontexts and bootstrapping keys in module-level globals (1-2.5 GB each), so running all of them in one pytest process accumulates tens of GB and gets pytest killed on the runner. Running every example in its own interpreter returns the memory to the OS after each test. * Add 128-bit guards to CKKS examples The examples added for 1.6.0 hard-coded FLEXIBLEAUTO scaling, which 128-bit CKKS rejects. Pick FIXEDAUTO and matching modulus sizes when get_native_int() is 128, the same way the older examples do, and skip the composite scaling and functional bootstrapping examples on 128-bit builds since those techniques only exist for 64-bit. * Move CKKS depth APIs to CryptoContext and do not expose the FHECKKSRNS class to Python * Expose the API-coverage backlog to Python - Fix bind_eval_multinplace_scalar_overloads, which registered EvalAddInPlace instead of EvalMultInPlace. The scalar EvalAddInPlace overloads are bound elsewhere, so nothing is lost. - Bind PrivateKey(cryptoContext). RecoverSharedKey() dereferences sk->GetCryptoContext(), so a default-constructed key crashed it. - Add CryptoContext.GetElementParams(), needed to call GetPlaintextForDecrypt(). - Add the CryptoContext overloads of SerializeEvalSumKey and check is_open(), so an unusable path returns False instead of a cereal error. - Add tests/test_api_coverage.py, which checks decrypted values rather than method presence. * Expose the BinFHE API-coverage backlog to Python Bind missing BinFHE APIs, plus LWESwitchingKey which KeySwitchGen returns and SwitchCTtoqn consumes. - Drop the LWEPrivateKey default constructor. BinFHEContext only checks for a null key, so an empty one segfaulted BTKeyGen, PubKeyGen and KeySwitchGen. Keys come from KeyGen(), KeyGenN() or deserialization. - Move the integer conversions into integer_conversions.h, replacing the copies in bindings.cpp, binfhe_bindings.cpp and fbt.cpp. - Widen LWECiphertext.GetModulus(), which truncated for NATIVE_INT=128. - Add tests/test_binfhe_api_coverage.py. * Document the new bindings and fix the existing docstrings - Add docstrings for the 79 bindings added by the two API-coverage commits, taken from the doxygen comments in openfhe-development. - Move the remaining docstrings out of the .cpp files into *_docs.h. fbt.cpp gets its own header, since these hold external-linkage globals. - Fix stale parameter names (keyId -> keyTag, i -> index and others), and add or drop the :param: and :return: entries that no longer matched. - Indent the 20 docstrings that were flush left. * Fix binding and build bugs, remove dead code, and list all examples in README - Fix MakeCoefPackedPlaintext kwarg bound as "noiseScaleDeg " (trailing space) - Return false early when EvalMultKey/EvalAutomorphismKey files cannot be opened - Make the GenerateLUTviaFunction callback exception-safe via thread_local + guard - Remove BinFHE bindings that could never be called (cereal save/load, getters returning unregistered types) and the unused PKE serialization wrappers/header - Replace manual enum re-export blocks with py::enum_::export_values() - Add missing py::arg names (CCParams/SchSwchParams setters, keys, plaintext, ciphertext) - Select Python before pybind11 in CMake and install to sysconfig platlib - Add regression tests; list all 59 examples in the README with fixed links * Fix various bugs: - Reject negative, oversized, and bool Python ints in PyIntToInteger - Fix and enable simple_bootstrap_stc_example() - Remove the unsafe default LWEPublicKey constructor - Check is_open() in the EvalMultKey/EvalAutomorphismKey/EvalBootstrapKey serializers - Correct BinFHE docstrings and add a timeout to the example runner * Add null-context guards and strengthen the test suite - Reject None CryptoContext in ConvertRLWEToCKKS and SchemeSwitchingDataSerializer, with tests covering all three serializer arguments passed as None - Add regression tests for unwritable key-serialization paths - Use tmp_path-based unusable paths; make the eval-sum round trip able to fail - Gate slow examples with the long marker; FE example behind RUN_HIGH_MEMORY_EXAMPLES - Automate the nested LUT callback test * Range-check integer conversions against a cached maximum instead of a decimal round trip, improving conversion performance. * Add a deferred CI workflow, expose __version__, and update the docs - New CI workflow reusing the Manual pipeline, pinned to OpenFHE v1.6.1; triggers stay commented out, with the PR-checkout and runner-policy preconditions documented in the file - Inject openfhe.__version__ from CMake and re-export it from the package, since the star import skips underscore names - Pin the version test to CMakeLists.txt as the single source of truth - Derive the Sphinx release from the module; refresh the copyright - Document LWESwitchingKey and the BinFHE deserialization functions * Fill the missing docstrings and fix the LUT tests on 32-bit builds - Replace all empty py::doc("") placeholders; commuted subtraction overloads get direction-correct text - Document CCParams, SchSwchParams, Ciphertext, and BinFHE context methods, noting that SchSwchParams getters require an object populated from a CKKS cryptocontext and that GetElements/GetElementsMutable return copies, not views - Use the plain TOY context in the LUT callback tests: the large-precision overload needs primes wider than NATIVE_SIZE=32 supports * Fix the integer-overflow test on 128-bit builds The test used the hardcoded value 3*10**19, which overflows a 64-bit NativeInteger but is representable on NATIVE_SIZE=128, so no OverflowError was raised and the CI job failed. Derive the overflow probes from the configured native size instead: native_max + 1 and native_max * 10. The conversion guard itself was correct. * Add docstrings to all remaining bindings All 661 public APIs in the openfhe module now carry a docstring (verified at runtime). Adds docstrings/serialization_docs.h for the (de)serialization functions, inline py::doc() for the CryptoContext getters/setters, key, Plaintext, Ciphertext and BinFHE/LWE methods and free functions, and class docstrings for every exposed class. * Resolve the remaining v1.6 review items - Reject None/empty arguments in the SchemeletRLWEMP entry points instead of segfaulting, and add a regression test for every guard - Fix the GetPublicKey docstring: only BTKeyGen(PUB_ENCRYPT) stores the key - Raise OverflowError for oversized ints on both math backends, and static_assert that the overflow check cannot silently switch off - Add a README section on the v1.6 breaking changes (FHECKKSRNS and the removed BinFHEContext attributes) - Install only the extension module (no stray __init__.py) and update the README install notes * Restore the __init__.py install for the wheel packager openfhe-python-packager composes the pip wheel as an openfhe/ package from the install tree; without __init__.py setuptools packages nothing, the wheel ships empty, and import openfhe fails in CI. * Release the GIL in compute-heavy PKE bindings and serialization Attach py::call_guard<py::gil_scoped_release> (the shared release_gil constant in bindings.h) to the PKE bindings whose C++ bodies never touch Python objects: the EvalAdd/Sub/Mult families, rotations and key switching, Encrypt/Decrypt, the Make*Plaintext encoders, key generation, multiparty decryption, bootstrapping, scheme switching, and polynomial/ Chebyshev evaluation, plus every (de)serialization entry point. Wrappers that must touch Python objects mid-body (the py::bytes serialization wrappers, EvalMultNoCheck's py::int_ conversion) release the GIL around their pure-C++ section instead. Also drop a dead local in the EvalAutomorphismKey string deserializer. Python threads can now run OpenFHE work in parallel instead of serializing on the GIL; callers that previously needed process pools (paying per-worker context/key re-deserialization and ciphertext IPC round trips) can share one in-memory CryptoContext across a thread pool. Measured on 4 threads with OMP_NUM_THREADS=1 at ring dimension 16384: EvalMult 2.35x, EvalAtIndex 2.80x, MakeCKKSPackedPlaintext 3.11x, ciphertext deserialization 4.80x. The thread-safety contract is unchanged from the C++ API but is now observable from Python and documented in bindings.h: the static evaluation-key maps are unsynchronized, so keys must not be generated, inserted, or deserialized while another thread evaluates. The BinFHE and FBT bindings are not yet covered and are left for a follow-up. * Remove the redundant buffer copies from bytes (de)serialization Deserialize the py::bytes wrappers straight from the bytes object's internal buffer through a non-owning streambuf, instead of copying the payload into a std::string and again into an istringstream; the GIL is released once the buffer is borrowed. Serialize into a single owned std::string through an appending streambuf, instead of copying out of a stringbuf; the only remaining copy in either direction is into the returned py::bytes. The JSON/string wrappers use the same streambufs, dropping their stringstream copies. Transient memory per call falls from roughly three times the payload to one, and at 1 MB ciphertexts (ring dimension 16384) serialization runs 3.5x faster and deserialization 1.65x faster single-threaded. * Make numpy a required runtime dependency Declare the module's runtime dependencies in requirements.txt, which openfhe-python-packager reads into the wheel's install_requires, and import numpy eagerly at module load so a missing install fails with a message naming the fix instead of a lazy mid-computation error. With numpy guaranteed, the numpy bindings are registered unconditionally. The README documents pip install -r requirements.txt in the source and conda build flows and in the test instructions. Add numpy fast paths for encode/decode and fix overload dispatch * Stop copying the digit decomposition in the fast-rotation bindings EvalFastRotationPrecompute now moves the decomposition into the carrier ciphertext, and EvalFastRotation/EvalFastRotationExt pass the C++ API an aliasing shared_ptr into the carrier's elements instead of deep-copying the full decomposition on every rotation call. Hoisted rotations run ~1.8x faster than repeated EvalRotate (8 rotations, ring dim 16384). Also accept signed rotation offsets like EvalRotate does (the uint32_t binding rejected them), add the GIL release EvalFastRotationExt was missing, and add a fast-vs-plain regression test with a reused precompute. * updates * Select the openfhe wheel by name in the docs wheel builder * Fix stale CKKS plaintext docs, install-prefix reconfigure bug, and README dependency notes * Correct the CKKS plaintext params docstrings and warn on pre-fix build directories --------- Co-authored-by: Dmitriy Suponitskiy <dsuponitskiy@dualitytech.com> Co-authored-by: Carlo Pascoe <cpascoe@dualitytech.com> --------- Co-authored-by: dsuponitskiy <28961198+dsuponitskiy@users.noreply.github.com> Co-authored-by: Dmitriy Suponitskiy <dsuponitskiy@dualitytech.com> Co-authored-by: Carlo Pascoe <cpascoe@dualitytech.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.