Compare commits

...

167 Commits

Author SHA1 Message Date
Mayeul@Zama
7e6adab801 update affected code 2023-11-20 10:01:12 +01:00
Mayeul@Zama
6df31476e9 update client decryption methods 2023-11-20 10:01:12 +01:00
Mayeul@Zama
40205d46e1 use decode structures to separate padding_bit, message and carry 2023-11-20 10:01:12 +01:00
Mayeul@Zama
a1cea9496a small simplification 2023-11-20 10:00:49 +01:00
Mayeul@Zama
abd4274b09 add missing doctest 2023-11-20 10:00:15 +01:00
Arthur Meyre
55775b8e02 fix(shortint): fix overflow behavior of NoiseLevel
- we will need to use a MAX/UNKNOWN level for forward compatibility with
old serialized ciphertexts, this patch ensures the add/mul behavior
saturates properly to usize::MAX to force a refresh in operations which
do it automatically
2023-11-17 18:34:02 +01:00
Arthur Meyre
523d561de6 chore(ci): add _ci_run_filter to standalone tests in shortint
- those tests were likely ignored, this is no longer the case
2023-11-17 18:34:02 +01:00
tmontaigu
61a50d0bcc chore(integer): make oveflowing_add/sub return BooleanBlock 2023-11-17 16:22:20 +01:00
Arthur Meyre
ee57f5658b chore(ci): refactor integer script and skip div and rem preferring div_rem 2023-11-17 15:00:50 +01:00
tmontaigu
9362965f50 feat(integer): add accessors to inner shortint sks
Users can access blocks from an integer but they don't have
the ability to use the inner shortint server key to process
individual blocks.

This adds an AsRef impl on integer ServerKey to allow that.

This also adds shortcuts to the integer ServerKey to get
the MessageModulus/CarryModulus (these are shorticuts
because users could do `integer_key.as_ref().message_modulus`.
2023-11-16 16:25:27 +01:00
Arthur Meyre
00fb60451d chore(ci): group signed and unsigned integer for better runtime homogeneity 2023-11-16 14:18:30 +01:00
Arthur Meyre
18b9fd4464 chore(ci): re-enable mistakenly disabled AVX512 for integers 2023-11-16 14:18:30 +01:00
Arthur Meyre
eace0bfb85 chore(ci): spread tests between two CI machines/workflow for faster runtime 2023-11-16 14:18:30 +01:00
Arthur Meyre
af1be5ebca chore(core): fix noise generation which could overflow the custom modulus
- updated some function name (for modulus checking) to be clearer on what
they do and when to use them
2023-11-16 08:58:40 +01:00
tmontaigu
916bd8a09f feat(hlapi): move if_then_else/cmux to FheBool
- This makes FheBool use integer::BooleanBlock internally.
- It makes comparisons (eq, ne, le, etc) return a FheBool instead of
  FheUint/FheInt.
- It also moves the if_then_else and cmux methods to FheBool.
- Adds casting from FheBool to FheUint/FheInt (but not from
  FheUint/FheInt to FheBool as we expect users to do `a.ne(0)`
  as its matches Rust)

BREAKING CHANGE:
    - Comparisons now return FheBool
    - if_then_else/cmux are now methods of FheBool.
2023-11-15 23:22:30 +01:00
tmontaigu
20cb0642ce refactor(hlapi): implement CastFrom for GenericInteger
And add the trait to the prelude so that users can use
it.
2023-11-15 23:22:30 +01:00
Arthur Meyre
151f9f6d82 chore(ci): fix build on main following several big merges 2023-11-15 13:29:08 +01:00
Arthur Meyre
8db8cb49e4 chore(shortint): add some flaky/failing doctests as actual tests
- check that those are actually failing or that they are a doctest bug
- add _ci_run_filter so that we can easily make sure tests run in CI even
if they don't have the "parameter format"
2023-11-15 11:10:44 +01:00
Arthur Meyre
b4583976a2 chore(tfhe): fix .gitignore for key cache
- this was not properly ignoring the keycache if a file had a specific
extension
2023-11-15 11:10:30 +01:00
Arthur Meyre
b450375da1 chore(integer): restore assert after using 3_3 params for CRT doctests
- fix max degree for CRT keys which don't need to propagate carries

BREAKING CHANGE:
pub API removed from pub interface
2023-11-15 11:10:30 +01:00
tmontaigu
f02f1fb297 feat(integer): add unsigned_oveflowing_add 2023-11-14 18:57:09 +01:00
Mayeul@Zama
17642fa703 refactor(shortint): remove unused EngineResult 2023-11-14 16:30:09 +01:00
Mayeul@Zama
23fa9b24bd refactor(shortint): separate lut generation from ShortintEngine 2023-11-14 16:30:09 +01:00
tmontaigu
0453b9bd60 fix(integer): fix signed_overflowing_sub using trivial 0 2023-11-13 15:43:33 +01:00
Arthur Meyre
9b2cf67911 chore(tfhe): fix required features for the generate_test_keys util 2023-11-13 10:05:17 +01:00
dependabot[bot]
36a7656048 chore(deps): bump tj-actions/changed-files from 40.1.0 to 40.1.1
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 40.1.0 to 40.1.1.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](18c8a4eceb...25ef3926d1)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-13 09:58:27 +01:00
Arthur Meyre
61c8eadd58 chore(ci): update Makefile for semver trick compatibility
- adding the tfhe package as a dependency is currently causing issues with
Cargo because of unified feature resolution it seems, it needs an
additional version specifier to disambiguate which package we are referring
to, an issue exists on their end but I don't think a fix is to be expected
soon https://github.com/rust-lang/cargo/issues/12891
- commiting this to main and then backporting the relevant pieces to 0.4.x
2023-11-10 15:35:38 +01:00
Arthur Meyre
fdd4d9d1cc chore(c_api): add more comments in the build.rs file and cbindgen.toml 2023-11-10 15:35:38 +01:00
Arthur Meyre
62700ab853 chore(tfhe): clarify dependency vs feature selection 2023-11-10 15:35:38 +01:00
Arthur Meyre
27445645e7 chore(c_api): have a way to skip cbindgen in a semver trick setting 2023-11-10 15:35:38 +01:00
tmontaigu
ea0cd26c0b chore(tfhe): fix builds on main 2023-11-10 15:15:31 +01:00
David Testé
ff48582679 test(core_crypto): silence dead code warnings on test utils 2023-11-10 09:35:16 +01:00
tmontaigu
a77c87ff12 refactor(hlapi): make GenericInteger generic over the Id 2023-11-09 20:33:53 +01:00
tmontaigu
6d143f1edc refactor(hlapi): remove unused FromParameters trait 2023-11-09 20:33:53 +01:00
Arthur Meyre
216e6b443a chore(tfhe): fix pedantic lints 2023-11-09 17:12:00 +01:00
Arthur Meyre
1400ae946c test(tfhe): add uniform random test
- use DKW test, it is e.g. used in
https://github.com/wch/r-source/blob/trunk/tests/p-r-random-tests.R

See Wikipedia DKW inequality
2023-11-09 17:12:00 +01:00
Arthur Meyre
c332902a05 feat(core): add support for non power of 2 moduli for random generation
- add convenience function to get truncated f64 value of an integer modulus
- update trait bounds for random generation for clearer diagnostics
2023-11-09 17:12:00 +01:00
Arthur Meyre
cf7a7f132d chore(doc): update a slightly wrong docstring 2023-11-09 14:38:43 +01:00
tmontaigu
6e0a3b9ad7 feat(integer): add BooleanBlock wrapper type
The BooleanBlock wrapper type is meant to convey the fact that
the ciphertext encrypts a 0 or 1.

Since its meant to be a simple wrapper, the goal for is to be flexible
and not add more burden than usefulness.

Hopefully this implementation somehow achieves that

Breaking Changes:
 - This changes the return type of comparisons from a T to
   a BooleanBlock. Requiring existing code to explicitely convert
   using `.into_radix`.
 - This makes the cmux/if_then_else functions take a BooleanValue
   as the input type  Requiring existing code to wrap their condition
   ciphertext in a new BooleanValue
2023-11-08 19:40:21 +01:00
Arthur Meyre
1f825dde08 chore(tfhe): bump version to 0.5.0 2023-11-08 15:55:22 +01:00
tmontaigu
f9222de47c feat(integer): add signed_overflowing_sub 2023-11-08 15:11:05 +01:00
Mayeul@Zama
5732e8dd7a test(hlapi): test base and compressed integer conformance 2023-11-08 09:25:55 +01:00
Mayeul@Zama
9db35c5474 chore(clippy): remove useless #[allow(warning)] 2023-11-07 16:47:04 +01:00
Mayeul@Zama
b69f73e8e6 chore(clippy): fix use_self warnings 2023-11-07 16:47:04 +01:00
Mayeul@Zama
90bdf75147 chore(clippy): enable nursery lints 2023-11-07 16:47:04 +01:00
Mayeul@Zama
233ea17adf chore(clippy): enable pedantic lints 2023-11-07 16:47:04 +01:00
David Testé
df6ee79841 chore(ci): test examples and apps in the ci 2023-11-07 10:58:03 +01:00
Mayeul@Zama
6497fb9a15 feat(shortint): update noise level in operations 2023-11-06 11:33:24 +01:00
Mayeul@Zama
d8894e3b69 feat(shortint): add noise level to ciphertexts 2023-11-06 11:33:24 +01:00
dependabot[bot]
42636bab13 chore(deps): bump tj-actions/changed-files from 40.0.0 to 40.1.0
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 40.0.0 to 40.1.0.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](af292f1e84...18c8a4eceb)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-06 09:42:04 +01:00
tmontaigu
ec27d3dc6f refactor(hlapi): remove wrapping of booleans
This commit removes the wrapping of the `tfhe::boolean`
that was done in the HLAPI, effectively making the HLAPI
only wrapping `tfhe::integer`.

FheBool is now reused to be a single shortint block
compatible with other type FheUint8,16,etc (previously they were not).

In the future, `tfhe::boolean` could be re-wrapped in hlapi, but
this time, to be used as a base for all integers and not just
FheBool.

BREAKING CHANGE:
- hlapi no longer wraps tfhe::boolean API.
- tfhe::ConfigBuilder::enable_bool/disable_bool/all_disabled/all_enabled
  removed. Now default configuration should be done using
  `tfhe::ConfigBuilder::default()`.
- `tfhe::ConfigBuilder::use_default_small_integer` removed
  use `tfhe::CondifBuilder::default_with_small_encryption()`
- Uninitialied{ClientKey, PublicKey, CompressedPublicKey} error types
  removed as these erros are no longer possible
2023-11-04 00:18:16 +01:00
Mayeul@Zama
5272c95de4 fix(shortint): fix modulus on LUT output in test 2023-11-03 09:45:22 +01:00
Mayeul@Zama
27d7ace3ef feat(shortint): fix keyswitching wrapping behavior 2023-11-03 09:45:22 +01:00
Mayeul@Zama
d80ab231a8 fix(shortint): add LUT generation without carry 2023-11-03 09:45:22 +01:00
tmontaigu
fe3fa531f9 refactor(hlapi): Remove shortint support from HLAPI
This removes the wrapping of shortints from the HLAPI,
the reasons are:

Contrary to integers for which we have different bit size
by combining different number of blocks from the _same_ key.
shortints had different bit size, but also different keys
which lead to:

- Not being able to cast between 2 different shortint type
  and between 1 shortint and 1 integer. Technically these casts
  are possible, but requires a keyswitch (and likely a PBS).
  But the keyswitch requires parameters, which may not always exists.

- Due to each shortint having different keys, the internal code to
  manage that made heavy use of macros to avoid having thousands of
  repeated lines. However, this made the code harder to follow / modify
  especially for people that were not familiar with that.

- In practive to really benefit from shortints, proper management of
  carry space is needed, however the HLAPI completely hides that,
  resulting in less optimal performances. In short, shortints
  are better used as a low level construct.

- Building a FheUint4 with two block of message_2_carry_2
  is likely to be faster the one message_4_carry_4 for most use
  cases.

So removing the wrapping of shortints will simplify the code, and
allow for more simplification later.
Also, it will allow us to expose Fhe{Ui/I}nt{2, 4, 6} types
which are compatible (cast_from/into) with Fhe{Ui/I}nt{8, 16, 32, etc}.

BREAKING CHANGE:
    - FheUint{2,3,4} removed from HLAPI
    - All HLAPI functions thied to shortints are removed
2023-10-31 09:32:05 +01:00
tmontaigu
5c1573c266 fix(integer): fix worst case noise growth in encrypted shifts
In encrypted shifts we pack 3 bits from 3 different blocks into the same
blocks by doing `b0 * 4 + 2 * b1 + b2`, and then do a PBS to simulate a
hardware mux gate.

If the inputs of shift (ie, in lhs << rhs, lhs != rhs, ie we don't do
lhs << lhs) this is fine regarding the norm2 noise.

However if we do things like `a << a` or `a >> a`, which is probably a
very rare thing but not impossible, the norm2 noise would go above the
limit that guarantees our error probability.

To fix that, we extract the bits that tells shift amount, so that they
are already properly aligned to their mux input position.
The packing becomes `b0 + 2 * b1 + b2` and so,
the noise growth is ok even in the worst case of doind `a << a`.
2023-10-30 15:02:02 +01:00
dependabot[bot]
7772e8112d chore(deps): bump tj-actions/changed-files from 39.2.3 to 40.0.0
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 39.2.3 to 40.0.0.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](95690f9ece...af292f1e84)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 12:07:44 +01:00
dependabot[bot]
5e92cb1475 chore(deps): bump JS-DevTools/npm-publish from 3.0.0 to 3.0.1
Bumps [JS-DevTools/npm-publish](https://github.com/js-devtools/npm-publish) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/js-devtools/npm-publish/releases)
- [Changelog](https://github.com/JS-DevTools/npm-publish/blob/main/CHANGELOG.md)
- [Commits](6fd3bc8dad...4b07b26a2f)

---
updated-dependencies:
- dependency-name: JS-DevTools/npm-publish
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 12:07:24 +01:00
dependabot[bot]
f51e19b071 chore(deps): bump actions/checkout from 4.1.0 to 4.1.1
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4.1.0...b4ffde65f46336ab88eb53be808477a3936bae11)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 12:06:53 +01:00
tmontaigu
aeb00ae584 chore(integer): use Arc<ServerKey> for executor
The goal is to avoid holding the key twice in memory
when both the executor and the test case needs the key
2023-10-27 18:01:55 +02:00
Arthur Meyre
ce5e9c1bdb chore(integer): more CRT tests and related fixes
- add remaining tests
- fix unchecked scalar mul for small carries
2023-10-27 11:30:00 +02:00
Arthur Meyre
4d4e124e94 chore(integer): add crt 32 bits tests with 5_1 params
- remove buggy unchecked_scalar_add_assign and replace by the proper
implementation which had a different name

BREAKING CHANGE:
removed an API entry point which was not required
2023-10-27 11:30:00 +02:00
Arthur Meyre
ca6d37e06f feat(integer): better handle trivial 0 blocks from LHS
- currently the filter only applied to the RHS but LHS can also benefit
from the filter
2023-10-27 10:31:24 +02:00
Mayeul@Zama
e3143315f3 fix(integer): disable broken assert in smart_crt_sub_assign 2023-10-27 09:43:51 +02:00
Mayeul@Zama
f8636fe814 feat(integer): add asserts in smart ops 2023-10-27 09:43:51 +02:00
tmontaigu
7e72400321 chore(doc): replace some ^ which could be interpreted as xor not pow 2023-10-26 23:42:58 +02:00
tmontaigu
728b409256 chore(integer): move comparator test out of it
Move the comparisons test (eq, ne, ge, gt, etc)
that were in the comparator module out of the comparator module.

This is so that in later commits will create test cases out
of these tests so they can, like other unsigned tests be
used to test other implementations of ServerKey
2023-10-25 10:31:55 +02:00
Arthur Meyre
d91404e567 chore(integer): remove empty where clause 2023-10-25 09:41:37 +02:00
David Testé
e11c3d7b7c chore(ci): add signed integer benchmarks to the CI 2023-10-25 09:14:00 +02:00
David Testé
6f8eeb043c chore(bench): add default ops for singed integers benchmarks 2023-10-25 09:14:00 +02:00
Arthur Meyre
00d55182b4 chore(ci): update examples to have a tmp dir to avoid rights issues in /tmp
- on machines where multiple users can log in, some files used for
serialization doctests would cause rights access issues and crash doctests
2023-10-23 15:03:18 +02:00
dependabot[bot]
6f6ce106c3 chore(deps): bump tj-actions/changed-files from 39.2.2 to 39.2.3
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 39.2.2 to 39.2.3.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](408093d9ff...95690f9ece)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 10:28:00 +02:00
dependabot[bot]
68fcbb5280 chore(deps): bump JS-DevTools/npm-publish from 2.2.2 to 3.0.0
Bumps [JS-DevTools/npm-publish](https://github.com/js-devtools/npm-publish) from 2.2.2 to 3.0.0.
- [Release notes](https://github.com/js-devtools/npm-publish/releases)
- [Changelog](https://github.com/JS-DevTools/npm-publish/blob/main/CHANGELOG.md)
- [Commits](fe72237be0...6fd3bc8dad)

---
updated-dependencies:
- dependency-name: JS-DevTools/npm-publish
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 10:27:35 +02:00
dependabot[bot]
3f46389cc8 chore(deps): bump actions/checkout from 4.1.0 to 4.1.1
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](8ade135a41...b4ffde65f4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 10:27:10 +02:00
Arthur Meyre
9e8dd01cb9 chore(ci): enable integer multi bit tests on M1 2023-10-20 17:55:38 +02:00
tmontaigu
0085ceb97b chore(ci): set node version 2023-10-20 10:24:50 +02:00
tmontaigu
be9a4d2d9c chore(wasm): update dependencies of wasm tests 2023-10-20 10:24:50 +02:00
Arthur Meyre
87421e8307 chore(ci): update M1 workflow to not explode the 6h GitHub limit
- run doc tests for CI with LTO off following M1 investigation
- LTO fat may be a cause of the wopbs flaky tests, disabling to check
2023-10-19 14:18:05 +02:00
Arthur Meyre
0c3919628f refactor(core): use avx512 intrinsics when available for data conversions
- we use inline assembly for now as rust does not propose those in the std
or core arch crates at the moment
- add tests for avx512 conversion
2023-10-19 13:21:19 +02:00
Arthur Meyre
f1c21888a7 chore(doc): encourage users to use dedicated keys to Radix or CRT 2023-10-19 09:52:22 +02:00
tmontaigu
2624beb7fa fix(integer): fix unsigned_overflowing_sub on trivials
unsigned_overflowing_sub does an independant subtraction
on each blocks with a correcting term being added to avoid
trashing the padding bit (lhs - rhs + correction).

The correction depended on rhs's degree.
e.g. if rhs's degree was in range 1..(msg_mod-1) -> correction =
     msg_mod

However if rhs's degree was zero (so rhs is a trivial 0), the correction
was also 0, however the borrow propagation rely on that correction to
always be added.
2023-10-18 19:26:01 +02:00
tmontaigu
e44c38a102 chore(ci): tell nvm to use node version 20 in wasm parallel tests 2023-10-18 19:04:27 +02:00
Arthur Meyre
4535230874 refactor(core): rename pbs_modulus_switch to fast_pbs_modulus_switch
- update docstring to reflect the change that has been done

BREAKING CHANGE:
pbs_modulus_switch is currently part of the public API and the rename is
therefore a breaking change
2023-10-17 16:53:19 +02:00
Arthur Meyre
a7b2d9b228 chore(ci): update check toolchain to latest nightly
- no new lints
2023-10-17 16:13:26 +02:00
Arthur Meyre
ab923a3ebc fix(crt): fix mul for non symmetrical parameters
- add non reg test for 32 bits mul with 5_1 parameters
2023-10-17 14:22:00 +02:00
Arthur Meyre
a0e85fb355 feat(core): add more custom moduli primitives to UnsignedInteger
As always for now the objective is to have functional custom modulus
implementations, not efficient ones

- add multiplication
- add leading_zeros
- add neg
2023-10-17 13:31:35 +02:00
Arthur Meyre
ecee305340 chore(core): change prelude algorithms imports 2023-10-17 13:31:35 +02:00
Mayeul@Zama
f08ea8cf85 fix(integer): fix max_degree formula 2023-10-17 11:35:08 +02:00
Mayeul@Zama
096e320b97 fix(crt): use 3_3 parameters for crt tests 2023-10-17 11:35:08 +02:00
Mayeul@Zama
95aac64c1c style(crt): compute modulus from base in tests 2023-10-17 11:35:08 +02:00
Mayeul@Zama
76aaa56691 fix(integer): fix small mul test 2023-10-17 11:35:08 +02:00
Mayeul@Zama
a40489bdd2 style(shortint): do not use assign ops on a cloned input 2023-10-17 11:35:08 +02:00
Mayeul@Zama
4bf617eb10 feat(shortint): cleanup input if necessary in ops 2023-10-17 11:35:08 +02:00
Mayeul@Zama
070073d229 feat(shortint): cleanup input if necessary in apply_lookup_table_bivariate 2023-10-17 11:35:08 +02:00
Arthur Meyre
6c1ca8e32b chore(core): use modular_distance instead of abs_diff in fft tests
- we are doing backwards conversions to the torus, so values could wrap
around near 0 or u64::MAX, take the modular distance which represents the
distance on the torus
2023-10-17 10:29:24 +02:00
Arthur Meyre
6523610ca4 refactor(core): refactor conversion code from f64 to i64
- observed that the subnormal case is already handled by the shift logic so
the special handling was not required
- add test for avx512 conversion
2023-10-17 10:29:24 +02:00
Arthur Meyre
41c20e22f5 chore(ci): enable AVX512 for integer and multi bit integer tests 2023-10-17 10:28:14 +02:00
J-B Orfila
4a00d25cb1 doc: updating doc for v0.4 2023-10-16 17:56:17 +02:00
tmontaigu
8c9ee64612 fix(integer): better estimate which algorithm to choose 2023-10-16 16:19:00 +02:00
tmontaigu
bfdfbfac0f chore(integer): add tests for default signed rotations/shifts 2023-10-16 16:16:07 +02:00
tmontaigu
dbe7bdcd5c feat(integer): map cmux to if_then_else 2023-10-16 16:15:49 +02:00
tmontaigu
6d77ff18ad chore(integer): add full_propagate test 2023-10-16 14:11:44 +02:00
tmontaigu
7d4d0e0b16 fix(integer): fix is_scalar_add_possible 2023-10-16 14:11:44 +02:00
Mayeul@Zama
b27762232c feat(wasm): add integers safe deserialization 2023-10-16 10:19:09 +02:00
Mayeul@Zama
f597d0f06f feat(c_api): add base and compress integers safe deserialization 2023-10-16 10:19:09 +02:00
dependabot[bot]
ee188448f3 chore(deps): bump tj-actions/changed-files from 39.2.1 to 39.2.2
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 39.2.1 to 39.2.2.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](db153baf73...408093d9ff)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 09:51:26 +02:00
Mayeul@Zama
ee49f048c7 style(integer): rename num_blocks_per_integer 2023-10-13 14:18:44 +02:00
Mayeul@Zama
a9b09ecc45 feat(c_api): add compact integer safe deserialization 2023-10-13 14:18:44 +02:00
Mayeul@Zama
efc243edc9 feat(global): refactor ciphertext conformance 2023-10-13 14:18:44 +02:00
tmontaigu
bc34411d3f feat(integer): speed-up division by using overflowing_sub
using overflowing sub allows to remove the comparison used
in the algorithm, giving significant performance boost.

before
             8        16       32      40       64       128        256
hpc7a:    `981 ms` `2.53 s` `6.41 s` `9.04 s` `16.1 s` `39.3 s` `1.55 min`
m6i:      `1.10 s` `2.97 s` `7.17 s` `10.5 s` `19.7 s` `50.2 s` `2.11 min`

afer:
             8        16       32      40       64       128        256
hpc7a:   `604 ms` `1.6 s`  `3.8 s`  `5.14 s` `9.4 s`  `22.4 s`  `54.613 s`
m6i:     `659 ms` `1.77 s` `4.4 s`  `5.9 s`  `11.5 s` `29.8 s`  `87.95 s`
2023-10-12 14:35:36 +02:00
J-B Orfila
c7923ff3ed refactor(shortint): update compact parameters 2023-10-12 11:56:50 +02:00
Arthur Meyre
7534b68e5c test(core): use polynomial tests from NTT PR
- initial work done in https://github.com/zama-ai/tfhe-rs/pull/394
- useful reworks of the tests have been waiting in that PR, this is to
have those tests while NTT usage gets validated

co-authored-by: sarah-ek <sarah.elkazdadi@zama.ai>
2023-10-12 10:40:15 +02:00
tmontaigu
655f7e6214 chore(hlapi): improve scalar type convertion 2023-10-10 17:18:32 +02:00
tmontaigu
b8556ddbd4 feat(hlapi): add C API support for FheInt 2023-10-10 17:18:32 +02:00
tmontaigu
cab7439064 fix(integer): handle trivial ct in if_then_else
if_then_else uses two calls to zero_out_if.

In zero_out_if, if the condition block given has a degree of 0
then it would return 0, without calling the predicate function.

This is not correct, as its the predicate function that
gives whether the output should be 0 or the original ciphertext.

Which meant that if if_then_else received a condition with a
degree of 0, it would always return 0.
2023-10-10 17:18:12 +02:00
tmontaigu
f8a8780651 fix(integer): remove remove if_then_else assert
unchecked_if_then_else had an assert that required
that the condition value looked like it encrypts a boolean.
This check was made using the degree.

However, the only cases where a value looks like it encrypts a boolean
value is when they are the result of a comparison (lt, le, eq, etc).

But there are other cases were the value holds a boolean value but
due to how degree works, it's not possible to know thus limiting the
use of if_then_else.

So we remove that assert, and rely on the developper knowing
its condition is 0 or 1.
2023-10-09 18:35:26 +02:00
tmontaigu
bb3c8e7d5d feat(integer): add unsigned_overflowing_sub 2023-10-09 15:39:41 +02:00
Arthur Meyre
69536960c3 chore: fix typos 2023-10-09 14:49:13 +02:00
dependabot[bot]
52a7c52a49 chore(deps): bump tj-actions/changed-files from 39.2.0 to 39.2.1
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 39.2.0 to 39.2.1.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](8238a41032...db153baf73)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 10:21:04 +02:00
tmontaigu
751c407ba5 feat(wasm): add FheInt support 2023-10-05 15:52:45 +02:00
Mayeul@Zama
492d348138 test(serialization): run tests in CI 2023-10-05 09:15:58 +02:00
Mayeul@Zama
e7df7eb5ef test(serialization): add serialization test 2023-10-05 09:15:58 +02:00
Mayeul@Zama
380ee52986 test(hlapi): test compact integer conformance 2023-10-05 09:15:58 +02:00
Mayeul@Zama
439a28f68b feat(global): impl ParameterSetConformant for ciphertexts 2023-10-05 09:15:58 +02:00
Mayeul@Zama
2eb1e37ca7 feat(global): add safe deserialization 2023-10-05 09:15:58 +02:00
Mayeul@Zama
eb1b136c45 feat(core): add to_equivalent_lwe_dimension 2023-10-05 09:15:58 +02:00
Mayeul@Zama
1376bcba7c chore(test): add type hint for rust-analyzer 2023-10-05 09:15:58 +02:00
tmontaigu
b5b4e54b9b feat(hlapi): add FheInt{8,16,32,64,128,256} 2023-10-04 20:41:19 +02:00
Arthur Meyre
23c2bd790a chore(test): fix incorrect memory buffer size in wopbs core_crypto tests 2023-10-04 14:17:33 +02:00
tmontaigu
251ee9aa0e chore(hlapi): add InnerCiphertext type to integer wrapper
Make the GenericInteger struct have a generic `InnerCiphertext`
instead of always RadixCiphertext.

This is to prepare the addition of signed types which will use a
SignedRadixCiphertext.
2023-10-03 16:26:09 +02:00
Arthur Meyre
fad066a996 refactor(core): remove a copy in the external product
- add an fft backward primitive that can use the input fourier buffer as
output as well
- gains 0.6 ms on 2_2 m6i.metal
2023-10-03 13:10:01 +02:00
tmontaigu
6ef1f22b33 feat(hlapi): tie scalar ops with corresponding clear type
Operations that used a scalar as right operand where generically
implemented meaning a user could, for example, add a u32 to a FheUint8.

Rust only allows operations between matching types, so we do the same
thing.

BREAKING CHANGE: This is a breaking change on the Rust API, but
for the better I believe. On the C API it is not a breaking change
as we already made that association as it was simpler to implement
2023-10-02 23:17:30 +02:00
tmontaigu
8cc8dba1ab feat(integer): add encryption of signed radix via compressed pk 2023-10-02 16:02:36 +02:00
tmontaigu
082328c91a feat(integer): add default signed_scalar div/rem/div_rem 2023-10-02 16:02:18 +02:00
tmontaigu
fdb6faa0a8 fix(integer): clean output quotient of division
The quotient was slowly computed by
getting a resut bit, shifting it to its position then adding it
to a quotient block, i.e quotient += bit << pos;

This meant that the output quotient was noisy, too noisy for
parameters like param_message_4_carry_4, and so the signed division
would then negate and cmux this quotient and due to the high noise,
some computations would fail, on param_message_4_carry_4.

To fix this we clean the quotient's noise before returning it.
2023-10-02 08:48:45 +02:00
Arthur Meyre
856440386f chore(csprng): the stabilized aarch64 intrisics were in Rust 1.72
- update the version accordingly
2023-09-29 18:33:39 +02:00
tmontaigu
2e8189514c feat(integer): make compact ciphertext compatible with signed 2023-09-28 20:41:38 +02:00
tmontaigu
29b2454cce feat(integer): add sign extend fn for SignedRadixCiphertext 2023-09-28 17:48:41 +02:00
tmontaigu
9ed2589c7a chore(integer): impl RecomposableSignedInteger for StaticSignedBigInt 2023-09-28 14:01:14 +02:00
tmontaigu
36b71529e6 chore(integer): make tests work with different ServerKey
This is a first step, a second step would be
to plug the non parallel radix tests so that
they are testing the same things.
2023-09-28 10:50:18 +02:00
Arthur Meyre
b738946d72 chore(core): add utils to test noise distribution for power of 2 q 2023-09-28 09:49:30 +02:00
David Testé
62f1425257 chore(bench): add missing unsigned integer operations 2023-09-28 08:47:39 +02:00
David Testé
44e491b93f style(integer): rename absolute_value functions to abs
Also add _parallelized suffix since the implementation is located in
radix_parallel directory.
2023-09-28 08:47:39 +02:00
tmontaigu
a470b26672 fix(integer): StaticSignedBigInt right shift 2023-09-27 18:37:25 +02:00
tmontaigu
015409424c chore(hlapi): remove unused keychain_member from macro 2023-09-27 14:33:24 +02:00
tmontaigu
37be751188 fix(integer): is_neg/sub/add possible
The way we did the is_neg/add/sub possible at the integer level was
incorrect in two ways.

1) We simply called the is_neg/add/sub_possible from
   the shortint impl on each block as if the were independant.
   However that is not the case, and to the check did not reflect
   actual computation.

2) We checked that we did not go beyond max degree on each block,
   However, a more correct approach would be to check that adding
   the potential carry from preceding block would not exceeding the
   current block max capacity.
2023-09-26 16:02:15 +02:00
sarah el kazdadi
2580a834af feat(core): optimize monic polynomial operations in pbs 2023-09-26 15:02:33 +02:00
David Testé
a029bd878e chore(ci): fix file exclusion for coverage reports 2023-09-26 08:58:36 +02:00
David Testé
400e7930b6 chore(ci): fix options typos for new tarpaulin version 2023-09-26 08:58:36 +02:00
David Testé
40d07c6bc3 chore(ci): speed-up boolean coverage
This is done by reducing the number of parameters set run in tests.
Using the keycache for the key switching key and public key tests also
help to reduce total run duration.
2023-09-26 08:58:36 +02:00
Mayeul@Zama
9dd2d39f1c style(global): fix typos 2023-09-25 17:27:29 +02:00
dependabot[bot]
4045a3bc2f chore(deps): bump tj-actions/changed-files from 39.0.2 to 39.2.0
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 39.0.2 to 39.2.0.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](6ee9cdc581...8238a41032)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-25 10:30:28 +02:00
dependabot[bot]
b4ffeccd46 chore(deps): bump actions/checkout from 4.0.0 to 4.1.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](3df4ab11eb...8ade135a41)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-25 10:30:22 +02:00
tmontaigu
7fe3ad3b6e feat(integer): improve scalar_mul
This changes the algorithm for scalar_mul.
The new algorithm allows to remove a lot of work.

For small precisions (16, 32, 64) the gains are in range 5%-10%
for higher precisions the gains are 25%-50%.

This also changes the mul to use the functions that sums many
clean ciphertexts in parallel. For mul, there is only a 5%-10%
improvements for 128bits and 256bits mul.
2023-09-22 15:45:07 +02:00
tmontaigu
7fdd4f9532 chore(integer): add default signed bitand/or/xor tests 2023-09-22 14:50:27 +02:00
Arthur Meyre
81eef39ddb feat(core): add parallel variant of extract_lwe_sample_from_glwe
- allows to quickly extract all coefficients packed in a GLWE cipehrtext
2023-09-22 10:55:02 +02:00
tmontaigu
b6459e3cda fix(integer): fix signed div_rem test for 0/0 2023-09-21 21:38:16 +02:00
Arthur Meyre
f2ef78c348 refactor(core): simplify closest_representable and pbs_modulus_switch
- both code were selecting the bit below the last representable bit,
extracted it and then added it to the bit above, the same effect can be
achieved by adding a 1 at the bit below the last representable bit
- update closest_representable to use an approach more like
pbs_modulus_switch yielding assembly with 42% less instructions (12 -> 7)
2023-09-21 15:54:53 +02:00
Mayeul@Zama
aef8f31621 chore(deps): update cargo dependencies 2023-09-21 15:11:13 +02:00
sarah el kazdadi
df78d178da fix(integer): replace unnecessary unsafe code in integer shift/add 2023-09-21 11:02:41 +02:00
Arthur Meyre
9297a886a4 chore(docs): fix docstring about encryption key choice 2023-09-20 16:02:55 +02:00
tmontaigu
28b4f91a32 fix(integer): only propagate if necessary after trimming
By unconditionally propagating carries after trimming
we would sometimes do work for nothing, and as propagating
carries is not cheap at all it would degrade performances.

So only propagate when necessary
2023-09-20 15:57:33 +02:00
David Testé
04fb46e41b chore(ci): print security level in parameters check
The devo profile is used to speed up the compilation phase.
2023-09-20 15:33:39 +02:00
David Testé
53da809f37 chore(ci): reduce max dimension threshold in lattice estimator 2023-09-20 09:39:50 +02:00
David Testé
723910c669 chore(ci): fix end-of-file newlines 2023-09-20 09:39:50 +02:00
David Testé
8ecf8879fb chore(ci): add end-of-file newline checks recipe 2023-09-20 09:39:50 +02:00
tmontaigu
2427f744f8 feat(integer): add unchecked implementation of signed ciphertext 2023-09-20 08:50:15 +02:00
429 changed files with 34899 additions and 18590 deletions

View File

@@ -51,7 +51,7 @@ jobs:
echo "Fork git sha: ${{ inputs.fork_git_sha }}"
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: ${{ inputs.fork_repo }}
ref: ${{ inputs.fork_git_sha }}
@@ -80,7 +80,7 @@ jobs:
- name: Run user docs tests
run: |
make test_user_doc
CARGO_PROFILE=release_lto_off make test_user_doc
- name: Run js on wasm API tests
run: |
@@ -110,6 +110,10 @@ jobs:
run: |
make test_high_level_api
- name: Run safe deserialization tests
run: |
make test_safe_deserialization
- name: Slack Notification
if: ${{ always() }}
continue-on-error: true

View File

@@ -1,4 +1,4 @@
name: AWS Integer Tests on CPU
name: AWS Unsigned Integer Tests on CPU
env:
CARGO_TERM_COLOR: always
@@ -23,13 +23,13 @@ on:
description: "Action runner name"
type: string
request_id:
description: 'Slab request ID'
description: "Slab request ID"
type: string
fork_repo:
description: 'Name of forked repo as user/repo'
description: "Name of forked repo as user/repo"
type: string
fork_git_sha:
description: 'Git SHA to checkout from fork'
description: "Git SHA to checkout from fork"
type: string
jobs:
@@ -50,7 +50,7 @@ jobs:
echo "Fork git sha: ${{ inputs.fork_git_sha }}"
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: ${{ inputs.fork_repo }}
ref: ${{ inputs.fork_git_sha }}
@@ -65,13 +65,21 @@ jobs:
toolchain: stable
default: true
- name: Gen Keys if required
run: |
make GEN_KEY_CACHE_MULTI_BIT_ONLY=TRUE gen_key_cache
- name: Run unsigned integer multi-bit tests
run: |
AVX512_SUPPORT=ON make test_unsigned_integer_multi_bit_ci
- name: Gen Keys if required
run: |
make gen_key_cache
- name: Run integer tests
- name: Run unsigned integer tests
run: |
BIG_TESTS_INSTANCE=TRUE make test_integer_ci
AVX512_SUPPORT=ON BIG_TESTS_INSTANCE=TRUE make test_unsigned_integer_ci
- name: Slack Notification
if: ${{ always() }}

View File

@@ -1,4 +1,4 @@
name: AWS Multi Bit Tests on CPU
name: AWS Signed Integer Tests on CPU
env:
CARGO_TERM_COLOR: always
@@ -23,13 +23,13 @@ on:
description: "Action runner name"
type: string
request_id:
description: 'Slab request ID'
description: "Slab request ID"
type: string
fork_repo:
description: 'Name of forked repo as user/repo'
description: "Name of forked repo as user/repo"
type: string
fork_git_sha:
description: 'Git SHA to checkout from fork'
description: "Git SHA to checkout from fork"
type: string
jobs:
@@ -50,7 +50,7 @@ jobs:
echo "Fork git sha: ${{ inputs.fork_git_sha }}"
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: ${{ inputs.fork_repo }}
ref: ${{ inputs.fork_git_sha }}
@@ -73,9 +73,17 @@ jobs:
run: |
make test_shortint_multi_bit_ci
- name: Run integer multi-bit tests
- name: Run signed integer multi-bit tests
run: |
make test_integer_multi_bit_ci
AVX512_SUPPORT=ON make test_signed_integer_multi_bit_ci
- name: Gen Keys if required
run: |
make gen_key_cache
- name: Run signed integer tests
run: |
AVX512_SUPPORT=ON BIG_TESTS_INSTANCE=TRUE make test_signed_integer_ci
- name: Slack Notification
if: ${{ always() }}

View File

@@ -50,7 +50,7 @@ jobs:
echo "Fork git sha: ${{ inputs.fork_git_sha }}"
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: ${{ inputs.fork_repo }}
ref: ${{ inputs.fork_git_sha }}
@@ -83,7 +83,7 @@ jobs:
- name: Run user docs tests
run: |
make test_user_doc
CARGO_PROFILE=release_lto_off make test_user_doc
- name: Gen Keys if required
run: |
@@ -100,6 +100,12 @@ jobs:
- name: Run example tests
run: |
make test_examples
make dark_market
- name: Run apps tests
run: |
make test_trivium
make test_kreyvium
- name: Slack Notification
if: ${{ always() }}

View File

@@ -50,7 +50,7 @@ jobs:
echo "Fork git sha: ${{ inputs.fork_git_sha }}"
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: ${{ inputs.fork_repo }}
ref: ${{ inputs.fork_git_sha }}

View File

@@ -19,6 +19,14 @@ on:
request_id:
description: "Slab request ID"
type: string
# This input is not used in this workflow but still mandatory since a calling workflow could
# use it. If a triggering command include a user_inputs field, then the triggered workflow
# must include this very input, otherwise the workflow won't be called.
# See start_full_benchmarks.yml as example.
user_inputs:
description: "Type of benchmarks to run"
type: string
default: "weekly_benchmarks"
env:
CARGO_TERM_COLOR: always
@@ -43,7 +51,7 @@ jobs:
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
@@ -94,7 +102,7 @@ jobs:
path: ${{ env.RESULTS_FILENAME }}
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab

View File

@@ -21,7 +21,17 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Install and run newline linter checks
if: matrix.os == 'ubuntu-latest'
run: |
wget https://github.com/fernandrone/linelint/releases/download/0.0.6/linelint-linux-amd64
echo "16b70fb7b471d6f95cbdc0b4e5dc2b0ac9e84ba9ecdc488f7bdf13df823aca4b linelint-linux-amd64" > checksum
sha256sum -c checksum || exit 1
chmod +x linelint-linux-amd64
mv linelint-linux-amd64 /usr/local/bin/linelint
make check_newline
- name: Run pcc checks
run: |

View File

@@ -50,7 +50,7 @@ jobs:
echo "Fork git sha: ${{ inputs.fork_git_sha }}"
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: ${{ inputs.fork_repo }}
ref: ${{ inputs.fork_git_sha }}
@@ -67,7 +67,7 @@ jobs:
- name: Check for file changes
id: changed-files
uses: tj-actions/changed-files@6ee9cdc5816333acda68e01cf12eedc619e28316
uses: tj-actions/changed-files@25ef3926d147cd02fc7e931c1ef50772bbb0d25d
with:
files_yaml: |
tfhe:
@@ -76,15 +76,16 @@ jobs:
- concrete-csprng/src/**
- name: Generate Keys
if: steps.changed-files.outputs.tfhe_any_changed == 'true'
run: |
make GEN_KEY_CACHE_COVERAGE_ONLY=TRUE gen_key_cache
- name: Run boolean coverage
- name: Run coverage for boolean
if: steps.changed-files.outputs.tfhe_any_changed == 'true'
run: |
make test_boolean_cov
- name: Run shortint coverage
- name: Run coverage for shortint
if: steps.changed-files.outputs.tfhe_any_changed == 'true'
run: |
make test_shortint_cov

View File

@@ -42,7 +42,7 @@ jobs:
steps:
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: ${{ inputs.fork_repo }}
ref: ${{ inputs.fork_git_sha }}

View File

@@ -44,7 +44,7 @@ jobs:
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
@@ -96,7 +96,7 @@ jobs:
path: ${{ env.RESULTS_FILENAME }}
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab

View File

@@ -19,6 +19,10 @@ on:
request_id:
description: "Slab request ID"
type: string
user_inputs:
description: "Type of benchmarks to run"
type: string
default: "weekly_benchmarks"
env:
CARGO_TERM_COLOR: always
@@ -26,8 +30,33 @@ env:
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
jobs:
prepare-matrix:
name: Prepare operations matrix
runs-on: ubuntu-latest
outputs:
op_flavor: ${{ steps.set_op_flavor.outputs.op_flavor }}
steps:
- name: Weekly benchmarks
if: ${{ github.event.inputs.user_inputs == 'weekly_benchmarks' }}
run: |
echo "OP_FLAVOR=[\"default\", \"default_comp\", \"default_scalar\", \"default_scalar_comp\"]" >> ${GITHUB_ENV}
- name: Quarterly benchmarks
if: ${{ github.event.inputs.user_inputs == 'quarterly_benchmarks' }}
run: |
echo "OP_FLAVOR=[\"default\", \"default_comp\", \"default_scalar\", \"default_scalar_comp\", \
\"smart\", \"smart_comp\", \"smart_scalar\", \"smart_parallelized\", \"smart_parallelized_comp\", \"smart_scalar_parallelized\", \"smart_scalar_parallelized_comp\", \
\"unchecked\", \"unchecked_comp\", \"unchecked_scalar\", \"unchecked_scalar_comp\", \
\"misc\"]" >> ${GITHUB_ENV}
- name: Set operation flavor output
id: set_op_flavor
run: |
echo "op_flavor=${{ toJSON(env.OP_FLAVOR) }}" >> ${GITHUB_OUTPUT}
integer-benchmarks:
name: Execute integer benchmarks for all operations flavor
needs: prepare-matrix
runs-on: ${{ github.event.inputs.runner_name }}
if: ${{ !cancelled() }}
continue-on-error: true
@@ -35,7 +64,7 @@ jobs:
max-parallel: 1
matrix:
command: [ integer, integer_multi_bit]
op_flavor: [ default, default_comp, default_scalar, default_scalar_comp, smart, smart_comp, smart_scalar, smart_parallelized, smart_parallelized_comp, smart_scalar_parallelized, unchecked, unchecked_comp, unchecked_scalar, unchecked_scalar_comp, misc ]
op_flavor: ${{ fromJson(needs.prepare-matrix.outputs.op_flavor) }}
steps:
- name: Instance configuration used
run: |
@@ -45,7 +74,7 @@ jobs:
echo "Request ID: ${{ inputs.request_id }}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
@@ -67,7 +96,7 @@ jobs:
override: true
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab

View File

@@ -44,7 +44,7 @@ jobs:
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
@@ -96,7 +96,7 @@ jobs:
path: ${{ env.RESULTS_FILENAME }}
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab

View File

@@ -15,7 +15,6 @@ env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-C target-cpu=native"
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
CARGO_PROFILE: release_lto_off
FAST_TESTS: "TRUE"
concurrency:
@@ -28,7 +27,7 @@ jobs:
runs-on: ["self-hosted", "m1mac"]
steps:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Install latest stable
uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af
@@ -86,7 +85,7 @@ jobs:
- name: Run user docs tests
run: |
make test_user_doc
CARGO_PROFILE=release_lto_off make test_user_doc
# JS tests are more easily launched in docker, we won't test that on M1 as docker is pretty
# slow on Apple machines due to the virtualization layer.
@@ -111,10 +110,9 @@ jobs:
run: |
make test_shortint_multi_bit_ci
# # These multi bit integer tests are too slow on M1 with low core count and low RAM
# - name: Run integer multi bit tests
# run: |
# make test_integer_multi_bit_ci
- name: Run integer multi bit tests
run: |
make test_integer_multi_bit_ci
remove_label:
name: Remove m1_test label

View File

@@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
@@ -49,7 +49,7 @@ jobs:
- name: Publish web package
if: ${{ inputs.push_web_package }}
uses: JS-DevTools/npm-publish@fe72237be0920f7a0cafd6a966c9b929c9466e9b
uses: JS-DevTools/npm-publish@4b07b26a2f6e0a51846e1870223e545bae91c552
with:
token: ${{ secrets.NPM_TOKEN }}
package: tfhe/pkg/package.json
@@ -65,7 +65,7 @@ jobs:
- name: Publish Node package
if: ${{ inputs.push_node_package }}
uses: JS-DevTools/npm-publish@fe72237be0920f7a0cafd6a966c9b929c9466e9b
uses: JS-DevTools/npm-publish@4b07b26a2f6e0a51846e1870223e545bae91c552
with:
token: ${{ secrets.NPM_TOKEN }}
package: tfhe/pkg/package.json

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0

View File

@@ -17,10 +17,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Checkout lattice-estimator
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: malb/lattice-estimator
path: lattice_estimator
@@ -32,7 +32,7 @@ jobs:
- name: Collect parameters
run: |
make write_params_to_file
CARGO_PROFILE=devo make write_params_to_file
- name: Perform security check
run: |

View File

@@ -19,6 +19,14 @@ on:
request_id:
description: "Slab request ID"
type: string
# This input is not used in this workflow but still mandatory since a calling workflow could
# use it. If a triggering command include a user_inputs field, then the triggered workflow
# must include this very input, otherwise the workflow won't be called.
# See start_full_benchmarks.yml as example.
user_inputs:
description: "Type of benchmarks to run"
type: string
default: "weekly_benchmarks"
env:
CARGO_TERM_COLOR: always
@@ -43,7 +51,7 @@ jobs:
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
@@ -84,7 +92,7 @@ jobs:
path: ${{ env.RESULTS_FILENAME }}
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab

View File

@@ -43,7 +43,7 @@ jobs:
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
@@ -94,7 +94,7 @@ jobs:
path: ${{ env.RESULTS_FILENAME }}
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab

View File

@@ -19,6 +19,14 @@ on:
request_id:
description: "Slab request ID"
type: string
# This input is not used in this workflow but still mandatory since a calling workflow could
# use it. If a triggering command include a user_inputs field, then the triggered workflow
# must include this very input, otherwise the workflow won't be called.
# See start_full_benchmarks.yml as example.
user_inputs:
description: "Type of benchmarks to run"
type: string
default: "weekly_benchmarks"
env:
CARGO_TERM_COLOR: always
@@ -43,7 +51,7 @@ jobs:
echo "Request ID: ${{ inputs.request_id }}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
@@ -65,7 +73,7 @@ jobs:
override: true
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab

View File

@@ -0,0 +1,129 @@
# Run signed integer benchmarks on an AWS instance and return parsed results to Slab CI bot.
name: Signed Integer benchmarks
on:
workflow_dispatch:
inputs:
instance_id:
description: "Instance ID"
type: string
instance_image_id:
description: "Instance AMI ID"
type: string
instance_type:
description: "Instance product type"
type: string
runner_name:
description: "Action runner name"
type: string
request_id:
description: "Slab request ID"
type: string
env:
CARGO_TERM_COLOR: always
RESULTS_FILENAME: parsed_benchmark_results_${{ github.sha }}.json
PARSE_INTEGER_BENCH_CSV_FILE: tfhe_rs_integer_benches_${{ github.sha }}.csv
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
jobs:
run-integer-benchmarks:
name: Execute signed integer benchmarks in EC2
runs-on: ${{ github.event.inputs.runner_name }}
if: ${{ !cancelled() }}
steps:
- name: Instance configuration used
run: |
echo "IDs: ${{ inputs.instance_id }}"
echo "AMI: ${{ inputs.instance_image_id }}"
echo "Type: ${{ inputs.instance_type }}"
echo "Request ID: ${{ inputs.request_id }}"
- name: Get benchmark date
run: |
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
- name: Set up home
# "Install rust" step require root user to have a HOME directory which is not set.
run: |
echo "HOME=/home/ubuntu" >> "${GITHUB_ENV}"
- name: Install rust
uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af
with:
toolchain: nightly
override: true
- name: Run benchmarks with AVX512
run: |
make AVX512_SUPPORT=ON FAST_BENCH=TRUE bench_signed_integer
- name: Parse benchmarks to csv
run: |
make PARSE_INTEGER_BENCH_CSV_FILE=${{ env.PARSE_INTEGER_BENCH_CSV_FILE }} \
parse_integer_benches
- name: Upload csv results artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
with:
name: ${{ github.sha }}_csv_integer
path: ${{ env.PARSE_INTEGER_BENCH_CSV_FILE }}
- name: Parse results
run: |
COMMIT_DATE="$(git --no-pager show -s --format=%cd --date=iso8601-strict ${{ github.sha }})"
COMMIT_HASH="$(git describe --tags --dirty)"
python3 ./ci/benchmark_parser.py target/criterion ${{ env.RESULTS_FILENAME }} \
--database tfhe_rs \
--hardware ${{ inputs.instance_type }} \
--project-version "${COMMIT_HASH}" \
--branch ${{ github.ref_name }} \
--commit-date "${COMMIT_DATE}" \
--bench-date "${{ env.BENCH_DATE }}" \
--walk-subdirs \
--name-suffix avx512 \
--throughput
- name: Upload parsed results artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
with:
name: ${{ github.sha }}_integer
path: ${{ env.RESULTS_FILENAME }}
- name: Checkout Slab repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab
token: ${{ secrets.CONCRETE_ACTIONS_TOKEN }}
- name: Send data to Slab
shell: bash
run: |
echo "Computing HMac on results file"
SIGNATURE="$(slab/scripts/hmac_calculator.sh ${{ env.RESULTS_FILENAME }} '${{ secrets.JOB_SECRET }}')"
echo "Sending results to Slab..."
curl -v -k \
-H "Content-Type: application/json" \
-H "X-Slab-Repository: ${{ github.repository }}" \
-H "X-Slab-Command: store_data_v2" \
-H "X-Hub-Signature-256: sha256=${SIGNATURE}" \
-d @${{ env.RESULTS_FILENAME }} \
${{ secrets.SLAB_URL }}
- name: Slack Notification
if: ${{ failure() }}
continue-on-error: true
uses: rtCamp/action-slack-notify@b24d75fe0e728a4bf9fc42ee217caa686d141ee8
env:
SLACK_COLOR: ${{ job.status }}
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
SLACK_MESSAGE: "Signed integer benchmarks failed. (${{ env.ACTION_RUN_URL }})"
SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

View File

@@ -0,0 +1,133 @@
# Run all signed integer benchmarks on an AWS instance and return parsed results to Slab CI bot.
name: Signed Integer full benchmarks
on:
workflow_dispatch:
inputs:
instance_id:
description: "Instance ID"
type: string
instance_image_id:
description: "Instance AMI ID"
type: string
instance_type:
description: "Instance product type"
type: string
runner_name:
description: "Action runner name"
type: string
request_id:
description: "Slab request ID"
type: string
user_inputs:
description: "Type of benchmarks to run"
type: string
default: "weekly_benchmarks"
env:
CARGO_TERM_COLOR: always
RESULTS_FILENAME: parsed_benchmark_results_${{ github.sha }}.json
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
jobs:
integer-benchmarks:
name: Execute signed integer benchmarks for all operations flavor
runs-on: ${{ github.event.inputs.runner_name }}
if: ${{ !cancelled() }}
continue-on-error: true
strategy:
max-parallel: 1
matrix:
command: [ integer, integer_multi_bit ]
op_flavor: [ default, default_comp, default_scalar, default_scalar_comp,
unchecked, unchecked_comp, unchecked_scalar, unchecked_scalar_comp ]
steps:
- name: Instance configuration used
run: |
echo "IDs: ${{ inputs.instance_id }}"
echo "AMI: ${{ inputs.instance_image_id }}"
echo "Type: ${{ inputs.instance_type }}"
echo "Request ID: ${{ inputs.request_id }}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
- name: Get benchmark details
run: |
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
echo "COMMIT_DATE=$(git --no-pager show -s --format=%cd --date=iso8601-strict ${{ github.sha }})" >> "${GITHUB_ENV}"
echo "COMMIT_HASH=$(git describe --tags --dirty)" >> "${GITHUB_ENV}"
- name: Set up home
# "Install rust" step require root user to have a HOME directory which is not set.
run: |
echo "HOME=/home/ubuntu" >> "${GITHUB_ENV}"
- name: Install rust
uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af
with:
toolchain: nightly
override: true
- name: Checkout Slab repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab
token: ${{ secrets.CONCRETE_ACTIONS_TOKEN }}
- name: Run benchmarks with AVX512
run: |
make AVX512_SUPPORT=ON BENCH_OP_FLAVOR=${{ matrix.op_flavor }} bench_signed_${{ matrix.command }}
- name: Parse results
run: |
python3 ./ci/benchmark_parser.py target/criterion ${{ env.RESULTS_FILENAME }} \
--database tfhe_rs \
--hardware ${{ inputs.instance_type }} \
--project-version "${{ env.COMMIT_HASH }}" \
--branch ${{ github.ref_name }} \
--commit-date "${{ env.COMMIT_DATE }}" \
--bench-date "${{ env.BENCH_DATE }}" \
--walk-subdirs \
--name-suffix avx512 \
--throughput
- name: Upload parsed results artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
with:
name: ${{ github.sha }}_${{ matrix.command }}_${{ matrix.op_flavor }}
path: ${{ env.RESULTS_FILENAME }}
- name: Send data to Slab
shell: bash
run: |
echo "Computing HMac on results file"
SIGNATURE="$(slab/scripts/hmac_calculator.sh ${{ env.RESULTS_FILENAME }} '${{ secrets.JOB_SECRET }}')"
echo "Sending results to Slab..."
curl -v -k \
-H "Content-Type: application/json" \
-H "X-Slab-Repository: ${{ github.repository }}" \
-H "X-Slab-Command: store_data_v2" \
-H "X-Hub-Signature-256: sha256=${SIGNATURE}" \
-d @${{ env.RESULTS_FILENAME }} \
${{ secrets.SLAB_URL }}
slack-notification:
name: Slack Notification
runs-on: ${{ github.event.inputs.runner_name }}
if: ${{ failure() }}
needs: integer-benchmarks
steps:
- name: Notify
continue-on-error: true
uses: rtCamp/action-slack-notify@b24d75fe0e728a4bf9fc42ee217caa686d141ee8
env:
SLACK_COLOR: ${{ job.status }}
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
SLACK_MESSAGE: "Signed integer full benchmarks failed. (${{ env.ACTION_RUN_URL }})"
SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

View File

@@ -0,0 +1,129 @@
# Run signed integer benchmarks with multi-bit cryptographic parameters on an AWS instance and return parsed results to Slab CI bot.
name: Signed Integer Multi-bit benchmarks
on:
workflow_dispatch:
inputs:
instance_id:
description: "Instance ID"
type: string
instance_image_id:
description: "Instance AMI ID"
type: string
instance_type:
description: "Instance product type"
type: string
runner_name:
description: "Action runner name"
type: string
request_id:
description: "Slab request ID"
type: string
env:
CARGO_TERM_COLOR: always
RESULTS_FILENAME: parsed_benchmark_results_${{ github.sha }}.json
PARSE_INTEGER_BENCH_CSV_FILE: tfhe_rs_integer_benches_${{ github.sha }}.csv
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
jobs:
run-integer-benchmarks:
name: Execute signed integer multi-bit benchmarks in EC2
runs-on: ${{ github.event.inputs.runner_name }}
if: ${{ !cancelled() }}
steps:
- name: Instance configuration used
run: |
echo "IDs: ${{ inputs.instance_id }}"
echo "AMI: ${{ inputs.instance_image_id }}"
echo "Type: ${{ inputs.instance_type }}"
echo "Request ID: ${{ inputs.request_id }}"
- name: Get benchmark date
run: |
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
- name: Set up home
# "Install rust" step require root user to have a HOME directory which is not set.
run: |
echo "HOME=/home/ubuntu" >> "${GITHUB_ENV}"
- name: Install rust
uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af
with:
toolchain: nightly
override: true
- name: Run multi-bit benchmarks with AVX512
run: |
make AVX512_SUPPORT=ON FAST_BENCH=TRUE bench_signed_integer_multi_bit
- name: Parse benchmarks to csv
run: |
make PARSE_INTEGER_BENCH_CSV_FILE=${{ env.PARSE_INTEGER_BENCH_CSV_FILE }} \
parse_integer_benches
- name: Upload csv results artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
with:
name: ${{ github.sha }}_csv_integer
path: ${{ env.PARSE_INTEGER_BENCH_CSV_FILE }}
- name: Parse results
run: |
COMMIT_DATE="$(git --no-pager show -s --format=%cd --date=iso8601-strict ${{ github.sha }})"
COMMIT_HASH="$(git describe --tags --dirty)"
python3 ./ci/benchmark_parser.py target/criterion ${{ env.RESULTS_FILENAME }} \
--database tfhe_rs \
--hardware ${{ inputs.instance_type }} \
--project-version "${COMMIT_HASH}" \
--branch ${{ github.ref_name }} \
--commit-date "${COMMIT_DATE}" \
--bench-date "${{ env.BENCH_DATE }}" \
--walk-subdirs \
--name-suffix avx512 \
--throughput
- name: Upload parsed results artifact
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
with:
name: ${{ github.sha }}_integer
path: ${{ env.RESULTS_FILENAME }}
- name: Checkout Slab repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab
token: ${{ secrets.CONCRETE_ACTIONS_TOKEN }}
- name: Send data to Slab
shell: bash
run: |
echo "Computing HMac on results file"
SIGNATURE="$(slab/scripts/hmac_calculator.sh ${{ env.RESULTS_FILENAME }} '${{ secrets.JOB_SECRET }}')"
echo "Sending results to Slab..."
curl -v -k \
-H "Content-Type: application/json" \
-H "X-Slab-Repository: ${{ github.repository }}" \
-H "X-Slab-Command: store_data_v2" \
-H "X-Hub-Signature-256: sha256=${SIGNATURE}" \
-d @${{ env.RESULTS_FILENAME }} \
${{ secrets.SLAB_URL }}
- name: Slack Notification
if: ${{ failure() }}
continue-on-error: true
uses: rtCamp/action-slack-notify@b24d75fe0e728a4bf9fc42ee217caa686d141ee8
env:
SLACK_COLOR: ${{ job.status }}
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
SLACK_MESSAGE: "Signed integer benchmarks failed. (${{ env.ACTION_RUN_URL }})"
SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

View File

@@ -20,10 +20,18 @@ on:
description: "Run integer benches"
type: boolean
default: true
signed_integer_bench:
description: "Run signed integer benches"
type: boolean
default: true
integer_multi_bit_bench:
description: "Run integer multi bit benches"
type: boolean
default: true
signed_integer_multi_bit_bench:
description: "Run signed integer multi bit benches"
type: boolean
default: true
pbs_bench:
description: "Run PBS benches"
type: boolean
@@ -38,17 +46,20 @@ jobs:
if: ${{ (github.event_name == 'push' && github.repository == 'zama-ai/tfhe-rs') || github.event_name == 'workflow_dispatch' }}
strategy:
matrix:
command: [boolean_bench, shortint_bench, integer_bench, integer_multi_bit_bench, pbs_bench, wasm_client_bench]
command: [ boolean_bench, shortint_bench,
integer_bench, integer_multi_bit_bench,
signed_integer_bench, signed_integer_multi_bit_bench,
pbs_bench, wasm_client_bench ]
runs-on: ubuntu-latest
steps:
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
- name: Check for file changes
id: changed-files
uses: tj-actions/changed-files@6ee9cdc5816333acda68e01cf12eedc619e28316
uses: tj-actions/changed-files@25ef3926d147cd02fc7e931c1ef50772bbb0d25d
with:
files_yaml: |
common_benches:
@@ -69,13 +80,23 @@ jobs:
integer_bench:
- tfhe/src/shortint/**
- tfhe/src/integer/**
- tfhe/benches/integer/**
- tfhe/benches/integer/bench.rs
- .github/workflows/integer_benchmark.yml
integer_multi_bit_bench:
- tfhe/src/shortint/**
- tfhe/src/integer/**
- tfhe/benches/integer/**
- .github/workflows/integer_benchmark.yml
- tfhe/benches/integer/bench.rs
- .github/workflows/integer_multi_bit_benchmark.yml
signed_integer_bench:
- tfhe/src/shortint/**
- tfhe/src/integer/**
- tfhe/benches/integer/signed_bench.rs
- .github/workflows/signed_integer_benchmark.yml
signed_integer_multi_bit_bench:
- tfhe/src/shortint/**
- tfhe/src/integer/**
- tfhe/benches/integer/signed_bench.rs
- .github/workflows/signed_integer_multi_bit_benchmark.yml
pbs_bench:
- tfhe/src/core_crypto/**
- tfhe/benches/core_crypto/**
@@ -85,7 +106,7 @@ jobs:
- .github/workflows/wasm_client_benchmark.yml
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab

View File

@@ -3,34 +3,57 @@ name: Start full suite benchmarks
on:
schedule:
# Job will be triggered each Saturday at 1a.m.
# Weekly benchmarks will be triggered each Saturday at 1a.m.
- cron: '0 1 * * 6'
# Quarterly benchmarks will be triggered right before end of quarter, the 25th of the current month at 4a.m.
# These benchmarks are far longer to execute hence the reason to run them only four time a year.
- cron: '0 4 25 MAR,JUN,SEP,DEC *'
workflow_dispatch:
inputs:
benchmark_type:
description: 'Benchmark type'
required: true
default: 'weekly'
type: choice
options:
- weekly
- quarterly
jobs:
start-benchmarks:
if: ${{ (github.event_name == 'schedule' && github.repository == 'zama-ai/tfhe-rs') || github.event_name == 'workflow_dispatch' }}
strategy:
matrix:
command: [ boolean_bench, shortint_full_bench, integer_full_bench, pbs_bench, wasm_client_bench ]
command: [ boolean_bench, shortint_full_bench, integer_full_bench,
signed_integer_full_bench, pbs_bench, wasm_client_bench ]
runs-on: ubuntu-latest
steps:
- name: Checkout tfhe-rs
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab
token: ${{ secrets.CONCRETE_ACTIONS_TOKEN }}
- name: Set benchmarks type as weekly
if: (github.event_name == 'workflow_dispatch' && inputs.benchmark_type == 'weekly') || github.event.schedule == '0 1 * * 6'
run: |
echo "BENCH_TYPE=weekly_benchmarks" >> "${GITHUB_ENV}"
- name: Set benchmarks type as quarterly
if: (github.event_name == 'workflow_dispatch' && inputs.benchmark_type == 'quarterly') || github.event.schedule == '0 4 25 MAR,JUN,SEP,DEC *'
run: |
echo "BENCH_TYPE=quarterly_benchmarks" >> "${GITHUB_ENV}"
- name: Start AWS job in Slab
shell: bash
run: |
echo -n '{"command": "${{ matrix.command }}", "git_ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}' > command.json
echo -n '{"command": "${{ matrix.command }}", "git_ref": "${{ github.ref }}", "sha": "${{ github.sha }}", "user_inputs": "${{ env.BENCH_TYPE }}"}' > command.json
SIGNATURE="$(slab/scripts/hmac_calculator.sh command.json '${{ secrets.JOB_SECRET }}')"
curl -v -k \
--fail-with-body \

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
- name: Save repo

View File

@@ -19,6 +19,14 @@ on:
request_id:
description: "Slab request ID"
type: string
# This input is not used in this workflow but still mandatory since a calling workflow could
# use it. If a triggering command include a user_inputs field, then the triggered workflow
# must include this very input, otherwise the workflow won't be called.
# See start_full_benchmarks.yml as example.
user_inputs:
description: "Type of benchmarks to run"
type: string
default: "weekly_benchmarks"
env:
CARGO_TERM_COLOR: always
@@ -43,7 +51,7 @@ jobs:
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
- name: Checkout tfhe-rs repo with tags
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0
@@ -95,7 +103,7 @@ jobs:
path: ${{ env.RESULTS_FILENAME }}
- name: Checkout Slab repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
repository: zama-ai/slab
path: slab

4
.gitignore vendored
View File

@@ -3,9 +3,9 @@ target/
.vscode/
# Path we use for internal-keycache during tests
./keys/
keys/
# In case of symlinked keys
./keys
keys
**/Cargo.lock
**/*.bin

14
.linelint.yml Normal file
View File

@@ -0,0 +1,14 @@
ignore:
- .git
- target
- tfhe/benchmarks_parameters
- tfhe/web_wasm_parallel_tests/node_modules
- tfhe/web_wasm_parallel_tests/dist
- keys
- coverage
rules:
# checks if file ends in a newline character
end-of-file:
enable: true
single-new-line: true

218
Makefile
View File

@@ -6,7 +6,7 @@ TARGET_ARCH_FEATURE:=$(shell ./scripts/get_arch_feature.sh)
RS_BUILD_TOOLCHAIN:=stable
CARGO_RS_BUILD_TOOLCHAIN:=+$(RS_BUILD_TOOLCHAIN)
CARGO_PROFILE?=release
MIN_RUST_VERSION:=$(shell grep rust-version tfhe/Cargo.toml | cut -d '=' -f 2 | xargs)
MIN_RUST_VERSION:=$(shell grep '^rust-version[[:space:]]*=' tfhe/Cargo.toml | cut -d '=' -f 2 | xargs)
AVX512_SUPPORT?=OFF
WASM_RUSTFLAGS:=
BIG_TESTS_INSTANCE?=FALSE
@@ -16,7 +16,17 @@ PARSE_INTEGER_BENCH_CSV_FILE?=tfhe_rs_integer_benches.csv
FAST_TESTS?=FALSE
FAST_BENCH?=FALSE
BENCH_OP_FLAVOR?=DEFAULT
COVERAGE_EXCLUDED_FILES = tfhe/benches/*,apps/trivium/src/*,tfhe/examples/*,tasks/src/*
NODE_VERSION=20
# sed: -n, do not print input stream, -e means a script/expression
# 1,/version/ indicates from the first line, to the line matching version at the start of the line
# p indicates to print, so we keep only the start of the Cargo.toml until we hit the first version
# entry which should be the version of tfhe
TFHE_CURRENT_VERSION:=\
$(shell sed -n -e '1,/^version/p' tfhe/Cargo.toml | \
grep '^version[[:space:]]*=' | cut -d '=' -f 2 | xargs)
# Cargo has a hard time distinguishing between our package from the workspace and a package that
# could be a dependency, so we build an unambiguous spec here
TFHE_SPEC:=tfhe@$(TFHE_CURRENT_VERSION)
# This is done to avoid forgetting it, we still precise the RUSTFLAGS in the commands to be able to
# copy paste the command in the terminal and change them if required without forgetting the flags
export RUSTFLAGS?=-C target-cpu=native
@@ -43,6 +53,22 @@ endif
REGEX_STRING?=''
REGEX_PATTERN?=''
# Exclude these files from coverage reports
define COVERAGE_EXCLUDED_FILES
--exclude-files apps/trivium/src/trivium/* \
--exclude-files apps/trivium/src/kreyvium/* \
--exclude-files apps/trivium/src/static_deque/* \
--exclude-files apps/trivium/src/trans_ciphering/* \
--exclude-files tasks/src/* \
--exclude-files tfhe/benches/boolean/* \
--exclude-files tfhe/benches/core_crypto/* \
--exclude-files tfhe/benches/shortint/* \
--exclude-files tfhe/benches/integer/* \
--exclude-files tfhe/benches/* \
--exclude-files tfhe/examples/regex_engine/* \
--exclude-files tfhe/examples/utilities/*
endef
.PHONY: rs_check_toolchain # Echo the rust toolchain used for checks
rs_check_toolchain:
@echo $(RS_CHECK_TOOLCHAIN)
@@ -84,7 +110,7 @@ install_wasm_pack: install_rs_build_toolchain
install_node:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | $(SHELL)
source ~/.bashrc
$(SHELL) -i -c 'nvm install node' || \
$(SHELL) -i -c 'nvm install $(NODE_VERSION)' || \
( echo "Unable to install node, unknown error." && exit 1 )
.PHONY: install_dieharder # Install dieharder for apt distributions or macOS
@@ -102,58 +128,71 @@ install_tarpaulin: install_rs_build_toolchain
cargo $(CARGO_RS_BUILD_TOOLCHAIN) install cargo-tarpaulin --locked || \
( echo "Unable to install cargo tarpaulin, unknown error." && exit 1 )
.PHONY: check_linelint_installed # Check if linelint newline linter is installed
check_linelint_installed:
@printf "\n" | linelint - > /dev/null 2>&1 || \
( echo "Unable to locate linelint. Try installing it: https://github.com/fernandrone/linelint/releases" && exit 1 )
.PHONY: fmt # Format rust code
fmt: install_rs_check_toolchain
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt
.PHONT: check_fmt # Check rust code format
.PHONY: check_fmt # Check rust code format
check_fmt: install_rs_check_toolchain
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt --check
.PHONY: fix_newline # Fix newline at end of file issues to be UNIX compliant
fix_newline: check_linelint_installed
linelint -a .
.PHONY: check_newline # Check for newline at end of file to be UNIX compliant
check_newline: check_linelint_installed
linelint .
.PHONY: clippy_core # Run clippy lints on core_crypto with and without experimental features
clippy_core: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
--features=$(TARGET_ARCH_FEATURE) \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
--features=$(TARGET_ARCH_FEATURE),experimental \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_boolean # Run clippy lints enabling the boolean features
clippy_boolean: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
--features=$(TARGET_ARCH_FEATURE),boolean \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_shortint # Run clippy lints enabling the shortint features
clippy_shortint: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
--features=$(TARGET_ARCH_FEATURE),shortint \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_integer # Run clippy lints enabling the integer features
clippy_integer: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
--features=$(TARGET_ARCH_FEATURE),integer \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy # Run clippy lints enabling the boolean, shortint, integer
clippy: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_c_api # Run clippy lints enabling the boolean, shortint and the C API
clippy_c_api: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_js_wasm_api # Run clippy lints enabling the boolean, shortint, integer and the js wasm API
clippy_js_wasm_api: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
--features=boolean-client-js-wasm-api,shortint-client-js-wasm-api,integer-client-js-wasm-api \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_tasks # Run clippy lints on helper tasks crate.
clippy_tasks:
@@ -164,13 +203,13 @@ clippy_tasks:
clippy_trivium: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy -p tfhe-trivium \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_all_targets # Run clippy lints on all targets (benches, examples, etc.)
clippy_all_targets:
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache \
-p tfhe -- --no-deps -D warnings
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,safe-deserialization \
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_concrete_csprng # Run clippy lints on concrete-csprng
clippy_concrete_csprng:
@@ -190,58 +229,58 @@ clippy_concrete_csprng
gen_key_cache: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) run --profile $(CARGO_PROFILE) \
--example generates_test_keys \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache -p tfhe -- \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache -- \
$(MULTI_BIT_ONLY) $(COVERAGE_ONLY)
.PHONY: build_core # Build core_crypto without experimental features
build_core: install_rs_build_toolchain install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE) -p tfhe
--features=$(TARGET_ARCH_FEATURE) -p $(TFHE_SPEC)
@if [[ "$(AVX512_SUPPORT)" == "ON" ]]; then \
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),$(AVX512_FEATURE) -p tfhe; \
--features=$(TARGET_ARCH_FEATURE),$(AVX512_FEATURE) -p $(TFHE_SPEC); \
fi
.PHONY: build_core_experimental # Build core_crypto with experimental features
build_core_experimental: install_rs_build_toolchain install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),experimental -p tfhe
--features=$(TARGET_ARCH_FEATURE),experimental -p $(TFHE_SPEC)
@if [[ "$(AVX512_SUPPORT)" == "ON" ]]; then \
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),experimental,$(AVX512_FEATURE) -p tfhe; \
--features=$(TARGET_ARCH_FEATURE),experimental,$(AVX512_FEATURE) -p $(TFHE_SPEC); \
fi
.PHONY: build_boolean # Build with boolean enabled
build_boolean: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),boolean -p tfhe --all-targets
--features=$(TARGET_ARCH_FEATURE),boolean -p $(TFHE_SPEC) --all-targets
.PHONY: build_shortint # Build with shortint enabled
build_shortint: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),shortint -p tfhe --all-targets
--features=$(TARGET_ARCH_FEATURE),shortint -p $(TFHE_SPEC) --all-targets
.PHONY: build_integer # Build with integer enabled
build_integer: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),integer -p tfhe --all-targets
--features=$(TARGET_ARCH_FEATURE),integer -p $(TFHE_SPEC) --all-targets
.PHONY: build_tfhe_full # Build with boolean, shortint and integer enabled
build_tfhe_full: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer -p tfhe --all-targets
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer -p $(TFHE_SPEC) --all-targets
.PHONY: build_c_api # Build the C API for boolean, shortint and integer
build_c_api: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api, \
-p tfhe
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api,safe-deserialization \
-p $(TFHE_SPEC)
.PHONY: build_c_api_experimental_deterministic_fft # Build the C API for boolean, shortint and integer with experimental deterministic FFT
build_c_api_experimental_deterministic_fft: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api,experimental-force_fft_algo_dif4 \
-p tfhe
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api,safe-deserialization,experimental-force_fft_algo_dif4 \
-p $(TFHE_SPEC)
.PHONY: build_web_js_api # Build the js API targeting the web browser
build_web_js_api: install_rs_build_toolchain install_wasm_pack
@@ -274,30 +313,30 @@ build_concrete_csprng: install_rs_build_toolchain
.PHONY: test_core_crypto # Run the tests of the core_crypto module including experimental ones
test_core_crypto: install_rs_build_toolchain install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),experimental -p tfhe -- core_crypto::
--features=$(TARGET_ARCH_FEATURE),experimental -p $(TFHE_SPEC) -- core_crypto::
@if [[ "$(AVX512_SUPPORT)" == "ON" ]]; then \
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),experimental,$(AVX512_FEATURE) -p tfhe -- core_crypto::; \
--features=$(TARGET_ARCH_FEATURE),experimental,$(AVX512_FEATURE) -p $(TFHE_SPEC) -- core_crypto::; \
fi
.PHONY: test_boolean # Run the tests of the boolean module
test_boolean: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),boolean -p tfhe -- boolean::
--features=$(TARGET_ARCH_FEATURE),boolean -p $(TFHE_SPEC) -- boolean::
.PHONY: test_boolean_cov # Run the tests of the boolean module with code coverage
test_boolean_cov: install_rs_check_toolchain install_tarpaulin
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) tarpaulin --profile $(CARGO_PROFILE) \
--out Xml --output-dir coverage/boolean --line --engine Llvm --timeout 500 \
--exclude-files $(COVERAGE_EXCLUDED_FILES) \
--out xml --output-dir coverage/boolean --line --engine llvm --timeout 500 \
$(COVERAGE_EXCLUDED_FILES) \
--features=$(TARGET_ARCH_FEATURE),boolean,internal-keycache,__coverage \
-p tfhe -- boolean::
-p $(TFHE_SPEC) -- boolean::
.PHONY: test_c_api_rs # Run the rust tests for the C API
test_c_api_rs: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api \
-p tfhe \
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api,safe-deserialization \
-p $(TFHE_SPEC) \
c_api
.PHONY: test_c_api_c # Run the C tests for the C API
@@ -324,45 +363,82 @@ test_shortint_multi_bit_ci: install_rs_build_toolchain install_cargo_nextest
.PHONY: test_shortint # Run all the tests for shortint
test_shortint: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache -p tfhe -- shortint::
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache -p $(TFHE_SPEC) -- shortint::
.PHONY: test_shortint_cov # Run the tests of the shortint module with code coverage
test_shortint_cov: install_rs_check_toolchain install_tarpaulin
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) tarpaulin --profile $(CARGO_PROFILE) \
--out Xml --output-dir coverage/shortint --line --engine Llvm --timeout 500 \
--exclude-files $(COVERAGE_EXCLUDED_FILES) \
--out xml --output-dir coverage/shortint --line --engine llvm --timeout 500 \
$(COVERAGE_EXCLUDED_FILES) \
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache,__coverage \
-p tfhe -- shortint::
-p $(TFHE_SPEC) -- shortint::
.PHONY: test_integer_ci # Run the tests for integer ci
test_integer_ci: install_rs_build_toolchain install_cargo_nextest
test_integer_ci: install_rs_check_toolchain install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_BUILD_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)"
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_CHECK_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)" --avx512-support "$(AVX512_SUPPORT)"
.PHONY: test_unsigned_integer_ci # Run the tests for unsigned integer ci
test_unsigned_integer_ci: install_rs_check_toolchain install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_CHECK_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)" --avx512-support "$(AVX512_SUPPORT)" \
--unsigned-only
.PHONY: test_signed_integer_ci # Run the tests for signed integer ci
test_signed_integer_ci: install_rs_check_toolchain install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_CHECK_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)" --avx512-support "$(AVX512_SUPPORT)" \
--signed-only
.PHONY: test_integer_multi_bit_ci # Run the tests for integer ci running only multibit tests
test_integer_multi_bit_ci: install_rs_build_toolchain install_cargo_nextest
test_integer_multi_bit_ci: install_rs_check_toolchain install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_BUILD_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)" --multi-bit
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_CHECK_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)" --multi-bit --avx512-support "$(AVX512_SUPPORT)"
.PHONY: test_unsigned_integer_multi_bit_ci # Run the tests for nsigned integer ci running only multibit tests
test_unsigned_integer_multi_bit_ci: install_rs_check_toolchain install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_CHECK_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)" --multi-bit --avx512-support "$(AVX512_SUPPORT)" \
--unsigned-only
.PHONY: test_signed_integer_multi_bit_ci # Run the tests for nsigned integer ci running only multibit tests
test_signed_integer_multi_bit_ci: install_rs_check_toolchain install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_CHECK_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)" --multi-bit --avx512-support "$(AVX512_SUPPORT)" \
--signed-only
.PHONY: test_safe_deserialization # Run the tests for safe deserialization
test_safe_deserialization: install_rs_build_toolchain install_cargo_nextest
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,safe-deserialization -p $(TFHE_SPEC) -- safe_deserialization::
.PHONY: test_integer # Run all the tests for integer
test_integer: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache -p tfhe -- integer::
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache -p $(TFHE_SPEC) -- integer::
.PHONY: test_high_level_api # Run all the tests for high_level_api
test_high_level_api: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache -p tfhe \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache -p $(TFHE_SPEC) \
-- high_level_api::
.PHONY: test_user_doc # Run tests from the .md documentation
test_user_doc: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) --doc \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache -p tfhe \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache -p $(TFHE_SPEC) \
-- test_user_docs::
.PHONY: test_regex_engine # Run tests for regex_engine example
@@ -425,18 +501,18 @@ format_doc_latex:
.PHONY: check_compile_tests # Build tests in debug without running them
check_compile_tests:
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --no-run \
--features=$(TARGET_ARCH_FEATURE),experimental,boolean,shortint,integer,internal-keycache \
-p tfhe
--features=$(TARGET_ARCH_FEATURE),experimental,boolean,shortint,integer,internal-keycache,safe-deserialization \
-p $(TFHE_SPEC)
@if [[ "$(OS)" == "Linux" || "$(OS)" == "Darwin" ]]; then \
"$(MAKE)" build_c_api; \
"$(MAKE)" build_c_api && \
./scripts/c_api_tests.sh --build-only; \
fi
.PHONY: build_nodejs_test_docker # Build a docker image with tools to run nodejs tests for wasm API
build_nodejs_test_docker:
DOCKER_BUILDKIT=1 docker build --build-arg RUST_TOOLCHAIN="$(RS_BUILD_TOOLCHAIN)" \
-f docker/Dockerfile.wasm_tests -t tfhe-wasm-tests .
-f docker/Dockerfile.wasm_tests --build-arg NODE_VERSION=$(NODE_VERSION) -t tfhe-wasm-tests .
.PHONY: test_nodejs_wasm_api_in_docker # Run tests for the nodejs on wasm API in a docker container
test_nodejs_wasm_api_in_docker: build_nodejs_test_docker
@@ -460,7 +536,8 @@ test_web_js_api_parallel: build_web_js_api_parallel
.PHONY: ci_test_web_js_api_parallel # Run tests for the web wasm api
ci_test_web_js_api_parallel: build_web_js_api_parallel
source ~/.nvm/nvm.sh && \
nvm use node && \
nvm install $(NODE_VERSION) && \
nvm use $(NODE_VERSION) && \
$(MAKE) -C tfhe/web_wasm_parallel_tests test-ci
.PHONY: no_tfhe_typo # Check we did not invert the h and f in tfhe
@@ -479,27 +556,42 @@ dieharder_csprng: install_dieharder build_concrete_csprng
# Benchmarks
#
.PHONY: bench_integer # Run benchmarks for integer
.PHONY: bench_integer # Run benchmarks for unsigned integer
bench_integer: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_OP_FLAVOR=$(BENCH_OP_FLAVOR) __TFHE_RS_FAST_BENCH=$(FAST_BENCH) \
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench integer-bench \
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache,$(AVX512_FEATURE) -p tfhe --
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC) --
.PHONY: bench_integer_multi_bit # Run benchmarks for integer using multi-bit parameters
.PHONY: bench_integer_multi_bit # Run benchmarks for unsigned integer using multi-bit parameters
bench_integer_multi_bit: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_TYPE=MULTI_BIT \
__TFHE_RS_BENCH_OP_FLAVOR=$(BENCH_OP_FLAVOR) __TFHE_RS_FAST_BENCH=$(FAST_BENCH) \
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench integer-bench \
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache,$(AVX512_FEATURE) -p tfhe --
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC) --
.PHONY: bench_signed_integer # Run benchmarks for signed integer
bench_signed_integer: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_OP_FLAVOR=$(BENCH_OP_FLAVOR) __TFHE_RS_FAST_BENCH=$(FAST_BENCH) \
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench integer-signed-bench \
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC) --
.PHONY: bench_signed_integer_multi_bit # Run benchmarks for signed integer using multi-bit parameters
bench_signed_integer_multi_bit: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_TYPE=MULTI_BIT \
__TFHE_RS_BENCH_OP_FLAVOR=$(BENCH_OP_FLAVOR) __TFHE_RS_FAST_BENCH=$(FAST_BENCH) \
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench integer-signed-bench \
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC) --
.PHONY: bench_shortint # Run benchmarks for shortint
bench_shortint: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_OP_FLAVOR=$(BENCH_OP_FLAVOR) \
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench shortint-bench \
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache,$(AVX512_FEATURE) -p tfhe
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC)
.PHONY: bench_shortint_multi_bit # Run benchmarks for shortint using multi-bit parameters
bench_shortint_multi_bit: install_rs_check_toolchain
@@ -507,20 +599,20 @@ bench_shortint_multi_bit: install_rs_check_toolchain
__TFHE_RS_BENCH_OP_FLAVOR=$(BENCH_OP_FLAVOR) \
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench shortint-bench \
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache,$(AVX512_FEATURE) -p tfhe --
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC) --
.PHONY: bench_boolean # Run benchmarks for boolean
bench_boolean: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench boolean-bench \
--features=$(TARGET_ARCH_FEATURE),boolean,internal-keycache,$(AVX512_FEATURE) -p tfhe
--features=$(TARGET_ARCH_FEATURE),boolean,internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC)
.PHONY: bench_pbs # Run benchmarks for PBS
bench_pbs: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench pbs-bench \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,$(AVX512_FEATURE) -p tfhe
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC)
.PHONY: bench_web_js_api_parallel # Run benchmarks for the web wasm api
bench_web_js_api_parallel: build_web_js_api_parallel
@@ -604,7 +696,7 @@ pcc: no_tfhe_typo no_dbg_log check_fmt lint_doc clippy_all check_compile_tests
fpcc: no_tfhe_typo no_dbg_log check_fmt lint_doc clippy_fast check_compile_tests
.PHONY: conformance # Automatically fix problems that can be fixed
conformance: fmt
conformance: fix_newline fmt
.PHONY: help # Generate list of targets with descriptions
help:

View File

@@ -70,9 +70,7 @@ use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint32, FheUint8};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Basic configuration to use homomorphic integers
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
// Key generation
let (client_key, server_keys) = generate_keys(config);

View File

@@ -17,7 +17,7 @@ path = "../../tfhe"
features = [ "boolean", "shortint", "integer", "aarch64-unix" ]
[dev-dependencies]
criterion = { version = "0.4", features = [ "html_reports" ]}
criterion = { version = "0.5.1", features = [ "html_reports" ]}
[[bench]]
name = "trivium"

View File

@@ -120,7 +120,7 @@ fn main() {
# FHE byte Trivium implementation
The same objects have also been implemented to stream bytes insead of booleans. They can be constructed and used in the same way via the functions `TriviumStreamByte::<u8>::new` and
The same objects have also been implemented to stream bytes instead of booleans. They can be constructed and used in the same way via the functions `TriviumStreamByte::<u8>::new` and
`TriviumStreamByte::<FheUint8>::new` with the same arguments as before. The `FheUint8` version is significantly slower than the `FheBool` version, because not running
with the same cryptographic parameters. Its interest lie in its trans-ciphering capabilities: `TriviumStreamByte<FheUint8>` implements the trait `TransCiphering`,
meaning it implements the functions `trans_encrypt_64`. This function takes as input a `FheUint64` and outputs a `FheUint64`, the output being

View File

@@ -6,7 +6,7 @@ use tfhe_trivium::KreyviumStream;
use criterion::Criterion;
pub fn kreyvium_bool_gen(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
@@ -41,7 +41,7 @@ pub fn kreyvium_bool_gen(c: &mut Criterion) {
}
pub fn kreyvium_bool_warmup(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();

View File

@@ -6,9 +6,8 @@ use tfhe_trivium::{KreyviumStreamByte, TransCiphering};
use criterion::Criterion;
pub fn kreyvium_byte_gen(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.enable_function_evaluation_integers()
let config = ConfigBuilder::default()
.enable_function_evaluation()
.build();
let (client_key, server_key) = generate_keys(config);
@@ -36,9 +35,8 @@ pub fn kreyvium_byte_gen(c: &mut Criterion) {
}
pub fn kreyvium_byte_trans(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.enable_function_evaluation_integers()
let config = ConfigBuilder::default()
.enable_function_evaluation()
.build();
let (client_key, server_key) = generate_keys(config);
@@ -67,9 +65,8 @@ pub fn kreyvium_byte_trans(c: &mut Criterion) {
}
pub fn kreyvium_byte_warmup(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.enable_function_evaluation_integers()
let config = ConfigBuilder::default()
.enable_function_evaluation()
.build();
let (client_key, server_key) = generate_keys(config);

View File

@@ -8,9 +8,7 @@ use tfhe_trivium::{KreyviumStreamShortint, TransCiphering};
use criterion::Criterion;
pub fn kreyvium_shortint_warmup(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (hl_client_key, hl_server_key) = generate_keys(config);
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();
@@ -60,9 +58,7 @@ pub fn kreyvium_shortint_warmup(c: &mut Criterion) {
}
pub fn kreyvium_shortint_gen(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (hl_client_key, hl_server_key) = generate_keys(config);
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();
@@ -107,9 +103,7 @@ pub fn kreyvium_shortint_gen(c: &mut Criterion) {
}
pub fn kreyvium_shortint_trans(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (hl_client_key, hl_server_key) = generate_keys(config);
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();

View File

@@ -6,7 +6,7 @@ use tfhe_trivium::TriviumStream;
use criterion::Criterion;
pub fn trivium_bool_gen(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB".to_string();
@@ -41,7 +41,7 @@ pub fn trivium_bool_gen(c: &mut Criterion) {
}
pub fn trivium_bool_warmup(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB".to_string();

View File

@@ -6,9 +6,7 @@ use tfhe_trivium::{TransCiphering, TriviumStreamByte};
use criterion::Criterion;
pub fn trivium_byte_gen(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB".to_string();
@@ -35,9 +33,7 @@ pub fn trivium_byte_gen(c: &mut Criterion) {
}
pub fn trivium_byte_trans(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB".to_string();
@@ -65,9 +61,7 @@ pub fn trivium_byte_trans(c: &mut Criterion) {
}
pub fn trivium_byte_warmup(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB".to_string();

View File

@@ -8,9 +8,7 @@ use tfhe_trivium::{TransCiphering, TriviumStreamShortint};
use criterion::Criterion;
pub fn trivium_shortint_warmup(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (hl_client_key, hl_server_key) = generate_keys(config);
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();
@@ -60,9 +58,7 @@ pub fn trivium_shortint_warmup(c: &mut Criterion) {
}
pub fn trivium_shortint_gen(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (hl_client_key, hl_server_key) = generate_keys(config);
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();
@@ -107,9 +103,7 @@ pub fn trivium_shortint_gen(c: &mut Criterion) {
}
pub fn trivium_shortint_trans(c: &mut Criterion) {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (hl_client_key, hl_server_key) = generate_keys(config);
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();

View File

@@ -1,5 +1,5 @@
//! This module implements the Kreyvium stream cipher, using booleans or FheBool
//! for the representaion of the inner bits.
//! for the representation of the inner bits.
use crate::static_deque::StaticDeque;
@@ -35,7 +35,7 @@ pub struct KreyviumStream<T> {
}
impl KreyviumStream<bool> {
/// Contructor for `KreyviumStream<bool>`: arguments are the secret key and the input vector.
/// Constructor for `KreyviumStream<bool>`: arguments are the secret key and the input vector.
/// Outputs a KreyviumStream object already initialized (1152 steps have been run before
/// returning)
pub fn new(mut key: [bool; 128], mut iv: [bool; 128]) -> KreyviumStream<bool> {
@@ -118,7 +118,7 @@ where
T: KreyviumBoolInput<T> + std::marker::Send + std::marker::Sync,
for<'a> &'a T: KreyviumBoolInput<T>,
{
/// Internal generic contructor: arguments are already prepared registers, and an optional FHE
/// Internal generic constructor: arguments are already prepared registers, and an optional FHE
/// server key
fn new_from_registers(
a_register: [T; 93],

View File

@@ -1,5 +1,5 @@
//! This module implements the Kreyvium stream cipher, using u8 or FheUint8
//! for the representaion of the inner bits.
//! for the representation of the inner bits.
use crate::static_deque::{StaticByteDeque, StaticByteDequeInput};
@@ -31,7 +31,7 @@ impl KreyviumByteInput<FheUint8> for &FheUint8 {}
/// representation of bits (u8 or FheUint8). To be able to compute FHE operations, it also owns
/// an Option for a ServerKey.
/// Since the original Kreyvium registers' sizes are not a multiple of 8, these registers (which
/// store byte-like objects) have a size that is the eigth of the closest multiple of 8 above the
/// store byte-like objects) have a size that is the eighth of the closest multiple of 8 above the
/// originals' sizes.
pub struct KreyviumStreamByte<T> {
a_byte: StaticByteDeque<12, T>,
@@ -43,7 +43,7 @@ pub struct KreyviumStreamByte<T> {
}
impl KreyviumStreamByte<u8> {
/// Contructor for `KreyviumStreamByte<u8>`: arguments are the secret key and the input vector.
/// Constructor for `KreyviumStreamByte<u8>`: arguments are the secret key and the input vector.
/// Outputs a KreyviumStream object already initialized (1152 steps have been run before
/// returning)
pub fn new(key_bytes: [u8; 16], iv_bytes: [u8; 16]) -> KreyviumStreamByte<u8> {
@@ -146,7 +146,7 @@ where
T: KreyviumByteInput<T> + Send,
for<'a> &'a T: KreyviumByteInput<T>,
{
/// Internal generic contructor: arguments are already prepared registers, and an optional FHE
/// Internal generic constructor: arguments are already prepared registers, and an optional FHE
/// server key
fn new_from_registers(
a_register: [T; 12],

View File

@@ -19,7 +19,7 @@ pub struct KreyviumStreamShortint {
}
impl KreyviumStreamShortint {
/// Contructor for KreyviumStreamShortint: arguments are the secret key and the input vector,
/// Constructor for KreyviumStreamShortint: arguments are the secret key and the input vector,
/// and a ServerKey reference. Outputs a KreyviumStream object already initialized (1152
/// steps have been run before returning)
pub fn new(

View File

@@ -170,7 +170,7 @@ fn kreyvium_test_4() {
#[test]
fn kreyvium_test_fhe_long() {
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
@@ -217,9 +217,7 @@ use tfhe::shortint::prelude::*;
#[test]
fn kreyvium_test_shortint_long() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (hl_client_key, hl_server_key) = generate_keys(config);
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();
@@ -302,9 +300,8 @@ fn kreyvium_test_clear_byte() {
#[test]
fn kreyvium_test_byte_long() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.enable_function_evaluation_integers()
let config = ConfigBuilder::default()
.enable_function_evaluation()
.build();
let (client_key, server_key) = generate_keys(config);
@@ -342,9 +339,8 @@ fn kreyvium_test_byte_long() {
#[test]
fn kreyvium_test_fhe_byte_transciphering_long() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.enable_function_evaluation_integers()
let config = ConfigBuilder::default()
.enable_function_evaluation()
.build();
let (client_key, server_key) = generate_keys(config);

View File

@@ -1,6 +1,6 @@
//! This module implements the StaticByteDeque struct: a deque of bytes. The idea
//! is that this is a wrapper around StaticDeque, but StaticByteDeque has an additional
//! functionnality: it can construct the "intermediate" bytes, made of parts of other bytes.
//! functionality: it can construct the "intermediate" bytes, made of parts of other bytes.
//! This is pretending to store bits, and allows accessing bits in chunks of 8 consecutive.
use crate::static_deque::StaticDeque;

View File

@@ -5,7 +5,7 @@
use core::ops::{Index, IndexMut};
/// StaticDeque: a struct implementing a deque whose size is known at compile time.
/// It has 2 members: the static array conatining the data (never empty), and a cursor
/// It has 2 members: the static array containing the data (never empty), and a cursor
/// equal to the index of the oldest element (and the next one to be overwritten).
#[derive(Clone)]
pub struct StaticDeque<const N: usize, T> {

View File

@@ -4,6 +4,7 @@
use crate::{KreyviumStreamByte, KreyviumStreamShortint, TriviumStreamByte, TriviumStreamShortint};
use tfhe::shortint::Ciphertext;
use tfhe::prelude::*;
use tfhe::{set_server_key, unset_server_key, FheUint64, FheUint8, ServerKey};
use rayon::prelude::*;

View File

@@ -232,7 +232,7 @@ fn trivium_test_clear_byte() {
#[test]
fn trivium_test_fhe_long() {
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB".to_string();
@@ -277,9 +277,7 @@ fn trivium_test_fhe_long() {
#[test]
fn trivium_test_fhe_byte_long() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB".to_string();
@@ -316,9 +314,7 @@ fn trivium_test_fhe_byte_long() {
#[test]
fn trivium_test_fhe_byte_transciphering_long() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
let key_string = "0053A6F94C9FF24598EB".to_string();
@@ -357,9 +353,7 @@ use tfhe::shortint::prelude::*;
#[test]
fn trivium_test_shortint_long() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (hl_client_key, hl_server_key) = generate_keys(config);
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();

View File

@@ -1,5 +1,5 @@
//! This module implements the Trivium stream cipher, using booleans or FheBool
//! for the representaion of the inner bits.
//! for the representation of the inner bits.
use crate::static_deque::StaticDeque;
@@ -33,7 +33,7 @@ pub struct TriviumStream<T> {
}
impl TriviumStream<bool> {
/// Contructor for `TriviumStream<bool>`: arguments are the secret key and the input vector.
/// Constructor for `TriviumStream<bool>`: arguments are the secret key and the input vector.
/// Outputs a TriviumStream object already initialized (1152 steps have been run before
/// returning)
pub fn new(key: [bool; 80], iv: [bool; 80]) -> TriviumStream<bool> {
@@ -94,7 +94,7 @@ where
T: TriviumBoolInput<T> + std::marker::Send + std::marker::Sync,
for<'a> &'a T: TriviumBoolInput<T>,
{
/// Internal generic contructor: arguments are already prepared registers, and an optional FHE
/// Internal generic constructor: arguments are already prepared registers, and an optional FHE
/// server key
fn new_from_registers(
a_register: [T; 93],

View File

@@ -1,5 +1,5 @@
//! This module implements the Trivium stream cipher, using u8 or FheUint8
//! for the representaion of the inner bits.
//! for the representation of the inner bits.
use crate::static_deque::{StaticByteDeque, StaticByteDequeInput};
@@ -31,7 +31,7 @@ impl TriviumByteInput<FheUint8> for &FheUint8 {}
/// representation of bits (u8 or FheUint8). To be able to compute FHE operations, it also owns
/// an Option for a ServerKey.
/// Since the original Trivium registers' sizes are not a multiple of 8, these registers (which
/// store byte-like objects) have a size that is the eigth of the closest multiple of 8 above the
/// store byte-like objects) have a size that is the eighth of the closest multiple of 8 above the
/// originals' sizes.
pub struct TriviumStreamByte<T> {
a_byte: StaticByteDeque<12, T>,
@@ -41,7 +41,7 @@ pub struct TriviumStreamByte<T> {
}
impl TriviumStreamByte<u8> {
/// Contructor for `TriviumStreamByte<u8>`: arguments are the secret key and the input vector.
/// Constructor for `TriviumStreamByte<u8>`: arguments are the secret key and the input vector.
/// Outputs a TriviumStream object already initialized (1152 steps have been run before
/// returning)
pub fn new(key: [u8; 10], iv: [u8; 10]) -> TriviumStreamByte<u8> {
@@ -111,7 +111,7 @@ where
T: TriviumByteInput<T> + Send,
for<'a> &'a T: TriviumByteInput<T>,
{
/// Internal generic contructor: arguments are already prepared registers, and an optional FHE
/// Internal generic constructor: arguments are already prepared registers, and an optional FHE
/// server key
fn new_from_registers(
a_register: [T; 12],

View File

@@ -17,9 +17,9 @@ pub struct TriviumStreamShortint {
}
impl TriviumStreamShortint {
/// Contructor for TriviumStreamShortint: arguments are the secret key and the input vector, and
/// a ServerKey reference. Outputs a TriviumStream object already initialized (1152 steps
/// have been run before returning)
/// Constructor for TriviumStreamShortint: arguments are the secret key and the input vector,
/// and a ServerKey reference. Outputs a TriviumStream object already initialized (1152
/// steps have been run before returning)
pub fn new(
key: [Ciphertext; 80],
iv: [u64; 80],

View File

@@ -36,23 +36,24 @@ def check_security(filename):
try:
# The lattice estimator is not able to manage such large dimension.
# If we have the security for smaller `n` then we have security for larger ones.
if param.n >= 32768:
if param.n > 16384:
param = param.updated(n = 16384)
usvp_level = LWE.primal_usvp(param, red_cost_model = model)
dual_level = LWE.dual_hybrid(param, red_cost_model = model)
estimator_level = log(min(usvp_level["rop"], dual_level["rop"]),2 )
security_level = f"security level = {estimator_level} bits"
if estimator_level < 127:
print("FAIL")
reason = f"attained security level = {estimator_level} bits target is 128 bits"
print("FAIL\t({security_level})")
reason = f"attained {security_level} target is 128 bits"
to_update.append((param, reason))
continue
except Exception as err:
print("FAIL")
to_update.append((param, f"{repr(err)}"))
else:
print("OK")
print(f"OK\t({security_level})")
return to_update
@@ -72,4 +73,4 @@ if __name__ == "__main__":
print(f"[{param.tag}] reason: {reason} (param)")
sys.exit(int(1)) # Explicit conversion is needed to make this call work
else:
print("All parameters passed the security check")
print("All parameters passed the security check")

View File

@@ -20,7 +20,10 @@ def main(args):
bench_function_id = bench_data["function_id"]
split = bench_function_id.split("::")
(_, function_name, parameter_set, bits) = split
if split.len() == 5: # Signed integers
(_, _, function_name, parameter_set, bits) = split
else: # Unsigned integers
(_, function_name, parameter_set, bits) = split
if "_scalar_" in bits:
(bits, scalar) = bits.split("_bits_scalar_")

View File

@@ -21,12 +21,12 @@ check_run_name = "CPU AWS Tests"
[command.cpu_integer_test]
workflow = "aws_tfhe_integer_tests.yml"
profile = "cpu-big"
check_run_name = "CPU Integer AWS Tests"
check_run_name = "CPU Unsigned Integer AWS Tests"
[command.cpu_multi_bit_test]
workflow = "aws_tfhe_multi_bit_tests.yml"
workflow = "aws_tfhe_signed_integer_tests.yml"
profile = "cpu-big"
check_run_name = "CPU AWS Multi Bit Tests"
check_run_name = "CPU Signed Integer AWS Tests"
[command.cpu_wasm_test]
workflow = "aws_tfhe_wasm_tests.yml"
@@ -43,6 +43,11 @@ workflow = "integer_full_benchmark.yml"
profile = "bench"
check_run_name = "Integer CPU AWS Benchmarks Full Suite"
[command.signed_integer_full_bench]
workflow = "signed_integer_full_benchmark.yml"
profile = "bench"
check_run_name = "Signed Integer CPU AWS Benchmarks Full Suite"
[command.integer_bench]
workflow = "integer_benchmark.yml"
profile = "bench"
@@ -53,6 +58,16 @@ workflow = "integer_multi_bit_benchmark.yml"
profile = "bench"
check_run_name = "Integer multi bit CPU AWS Benchmarks"
[command.signed_integer_bench]
workflow = "signed_integer_benchmark.yml"
profile = "bench"
check_run_name = "Signed integer CPU AWS Benchmarks"
[command.signed_integer_multi_bit_bench]
workflow = "signed_integer_multi_bit_benchmark.yml"
profile = "bench"
check_run_name = "Signed integer multi bit CPU AWS Benchmarks"
[command.shortint_full_bench]
workflow = "shortint_full_benchmark.yml"
profile = "bench"

View File

@@ -9,6 +9,7 @@ documentation = "https://docs.zama.ai/tfhe-rs"
repository = "https://github.com/zama-ai/tfhe-rs"
readme = "README.md"
keywords = ["fully", "homomorphic", "encryption", "fhe", "cryptography"]
rust-version = "1.72"
[dependencies]
aes = "0.8.2"
@@ -19,8 +20,8 @@ libc = "0.2.133"
[dev-dependencies]
rand = "0.8.3"
criterion = "0.3"
clap = "=4.2.7"
criterion = "0.5.1"
clap = "=4.4.4"
[features]
parallel = ["rayon"]

View File

@@ -17,7 +17,7 @@ pub struct BytesPerChild(pub usize);
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct ByteCount(pub u128);
/// An error occuring during a generator fork.
/// An error occurring during a generator fork.
#[derive(Debug)]
pub enum ForkError {
ForkTooLarge,
@@ -145,7 +145,7 @@ pub mod generator_generic_test {
/// Checks that the PRNG roughly generates uniform numbers.
///
/// To do that, we perform an histogram of the occurences of each byte value, over a fixed
/// To do that, we perform an histogram of the occurrences of each byte value, over a fixed
/// number of samples and check that the empirical probabilities of the bins are close to
/// the theoretical probabilities.
pub fn test_roughly_uniform<G: RandomGenerator>() {

View File

@@ -3,7 +3,7 @@
//! When initializing a generator, one needs to provide a [`Seed`], which is then used as key to the
//! AES blockcipher. As a consequence, the quality of the outputs of the generator is directly
//! conditioned by the quality of this seed. This module proposes different mechanisms to deliver
//! seeds that can accomodate varying scenarios.
//! seeds that can accommodate varying scenarios.
/// A seed value, used to initialize a generator.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -15,7 +15,7 @@ pub trait Seeder {
fn seed(&mut self) -> Seed;
/// Check whether the seeder can be used on the current machine. This function may check if some
/// required CPU features are available or if some OS features are availble for example.
/// required CPU features are available or if some OS features are available for example.
fn is_available() -> bool
where
Self: Sized;

View File

@@ -11,6 +11,7 @@ RUN sed -i 's|^deb http://archive.ubuntu.com/ubuntu/|deb http://mirror.ubuntu.ik
ENV CARGO_TARGET_DIR=/root/tfhe-rs-target
ARG RUST_TOOLCHAIN="stable"
ARG NODE_VERSION
WORKDIR /tfhe-wasm-tests
@@ -34,6 +35,6 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > install-rustup.s
chmod +x install-node.sh && \
./install-node.sh && \
. "$HOME/.nvm/nvm.sh" && \
bash -i -c 'nvm install node && nvm use node'
bash -i -c 'nvm install ${NODE_VERSION} && nvm use ${NODE_VERSION}'
WORKDIR /tfhe-wasm-tests/tfhe-rs/

View File

@@ -8,14 +8,23 @@ function usage() {
echo "--help Print this message"
echo "--rust-toolchain The toolchain to run the tests with default: stable"
echo "--multi-bit Run multi-bit tests only: default off"
echo "--unsigned-only Run only unsigned integer tests, by default both signed and unsigned tests are run"
echo "--signed-only Run only signed integer tests, by default both signed and unsigned tests are run"
echo "--cargo-profile The cargo profile used to build tests"
echo "--avx512-support Set to ON to enable avx512"
echo
}
RUST_TOOLCHAIN="+stable"
multi_bit=""
not_multi_bit="_multi_bit"
# Run signed test by default
signed=""
not_signed=""
cargo_profile="release"
# TODO: revert to release once the bug is properly fixed/identified
cargo_profile_doctests="release_lto_off"
avx512_feature=""
while [ -n "$1" ]
do
@@ -35,11 +44,28 @@ do
not_multi_bit=""
;;
"--unsigned-only" )
signed=""
not_signed="_signed"
;;
"--signed-only" )
signed="_signed"
not_signed=""
;;
"--cargo-profile" )
shift
cargo_profile="$1"
;;
"--avx512-support" )
shift
if [[ "$1" == "ON" ]]; then
avx512_feature=nightly-avx512
fi
;;
*)
echo "Unknown param : $1"
exit 1
@@ -62,104 +88,86 @@ if [[ $(uname) == "Darwin" ]]; then
nproc_bin="sysctl -n hw.logicalcpu"
fi
n_threads="$(${nproc_bin})"
# TODO autodetect/have a finer CPU count depending on memory
num_cpu_threads="$(${nproc_bin})"
if uname -a | grep "arm64"; then
if [[ $(uname) == "Darwin" ]]; then
# Keys are 4.7 gigs at max, CI M1 macs only has 8 gigs of RAM
n_threads=1
small_instance_n_threads=1
fi
else
# Keys are 4.7 gigs at max, test machine has 32 gigs of RAM
n_threads=6
small_instance_n_threads=6
fi
if [[ "${BIG_TESTS_INSTANCE}" != TRUE ]]; then
if [[ "${FAST_TESTS}" != TRUE ]]; then
# block pbs are too slow for high params
# mul_crt_4_4 is extremely flaky (~80% failure)
# test_wopbs_bivariate_crt_wopbs_param_message generate tables that are too big at the moment
# test_integer_smart_mul_param_message_4_carry_4_ks_pbs is too slow
# so is test_integer_default_add_sequence_multi_thread_param_message_4_carry_4_ks_pbs
filter_expression="""\
test(/^integer::.*${multi_bit}/) \
${not_multi_bit:+"and not test(~${not_multi_bit})"} \
and not test(/.*_block_pbs(_base)?_param_message_[34]_carry_[34]_ks_pbs$/) \
and not test(~mul_crt_param_message_4_carry_4_ks_pbs) \
and not test(/.*test_wopbs_bivariate_crt_wopbs_param_message_[34]_carry_[34]_ks_pbs$/) \
and not test(/.*test_integer_smart_mul_param_message_4_carry_4_ks_pbs$/) \
and not test(/.*test_integer_default_add_sequence_multi_thread_param_message_4_carry_4_ks_pbs$/)"""
else
# test only fast default operations with only two set of parameters
filter_expression="""\
test(/^integer::.*${multi_bit}/) \
${not_multi_bit:+"and not test(~${not_multi_bit})"} \
and test(/.*_default_.*?_param${multi_bit}_message_[2-3]_carry_[2-3]${multi_bit:+"_group_2"}_ks_pbs/) \
and not test(/.*_param_message_[14]_carry_[14]_ks_pbs$/) \
and not test(/.*default_add_sequence_multi_thread_param_message_3_carry_3_ks_pbs$/)"""
fi
cargo "${RUST_TOOLCHAIN}" nextest run \
--tests \
--cargo-profile "${cargo_profile}" \
--package tfhe \
--profile ci \
--features="${ARCH_FEATURE}",integer,internal-keycache \
--test-threads "${n_threads}" \
-E "$filter_expression"
if [[ "${multi_bit}" == "" ]]; then
cargo "${RUST_TOOLCHAIN}" test \
--profile "${cargo_profile}" \
--package tfhe \
--features="${ARCH_FEATURE}",integer,internal-keycache \
--doc \
-- integer::
fi
if [[ "${BIG_TESTS_INSTANCE}" == TRUE ]]; then
test_threads="$((num_cpu_threads * 1 / 2))"
doctest_threads="${num_cpu_threads}"
else
if [[ "${FAST_TESTS}" != TRUE ]]; then
# block pbs are too slow for high params
# mul_crt_4_4 is extremely flaky (~80% failure)
# test_wopbs_bivariate_crt_wopbs_param_message generate tables that are too big at the moment
# test_integer_smart_mul_param_message_4_carry_4_ks_pbs is too slow
# so is test_integer_default_add_sequence_multi_thread_param_message_4_carry_4_ks_pbs
filter_expression="""\
test_threads="${small_instance_n_threads}"
doctest_threads="${num_cpu_threads}"
fi
# block pbs are too slow for high params
# mul_crt_4_4 is extremely flaky (~80% failure)
# test_wopbs_bivariate_crt_wopbs_param_message generate tables that are too big at the moment
# test_integer_smart_mul_param_message_4_carry_4_ks_pbs is too slow
# so is test_integer_default_add_sequence_multi_thread_param_message_4_carry_4_ks_pbs
# we skip smart_div, smart_rem which are already covered by the smar_div_rem test
# we similarly skip default_div, default_rem which are covered by default_div_rem
full_test_filter_expression="""\
test(/^integer::.*${multi_bit}/) \
${signed:+"and test(/^integer::.*${signed}/)"} \
${not_multi_bit:+"and not test(~${not_multi_bit})"} \
${not_signed:+"and not test(~${not_signed})"} \
and not test(/.*integer_smart_div_param/) \
and not test(/.*integer_smart_rem_param/) \
and not test(/.*integer_default_div_param/) \
and not test(/.*integer_default_rem_param/) \
and not test(/.*_block_pbs(_base)?_param_message_[34]_carry_[34]_ks_pbs$/) \
and not test(~mul_crt_param_message_4_carry_4_ks_pbs) \
and not test(/.*test_wopbs_bivariate_crt_wopbs_param_message_[34]_carry_[34]_ks_pbs$/) \
and not test(/.*test_integer_smart_mul_param_message_4_carry_4_ks_pbs$/) \
and not test(/.*test_integer_default_add_sequence_multi_thread_param_message_4_carry_4_ks_pbs$/)"""
else
# test only fast default operations with only two set of parameters
filter_expression="""\
# test only fast default operations with only two set of parameters
# we skip default_div, default_rem which are covered by default_div_rem
fast_test_filter_expression="""\
test(/^integer::.*${multi_bit}/) \
${signed:+"and test(/^integer::.*${signed}/)"} \
${not_multi_bit:+"and not test(~${not_multi_bit})"} \
${not_signed:+"and not test(~${not_signed})"} \
and test(/.*_default_.*?_param${multi_bit}_message_[2-3]_carry_[2-3]${multi_bit:+"_group_2"}_ks_pbs/) \
and not test(/.*integer_default_div_param/) \
and not test(/.*integer_default_rem_param/) \
and not test(/.*_param_message_[14]_carry_[14]_ks_pbs$/) \
and not test(/.*default_add_sequence_multi_thread_param_message_3_carry_3_ks_pbs$/)"""
fi
num_cpu_threads="$(${nproc_bin})"
num_threads=$((num_cpu_threads * 1 / 2))
cargo "${RUST_TOOLCHAIN}" nextest run \
--tests \
--cargo-profile "${cargo_profile}" \
if [[ "${FAST_TESTS}" == "TRUE" ]]; then
echo "Running 'fast' test set'"
filter_expression="${fast_test_filter_expression}"
else
echo "Running 'slow' test set"
filter_expression="${full_test_filter_expression}"
fi
cargo "${RUST_TOOLCHAIN}" nextest run \
--tests \
--cargo-profile "${cargo_profile}" \
--package tfhe \
--profile ci \
--features="${ARCH_FEATURE}",integer,internal-keycache,"${avx512_feature}" \
--test-threads "${test_threads}" \
-E "$filter_expression"
if [[ "${multi_bit}" == "" ]]; then
cargo "${RUST_TOOLCHAIN}" test \
--profile "${cargo_profile_doctests}" \
--package tfhe \
--profile ci \
--features="${ARCH_FEATURE}",integer,internal-keycache \
--test-threads $num_threads \
-E "$filter_expression"
if [[ "${multi_bit}" == "" ]]; then
cargo "${RUST_TOOLCHAIN}" test \
--profile "${cargo_profile}" \
--package tfhe \
--features="${ARCH_FEATURE}",integer,internal-keycache \
--doc \
-- --test-threads="$(${nproc_bin})" integer::
fi
--features="${ARCH_FEATURE}",integer,internal-keycache,"${avx512_feature}" \
--doc \
-- --test-threads="${doctest_threads}" integer::
fi
echo "Test ran in $SECONDS seconds"

View File

@@ -94,6 +94,7 @@ or test(/^shortint::.*_param${multi_bit}_message_2_carry_3${multi_bit:+"_group_[
or test(/^shortint::.*_param${multi_bit}_message_3_carry_1${multi_bit:+"_group_[0-9]"}(_compact_pk)?_ks_pbs/) \
or test(/^shortint::.*_param${multi_bit}_message_3_carry_2${multi_bit:+"_group_[0-9]"}(_compact_pk)?_ks_pbs/) \
or test(/^shortint::.*_param${multi_bit}_message_3_carry_3${multi_bit:+"_group_[0-9]"}(_compact_pk)?_ks_pbs/) \
or test(/^shortint::.*_ci_run_filter/) \
)\
and not test(~smart_add_and_mul)""" # This test is too slow
else
@@ -159,6 +160,7 @@ or test(/^shortint::.*_param${multi_bit}_message_3_carry_1${multi_bit:+"_group_[
or test(/^shortint::.*_param${multi_bit}_message_3_carry_2${multi_bit:+"_group_[0-9]"}(_compact_pk)?_ks_pbs/) \
or test(/^shortint::.*_param${multi_bit}_message_3_carry_3${multi_bit:+"_group_[0-9]"}(_compact_pk)?_ks_pbs/) \
or test(/^shortint::.*_param${multi_bit}_message_4_carry_4${multi_bit:+"_group_[0-9]"}(_compact_pk)?_ks_pbs/) \
or test(/^shortint::.*_ci_run_filter/) \
)\
and not test(~smart_add_and_mul)""" # This test is too slow
else

View File

@@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = "3.1"
clap = "=4.4.4"
lazy_static = "1.4"
log = "0.4"
simplelog = "0.12"

2
tfhe/.gitignore vendored
View File

@@ -1 +1 @@
build/
build/

View File

@@ -1,6 +1,6 @@
[package]
name = "tfhe"
version = "0.4.0"
version = "0.5.0"
edition = "2021"
readme = "../README.md"
keywords = ["fully", "homomorphic", "encryption", "fhe", "cryptography"]
@@ -26,16 +26,16 @@ rand = "0.8.5"
rand_distr = "0.4.3"
paste = "1.0.7"
lazy_static = { version = "1.4.0" }
criterion = "0.4.0"
criterion = "0.5.1"
doc-comment = "0.3.3"
serde_json = "1.0.94"
# clap has to be pinned as its minimum supported rust version
# changes often between minor releases, which breaks our CI
clap = { version = "=4.2.7", features = ["derive"] }
clap = { version = "=4.4.4", features = ["derive"] }
# Used in user documentation
bincode = "1.3.3"
fs2 = { version = "0.4.3" }
itertools = "0.10.5"
itertools = "0.11.0"
# For erf and normality test
libm = "0.2.6"
# Begin regex-engine deps
@@ -46,10 +46,10 @@ log = "0.4.19"
# End regex-engine deps
[build-dependencies]
cbindgen = { version = "0.24.3", optional = true }
cbindgen = { version = "0.26.0", optional = true }
[dependencies]
concrete-csprng = { version = "0.4.0", path= "../concrete-csprng", features = [
concrete-csprng = { version = "0.4.0", path = "../concrete-csprng", features = [
"generator_fallback",
"parallel",
] }
@@ -64,7 +64,7 @@ dyn-stack = { version = "0.9" }
paste = { version = "1.0.7", optional = true }
fs2 = { version = "0.4.3", optional = true }
# While we wait for repeat_n in rust standard library
itertools = "0.10.5"
itertools = "0.11.0"
# wasm deps
wasm-bindgen = { version = "0.2.86", features = [
@@ -73,7 +73,7 @@ wasm-bindgen = { version = "0.2.86", features = [
wasm-bindgen-rayon = { version = "1.0", optional = true }
js-sys = { version = "0.3", optional = true }
console_error_panic_hook = { version = "0.1.7", optional = true }
serde-wasm-bindgen = { version = "0.4", optional = true }
serde-wasm-bindgen = { version = "0.6.0", optional = true }
getrandom = { version = "0.2.8", optional = true }
bytemuck = "1.13.1"
@@ -82,32 +82,36 @@ bytemuck = "1.13.1"
boolean = ["dep:paste"]
shortint = ["dep:paste"]
integer = ["shortint", "dep:paste"]
internal-keycache = ["lazy_static", "dep:fs2", "bincode", "dep:paste"]
internal-keycache = ["dep:lazy_static", "dep:fs2", "dep:bincode", "dep:paste"]
safe-deserialization = ["dep:bincode"]
# Experimental section
experimental = []
experimental-force_fft_algo_dif4 = []
# End experimental section
__c_api = ["cbindgen", "bincode", "dep:paste"]
__c_api = ["dep:cbindgen", "dep:bincode", "dep:paste"]
# For the semver trick to skip the build.rs
__force_skip_cbindgen = []
boolean-c-api = ["boolean", "__c_api"]
shortint-c-api = ["shortint", "__c_api"]
high-level-c-api = ["boolean-c-api", "shortint-c-api", "integer", "__c_api"]
__wasm_api = [
"wasm-bindgen",
"js-sys",
"console_error_panic_hook",
"serde-wasm-bindgen",
"getrandom",
"dep:wasm-bindgen",
"dep:js-sys",
"dep:console_error_panic_hook",
"dep:serde-wasm-bindgen",
"dep:getrandom",
"getrandom/js",
"bincode",
"dep:bincode",
"safe-deserialization",
]
boolean-client-js-wasm-api = ["boolean", "__wasm_api"]
shortint-client-js-wasm-api = ["shortint", "__wasm_api"]
integer-client-js-wasm-api = ["integer", "__wasm_api"]
high-level-client-js-wasm-api = ["boolean", "shortint", "integer", "__wasm_api"]
parallel-wasm-api = ["wasm-bindgen-rayon"]
parallel-wasm-api = ["dep:wasm-bindgen-rayon"]
nightly-avx512 = ["concrete-fft/nightly", "pulp/nightly"]
@@ -182,6 +186,12 @@ path = "benches/integer/bench.rs"
harness = false
required-features = ["integer", "internal-keycache"]
[[bench]]
name = "integer-signed-bench"
path = "benches/integer/signed_bench.rs"
harness = false
required-features = ["integer", "internal-keycache"]
[[bench]]
name = "keygen"
path = "benches/keygen/bench.rs"
@@ -204,7 +214,7 @@ required-features = ["shortint", "internal-keycache"]
[[example]]
name = "generates_test_keys"
path = "examples/utilities/generates_test_keys.rs"
required-features = ["shortint", "internal-keycache"]
required-features = ["boolean", "shortint", "internal-keycache"]
[[example]]
name = "boolean_key_sizes"

View File

@@ -43,7 +43,7 @@ pub fn write_to_json_boolean<T: Into<CryptoParametersRecord<u32>>>(
// Put all `bench_function` in one place
// so the keygen is only run once per parameters saving time.
fn benchs(c: &mut Criterion, params: BooleanParameters, parameter_name: &str) {
fn benches(c: &mut Criterion, params: BooleanParameters, parameter_name: &str) {
let mut bench_group = c.benchmark_group("gates_benches");
let cks = ClientKey::new(&params);
@@ -83,15 +83,15 @@ fn benchs(c: &mut Criterion, params: BooleanParameters, parameter_name: &str) {
}
fn bench_default_parameters(c: &mut Criterion) {
benchs(c, DEFAULT_PARAMETERS, "DEFAULT_PARAMETERS");
benches(c, DEFAULT_PARAMETERS, "DEFAULT_PARAMETERS");
}
fn bench_default_parameters_ks_pbs(c: &mut Criterion) {
benchs(c, DEFAULT_PARAMETERS_KS_PBS, "DEFAULT_PARAMETERS_KS_PBS");
benches(c, DEFAULT_PARAMETERS_KS_PBS, "DEFAULT_PARAMETERS_KS_PBS");
}
fn bench_low_prob_parameters(c: &mut Criterion) {
benchs(
benches(
c,
PARAMETERS_ERROR_PROB_2_POW_MINUS_165,
"PARAMETERS_ERROR_PROB_2_POW_MINUS_165",
@@ -99,7 +99,7 @@ fn bench_low_prob_parameters(c: &mut Criterion) {
}
fn bench_low_prob_parameters_ks_pbs(c: &mut Criterion) {
benchs(
benches(
c,
PARAMETERS_ERROR_PROB_2_POW_MINUS_165_KS_PBS,
"PARAMETERS_ERROR_PROB_2_POW_MINUS_165_KS_PBS",
@@ -107,5 +107,5 @@ fn bench_low_prob_parameters_ks_pbs(c: &mut Criterion) {
}
fn bench_tfhe_lib_parameters(c: &mut Criterion) {
benchs(c, TFHE_LIB_PARAMETERS, " TFHE_LIB_PARAMETERS");
benches(c, TFHE_LIB_PARAMETERS, " TFHE_LIB_PARAMETERS");
}

View File

@@ -130,7 +130,7 @@ fn multi_bit_pbs<Scalar: UnsignedTorus + CastInto<usize> + CastFrom<usize> + Syn
);
let id = format!("Multi Bit PBS {}", Scalar::BITS);
#[allow(clippy::unit_arg)]
{
c.bench_function(&id, |b| {
b.iter(|| {

View File

@@ -12,7 +12,7 @@ use rand::prelude::*;
use rand::Rng;
use std::vec::IntoIter;
use tfhe::integer::keycache::KEY_CACHE;
use tfhe::integer::{RadixCiphertext, ServerKey};
use tfhe::integer::{IntegerKeyKind, RadixCiphertext, ServerKey};
use tfhe::keycache::NamedParam;
use tfhe::integer::U256;
@@ -118,7 +118,7 @@ fn bench_server_key_binary_function_dirty_inputs<F>(
let bench_id = format!("{bench_name}::{param_name}::{bit_size}_bits");
bench_group.bench_function(&bench_id, |b| {
let (cks, sks) = KEY_CACHE.get_from_params(param);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let encrypt_two_values = || {
let clear_0 = gen_random_u256(&mut rng);
@@ -186,7 +186,7 @@ fn bench_server_key_binary_function_clean_inputs<F>(
let bench_id = format!("{bench_name}::{param_name}::{bit_size}_bits");
bench_group.bench_function(&bench_id, |b| {
let (cks, sks) = KEY_CACHE.get_from_params(param);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let encrypt_two_values = || {
let clear_0 = gen_random_u256(&mut rng);
@@ -243,7 +243,7 @@ fn bench_server_key_unary_function_dirty_inputs<F>(
let bench_id = format!("{bench_name}::{param_name}::{bit_size}_bits");
bench_group.bench_function(&bench_id, |b| {
let (cks, sks) = KEY_CACHE.get_from_params(param);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let encrypt_one_value = || {
let clear_0 = gen_random_u256(&mut rng);
@@ -308,7 +308,7 @@ fn bench_server_key_unary_function_clean_inputs<F>(
let bench_id = format!("{bench_name}::{param_name}::{bit_size}_bits");
bench_group.bench_function(&bench_id, |b| {
let (cks, sks) = KEY_CACHE.get_from_params(param);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let encrypt_one_value = || {
let clear_0 = gen_random_u256(&mut rng);
@@ -362,7 +362,7 @@ fn bench_server_key_binary_scalar_function_dirty_inputs<F, G>(
let bench_id = format!("{bench_name}::{param_name}::{bit_size}_bits");
bench_group.bench_function(&bench_id, |b| {
let (cks, sks) = KEY_CACHE.get_from_params(param);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let encrypt_one_value = || {
let clear_0 = gen_random_u256(&mut rng);
@@ -435,7 +435,7 @@ fn bench_server_key_binary_scalar_function_clean_inputs<F, G>(
let bench_id = format!("{bench_name}::{param_name}::{bit_size}_bits_scalar_{bit_size}");
bench_group.bench_function(&bench_id, |b| {
let (cks, sks) = KEY_CACHE.get_from_params(param);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let encrypt_one_value = || {
let clear_0 = gen_random_u256(&mut rng);
@@ -515,7 +515,7 @@ fn if_then_else_parallelized(c: &mut Criterion) {
let bench_id = format!("{bench_name}::{param_name}::{bit_size}_bits");
bench_group.bench_function(&bench_id, |b| {
let (cks, sks) = KEY_CACHE.get_from_params(param);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let encrypt_tree_values = || {
let clear_0 = gen_random_u256(&mut rng);
@@ -524,7 +524,7 @@ fn if_then_else_parallelized(c: &mut Criterion) {
let clear_1 = gen_random_u256(&mut rng);
let ct_1 = cks.encrypt_radix(clear_1, num_block);
let cond = sks.create_trivial_radix(rng.gen_bool(0.5) as u64, num_block);
let cond = sks.create_trivial_boolean_block(rng.gen_bool(0.5));
(cond, ct_0, ct_1)
};
@@ -650,15 +650,23 @@ define_server_key_bench_fn!(method_name: smart_bitxor, display_name: bitxor);
define_server_key_bench_fn!(method_name: smart_add_parallelized, display_name: add);
define_server_key_bench_fn!(method_name: smart_sub_parallelized, display_name: sub);
define_server_key_bench_fn!(method_name: smart_mul_parallelized, display_name: mul);
define_server_key_bench_fn!(method_name: smart_div_parallelized, display_name: div);
define_server_key_bench_fn!(method_name: smart_div_rem_parallelized, display_name: div_mod);
define_server_key_bench_fn!(method_name: smart_rem_parallelized, display_name: rem);
define_server_key_bench_fn!(method_name: smart_bitand_parallelized, display_name: bitand);
define_server_key_bench_fn!(method_name: smart_bitxor_parallelized, display_name: bitxor);
define_server_key_bench_fn!(method_name: smart_bitor_parallelized, display_name: bitor);
define_server_key_bench_fn!(method_name: smart_rotate_right_parallelized, display_name: rotate_right);
define_server_key_bench_fn!(method_name: smart_rotate_left_parallelized, display_name: rotate_left);
define_server_key_bench_fn!(method_name: smart_right_shift_parallelized, display_name: right_shift);
define_server_key_bench_fn!(method_name: smart_left_shift_parallelized, display_name: left_shift);
define_server_key_bench_default_fn!(method_name: add_parallelized, display_name: add);
define_server_key_bench_default_fn!(method_name: sub_parallelized, display_name: sub);
define_server_key_bench_default_fn!(method_name: mul_parallelized, display_name: mul);
define_server_key_bench_default_fn!(method_name: div_parallelized, display_name: div);
define_server_key_bench_default_fn!(method_name: rem_parallelized, display_name: modulo);
define_server_key_bench_default_fn!(method_name: div_rem_parallelized, display_name: div_mod);
define_server_key_bench_default_fn!(method_name: bitand_parallelized, display_name: bitand);
define_server_key_bench_default_fn!(method_name: bitxor_parallelized, display_name: bitxor);
define_server_key_bench_default_fn!(method_name: bitor_parallelized, display_name: bitor);
@@ -671,7 +679,11 @@ define_server_key_bench_default_fn!(method_name: unchecked_bitand, display_name:
define_server_key_bench_default_fn!(method_name: unchecked_bitor, display_name: bitor);
define_server_key_bench_default_fn!(method_name: unchecked_bitxor, display_name: bitxor);
define_server_key_bench_default_fn!(method_name: unchecked_add_parallelized, display_name: add);
define_server_key_bench_default_fn!(method_name: unchecked_mul_parallelized, display_name: mul);
define_server_key_bench_default_fn!(method_name: unchecked_div_parallelized, display_name: div);
define_server_key_bench_default_fn!(method_name: unchecked_rem_parallelized, display_name: modulo);
define_server_key_bench_default_fn!(method_name: unchecked_div_rem_parallelized, display_name: div_mod);
define_server_key_bench_default_fn!(
method_name: unchecked_bitand_parallelized,
display_name: bitand
@@ -684,6 +696,38 @@ define_server_key_bench_default_fn!(
method_name: unchecked_bitxor_parallelized,
display_name: bitxor
);
define_server_key_bench_default_fn!(
method_name: unchecked_rotate_right_parallelized,
display_name: rotate_right
);
define_server_key_bench_default_fn!(
method_name: unchecked_rotate_left_parallelized,
display_name: rotate_left
);
define_server_key_bench_default_fn!(
method_name: unchecked_right_shift_parallelized,
display_name: right_shift
);
define_server_key_bench_default_fn!(
method_name: unchecked_left_shift_parallelized,
display_name: left_shift
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_bitand_parallelized,
display_name: bitand,
rng_func: default_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_bitor_parallelized,
display_name: bitor,
rng_func: default_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_bitxor_parallelized,
display_name: bitxor,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_add,
@@ -716,6 +760,46 @@ define_server_key_bench_scalar_fn!(
display_name: mul,
rng_func: mul_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_div_parallelized,
display_name: div,
rng_func: div_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_rem_parallelized,
display_name: modulo,
rng_func: div_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_div_rem_parallelized,
display_name: div_mod,
rng_func: div_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_bitand_parallelized,
display_name: bitand,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_bitor_parallelized,
display_name: bitor,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_bitxor_parallelized,
display_name: bitxor,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_rotate_left_parallelized,
display_name: rotate_left,
rng_func: shift_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_rotate_right_parallelized,
display_name: rotate_right,
rng_func: shift_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: scalar_add_parallelized,
@@ -742,6 +826,11 @@ define_server_key_bench_scalar_default_fn!(
display_name: modulo,
rng_func: div_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: scalar_div_rem_parallelized,
display_name: div_mod,
rng_func: div_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: scalar_left_shift_parallelized,
display_name: left_shift,
@@ -762,6 +851,22 @@ define_server_key_bench_scalar_default_fn!(
display_name: rotate_right,
rng_func: shift_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: scalar_bitand_parallelized,
display_name: bitand,
rng_func: default_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: scalar_bitor_parallelized,
display_name: bitor,
rng_func: default_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: scalar_bitxor_parallelized,
display_name: bitxor,
rng_func: default_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: scalar_eq_parallelized,
display_name: equal,
@@ -803,6 +908,47 @@ define_server_key_bench_scalar_default_fn!(
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_eq_parallelized,
display_name: equal,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_ne_parallelized,
display_name: not_equal,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_le_parallelized,
display_name: less_or_equal,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_lt_parallelized,
display_name: less_than,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_ge_parallelized,
display_name: greater_or_equal,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_gt_parallelized,
display_name: greater_than,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_max_parallelized,
display_name: max,
rng_func: default_scalar
);
define_server_key_bench_scalar_fn!(
method_name: smart_scalar_min_parallelized,
display_name: min,
rng_func: default_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_add,
display_name: add,
@@ -818,10 +964,50 @@ define_server_key_bench_scalar_default_fn!(
display_name: mul,
rng_func: mul_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_div_parallelized,
display_name: div,
rng_func: div_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_rem_parallelized,
display_name: modulo,
rng_func: div_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_div_rem_parallelized,
display_name: div_mod,
rng_func: div_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_rotate_right_parallelized,
display_name: rotate_right,
rng_func: shift_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_rotate_left_parallelized,
display_name: rotate_left,
rng_func: shift_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_right_shift_parallelized,
display_name: right_shift,
rng_func: shift_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_left_shift_parallelized,
display_name: left_shift,
rng_func: shift_scalar
);
define_server_key_bench_unary_fn!(method_name: smart_neg, display_name: negation);
define_server_key_bench_unary_fn!(method_name: smart_neg_parallelized, display_name: negation);
define_server_key_bench_unary_fn!(method_name: smart_abs_parallelized, display_name: abs);
define_server_key_bench_unary_default_fn!(method_name: neg_parallelized, display_name: negation);
define_server_key_bench_unary_default_fn!(method_name: abs_parallelized, display_name: abs);
define_server_key_bench_unary_default_fn!(method_name: unchecked_abs_parallelized, display_name: abs);
define_server_key_bench_unary_fn!(method_name: full_propagate, display_name: carry_propagation);
define_server_key_bench_unary_fn!(
@@ -832,6 +1018,7 @@ define_server_key_bench_unary_fn!(
define_server_key_bench_default_fn!(method_name: unchecked_max, display_name: max);
define_server_key_bench_default_fn!(method_name: unchecked_min, display_name: min);
define_server_key_bench_default_fn!(method_name: unchecked_eq, display_name: equal);
define_server_key_bench_default_fn!(method_name: unchecked_ne, display_name: not_equal);
define_server_key_bench_default_fn!(method_name: unchecked_lt, display_name: less_than);
define_server_key_bench_default_fn!(method_name: unchecked_le, display_name: less_or_equal);
define_server_key_bench_default_fn!(method_name: unchecked_gt, display_name: greater_than);
@@ -840,6 +1027,7 @@ define_server_key_bench_default_fn!(method_name: unchecked_ge, display_name: gre
define_server_key_bench_default_fn!(method_name: unchecked_max_parallelized, display_name: max);
define_server_key_bench_default_fn!(method_name: unchecked_min_parallelized, display_name: min);
define_server_key_bench_default_fn!(method_name: unchecked_eq_parallelized, display_name: equal);
define_server_key_bench_default_fn!(method_name: unchecked_ne_parallelized, display_name: not_equal);
define_server_key_bench_default_fn!(
method_name: unchecked_lt_parallelized,
display_name: less_than
@@ -857,9 +1045,35 @@ define_server_key_bench_default_fn!(
display_name: greater_or_equal
);
define_server_key_bench_scalar_default_fn!(method_name: unchecked_scalar_max_parallelized, display_name: max,rng_func: default_scalar);
define_server_key_bench_scalar_default_fn!(method_name: unchecked_scalar_min_parallelized, display_name: min,rng_func: default_scalar);
define_server_key_bench_scalar_default_fn!(method_name: unchecked_scalar_eq_parallelized, display_name: equal,rng_func: default_scalar);
define_server_key_bench_scalar_default_fn!(method_name: unchecked_scalar_ne_parallelized, display_name: not_equal,rng_func: default_scalar);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_lt_parallelized,
display_name: less_than,
rng_func: default_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_le_parallelized,
display_name: less_or_equal,
rng_func: default_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_gt_parallelized,
display_name: greater_than,
rng_func: default_scalar
);
define_server_key_bench_scalar_default_fn!(
method_name: unchecked_scalar_ge_parallelized,
display_name: greater_or_equal,
rng_func: default_scalar
);
define_server_key_bench_fn!(method_name: smart_max, display_name: max);
define_server_key_bench_fn!(method_name: smart_min, display_name: min);
define_server_key_bench_fn!(method_name: smart_eq, display_name: equal);
define_server_key_bench_fn!(method_name: smart_ne, display_name: not_equal);
define_server_key_bench_fn!(method_name: smart_lt, display_name: less_than);
define_server_key_bench_fn!(method_name: smart_le, display_name: less_or_equal);
define_server_key_bench_fn!(method_name: smart_gt, display_name: greater_than);
@@ -868,6 +1082,7 @@ define_server_key_bench_fn!(method_name: smart_ge, display_name: greater_or_equa
define_server_key_bench_fn!(method_name: smart_max_parallelized, display_name: max);
define_server_key_bench_fn!(method_name: smart_min_parallelized, display_name: min);
define_server_key_bench_fn!(method_name: smart_eq_parallelized, display_name: equal);
define_server_key_bench_fn!(method_name: smart_ne_parallelized, display_name: not_equal);
define_server_key_bench_fn!(method_name: smart_lt_parallelized, display_name: less_than);
define_server_key_bench_fn!(
method_name: smart_le_parallelized,
@@ -923,6 +1138,7 @@ criterion_group!(
smart_max,
smart_min,
smart_eq,
smart_ne,
smart_lt,
smart_le,
smart_gt,
@@ -931,12 +1147,21 @@ criterion_group!(
criterion_group!(
smart_parallelized_ops,
smart_neg_parallelized,
smart_abs_parallelized,
smart_add_parallelized,
smart_sub_parallelized,
smart_mul_parallelized,
// smart_div_parallelized,
// smart_rem_parallelized,
smart_div_rem_parallelized, // For ciphertext div == rem == div_rem
smart_bitand_parallelized,
smart_bitor_parallelized,
smart_bitxor_parallelized,
smart_rotate_right_parallelized,
smart_rotate_left_parallelized,
smart_right_shift_parallelized,
smart_left_shift_parallelized,
);
criterion_group!(
@@ -944,6 +1169,7 @@ criterion_group!(
smart_max_parallelized,
smart_min_parallelized,
smart_eq_parallelized,
smart_ne_parallelized,
smart_lt_parallelized,
smart_le_parallelized,
smart_gt_parallelized,
@@ -952,12 +1178,14 @@ criterion_group!(
criterion_group!(
default_parallelized_ops,
neg_parallelized,
abs_parallelized,
add_parallelized,
sub_parallelized,
mul_parallelized,
div_parallelized,
rem_parallelized,
neg_parallelized,
// div_parallelized,
// rem_parallelized,
div_rem_parallelized,
bitand_parallelized,
bitnot_parallelized,
bitor_parallelized,
@@ -993,6 +1221,26 @@ criterion_group!(
smart_scalar_add_parallelized,
smart_scalar_sub_parallelized,
smart_scalar_mul_parallelized,
smart_scalar_div_parallelized,
smart_scalar_rem_parallelized, // For scalar rem == div_rem
// smart_scalar_div_rem_parallelized,
smart_scalar_bitand_parallelized,
smart_scalar_bitor_parallelized,
smart_scalar_bitxor_parallelized,
smart_scalar_rotate_right_parallelized,
smart_scalar_rotate_left_parallelized,
);
criterion_group!(
smart_scalar_parallelized_ops_comp,
smart_scalar_max_parallelized,
smart_scalar_min_parallelized,
smart_scalar_eq_parallelized,
smart_scalar_ne_parallelized,
smart_scalar_lt_parallelized,
smart_scalar_le_parallelized,
smart_scalar_gt_parallelized,
smart_scalar_ge_parallelized,
);
criterion_group!(
@@ -1002,10 +1250,14 @@ criterion_group!(
scalar_mul_parallelized,
scalar_div_parallelized,
scalar_rem_parallelized,
// scalar_div_rem_parallelized,
scalar_left_shift_parallelized,
scalar_right_shift_parallelized,
scalar_rotate_left_parallelized,
scalar_rotate_right_parallelized,
scalar_bitand_parallelized,
scalar_bitor_parallelized,
scalar_bitxor_parallelized,
);
criterion_group!(
@@ -1030,11 +1282,40 @@ criterion_group!(
unchecked_bitxor,
);
criterion_group!(
unchecked_parallelized_ops,
unchecked_abs_parallelized,
unchecked_add_parallelized,
unchecked_mul_parallelized,
// unchecked_div_parallelized,
// unchecked_rem_parallelized,
unchecked_div_rem_parallelized,
unchecked_bitand_parallelized,
unchecked_bitor_parallelized,
unchecked_bitxor_parallelized,
unchecked_rotate_right_parallelized,
unchecked_rotate_left_parallelized,
unchecked_right_shift_parallelized,
unchecked_left_shift_parallelized,
);
criterion_group!(
unchecked_parallelized_ops_comp,
unchecked_eq_parallelized,
unchecked_ne_parallelized,
unchecked_gt_parallelized,
unchecked_ge_parallelized,
unchecked_lt_parallelized,
unchecked_max_parallelized,
unchecked_min_parallelized,
);
criterion_group!(
unchecked_ops_comp,
unchecked_max,
unchecked_min,
unchecked_eq,
unchecked_ne,
unchecked_lt,
unchecked_le,
unchecked_gt,
@@ -1046,20 +1327,28 @@ criterion_group!(
unchecked_scalar_add,
unchecked_scalar_sub,
unchecked_scalar_mul_parallelized,
unchecked_bitand_parallelized,
unchecked_bitor_parallelized,
unchecked_bitxor_parallelized,
unchecked_scalar_div_parallelized,
unchecked_scalar_rem_parallelized,
// unchecked_scalar_div_rem_parallelized,
unchecked_scalar_bitand_parallelized,
unchecked_scalar_bitor_parallelized,
unchecked_scalar_bitxor_parallelized,
unchecked_scalar_rotate_right_parallelized,
unchecked_scalar_rotate_left_parallelized,
unchecked_scalar_right_shift_parallelized,
unchecked_scalar_left_shift_parallelized,
);
criterion_group!(
unchecked_scalar_ops_comp,
unchecked_max_parallelized,
unchecked_min_parallelized,
unchecked_eq_parallelized,
unchecked_lt_parallelized,
unchecked_le_parallelized,
unchecked_gt_parallelized,
unchecked_ge_parallelized,
unchecked_scalar_max_parallelized,
unchecked_scalar_min_parallelized,
unchecked_scalar_eq_parallelized,
unchecked_scalar_ne_parallelized,
unchecked_scalar_lt_parallelized,
unchecked_scalar_le_parallelized,
unchecked_scalar_gt_parallelized,
unchecked_scalar_ge_parallelized,
);
criterion_group!(misc, full_propagate, full_propagate_parallelized);
@@ -1078,7 +1367,9 @@ fn main() {
"smart_parallelized" => smart_parallelized_ops(),
"smart_parallelized_comp" => smart_parallelized_ops_comp(),
"smart_scalar_parallelized" => smart_scalar_parallelized_ops(),
"smart_scalar_parallelized_comp" => smart_scalar_parallelized_ops_comp(),
"unchecked" => unchecked_ops(),
"unchecked_parallelized" => unchecked_parallelized_ops(),
"unchecked_comp" => unchecked_ops_comp(),
"unchecked_scalar" => unchecked_scalar_ops(),
"unchecked_scalar_comp" => unchecked_scalar_ops_comp(),

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
#[cfg(feature = "__c_api")]
#[cfg(all(feature = "__c_api", not(feature = "__force_skip_cbindgen")))]
fn gen_c_api() {
use std::env;
use std::path::PathBuf;
@@ -32,14 +32,15 @@ fn gen_c_api() {
}
extern crate cbindgen;
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let crate_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
let package_name = env::var("CARGO_PKG_NAME").unwrap();
let output_file = target_dir()
.join(format!("{package_name}.h"))
.display()
.to_string();
let output_file = target_dir().join(format!("{package_name}.h"));
let parse_expand_features_vec = vec![
// Note that this list may not be complete, but as macro expansion is used mostly/only for
// the C API and the HL API, this is fine, if the C API build fails or generates invalid
// headers then you likely need to add other features that will be forwarded to Cargo
// expand
#[cfg(feature = "__c_api")]
"__c_api",
#[cfg(feature = "boolean-c-api")]
@@ -63,8 +64,8 @@ fn gen_c_api() {
};
cbindgen::Builder::new()
.with_crate(crate_dir.clone())
.with_config(cbindgen::Config::from_root_or_default(crate_dir))
.with_crate(crate_dir.as_path())
.with_config(cbindgen::Config::from_file(crate_dir.join("cbindgen.toml")).unwrap())
.with_parse_expand(&parse_expand_vec)
.with_parse_expand_features(&parse_expand_features_vec)
.generate()
@@ -73,6 +74,6 @@ fn gen_c_api() {
}
fn main() {
#[cfg(feature = "__c_api")]
#[cfg(all(feature = "__c_api", not(feature = "__force_skip_cbindgen")))]
gen_c_api()
}

View File

@@ -37,4 +37,3 @@ foreach (testsourcefile ${TEST_CASES})
# Enabled asserts even in release mode
add_definitions(-UNDEBUG)
endforeach (testsourcefile ${TEST_CASES})

View File

@@ -99,8 +99,7 @@ int main(void) {
ConfigBuilder *builder;
Config *config;
config_builder_all_disabled(&builder);
config_builder_enable_default_integers_small(&builder);
config_builder_default(&builder);
config_builder_build(builder, &config);
ClientKey *client_key = NULL;

View File

@@ -110,13 +110,140 @@ int uint256_public_key(const ClientKey *client_key, const PublicKey *public_key)
return ok;
}
int int256_client_key(const ClientKey *client_key) {
int ok;
FheInt256 *lhs = NULL;
FheInt256 *rhs = NULL;
FheInt256 *result = NULL;
FheInt64 *cast_result = NULL;
// This is +1
I256 lhs_clear = {1, 0, 0, 0};
// This is -1
I256 rhs_clear = {UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX};
I256 result_clear = {0};
ok = fhe_int256_try_encrypt_with_client_key_i256(lhs_clear, client_key, &lhs);
assert(ok == 0);
ok = fhe_int256_try_encrypt_with_client_key_i256(rhs_clear, client_key, &rhs);
assert(ok == 0);
ok = fhe_int256_add(lhs, rhs, &result);
assert(ok == 0);
ok = fhe_int256_decrypt(result, client_key, &result_clear);
assert(ok == 0);
// We did 1 + (-1), so we expect 0
assert(result_clear.w0 == 0);
assert(result_clear.w1 == 0);
assert(result_clear.w2 == 0);
assert(result_clear.w3 == 0);
fhe_int256_destroy(result);
ok = fhe_int256_sub(lhs, rhs, &result);
assert(ok == 0);
ok = fhe_int256_decrypt(result, client_key, &result_clear);
assert(ok == 0);
// We did 1 - (-1), so we expect 2
assert(result_clear.w0 == 2);
assert(result_clear.w1 == 0);
assert(result_clear.w2 == 0);
assert(result_clear.w3 == 0);
// try some casting
ok = fhe_int256_cast_into_fhe_int64(result, &cast_result);
assert(ok == 0);
int64_t u64_clear;
ok = fhe_int64_decrypt(cast_result, client_key, &u64_clear);
assert(ok == 0);
assert(u64_clear == 2);
fhe_int256_destroy(lhs);
fhe_int256_destroy(rhs);
fhe_int256_destroy(result);
fhe_int64_destroy(cast_result);
return ok;
}
int int256_encrypt_trivial(const ClientKey *client_key) {
int ok;
FheInt256 *lhs = NULL;
FheInt256 *rhs = NULL;
FheInt256 *result = NULL;
I256 lhs_clear = {1, 2, 3, 4};
I256 rhs_clear = {5, 6, 7, 8};
I256 result_clear = {0};
ok = fhe_int256_try_encrypt_trivial_i256(lhs_clear, &lhs);
assert(ok == 0);
ok = fhe_int256_try_encrypt_trivial_i256(rhs_clear, &rhs);
assert(ok == 0);
ok = fhe_int256_add(lhs, rhs, &result);
assert(ok == 0);
ok = fhe_int256_decrypt(result, client_key, &result_clear);
assert(ok == 0);
assert(result_clear.w0 == 6);
assert(result_clear.w1 == 8);
assert(result_clear.w2 == 10);
assert(result_clear.w3 == 12);
fhe_int256_destroy(lhs);
fhe_int256_destroy(rhs);
fhe_int256_destroy(result);
return ok;
}
int int256_public_key(const ClientKey *client_key, const PublicKey *public_key) {
int ok;
FheInt256 *lhs = NULL;
FheInt256 *rhs = NULL;
FheInt256 *result = NULL;
// This is +1
I256 lhs_clear = {1, 0, 0, 0};
// This is -1
I256 rhs_clear = {UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX};
I256 result_clear = {0};
ok = fhe_int256_try_encrypt_with_public_key_i256(lhs_clear, public_key, &lhs);
assert(ok == 0);
ok = fhe_int256_try_encrypt_with_public_key_i256(rhs_clear, public_key, &rhs);
assert(ok == 0);
ok = fhe_int256_sub(lhs, rhs, &result);
assert(ok == 0);
ok = fhe_int256_decrypt(result, client_key, &result_clear);
assert(ok == 0);
// We did 1 - (-1), so we expect 2
assert(result_clear.w0 == 2);
assert(result_clear.w1 == 0);
assert(result_clear.w2 == 0);
assert(result_clear.w3 == 0);
fhe_int256_destroy(lhs);
fhe_int256_destroy(rhs);
fhe_int256_destroy(result);
return ok;
}
int main(void) {
int ok = 0;
ConfigBuilder *builder;
Config *config;
config_builder_all_disabled(&builder);
config_builder_enable_default_integers_small(&builder);
config_builder_default(&builder);
config_builder_build(builder, &config);
ClientKey *client_key = NULL;
@@ -132,6 +259,10 @@ int main(void) {
uint256_encrypt_trivial(client_key);
uint256_public_key(client_key, public_key);
int256_client_key(client_key);
int256_encrypt_trivial(client_key);
int256_public_key(client_key, public_key);
client_key_destroy(client_key);
public_key_destroy(public_key);
server_key_destroy(server_key);

View File

@@ -102,8 +102,7 @@ int main(void) {
ConfigBuilder *builder;
Config *config;
config_builder_all_disabled(&builder);
config_builder_enable_default_bool(&builder);
config_builder_default(&builder);
config_builder_build(builder, &config);
ClientKey *client_key = NULL;

View File

@@ -78,7 +78,7 @@ int uint256_encrypt_trivial(const ClientKey *client_key) {
return ok;
}
int uint256_public_key(const ClientKey *client_key,
int uint256_compact_public_key(const ClientKey *client_key,
const CompressedCompactPublicKey *compressed_public_key) {
int ok;
CompactPublicKey *public_key = NULL;
@@ -112,7 +112,7 @@ int uint256_public_key(const ClientKey *client_key,
lhs = expand_output[0];
rhs = expand_output[1];
// We can destroy the compact list
// The expanded ciphertext are independant from it
// The expanded ciphertext are independent from it
compact_fhe_uint256_list_destroy(list);
ok = fhe_uint256_sub(lhs, rhs, &result);
@@ -158,14 +158,88 @@ int uint256_public_key(const ClientKey *client_key,
return ok;
}
int int32_compact_public_key(const ClientKey *client_key,
const CompressedCompactPublicKey *compressed_public_key) {
int ok;
CompactPublicKey *public_key = NULL;
FheInt32 *lhs = NULL;
FheInt32 *rhs = NULL;
FheInt32 *result = NULL;
CompactFheInt32List *list = NULL;
int32_t result_clear = 0;
int32_t clears[2] = {-9482394, 98712234};
ok = compressed_compact_public_key_decompress(compressed_public_key, &public_key);
assert(ok == 0);
// Compact list example
{
ok = compact_fhe_int32_list_try_encrypt_with_compact_public_key_i32(&clears[0], 2,
public_key, &list);
assert(ok == 0);
size_t len = 0;
ok = compact_fhe_int32_list_len(list, &len);
assert(ok == 0);
assert(len == 2);
FheInt32 *expand_output[2] = {NULL};
ok = compact_fhe_int32_list_expand(list, &expand_output[0], 2);
assert(ok == 0);
// transfer ownership
lhs = expand_output[0];
rhs = expand_output[1];
// We can destroy the compact list
// The expanded ciphertext are independent from it
compact_fhe_int32_list_destroy(list);
ok = fhe_int32_sub(lhs, rhs, &result);
assert(ok == 0);
ok = fhe_int32_decrypt(result, client_key, &result_clear);
assert(ok == 0);
assert(result_clear == clears[0] - clears[1]);
fhe_int32_destroy(lhs);
fhe_int32_destroy(rhs);
fhe_int32_destroy(result);
}
{
ok = fhe_int32_try_encrypt_with_compact_public_key_i32(clears[0], public_key, &lhs);
assert(ok == 0);
ok = fhe_int32_try_encrypt_with_compact_public_key_i32(clears[1], public_key, &rhs);
assert(ok == 0);
ok = fhe_int32_add(lhs, rhs, &result);
assert(ok == 0);
ok = fhe_int32_decrypt(result, client_key, &result_clear);
assert(ok == 0);
assert(result_clear == clears[0] + clears[1]);
fhe_int32_destroy(lhs);
fhe_int32_destroy(rhs);
fhe_int32_destroy(result);
}
compact_public_key_destroy(public_key);
return ok;
}
int main(void) {
int ok = 0;
{
ConfigBuilder *builder;
Config *config;
config_builder_all_disabled(&builder);
config_builder_enable_custom_integers(&builder,
config_builder_default(&builder);
config_builder_use_custom_parameters(&builder,
SHORTINT_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS);
config_builder_build(builder, &config);
@@ -180,7 +254,8 @@ int main(void) {
uint256_client_key(client_key);
uint256_encrypt_trivial(client_key);
uint256_public_key(client_key, compressed_public_key);
uint256_compact_public_key(client_key, compressed_public_key);
int32_compact_public_key(client_key, compressed_public_key);
client_key_destroy(client_key);
compressed_compact_public_key_destroy(compressed_public_key);
@@ -191,8 +266,8 @@ int main(void) {
ConfigBuilder *builder;
Config *config;
config_builder_all_disabled(&builder);
config_builder_enable_custom_integers(&builder,
config_builder_default(&builder);
config_builder_use_custom_parameters(&builder,
SHORTINT_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_PBS_KS);
config_builder_build(builder, &config);
@@ -207,7 +282,8 @@ int main(void) {
uint256_client_key(client_key);
uint256_encrypt_trivial(client_key);
uint256_public_key(client_key, compressed_public_key);
uint256_compact_public_key(client_key, compressed_public_key);
int32_compact_public_key(client_key, compressed_public_key);
client_key_destroy(client_key);
compressed_compact_public_key_destroy(compressed_public_key);

View File

@@ -64,6 +64,67 @@ int uint8_public_key(const ClientKey *client_key, const PublicKey *public_key) {
return ok;
}
int uint8_safe_serialization(const ClientKey *client_key, const ServerKey *server_key) {
int ok;
CompactFheUint8 *lhs = NULL;
CompactFheUint8 *deserialized_lhs = NULL;
CompactFheUint8 *result = NULL;
Buffer value_buffer = {.pointer = NULL, .length = 0};
Buffer cks_buffer = {.pointer = NULL, .length = 0};
BufferView deser_view = {.pointer = NULL, .length = 0};
ClientKey *deserialized_client_key = NULL;
const uint64_t max_serialization_size = UINT64_C(1) << UINT64_C(20);
uint8_t lhs_clear = 123;
ok = client_key_serialize(client_key, &cks_buffer);
assert(ok == 0);
deser_view.pointer = cks_buffer.pointer;
deser_view.length = cks_buffer.length;
ok = client_key_deserialize(deser_view, &deserialized_client_key);
assert(ok == 0);
struct CompactPublicKey *public_key;
ok = compact_public_key_new(deserialized_client_key, &public_key);
assert(ok == 0);
ok = compact_fhe_uint8_try_encrypt_with_compact_public_key_u8(lhs_clear, public_key, &lhs);
assert(ok == 0);
ok = compact_fhe_uint8_safe_serialize(lhs, &value_buffer, max_serialization_size);
assert(ok == 0);
deser_view.pointer = value_buffer.pointer;
deser_view.length = value_buffer.length;
ok = compact_fhe_uint8_safe_deserialize_conformant(deser_view, max_serialization_size, server_key,
&deserialized_lhs);
assert(ok == 0);
FheUint8 *expanded = NULL;
ok = compact_fhe_uint8_expand(deserialized_lhs, &expanded);
assert(ok == 0);
uint8_t clear;
ok = fhe_uint8_decrypt(expanded, deserialized_client_key, &clear);
assert(ok == 0);
assert(clear == lhs_clear);
if (value_buffer.pointer != NULL) {
destroy_buffer(&value_buffer);
}
compact_fhe_uint8_destroy(lhs);
compact_fhe_uint8_destroy(deserialized_lhs);
compact_fhe_uint8_destroy(result);
fhe_uint8_destroy(expanded);
return ok;
}
int uint8_serialization(const ClientKey *client_key) {
int ok;
FheUint8 *lhs = NULL;
@@ -142,9 +203,7 @@ int main(void) {
ConfigBuilder *builder;
Config *config;
ok = config_builder_all_disabled(&builder);
assert(ok == 0);
ok = config_builder_enable_default_integers(&builder);
ok = config_builder_default(&builder);
assert(ok == 0);
ok = config_builder_build(builder, &config);
assert(ok == 0);
@@ -159,6 +218,8 @@ int main(void) {
assert(ok == 0);
ok = uint8_serialization(client_key);
assert(ok == 0);
ok = uint8_safe_serialization(client_key, server_key);
assert(ok == 0);
ok = uint8_compressed(client_key);
assert(ok == 0);
@@ -179,9 +240,7 @@ int main(void) {
ConfigBuilder *builder;
Config *config;
ok = config_builder_all_disabled(&builder);
assert(ok == 0);
ok = config_builder_enable_default_integers_small(&builder);
ok = config_builder_default_with_small_encryption(&builder);
assert(ok == 0);
ok = config_builder_build(builder, &config);
assert(ok == 0);

View File

@@ -114,14 +114,15 @@ bitflags = false
############## Options for How Your Rust library Should Be Parsed ##############
[parse]
parse_deps = true
include = ["tfhe"]
parse_deps = false
include = []
exclude = []
clean = false
extra_bindings = []
[parse.expand]
# Managed by build.rs to programmatically select features when required
crates = []
all_features = false
default_features = true

View File

@@ -5,7 +5,7 @@
## Getting Started
* [Installation](getting_started/installation.md)
* [Quick Start](getting_started/quick_start.md)
* [Operations](getting_started/operations.md)
* [Types & Operations](getting_started/operations.md)
* [Benchmarks](getting_started/benchmarks.md)
* [Security and Cryptography](getting_started/security_and_cryptography.md)
@@ -56,4 +56,3 @@
## API references
* [docs.rs](https://docs.rs/tfhe/)

View File

@@ -504,7 +504,7 @@ Pattern | Description
`/^abc$/` | Matches with content that equals exactly `abc` (case sensitive)
`/^abc$/i` | Matches with content that equals `abc` (case insensitive)
`/abc/` | Matches with content that contains somewhere `abc`
`/ab?c/` | Matches with content that contains somewhere `abc` or somwhere `ab`
`/ab?c/` | Matches with content that contains somewhere `abc` or somewhere `ab`
`/^ab*c$/` | For example, matches with: `ac`, `abc`, `abbbbc`
`/^[a-c]b\|cd$/` | Matches with: `ab`, `bb`, `cb`, `cd`
`/^[a-c]b\|cd$/i` | Matches with: `ab`, `Ab`, `aB`, ..., `cD`, `CD`

View File

@@ -9,7 +9,7 @@ Welcome to this tutorial about `TFHE-rs` `core_crypto` module.
To use `TFHE-rs`, it first has to be added as a dependency in the `Cargo.toml`:
```toml
tfhe = { version = "0.4.0", features = [ "x86_64-unix" ] }
tfhe = { version = "0.5.0", features = [ "x86_64-unix" ] }
```
This enables the `x86_64-unix` feature to have efficient implementations of various algorithms for `x86_64` CPUs on a Unix-like system. The 'unix' suffix indicates that the `UnixSeeder`, which uses `/dev/random` to generate random numbers, is activated as a fallback if no hardware number generator is available (like `rdseed` on `x86_64` or if the [`Randomization Services`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc) on Apple platforms are not available). To avoid having the `UnixSeeder` as a potential fallback or to run on non-Unix systems (e.g., Windows), the `x86_64` feature is sufficient.
@@ -19,19 +19,19 @@ For Apple Silicon, the `aarch64-unix` or `aarch64` feature should be enabled. `a
In short: For `x86_64`-based machines running Unix-like OSes:
```toml
tfhe = { version = "0.4.0", features = ["x86_64-unix"] }
tfhe = { version = "0.5.0", features = ["x86_64-unix"] }
```
For Apple Silicon or aarch64-based machines running Unix-like OSes:
```toml
tfhe = { version = "0.4.0", features = ["aarch64-unix"] }
tfhe = { version = "0.5.0", features = ["aarch64-unix"] }
```
For `x86_64`-based machines with the [`rdseed instruction`](https://en.wikipedia.org/wiki/RDRAND) running Windows:
```toml
tfhe = { version = "0.4.0", features = ["x86_64"] }
tfhe = { version = "0.5.0", features = ["x86_64"] }
```
### Commented code to double a 2-bit message in a leveled fashion and using a PBS with the `core_crypto` module.
@@ -249,7 +249,7 @@ pub fn main() {
println!("Checking result...");
assert_eq!(6, pbs_multiplication_result);
println!(
"Mulitplication via PBS result is correct! Expected 6, got {pbs_multiplication_result}"
"Multiplication via PBS result is correct! Expected 6, got {pbs_multiplication_result}"
);
}
```

View File

@@ -35,7 +35,7 @@ fn main() {
Note that both the `client_key` and `server_key` implement the `Serialize` and `Deserialize` traits. This way you can use any compatible serializer to store/send the data. To store the `server_key` in a binary file, you can use the `bincode` library:
```rust
use std::fs::File;
use std::fs::{File, create_dir_all};
use std::io::{Write, Read};
use tfhe::boolean::prelude::*;
@@ -49,7 +49,13 @@ fn main() {
// We serialize the server key to bytes, and store them in a file:
let encoded: Vec<u8> = bincode::serialize(&server_key).unwrap();
let server_key_file = "/tmp/tutorial_server_key.bin";
// Create a tmp dir with the current user name to avoid cluttering the /tmp dir
let user = std::env::var("USER").unwrap_or_else(|_| "unknown_user".to_string());
let tmp_dir_for_user = &format!("/tmp/{user}");
create_dir_all(tmp_dir_for_user).unwrap();
let server_key_file = &format!("{tmp_dir_for_user}/tutorial_server_key.bin");
// We write the server key to a file:
let mut file = File::create(server_key_file)

View File

@@ -8,7 +8,7 @@ Here is an example using the `bincode` serialization library, which serializes t
binary format:
```rust
use std::fs::File;
use std::fs::{File, create_dir_all};
use std::io::{Write, Read};
use tfhe::boolean::prelude::*;
@@ -20,8 +20,14 @@ fn main() {
let encoded_server_key: Vec<u8> = bincode::serialize(&server_key).unwrap();
let encoded_client_key: Vec<u8> = bincode::serialize(&client_key).unwrap();
let server_key_file = "/tmp/ser_example_server_key.bin";
let client_key_file = "/tmp/ser_example_client_key.bin";
// Create a tmp dir with the current user name to avoid cluttering the /tmp dir
let user = std::env::var("USER").unwrap_or_else(|_| "unknown_user".to_string());
let tmp_dir_for_user = &format!("/tmp/{user}");
create_dir_all(tmp_dir_for_user).unwrap();
let server_key_file = &format!("{tmp_dir_for_user}/ser_example_server_key.bin");
let client_key_file = &format!("{tmp_dir_for_user}/ser_example_client_key.bin");
// We write the keys to files:
let mut file = File::create(server_key_file)

View File

@@ -17,7 +17,7 @@ This crate implements two ways to represent an integer:
The first possibility to represent a large integer is to use a Radix-based decomposition on the plaintexts. Let $$B \in \mathbb{N}$$ be a basis such that the size of $$B$$ is smaller than (or equal to) 4 bits. Then, an integer $$m \in \mathbb{N}$$ can be written as $$m = m_0 + m_1*B + m_2*B^2 + ...$$, where each $$m_i$$ is strictly smaller than $$B$$. Each $$m_i$$ is then independently encrypted. In the end, an Integer ciphertext is defined as a set of shortint ciphertexts.
The definition of an integer requires a basis and a number of blocks. This is done at key generation. Below, the keys are dedicated to unsigned integers encrypting messages over 8 bits, using a basis over 2 bits (i.e., $$B=2^2$$) and 4 blocks.
The definition of an integer requires a basis and a number of blocks. These parameters are chosen at key generation. Below, the keys are dedicated to integers encrypting messages over 8 bits, using a basis over 2 bits (i.e., $$B=2^2$$) and 4 blocks.
```rust
use tfhe::integer::gen_keys_radix;
@@ -93,6 +93,10 @@ Each operation may come in different 'flavors':
Not all operations have these 4 flavors, as some of them are implemented in a way that the operation is always possible without ever exceeding the plaintext space capacity.
{% hint style="info" %}
If you don't know which flavor to use, you should use the `default` one.
{% endhint %}
## How to use each operation type
Let's try to do a circuit evaluation using the different flavors of already introduced operations. For a very small circuit, the `unchecked` flavor may be enough to do the computation correctly. Otherwise, `checked` and `smart` are the best options.
@@ -162,12 +166,15 @@ fn main() {
assert!(result.is_ok());
let result = server_key.checked_sub_assign(&mut ct_1, &ct_2);
assert!(result.is_ok());
let result = server_key.checked_add_assign(&mut ct_1, &ct_3);
assert!(result.is_err());
// We use the client key to decrypt the output of the circuit:
// Only the scalar multiplication could be done
let output: u64 = client_key.decrypt(&ct_1);
assert_eq!(output, (msg1 * scalar) % modulus as u64);
assert_eq!(output, ((msg1 * scalar) - msg2) % modulus as u64);
}
```
@@ -208,6 +215,14 @@ fn main() {
}
```
{% hint style="warning" %}
You must avoid cloning the inputs when calling `smart` operations to preserve performance. For instance, you SHOULD NOT have these kind of patterns in the code:
```Rust
sks.smart_add(&mut a.clone(), &mut b.clone());
```
{% endhint %}
The main advantage of the default flavor is to ensure predictable timings, as long as only this kind of operation is used. Only the parallelized version of the operations is provided.
{% hint style="warning" %}

View File

@@ -1,6 +1,6 @@
# Tutorial
`tfhe::integer` is dedicated to unsigned integers smaller than 256 bits. The steps to homomorphically evaluate an integer circuit are described here.
`tfhe::integer` is dedicated to integers smaller than 256 bits. The steps to homomorphically evaluate an integer circuit are described here.
## Key Types
@@ -25,7 +25,7 @@ To generate the keys, a user needs two parameters:
* A set of `shortint` cryptographic parameters.
* The number of ciphertexts used to encrypt an integer (we call them "shortint blocks").
We are now going to build a pair of keys that can encrypt an **8-bit** integer by using **4** shortint blocks that store **2** bits of message each.
We are now going to build a pair of keys that can encrypt **8-bit** integers (signed or unsigned) by using **4** shortint blocks that store **2** bits of message each.
```rust
use tfhe::integer::gen_keys_radix;

View File

@@ -40,8 +40,7 @@ use tfhe::{ConfigBuilder, generate_keys, set_server_key, FheUint8};
use tfhe::prelude::*;
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
let config = ConfigBuilder::default()
.build();
let (client_key, server_key) = generate_keys(config);
@@ -141,7 +140,7 @@ use tfhe::integer::gen_keys_radix;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
fn main() {
// We create keys for radix represention to create 16 bits integers
// We create keys for radix representation to create 16 bits integers
// using 8 blocks of 2 bits
let (cks, sks) = gen_keys_radix(PARAM_MESSAGE_2_CARRY_2, 8);

View File

@@ -37,8 +37,14 @@ Each operation may come in different 'flavors':
Not all operations have these 4 flavors, as some of them are implemented in a way that the operation is always possible without ever exceeding the plaintext space capacity.
{% hint style="info" %}
If you don't know which flavor to use, you should use the `default` one.
{% endhint %}
## How to use operation types
Let's try to do a circuit evaluation using the different flavors of operations that we have already introduced. For a very small circuit, the `unchecked` flavour may be enough to do the computation correctly. Otherwise,`checked` and `smart` are the best options.
Let's do a scalar multiplication, a subtraction, and a multiplication.
@@ -367,14 +373,14 @@ fn main() {
let modulus = client_key.parameters.message_modulus().0 as u64;
// We use the private client key to encrypt two messages:
let ct_1 = client_key.encrypt(msg1);
let mut ct_1 = client_key.encrypt(msg1);
let mut ct_2 = client_key.encrypt(msg2);
// Compute the lookup table for the bivariate functions
let acc = server_key.generate_lookup_table_bivariate(|x,y| (x.count_ones()
+ y.count_ones()) as u64 % modulus );
let ct_res = server_key.smart_apply_lookup_table_bivariate(&ct_1, &mut ct_2, &acc);
let ct_res = server_key.smart_apply_lookup_table_bivariate(&mut ct_1, &mut ct_2, &acc);
// We use the client key to decrypt the output of the circuit:
let output = client_key.decrypt(&ct_res);

View File

@@ -1,6 +1,6 @@
# Tutorial
`tfhe::shortint` is dedicated to small unsigned integers smaller than 8 bits. The steps to homomorphically evaluate a circuit are described below.
`tfhe::shortint` is dedicated to unsigned integers smaller than 8 bits. The steps to homomorphically evaluate a circuit are described below.
## Key generation

View File

@@ -1,101 +1,106 @@
# Benchmarks
Due to their nature, homomorphic operations are naturally slower than their clear equivalent. Some timings are exposed for basic operations. For completeness, benchmarks for other libraries are also given.
Due to their nature, homomorphic operations are naturally slower than their cleartext equivalents. Some timings are exposed for basic operations. For completeness, benchmarks for other libraries are also given.
{% hint style="info" %}
All benchmarks were launched on an AWS m6i.metal with the following specifications: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz and 512GB of RAM.
{% endhint %}
## Integer
This measures the execution time for some operation sets of tfhe-rs::integer (the unsigned version). Note that the timings for `FheInt` (i.e., the signed integers) are similar.
| Operation \ Size | `FheUint8` | `FheUint16` | `FheUint32` | `FheUint64` | `FheUint128` | `FheUint256` |
|--------------------------------------------------------|------------|-------------|-------------|-------------|--------------|--------------|
| Negation (`-`) | 70.9 ms | 99.3 ms | 129 ms | 180 ms | 239 ms | 333 ms |
| Add / Sub (`+`,`-`) | 70.5 ms | 100 ms | 132 ms | 186 ms | 249 ms | 334 ms |
| Mul (`x`) | 144 ms | 216 ms | 333 ms | 832 ms | 2.50 s | 8.85 s |
| Equal / Not Equal (`eq`, `ne`) | 36.1 ms | 36.5 ms | 57.4 ms | 64.2 ms | 67.3 ms | 78.1 ms |
| Comparisons (`ge`, `gt`, `le`, `lt`) | 52.6 ms | 73.1 ms | 98.8 ms | 124 ms | 165 ms | 201 ms |
| Max / Min (`max`,`min`) | 76.2 ms | 102 ms | 135 ms | 171 ms | 212 ms | 301 ms |
| Bitwise operations (`&`, `\|`, `^`) | 19.4 ms | 20.3 ms | 21.0 ms | 27.2 ms | 31.6 ms | 40.2 ms |
| Div / Rem (`/`, `%`) | 729 ms | 1.93 s | 4.81 s | 12.2 s | 30.7 s | 89.6 s |
| Left / Right Shifts (`<<`, `>>`) | 99.4 ms | 129 ms | 180 ms | 243 ms | 372 ms | 762 ms |
| Left / Right Rotations (`left_rotate`, `right_rotate`) | 103 ms | 128 ms | 182 ms | 241 ms | 374 ms | 763 ms |
All timings are related to parallelized Radix-based integer operations, where each block is encrypted using the default parameters (i.e., PARAM\_MESSAGE\_2\_CARRY\_2\_KS\_PBS, more information about parameters can be found [here](../fine_grained_api/shortint/parameters.md)).
To ensure predictable timings, the operation flavor is the `default` one: the carry is propagated if needed. The operation costs may be reduced by using `unchecked`, `checked`, or `smart`.
## Shortint
This measures the execution time for some operations using various parameter sets of tfhe-rs::shortint. Except for `unchecked_add`, all timings are related to the `default` operations. This flavor ensures predictable timings for an operation along the entire circuit by clearing the carry space after each operation.
This uses the Concrete FFT + AVX-512 configuration.
| Parameter set | PARAM\_MESSAGE\_1\_CARRY\_1 | PARAM\_MESSAGE\_2\_CARRY\_2 | PARAM\_MESSAGE\_3\_CARRY\_3 | PARAM\_MESSAGE\_4\_CARRY\_4 |
|------------------------------------|-----------------------------|-----------------------------|-----------------------------|-----------------------------|
| unchecked\_add | 348 ns | 413 ns | 2.95 µs | 12.1 µs |
| add | 7.59 ms | 17.0 ms | 121 ms | 835 ms |
| mul\_lsb | 8.13 ms | 16.8 ms | 121 ms | 827 ms |
| keyswitch\_programmable\_bootstrap | 7.28 ms | 16.6 ms | 121 ms | 811 ms |
## Boolean
This measures the execution time of a single binary Boolean gate.
### tfhe-rs::boolean.
| Parameter set | Concrete FFT | Concrete FFT + AVX-512 |
| --------------------- | ------------ | ---------------------- |
| DEFAULT\_PARAMETERS | 8.8ms | 6.8ms |
| TFHE\_LIB\_PARAMETERS | 13.6ms | 10.9ms |
| Parameter set | Concrete FFT + AVX-512 |
|------------------------------------------------------|------------------------|
| DEFAULT\_PARAMETERS\_KS\_PBS | 9.19 ms |
| PARAMETERS\_ERROR\_PROB\_2\_POW\_MINUS\_165\_KS\_PBS | 14.1 ms |
| TFHE\_LIB\_PARAMETERS | 10.0 ms |
### tfhe-lib.
| Parameter set | fftw | spqlios-fma |
| ------------------------------------------------ | ------ | ----------- |
| default\_128bit\_gate\_bootstrapping\_parameters | 28.9ms | 15.7ms |
Using the same m6i.metal machine as the one for tfhe-rs, the timings are:
### OpenFHE.
| Parameter set | spqlios-fma |
|--------------------------------------------------|-------------|
| default\_128bit\_gate\_bootstrapping\_parameters | 15.4 ms |
| Parameter set | GINX | GINX (Intel HEXL) |
| ------------- | ----- | ----------------- |
| STD\_128 | 172ms | 78ms |
| MEDIUM | 113ms | 50.2ms |
### OpenFHE (v1.1.1).
Following the official instructions from OpenFHE, `clang14` and the following command are used to setup the project:
`cmake -DNATIVE_SIZE=32 -DWITH_NATIVEOPT=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DWITH_OPENMP=OFF ..`
To use the HEXL library, the configuration used is as follows:
```bash
export CXX=clang++
export CC=clang
scripts/configure.sh
Release -> y
hexl -> y
scripts/build-openfhe-development-hexl.sh
```
Using the same m6i.metal machine as the one for tfhe-rs, the timings are:
| Parameter set | GINX | GINX w/ Intel HEXL |
|----------------------------------|---------|--------------------|
| FHEW\_BINGATE/STD128\_OR | 40.2 ms | 31.0 ms |
| FHEW\_BINGATE/STD128\_LMKCDEY_OR | 38.6 ms | 28.4 ms |
## Integer
This measures the execution time for some operation sets of tfhe-rs::integer.
## How to reproduce TFHE-rs benchmarks
| Operation \ Size | `FheUint8` | `FheUint16` | `FheUint32` | ` FheUint64` | `FheUint128` | `FheUint256` |
|--------------------------------------------------------|------------|-------------|-------------|--------------|--------------|--------------|
| Negation (`-`) | 80.4 ms | 106 ms | 132 ms | 193 ms | 257 ms | 348 ms |
| Add / Sub (`+`,`-`) | 81.5 ms | 110 ms | 139 ms | 200 ms | 262 ms | 355 ms |
| Mul (`x`) | 150 ms | 221 ms | 361 ms | 928 ms | 2.90 s | 10.97 s |
| Equal / Not Equal (`eq`, `ne`) | 39.4 ms | 40.2 ms | 61.1 ms | 66.4 ms | 74.5 ms | 85.7 ms |
| Comparisons (`ge`, `gt`, `le`, `lt`) | 57.5 ms | 79.6 ms | 105 ms | 136 ms | 174 ms | 219 ms |
| Max / Min (`max`,`min`) | 100 ms | 130 ms | 163 ms | 204 ms | 245 ms | 338 ms |
| Bitwise operations (`&`, `|`, `^`) | 20.7 ms | 21.1 ms | 22.6 ms | 30.2 ms | 34.1 ms | 42.1 ms |
| Div / Rem (`/`, `%`) | 1.37 s | 3.50 s | 9.12 s | 23.9 s | 59.9 s | 149.2 s |
| Left / Right Shifts (`<<`, `>>`) | 106 ms | 140 ms | 202 ms | 262 ms | 403 ms | 827 ms |
| Left / Right Rotations (`left_rotate`, `right_rotate`) | 105 ms | 140 ms | 199 ms | 263 ms | 403 ms | 829 ms |
All timings are related to parallelized Radix-based integer operations, where each block is encrypted using the default parameters (i.e., PARAM\_MESSAGE\_2\_CARRY\_2, more information about parameters can be found [here](../fine_grained_api/shortint/parameters.md)).
To ensure predictable timings, the operation flavor is the `default` one: the carry is propagated if needed. The operation costs could be reduced by using `unchecked`, `checked`, or `smart`.
## Shortint
This measures the execution time for some operations using various parameter sets of tfhe-rs::shortint.
This uses the Concrete FFT + AVX-512 configuration.
| Parameter set | unchecked\_add | unchecked\_mul\_lsb | keyswitch\_programmable\_bootstrap |
|-----------------------------|----------------|---------------------|------------------------------------|
| PARAM\_MESSAGE\_1\_CARRY\_1 | 338 ns | 8.3 ms | 8.1 ms |
| PARAM\_MESSAGE\_2\_CARRY\_2 | 406 ns | 18.4 ms | 18.4 ms |
| PARAM\_MESSAGE\_3\_CARRY\_3 | 3.06 µs | 134 ms | 129.4 ms |
| PARAM\_MESSAGE\_4\_CARRY\_4 | 11.7 µs | 854 ms | 828.1 ms |
Next, the timings for the operation flavor `default` are given. This flavor ensures predictable timings of an operation along the entire circuit by clearing the carry space after each operation.
| Parameter set | add | mul\_lsb | keyswitch\_programmable\_bootstrap |
| --------------------------- | -------------- | ------------------- | ---------------------------------- |
| PARAM\_MESSAGE\_1\_CARRY\_1 | 7.90 ms | 8.00 ms | 8.10 ms |
| PARAM\_MESSAGE\_2\_CARRY\_2 | 18.4 ms | 18.1 ms | 18.4 ms |
| PARAM\_MESSAGE\_3\_CARRY\_3 | 131.5 ms | 129.5 ms | 129.4 ms |
| PARAM\_MESSAGE\_4\_CARRY\_4 | 852.5 ms | 839.7 ms | 828.1 ms |
## How to reproduce benchmarks
TFHE-rs benchmarks can easily be reproduced from the [sources](https://github.com/zama-ai/tfhe-rs).
TFHE-rs benchmarks can be easily reproduced from [source](https://github.com/zama-ai/tfhe-rs).
```shell
#Boolean benchmarks:
make bench_boolean
make AVX512_SUPPORT=ON bench_boolean
#Integer benchmarks:
make bench_integer
#Shortint benchmarks:
make bench_shortint
```
If the host machine supports AVX-512, then the argument `AVX512_SUPPORT=ON' should be added, e.g.:
```shell
#Integer benchmarks:
make AVX512_SUPPORT=ON bench_integer
#Shortint benchmarks:
make AVX512_SUPPORT=ON bench_shortint
```
If the host machine does not support AVX512, then turning on `AVX512_SUPPORT` will not provide any speed-up.

View File

@@ -4,12 +4,22 @@
## Importing into your project
To use `TFHE-rs` in your project, you first need to add it as a dependency in your `Cargo.toml`:
To use `TFHE-rs` in your project, you first need to add it as a dependency in your `Cargo.toml`.
If you are using an `x86` machine:
```toml
tfhe = { version = "0.4.0", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
tfhe = { version = "0.5.0", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
```
If you are using an `ARM` machine:
```toml
tfhe = { version = "0.5.0", features = [ "boolean", "shortint", "integer", "aarch64-unix" ] }
```
{% hint style="info" %}
You need to use a Rust version >= 1.72 to compile TFHE-rs.
{% endhint %}
{% hint style="success" %}
When running code that uses `TFHE-rs`, it is highly recommended to run in release mode with cargo's `--release` flag to have the best possible performance
{% endhint %}
@@ -25,7 +35,3 @@ TFHE-rs is supported on Linux (x86, aarch64), macOS (x86, aarch64) and Windows (
| Linux | `x86_64-unix` | `aarch64-unix`\* |
| macOS | `x86_64-unix` | `aarch64-unix`\* |
| Windows | `x86_64` | Unsupported |
{% hint style="info" %}
Users who have ARM devices can compile TFHE-rs using a stable toolchain with version >= 1.72 (see [Configuration](../how_to/rust_configuration.md) for more details).
{% endhint %}

View File

@@ -1,260 +1,57 @@
# Operations
# Homomorphic Types and Operations
The table below contains an overview of the available operations in `TFHE-rs`. More details, and further examples, are given in the following sections.
## Types
`TFHE-rs` includes two main types to represent encrypted data:
- `FheUint`: this is the homomorphic equivalent of Rust unsigned integers `u8, u16, ...`
- `FheInt`: this is the homomorphic equivalent of Rust (signed) integers `i8, i16, ...`
| name | symbol | FheUint/FheUint | FheUint/Uint | Uint/FheUint |
|-----------------------|-------------|--------------------|--------------------------|--------------------------|
| Neg | `-` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Add | `+` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Sub | `-` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Mul | `*` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Div | `/` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Rem | `%` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Not | `!` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| BitAnd | `&` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| BitOr | `\|` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| BitXor | `^` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Shr | `>>` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Shl | `<<` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Min | `min` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Max | `max` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Greater than | `gt` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Greater or equal than | `ge` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Lower than | `lt` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Lower or equal than | `le` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Equal | `eq` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| Cast (into dest type) | `cast_into` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: |
| Cast (from src type) | `cast_from` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: |
In the same manner as many programming languages, the number of bits used to represent the data must be chosen when declaring a variable. For instance:
## Boolean Operations
```Rust
// let clear_a: u64 = 7;
let mut a = FheUint64::try_encrypt(clear_a, &keys)?;
Native homomorphic Booleans support common Boolean operations.
// let clear_b: i8 = 3;
let mut b = FheInt8::try_encrypt(clear_b, &keys)?;
The list of supported operations is:
| name | symbol | type |
| ------------------------------------------------------------- | ------ | ------ |
| [BitAnd](https://doc.rust-lang.org/std/ops/trait.BitAnd.html) | `&` | Binary |
| [BitOr](https://doc.rust-lang.org/std/ops/trait.BitOr.html) | `\|` | Binary |
| [BitXor](https://doc.rust-lang.org/std/ops/trait.BitXor.html) | `^` | Binary |
| [Not](https://doc.rust-lang.org/std/ops/trait.Not.html) | `!` | Unary |
## ShortInt Operations
Native small homomorphic integer types (e.g., FheUint3 or FheUint4) easily compute various operations. In general, computing over encrypted data is as easy as computing over clear data, since the same operation symbol is used. The addition between two ciphertexts is done using the symbol `+` between two FheUint values. Many operations can be computed between a clear value (i.e. a scalar) and a ciphertext.
In Rust, operations on native types are modular. For example, computations on `u8` are carried out modulo $$2^{8}$$. A similar idea applies for FheUintX, where operations are done modulo $$2^{X}$$. For FheUint3, operations are done modulo $$8 = 2^{3}$$.
### Arithmetic operations.
Small homomorphic integer types support all common arithmetic operations, meaning `+`, `-`, `x`, `/`, `mod`.
The division operation implements a subtlety: since data is encrypted, it is possible to compute a division by 0. In this case, the division is tweaked so that dividing by 0 returns the max possible value for the message.
The list of supported operations is:
| name | symbol | type |
| ------------------------------------------------------- | ------ | ------ |
| [Add](https://doc.rust-lang.org/std/ops/trait.Add.html) | `+` | Binary |
| [Sub](https://doc.rust-lang.org/std/ops/trait.Sub.html) | `-` | Binary |
| [Mul](https://doc.rust-lang.org/std/ops/trait.Mul.html) | `*` | Binary |
| [Div](https://doc.rust-lang.org/std/ops/trait.Div.html) | `/` | Binary |
| [Rem](https://doc.rust-lang.org/std/ops/trait.Rem.html) | `%` | Binary |
| [Neg](https://doc.rust-lang.org/std/ops/trait.Neg.html) | `-` | Unary |
A simple example on how to use these operations:
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint3};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled().enable_default_uint3().build();
let (keys, server_keys) = generate_keys(config);
set_server_key(server_keys);
let clear_a = 7;
let clear_b = 3;
let clear_c = 2;
let mut a = FheUint3::try_encrypt(clear_a, &keys)?;
let mut b = FheUint3::try_encrypt(clear_b, &keys)?;
let mut c = FheUint3::try_encrypt(clear_c, &keys)?;
a = a * &b; // Clear equivalent computations: 7 * 3 mod 8 = 5
b = &b + &c; // Clear equivalent computations: 3 + 2 mod 8 = 5
b = b - 5; // Clear equivalent computations: 5 - 5 mod 8 = 0
let dec_a = a.decrypt(&keys);
let dec_b = b.decrypt(&keys);
// We homomorphically swapped values using bitwise operations
assert_eq!(dec_a, (clear_a * clear_b) % 8);
assert_eq!(dec_b, ((clear_b + clear_c) - 5) % 8);
Ok(())
}
// let clear_c: u128 = 2;
let mut c = FheUint128::try_encrypt(clear_c, &keys)?;
```
### Bitwise operations.
## Operation list
The table below contains an overview of the available operations in `TFHE-rs`. The notation `Enc` (for Encypted) either refers to `FheInt` or `FheUint`, for any size between 1 and 256-bits.
Small homomorphic integer types support some bitwise operations.
More details, and further examples, are given in the following sections.
The list of supported operations is:
| name | symbol | `Enc`/`Enc` | `Enc`/ `Int` |
|-----------------------|----------------|--------------------|--------------------------|
| Neg | `-` | :heavy_check_mark: | :heavy_check_mark: |
| Add | `+` | :heavy_check_mark: | :heavy_check_mark: |
| Sub | `-` | :heavy_check_mark: | :heavy_check_mark: |
| Mul | `*` | :heavy_check_mark: | :heavy_check_mark: |
| Div | `/` | :heavy_check_mark: | :heavy_check_mark: |
| Rem | `%` | :heavy_check_mark: | :heavy_check_mark: |
| Not | `!` | :heavy_check_mark: | :heavy_check_mark: |
| BitAnd | `&` | :heavy_check_mark: | :heavy_check_mark: |
| BitOr | `\|` | :heavy_check_mark: | :heavy_check_mark: |
| BitXor | `^` | :heavy_check_mark: | :heavy_check_mark: |
| Shr | `>>` | :heavy_check_mark: | :heavy_check_mark: |
| Shl | `<<` | :heavy_check_mark: | :heavy_check_mark: |
| Min | `min` | :heavy_check_mark: | :heavy_check_mark: |
| Max | `max` | :heavy_check_mark: | :heavy_check_mark: |
| Greater than | `gt` | :heavy_check_mark: | :heavy_check_mark: |
| Greater or equal than | `ge` | :heavy_check_mark: | :heavy_check_mark: |
| Lower than | `lt` | :heavy_check_mark: | :heavy_check_mark: |
| Lower or equal than | `le` | :heavy_check_mark: | :heavy_check_mark: |
| Equal | `eq` | :heavy_check_mark: | :heavy_check_mark: |
| Cast (into dest type) | `cast_into` | :heavy_check_mark: | :heavy_multiplication_x: |
| Cast (from src type) | `cast_from` | :heavy_check_mark: | :heavy_multiplication_x: |
| Ternary operator | `if_then_else` | :heavy_check_mark: | :heavy_multiplication_x: |
| name | symbol | type |
|--------------------------------------------------------------------------------------|----------------|--------|
| [Not](https://doc.rust-lang.org/std/ops/trait.Not.html) | `!` | Unary |
| [BitAnd](https://doc.rust-lang.org/std/ops/trait.BitAnd.html) | `&` | Binary |
| [BitOr](https://doc.rust-lang.org/std/ops/trait.BitOr.html) | `\|` | Binary |
| [BitXor](https://doc.rust-lang.org/std/ops/trait.BitXor.html) | `^` | Binary |
| [Shr](https://doc.rust-lang.org/std/ops/trait.Shr.html) | `>>` | Binary |
| [Shl](https://doc.rust-lang.org/std/ops/trait.Shl.html) | `<<` | Binary |
| [Rotate Right](https://doc.rust-lang.org/std/primitive.u32.html#method.rotate_right) | `rotate_right` | Binary |
| [Rotate Left](https://doc.rust-lang.org/std/primitive.u32.html#method.rotate_left) | `rotate_left` | Binary |
A simple example on how to use these operations:
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint3};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled().enable_default_uint3().build();
let (keys, server_keys) = generate_keys(config);
set_server_key(server_keys);
let clear_a = 7;
let clear_b = 3;
let mut a = FheUint3::try_encrypt(clear_a, &keys)?;
let mut b = FheUint3::try_encrypt(clear_b, &keys)?;
a = a ^ &b;
b = b ^ &a;
a = a ^ &b;
let dec_a = a.decrypt(&keys);
let dec_b = b.decrypt(&keys);
// We homomorphically swapped values using bitwise operations
assert_eq!(dec_a, clear_b);
assert_eq!(dec_b, clear_a);
Ok(())
}
```
### Comparisons.
Small homomorphic integer types support comparison operations.
Due to some Rust limitations, it is not possible to overload the comparison symbols because of the inner definition of the operations. Rust expects to have a Boolean as an output, whereas a ciphertext is returned when using homomorphic types.
You will need to use different methods instead of using symbols for the comparisons. These methods follow the same naming conventions as the two standard Rust traits:
* [PartialOrd](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html)
* [PartialEq](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html)
The list of supported operations is:
| name | symbol | type |
|-----------------------------------------------------------------------------|--------|--------|
| [Equal ](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html) | `eq` | Binary |
| [Not Equal ](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html) | `ne` | Binary |
| [Greater Than ](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `gt` | Binary |
| [Greater or Equal](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `ge` | Binary |
| [Lower ](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `lt` | Binary |
| [Lower or Equal ](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `le` | Binary |
A simple example on how to use these operations:
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint3};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled().enable_default_uint3().build();
let (keys, server_keys) = generate_keys(config);
set_server_key(server_keys);
let clear_a = 7;
let clear_b = 3;
let mut a = FheUint3::try_encrypt(clear_a, &keys)?;
let mut b = FheUint3::try_encrypt(clear_b, &keys)?;
assert_eq!(a.gt(&b).decrypt(&keys) != 0, true);
assert_eq!(b.le(&a).decrypt(&keys) != 0, true);
Ok(())
}
```
### Univariate function evaluation.
The shortint type also supports the computation of univariate functions, which make use of TFHE's _programmable bootstrapping_.
A simple example on how to use these operations:
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint4};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled().enable_default_uint4().build();
let (keys, server_keys) = generate_keys(config);
set_server_key(server_keys);
let pow_5 = |value: u64| {
value.pow(5) % FheUint4::MODULUS as u64
};
let clear_a = 12;
let a = FheUint4::try_encrypt(12, &keys)?;
let c = a.map(pow_5);
let decrypted = c.decrypt(&keys);
assert_eq!(decrypted, pow_5(clear_a) as u8);
Ok(())
}
```
### Bivariate function evaluations.
Using the shortint type allows you to evaluate bivariate functions (i.e., functions that take two ciphertexts as input).
A simple code example:
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint2};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled().enable_default_uint2().build();
let (keys, server_keys) = generate_keys(config);
set_server_key(server_keys);
let clear_a = 1;
let clear_b = 3;
let a = FheUint2::try_encrypt(clear_a, &keys)?;
let b = FheUint2::try_encrypt(clear_b, &keys)?;
let c = a.bivariate_function(&b, std::cmp::max);
let decrypted = c.decrypt(&keys);
assert_eq!(decrypted, std::cmp::max(clear_a, clear_b) as u8);
Ok(())
}
```
## Integer
In TFHE-rs, integers are used to encrypt any messages larger than 4 bits. All supported operations are listed below.
In `TFHE-rs`, integers are used to encrypt all messages which are larger than 4 bits. All supported operations are listed below.
### Arithmetic operations.
@@ -271,40 +68,43 @@ The list of supported operations is:
| [Div](https://doc.rust-lang.org/std/ops/trait.Div.html)* | `/` | Binary |
| [Rem](https://doc.rust-lang.org/std/ops/trait.Rem.html)* | `%` | Binary |
For division by $$0$$, the convention is to return $$modulus - 1$$. For instance, for FheUint8, the modulus is $$2^8=256$$, so a division by $$0$$ will return an encryption of $$255$$.
For the remainder operator, the convention is to return the first input without any modification. For instance, for $$ct1 = FheUint8(63)$$ and $$ct2 = FheUint8(0)$$, then $$ct1 % ct2$$ will return $$FheUint8(63)$$.
For division by 0, the convention is to return `modulus - 1`. For instance, for `FheUint8`, the modulus is $$2^8=256$$, so a division by 0 will return an encryption of 255.
For the remainder operator, the convention is to return the first input without any modification. For instance, if `ct1 = FheUint8(63)` and `ct2 = FheUint8(0)` then `ct1 % ct2` will return `FheUint8(63)`.
A simple example on how to use these operations:
A simple example of how to use these operations:
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8};
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheInt8, FheUint8};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled().enable_default_integers().build();
let config = ConfigBuilder::default().build();
let (keys, server_keys) = generate_keys(config);
set_server_key(server_keys);
let clear_a = 15_u64;
let clear_b = 27_u64;
let clear_c = 43_u64;
let clear_d = -87_i64;
let mut a = FheUint8::try_encrypt(clear_a, &keys)?;
let mut b = FheUint8::try_encrypt(clear_b, &keys)?;
let mut c = FheUint8::try_encrypt(clear_c, &keys)?;
let mut d = FheInt8::try_encrypt(clear_d, &keys)?;
a = a * &b; // Clear equivalent computations: 15 * 27 mod 256 = 149
b = &b + &c; // Clear equivalent computations: 27 + 43 mod 256 = 70
a = a * &b; // Clear equivalent computations: 15 * 27 mod 256 = 149
b = &b + &c; // Clear equivalent computations: 27 + 43 mod 256 = 70
b = b - 76u8; // Clear equivalent computations: 70 - 76 mod 256 = 250
d = d - 13i8; // Clear equivalent computations: -87 - 13 = 100 in [-128, 128[
let dec_a: u8 = a.decrypt(&keys);
let dec_b: u8 = b.decrypt(&keys);
let dec_d: i8 = d.decrypt(&keys);
assert_eq!(dec_a, ((clear_a * clear_b) % 256_u64) as u8);
assert_eq!(dec_b, (((clear_b + clear_c).wrapping_sub(76_u64)) % 256_u64) as u8);
assert_eq!(dec_d, (clear_d - 13) as i8);
Ok(())
}
@@ -327,14 +127,14 @@ The list of supported operations is:
| [Rotate Right](https://doc.rust-lang.org/std/primitive.u32.html#method.rotate_right) | `rotate_right` | Binary |
| [Rotate Left](https://doc.rust-lang.org/std/primitive.u32.html#method.rotate_left) | `rotate_left` | Binary |
A simple example on how to use these operations:
A simple example of how to use these operations:
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled().enable_default_integers().build();
let config = ConfigBuilder::default().build();
let (keys, server_keys) = generate_keys(config);
set_server_key(server_keys);
@@ -361,7 +161,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
### Comparisons.
Homomorphic integers support comparison operations. Since Rust does not allow the overloading of these operations, a simple function has been associated to each one.
Homomorphic integers support comparison operations.
Due to some Rust limitations, it is not possible to overload the comparison symbols because of the inner definition of the operations. This is because Rust expects to have a Boolean as an output, whereas a ciphertext is returned when using homomorphic types.
You will need to use different methods instead of using symbols for the comparisons. These methods follow the same naming conventions as the two standard Rust traits:
* [PartialOrd](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html)
* [PartialEq](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html)
The list of supported operations is:
@@ -374,22 +181,22 @@ The list of supported operations is:
| [Lower ](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `lt` | Binary |
| [Lower or Equal ](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `le` | Binary |
A simple example on how to use these operations:
A simple example of how to use these operations:
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8};
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheInt8};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled().enable_default_integers().build();
let config = ConfigBuilder::default().build();
let (keys, server_keys) = generate_keys(config);
set_server_key(server_keys);
let clear_a:u8 = 164;
let clear_b:u8 = 212;
let clear_a: i8 = -121;
let clear_b: i8 = 87;
let mut a = FheUint8::try_encrypt(clear_a, &keys)?;
let mut b = FheUint8::try_encrypt(clear_b, &keys)?;
let mut a = FheInt8::try_encrypt(clear_a, &keys)?;
let mut b = FheInt8::try_encrypt(clear_b, &keys)?;
let greater = a.gt(&b);
let greater_or_equal = a.ge(&b);
@@ -397,18 +204,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let lower_or_equal = a.le(&b);
let equal = a.eq(&b);
let dec_gt : u8 = greater.decrypt(&keys);
let dec_ge : u8 = greater_or_equal.decrypt(&keys);
let dec_lt : u8 = lower.decrypt(&keys);
let dec_le : u8 = lower_or_equal.decrypt(&keys);
let dec_eq : u8 = equal.decrypt(&keys);
let dec_gt = greater.decrypt(&keys);
let dec_ge = greater_or_equal.decrypt(&keys);
let dec_lt = lower.decrypt(&keys);
let dec_le = lower_or_equal.decrypt(&keys);
let dec_eq = equal.decrypt(&keys);
// We homomorphically swapped values using bitwise operations
assert_eq!(dec_gt, (clear_a > clear_b ) as u8);
assert_eq!(dec_ge, (clear_a >= clear_b) as u8);
assert_eq!(dec_lt, (clear_a < clear_b ) as u8);
assert_eq!(dec_le, (clear_a <= clear_b) as u8);
assert_eq!(dec_eq, (clear_a == clear_b) as u8);
assert_eq!(dec_gt, clear_a > clear_b);
assert_eq!(dec_ge, clear_a >= clear_b);
assert_eq!(dec_lt, clear_a < clear_b);
assert_eq!(dec_le, clear_a <= clear_b);
assert_eq!(dec_eq, clear_a == clear_b);
Ok(())
}
@@ -423,14 +229,14 @@ Homomorphic integers support the min/max operations.
| Min | `min` | Binary |
| Max | `max` | Binary |
A simple example on how to use these operations:
A simple example of how to use these operations:
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled().enable_default_integers().build();
let config = ConfigBuilder::default().build();
let (keys, server_keys) = generate_keys(config);
set_server_key(server_keys);
@@ -446,7 +252,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let dec_min : u8 = min.decrypt(&keys);
let dec_max : u8 = max.decrypt(&keys);
// We homomorphically swapped values using bitwise operations
assert_eq!(dec_min, u8::min(clear_a, clear_b));
assert_eq!(dec_max, u8::max(clear_a, clear_b));
@@ -454,19 +259,67 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
```
### Casting.
### Ternary conditional operator.
The ternary conditional operator allows computing conditional instructions of the form `if cond { choice_if } else { choice_else }`.
| name | symbol | type |
|------------------|----------------|---------|
| Ternary operator | `if_then_else` | Ternary |
The syntax is `encrypted_condition.if_then_else(encrypted_choice_if, encrypted_choice_else)`. The `encrypted_condition` should be an encryption of 0 or 1 in order to be valid.
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheInt32};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Basic configuration to use homomorphic integers
let config = ConfigBuilder::default().build();
// Key generation
let (client_key, server_keys) = generate_keys(config);
let clear_a = 32i32;
let clear_b = -45i32;
// Encrypting the input data using the (private) client_key
// FheInt32: Encrypted equivalent to i32
let encrypted_a = FheInt32::try_encrypt(clear_a, &client_key)?;
let encrypted_b = FheInt32::try_encrypt(clear_b, &client_key)?;
// On the server side:
set_server_key(server_keys);
// Clear equivalent computations: 32 > -45
let encrypted_comp = &encrypted_a.gt(&encrypted_b);
let clear_res = encrypted_comp.decrypt(&client_key);
assert_eq!(clear_res, clear_a > clear_b);
// `encrypted_comp` is a FheBool, thus it encrypts a boolean value.
// This acts as a condition on which the
// `if_then_else` function can be applied on.
// Clear equivalent computations:
// if 32 > -45 {result = 32} else {result = -45}
let encrypted_res = &encrypted_comp.if_then_else(&encrypted_a, &encrypted_b);
let clear_res: i32 = encrypted_res.decrypt(&client_key);
assert_eq!(clear_res, clear_a);
Ok(())
}
```
### Casting.
Casting between integer types is possible via the `cast_from` associated function
or the `cast_into` method.
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8, FheUint32, FheUint16};
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheInt16, FheUint8, FheUint32, FheUint16};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
// Casting requires server_key to set
@@ -503,6 +356,30 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(da, (clear as u32) as u8);
}
{
let clear = 12_837i16;
let a = FheInt16::encrypt(clear, &client_key);
// Casting from FheInt16 to FheUint16
let a = FheUint16::cast_from(a);
let da: u16 = a.decrypt(&client_key);
assert_eq!(da, clear as u16);
}
Ok(())
}
```
## Boolean Operations
Native homomorphic Booleans support common Boolean operations.
The list of supported operations is:
| name | symbol | type |
| ------------------------------------------------------------- | ------ | ------ |
| [BitAnd](https://doc.rust-lang.org/std/ops/trait.BitAnd.html) | `&` | Binary |
| [BitOr](https://doc.rust-lang.org/std/ops/trait.BitOr.html) | `\|` | Binary |
| [BitXor](https://doc.rust-lang.org/std/ops/trait.BitXor.html) | `^` | Binary |
| [Not](https://doc.rust-lang.org/std/ops/trait.Not.html) | `!` | Unary |

View File

@@ -18,9 +18,7 @@ use tfhe::{ConfigBuilder, generate_keys, set_server_key, FheUint8};
use tfhe::prelude::*;
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
// Client-side
let (client_key, server_key) = generate_keys(config);
@@ -46,7 +44,7 @@ fn main() {
The default configuration for x86 Unix machines:
```toml
tfhe = { version = "0.4.0", features = ["integer", "x86_64-unix"]}
tfhe = { version = "0.5.0", features = ["integer", "x86_64-unix"]}
```
Configuration options for different platforms can be found [here](../getting_started/installation.md). Other rust and homomorphic types features can be found [here](../how_to/rust_configuration.md).
@@ -76,9 +74,8 @@ The config is generated by first creating a builder with all types deactivated.
use tfhe::{ConfigBuilder, generate_keys};
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
}
@@ -98,9 +95,7 @@ This function will **move** the server key to an internal state of the crate and
use tfhe::{ConfigBuilder, generate_keys, set_server_key};
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
@@ -139,6 +134,3 @@ let clear_result = clear_a + clear_b;
assert_eq!(decrypted_result, clear_result);
```

View File

@@ -77,7 +77,7 @@ The figure below illustrates this problem in the case of an addition, where an e
### Programmable BootStrapping (PBS)
The bootstrapping of TFHE has the particularity of being programmable: this means that any function can be homomorphically computed over an encrypted input, while also reducing the noise. These functions are represented by look-up tables. The computation of a PBS is in general either preceded or followed by a keyswitch, which is an operation used to change the encryption key. The output ciphertext is then encrypted with the same key as the input one. To do this, two (public) evaluation keys are required: a boostrapping key and a keyswitching key. These operations are quite complex to describe, more information about these operations (or about TFHE in general) can be found here [TFHE Deep Dive](https://www.zama.ai/post/tfhe-deep-dive-part-1).
The bootstrapping of TFHE has the particularity of being programmable: this means that any function can be homomorphically computed over an encrypted input, while also reducing the noise. These functions are represented by look-up tables. The computation of a PBS is in general either preceded or followed by a keyswitch, which is an operation used to change the encryption key. The output ciphertext is then encrypted with the same key as the input one. To do this, two (public) evaluation keys are required: a bootstrapping key and a keyswitching key. These operations are quite complex to describe, more information about these operations (or about TFHE in general) can be found here [TFHE Deep Dive](https://www.zama.ai/post/tfhe-deep-dive-part-1).
### Carry.

View File

@@ -13,9 +13,7 @@ use tfhe::prelude::*;
use tfhe::{ConfigBuilder, generate_keys, set_server_key, CompressedFheUint16};
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, _) = generate_keys(config);
let clear = 12_837u16;
@@ -48,9 +46,7 @@ use tfhe::{
};
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let cks = ClientKey::generate(config);
let compressed_sks = CompressedServerKey::new(&cks);
@@ -84,7 +80,7 @@ fn main() {
This example shows how to compress the classical public keys.
{% hint style="warning" %}
It is not currently recommended to use the CompressedPublicKey to encrypt ciphertexts without first decompressing it. In case the resulting PublicKey is too large to fit in memory the encryption with the CompressedPublicKey will be very slow, this is a known problem and will be adressed in future releases.
It is not currently recommended to use the CompressedPublicKey to encrypt ciphertexts without first decompressing it. In case the resulting PublicKey is too large to fit in memory the encryption with the CompressedPublicKey will be very slow, this is a known problem and will be addressed in future releases.
{% endhint %}
```rust
@@ -92,9 +88,7 @@ use tfhe::prelude::*;
use tfhe::{ConfigBuilder, generate_keys, set_server_key, FheUint8, CompressedPublicKey};
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, _) = generate_keys(config);
let compressed_public_key = CompressedPublicKey::new(&client_key);
@@ -122,8 +116,8 @@ use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, CompressedCompactPublicKey, ConfigBuilder, FheUint8};
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_custom_integers(
let config = ConfigBuilder::default()
.use_custom_parameters(
tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS,
None,
)

View File

@@ -10,8 +10,8 @@ use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint32};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled()
.enable_custom_integers(
let config = ConfigBuilder::default()
.use_custom_parameters(
tfhe::shortint::parameters::PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS,
None,
)
@@ -41,8 +41,8 @@ use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint32};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ConfigBuilder::all_disabled()
.enable_custom_integers(
let config = ConfigBuilder::default()
.use_custom_parameters(
tfhe::shortint::parameters::PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS.with_deterministic_execution(),
None,
)
@@ -63,6 +63,3 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
```

View File

@@ -12,9 +12,7 @@ use tfhe::prelude::*;
use tfhe::{ConfigBuilder, generate_keys, set_server_key, FheUint8, PublicKey};
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, _) = generate_keys(config);
let public_key = PublicKey::new(&client_key);
@@ -34,8 +32,8 @@ use tfhe::prelude::*;
use tfhe::{ConfigBuilder, generate_keys, set_server_key, FheUint8, CompactPublicKey};
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_custom_integers(
let config = ConfigBuilder::default()
.use_custom_parameters(
tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS,
None,
)
@@ -49,4 +47,3 @@ fn main() {
assert_eq!(clear, 255u8);
}
```

View File

@@ -1,6 +1,6 @@
# Using the right toolchain for TFHE-rs.
TFHE-rs only requires a nighlty toolchain for building the C API and using advanced SIMD instructions, otherwise you can use a stable toolchain (with version >= 1.72 for ARM devices)
TFHE-rs only requires a nightly toolchain for building the C API and using advanced SIMD instructions, otherwise you can use a stable toolchain (with version >= 1.72)
Install the needed Rust toolchain:
```shell
@@ -27,7 +27,7 @@ cargo +nightly test
```shell
# This should not be necessary by default, but if you want to make sure your configuration is
# correct you can still set the overriden toolchain to stable
# correct you can still set the overridden toolchain to stable
rustup override set stable
# cargo will use the `stable` toolchain.
cargo build
@@ -52,11 +52,11 @@ rustup show
This crate exposes two kinds of data types. Each kind is enabled by activating its corresponding feature in the TOML line. Each kind may have multiple types:
| Kind | Features | Type(s) |
| --------- | ---------- | --------------------------------- |
| Booleans | `boolean` | Booleans |
| ShortInts | `shortint` | Short unsigned integers |
| Integers | `integer` | Arbitrary-sized unsigned integers |
| Kind | Features | Type(s) |
|-----------|------------|---------------------------|
| Booleans | `boolean` | Booleans |
| ShortInts | `shortint` | Short integers |
| Integers | `integer` | Arbitrary-sized integers |
## AVX-512

View File

@@ -11,7 +11,7 @@ To serialize our data, a [data format](https://serde.rs/#data-formats) should be
[dependencies]
# ...
tfhe = { version = "0.4.0", features = ["integer","x86_64-unix"]}
tfhe = { version = "0.5.0", features = ["integer","x86_64-unix"]}
bincode = "1.3.3"
```
@@ -26,9 +26,7 @@ use tfhe::{ConfigBuilder, ServerKey, generate_keys, set_server_key, FheUint8};
use tfhe::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>>{
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let ( client_key, server_key) = generate_keys(config);

View File

@@ -68,8 +68,7 @@ pub fn ex4<FheType, ClearType>(a: FheType, b: FheType, pt: ClearType) -> FheType
}
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
let config = ConfigBuilder::default()
.build();
let (client_key, server_keys) = generate_keys(config);

View File

@@ -1,4 +1,4 @@
# Trival Ciphertext
# Trivial Ciphertext
Sometimes, the server side needs to initialize a value.
For example, when computing the sum of a list of ciphertext,
@@ -11,9 +11,7 @@ the server can do a *trivial encryption*
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8};
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, sks) = generate_keys(config);
set_server_key(sks);
@@ -38,9 +36,7 @@ value if the ciphertext/clear-value operation (often called scalar operation) yo
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint32};
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
.build();
let config = ConfigBuilder::default().build();
let (client_key, sks) = generate_keys(config);
set_server_key(sks);

View File

@@ -24,7 +24,7 @@ To use the `FheUint8` type, the `integer` feature must be activated:
[dependencies]
# Default configuration for x86 Unix machines:
tfhe = { version = "0.4.0", features = ["integer", "x86_64-unix"]}
tfhe = { version = "0.5.0", features = ["integer", "x86_64-unix"]}
```
Other configurations can be found [here](../getting_started/installation.md).
@@ -69,7 +69,7 @@ use tfhe::FheUint8;
pub const UP_LOW_DISTANCE: u8 = 32;
fn to_lower(c: &FheUint8) -> FheUint8 {
c + (c.gt(64) & c.lt(91)) * UP_LOW_DISTANCE
c + FheUint8::cast_from(c.gt(64) & c.lt(91)) * UP_LOW_DISTANCE
}
```
@@ -86,11 +86,11 @@ struct FheAsciiString {
}
fn to_upper(c: &FheUint8) -> FheUint8 {
c - (c.gt(96) & c.lt(123)) * UP_LOW_DISTANCE
c - FheUint8::cast_from(c.gt(96) & c.lt(123)) * UP_LOW_DISTANCE
}
fn to_lower(c: &FheUint8) -> FheUint8 {
c + (c.gt(64) & c.lt(91)) * UP_LOW_DISTANCE
c + FheUint8::cast_from(c.gt(64) & c.lt(91)) * UP_LOW_DISTANCE
}
impl FheAsciiString {
@@ -131,8 +131,7 @@ impl FheAsciiString {
}
fn main() {
let config = ConfigBuilder::all_disabled()
.enable_default_integers()
let config = ConfigBuilder::default()
.build();
let (client_key, server_key) = generate_keys(config);

View File

@@ -15,13 +15,11 @@ This function returns a Boolean that will be either `true` or `false` so that th
### Non-generic version.
To use Booleans, the `booleans` feature in our Cargo.toml must be enabled:
```toml
# Cargo.toml
# Default configuration for x86 Unix machines:
tfhe = { version = "0.4.0", features = ["boolean", "x86_64-unix"]}
tfhe = { version = "0.5.0", features = ["integer", "x86_64-unix"]}
```
Other configurations can be found [here](../getting_started/installation.md).
@@ -129,7 +127,7 @@ fn check_parity_bit_validity(bits: &[bool], mode: ParityMode, parity_bit: bool)
}
fn main() {
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
@@ -347,7 +345,7 @@ fn check_parity_bit_validity(bits: &[bool], mode: ParityMode, parity_bit: bool)
}
fn main() {
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
let config = ConfigBuilder::default().build();
let ( client_key, server_key) = generate_keys(config);

View File

@@ -3,7 +3,7 @@ use std::time::Instant;
use rayon::prelude::*;
use tfhe::integer::ciphertext::RadixCiphertext;
use tfhe::integer::ServerKey;
use tfhe::integer::{IntegerCiphertext, ServerKey};
use crate::NUMBER_OF_BLOCKS;
@@ -70,10 +70,12 @@ fn fill_orders(
);
// total_orders > prefix_sum
let mut cond = server_key.smart_gt_parallelized(
&mut total_orders.clone(),
&mut previous_prefix_sum.clone(),
);
let mut cond = server_key
.smart_gt_parallelized(
&mut total_orders.clone(),
&mut previous_prefix_sum.clone(),
)
.into_radix(diff.blocks().len(), server_key);
// (total_orders - previous_prefix_sum) * (total_orders > previous_prefix_sum)
// = (total_orders - previous_prefix_sum).max(0)

View File

@@ -2,7 +2,7 @@ use std::time::Instant;
use tfhe::integer::ciphertext::RadixCiphertext;
use tfhe::integer::keycache::IntegerKeyCache;
use tfhe::integer::ServerKey;
use tfhe::integer::{IntegerKeyKind, ServerKey};
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
mod fhe;
@@ -73,7 +73,8 @@ fn test_volume_match_fhe(
) {
println!("Generating keys...");
let time = Instant::now();
let (client_key, server_key) = IntegerKeyCache.get_from_params(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let (client_key, server_key) =
IntegerKeyCache.get_from_params(PARAM_MESSAGE_2_CARRY_2_KS_PBS, IntegerKeyKind::Radix);
println!("Keys generated in {:?}", time.elapsed());
println!("Running test cases for the FHE implementation");

View File

@@ -1,6 +1,6 @@
use std::collections::HashMap;
use std::rc::Rc;
use tfhe::integer::{RadixCiphertext, ServerKey};
use tfhe::integer::{IntegerCiphertext, RadixCiphertext, ServerKey};
use crate::parser::u8_to_char;
@@ -72,7 +72,12 @@ impl Execution {
let mut ct_a = a.0.clone();
let mut ct_b = b.0.clone();
(exec.sk.smart_eq(&mut ct_a, &mut ct_b), ctx.clone())
(
exec.sk
.smart_eq(&mut ct_a, &mut ct_b)
.into_radix(ct_a.blocks().len(), &exec.sk),
ctx.clone(),
)
}),
)
}
@@ -89,7 +94,12 @@ impl Execution {
let mut ct_a = a.0.clone();
let mut ct_b = b.0.clone();
(exec.sk.smart_gt(&mut ct_a, &mut ct_b), ctx.clone())
(
exec.sk
.smart_gt(&mut ct_a, &mut ct_b)
.into_radix(ct_a.blocks().len(), &exec.sk),
ctx.clone(),
)
}),
)
}
@@ -106,7 +116,12 @@ impl Execution {
let mut ct_a = a.0.clone();
let mut ct_b = b.0.clone();
(exec.sk.smart_le(&mut ct_a, &mut ct_b), ctx.clone())
(
exec.sk
.smart_le(&mut ct_a, &mut ct_b)
.into_radix(ct_a.blocks().len(), &exec.sk),
ctx.clone(),
)
}),
)
}

Some files were not shown because too many files have changed in this diff Show More