Contributing

This document provides guidance on how to contribute to TFHE-rs.

There are two ways to contribute:

  • Report issues: Open issues on GitHub to report bugs, suggest improvements, or note typos.

  • Submit codes: To become an official contributor, you must sign our Contributor License Agreement (CLA). Our CLA-bot will guide you through this process when you open your first pull request.

1. Setting up the project

Start by forkingarrow-up-right the TFHE-rs repository.

circle-info
  • Rust version: Ensure that you use a Rust version >= 1.81 to compile TFHE-rs.

  • Incompatibility: AArch64-based machines are not yet supported for Windows as it's currently missing an entropy source to be able to seed the CSPRNGsarrow-up-right used in TFHE-rs.

  • Performance: For optimal performance, it is highly recommended to run TFHE-rs code in release mode with cargo's --release flag.

To get more details about the library, please refer to the documentationarrow-up-right.

2. Creating a new branch

When creating your branch, make sure to use the following format :

git checkout -b {feat|fix|docs|chore…}/short_description

For example:

git checkout -b feat/new_feature_X

3. Before committing

3.1 Linting

Each commit to TFHE-rs should conform to the standards of the project. In particular, every source code, docker or workflows files should be linted to prevent programmatic and stylistic errors.

  • Rust source code linters: clippy

  • Typescript/Javascript source code linters: eslint, prettier

To apply automatic code formatting, run:

You can perform linting of all Cargo targets with:

3.2 Testing

Your contributions must include comprehensive documentation and tests without breaking existing tests. To run pre-commit checks, execute:

This command ensure that all the targets in the library are building correctly. For a faster check, use:

If you're contributing to GPU code, run also:

Unit testing suites are heavy and can require a lot of computing power and RAM availability. Whilst tests are run automatically in continuous integration pipeline, you can run tests locally.

All unit tests have a command formatted as:

Run make help to display a list of all the commands available.

To quickly test your changes locally, follow these steps:

  1. Locate where the code has changed.

  2. Add (or modify) a Cargo test filter to the corresponding make target in Makefile.

  3. Run the target.

circle-check

For example, if you made changes in tfhe/src/integer/*, you can test them with the following steps:

  1. In test_integer target, replace the filter -- integer:: by -- my_new_test.

  2. Run make test_integer.

4. Committing

TFHE-rs follows the conventional commit specification to maintain a consistent commit history, essential for Semantic Versioning (semver.orgarrow-up-right). Commit messages are automatically checked in CI and will be rejected if they do not comply, so make sure that you follow the commit conventions detailed on [this page] (https://www.conventionalcommits.org/en/v1.0.0/).

5. Rebasing

Before creating a pull request, rebase your branch on the repository's main branch. Merge commits are not permitted, thus rebasing ensures fewer conflicts and a smoother PR review process.

6. Opening a Pull Request

Once your changes are ready, open a pull request.

For instructions on creating a PR from a fork, refer to GitHub's official documentationarrow-up-right.

7. Continuous integration

Before a pull request can be merged, several test suites run automatically. Below is an overview of the CI process:

spinner

[!Note] Useful details:

  • pipeline is triggered by humans

  • review team is located in Paris timezone, pipeline launch will most likely happen during office hours

  • direct changes to CI related files are not allowed for external contributors

  • run make pcc to fix any build errors before pushing commits

8. Data versioning

Data serialized with TFHE-rs must remain backward compatible. This is done using the tfhe-versionablearrow-up-right crate.

If you modify a type that derives Versionize in a backward-incompatible way, an upgrade implementation must be provided.

For example, these changes are data breaking:

  • Adding a field to a struct.

  • Changing the order of the fields within a struct or the variants within an enum.

  • Renaming a field of a struct or a variant of an enum.

  • Changing the type of field in a struct or a variant in an enum.

On the contrary, these changes are not data breaking:

  • Renaming a type (unless it implements the Named trait).

  • Adding a variant to the end of an enum.

Example: adding a field

Suppose you want to add an i32 field to a type named MyType. The original type is defined as:

And you want to change it to:

Follow these steps:

  1. Navigate to the definition of the dispatch enum of this type. This is the type inside the #[versionize(MyTypeVersions)] macro attribute. In general, this type has the same name as the base type with a Versions suffix. You should find something like

  1. Add a new variant to the enum to preserve the previous version of the type. You can simply copy and paste the previous definition of the type and add a version suffix:

  1. Implement the Upgrade trait to define how we should go from the previous version to the current version:

  1. Fix the upgrade target of the previous version. In this example, impl Upgrade<MyType> for MyTypeV0 { should simply be changed to impl Upgrade<MyTypeV1> for MyTypeV0 {

Last updated

Was this helpful?