mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-11 07:38:08 -05:00
Compare commits
12 Commits
al/ci_fixe
...
0.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
956c4080f5 | ||
|
|
fea1b4db92 | ||
|
|
13c1fcb6e7 | ||
|
|
69b9bd3860 | ||
|
|
747693e889 | ||
|
|
e452d5d6d2 | ||
|
|
5425ba5199 | ||
|
|
aeda381f12 | ||
|
|
9b2cccfee6 | ||
|
|
b534f6a406 | ||
|
|
7a72dd2619 | ||
|
|
343f31e070 |
2
.github/workflows/aws_tfhe_integer_tests.yml
vendored
2
.github/workflows/aws_tfhe_integer_tests.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
echo "Type: ${{ github.event.inputs.instance_type }}"
|
||||
echo "Request ID: ${{ github.event.inputs.request_id }}"
|
||||
|
||||
- uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
|
||||
- name: Set up home
|
||||
run: |
|
||||
|
||||
2
.github/workflows/aws_tfhe_tests.yml
vendored
2
.github/workflows/aws_tfhe_tests.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
echo "Type: ${{ github.event.inputs.instance_type }}"
|
||||
echo "Request ID: ${{ github.event.inputs.request_id }}"
|
||||
|
||||
- uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
|
||||
- name: Set up home
|
||||
run: |
|
||||
|
||||
40
.github/workflows/boolean_benchmark.yml
vendored
40
.github/workflows/boolean_benchmark.yml
vendored
@@ -5,19 +5,19 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
instance_id:
|
||||
description: 'Instance ID'
|
||||
description: "Instance ID"
|
||||
type: string
|
||||
instance_image_id:
|
||||
description: 'Instance AMI ID'
|
||||
description: "Instance AMI ID"
|
||||
type: string
|
||||
instance_type:
|
||||
description: 'Instance product type'
|
||||
description: "Instance product type"
|
||||
type: string
|
||||
runner_name:
|
||||
description: 'Action runner name'
|
||||
description: "Action runner name"
|
||||
type: string
|
||||
request_id:
|
||||
description: 'Slab request ID'
|
||||
description: "Slab request ID"
|
||||
type: string
|
||||
|
||||
env:
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Checkout tfhe-rs repo with tags
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -57,9 +57,9 @@ jobs:
|
||||
toolchain: nightly
|
||||
override: true
|
||||
|
||||
- name: Run benchmarks
|
||||
- name: Run benchmarks with AVX512
|
||||
run: |
|
||||
make bench_boolean
|
||||
make AVX512_SUPPORT=ON bench_boolean
|
||||
|
||||
- name: Parse results
|
||||
run: |
|
||||
@@ -73,24 +73,8 @@ jobs:
|
||||
--commit-date "${COMMIT_DATE}" \
|
||||
--bench-date "${{ env.BENCH_DATE }}" \
|
||||
--walk-subdirs \
|
||||
--throughput
|
||||
|
||||
- name: Remove previous raw results
|
||||
run: |
|
||||
rm -rf target/criterion
|
||||
|
||||
- name: Run benchmarks with AVX512
|
||||
run: |
|
||||
make AVX512_SUPPORT=ON bench_boolean
|
||||
|
||||
- name: Parse AVX512 results
|
||||
run: |
|
||||
python3 ./ci/benchmark_parser.py target/criterion ${{ env.RESULTS_FILENAME }} \
|
||||
--hardware ${{ inputs.instance_type }} \
|
||||
--name-suffix avx512 \
|
||||
--walk-subdirs \
|
||||
--throughput \
|
||||
--append-results
|
||||
--throughput
|
||||
|
||||
- name: Measure key sizes
|
||||
run: |
|
||||
@@ -101,7 +85,7 @@ jobs:
|
||||
python3 ./ci/benchmark_parser.py tfhe/boolean_key_sizes.csv ${{ env.RESULTS_FILENAME }} \
|
||||
--key-sizes \
|
||||
--append-results
|
||||
|
||||
|
||||
- name: Upload parsed results artifact
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
|
||||
with:
|
||||
@@ -109,7 +93,7 @@ jobs:
|
||||
path: ${{ env.RESULTS_FILENAME }}
|
||||
|
||||
- name: Checkout Slab repo
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
repository: zama-ai/slab
|
||||
path: slab
|
||||
@@ -118,7 +102,7 @@ jobs:
|
||||
- name: Send data to Slab
|
||||
shell: bash
|
||||
env:
|
||||
COMPRESSED_RESULTS : ${{ env.RESULTS_FILENAME }}.gz
|
||||
COMPRESSED_RESULTS: ${{ env.RESULTS_FILENAME }}.gz
|
||||
run: |
|
||||
echo "Computing HMac on results file"
|
||||
SIGNATURE="$(slab/scripts/hmac_calculator.sh ${{ env.RESULTS_FILENAME }} '${{ secrets.JOB_SECRET }}')"
|
||||
|
||||
2
.github/workflows/cargo_build.yml
vendored
2
.github/workflows/cargo_build.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
|
||||
- name: Run pcc checks
|
||||
run: |
|
||||
|
||||
36
.github/workflows/integer_benchmark.yml
vendored
36
.github/workflows/integer_benchmark.yml
vendored
@@ -5,19 +5,19 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
instance_id:
|
||||
description: 'Instance ID'
|
||||
description: "Instance ID"
|
||||
type: string
|
||||
instance_image_id:
|
||||
description: 'Instance AMI ID'
|
||||
description: "Instance AMI ID"
|
||||
type: string
|
||||
instance_type:
|
||||
description: 'Instance product type'
|
||||
description: "Instance product type"
|
||||
type: string
|
||||
runner_name:
|
||||
description: 'Action runner name'
|
||||
description: "Action runner name"
|
||||
type: string
|
||||
request_id:
|
||||
description: 'Slab request ID'
|
||||
description: "Slab request ID"
|
||||
type: string
|
||||
|
||||
env:
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Checkout tfhe-rs repo with tags
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -57,9 +57,9 @@ jobs:
|
||||
toolchain: nightly
|
||||
override: true
|
||||
|
||||
- name: Run benchmarks
|
||||
- name: Run benchmarks with AVX512
|
||||
run: |
|
||||
make bench_integer
|
||||
make AVX512_SUPPORT=ON bench_integer
|
||||
|
||||
- name: Parse results
|
||||
run: |
|
||||
@@ -73,24 +73,8 @@ jobs:
|
||||
--commit-date "${COMMIT_DATE}" \
|
||||
--bench-date "${{ env.BENCH_DATE }}" \
|
||||
--walk-subdirs \
|
||||
--throughput
|
||||
|
||||
- name: Remove previous raw results
|
||||
run: |
|
||||
rm -rf target/criterion
|
||||
|
||||
- name: Run benchmarks with AVX512
|
||||
run: |
|
||||
make AVX512_SUPPORT=ON bench_integer
|
||||
|
||||
- name: Parse AVX512 results
|
||||
run: |
|
||||
python3 ./ci/benchmark_parser.py target/criterion ${{ env.RESULTS_FILENAME }} \
|
||||
--hardware ${{ inputs.instance_type }} \
|
||||
--walk-subdirs \
|
||||
--name-suffix avx512 \
|
||||
--throughput \
|
||||
--append-results
|
||||
--throughput
|
||||
|
||||
- name: Upload parsed results artifact
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
|
||||
@@ -99,7 +83,7 @@ jobs:
|
||||
path: ${{ env.RESULTS_FILENAME }}
|
||||
|
||||
- name: Checkout Slab repo
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
repository: zama-ai/slab
|
||||
path: slab
|
||||
|
||||
2
.github/workflows/m1_tests.yml
vendored
2
.github/workflows/m1_tests.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
runs-on: ["self-hosted", "m1mac"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
|
||||
- name: Install latest stable
|
||||
uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af
|
||||
|
||||
15
.github/workflows/pbs_benchmark.yml
vendored
15
.github/workflows/pbs_benchmark.yml
vendored
@@ -5,22 +5,21 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
instance_id:
|
||||
description: 'Instance ID'
|
||||
description: "Instance ID"
|
||||
type: string
|
||||
instance_image_id:
|
||||
description: 'Instance AMI ID'
|
||||
description: "Instance AMI ID"
|
||||
type: string
|
||||
instance_type:
|
||||
description: 'Instance product type'
|
||||
description: "Instance product type"
|
||||
type: string
|
||||
runner_name:
|
||||
description: 'Action runner name'
|
||||
description: "Action runner name"
|
||||
type: string
|
||||
request_id:
|
||||
description: 'Slab request ID'
|
||||
description: "Slab request ID"
|
||||
type: string
|
||||
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RESULTS_FILENAME: parsed_benchmark_results_${{ github.sha }}.json
|
||||
@@ -43,7 +42,7 @@ jobs:
|
||||
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Checkout tfhe-rs repo with tags
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -84,7 +83,7 @@ jobs:
|
||||
path: ${{ env.RESULTS_FILENAME }}
|
||||
|
||||
- name: Checkout Slab repo
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
repository: zama-ai/slab
|
||||
path: slab
|
||||
|
||||
37
.github/workflows/shortint_benchmark.yml
vendored
37
.github/workflows/shortint_benchmark.yml
vendored
@@ -5,22 +5,21 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
instance_id:
|
||||
description: 'Instance ID'
|
||||
description: "Instance ID"
|
||||
type: string
|
||||
instance_image_id:
|
||||
description: 'Instance AMI ID'
|
||||
description: "Instance AMI ID"
|
||||
type: string
|
||||
instance_type:
|
||||
description: 'Instance product type'
|
||||
description: "Instance product type"
|
||||
type: string
|
||||
runner_name:
|
||||
description: 'Action runner name'
|
||||
description: "Action runner name"
|
||||
type: string
|
||||
request_id:
|
||||
description: 'Slab request ID'
|
||||
description: "Slab request ID"
|
||||
type: string
|
||||
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RESULTS_FILENAME: parsed_benchmark_results_${{ github.sha }}.json
|
||||
@@ -43,7 +42,7 @@ jobs:
|
||||
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Checkout tfhe-rs repo with tags
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -58,9 +57,9 @@ jobs:
|
||||
toolchain: nightly
|
||||
override: true
|
||||
|
||||
- name: Run benchmarks
|
||||
- name: Run benchmarks with AVX512
|
||||
run: |
|
||||
make bench_shortint
|
||||
make AVX512_SUPPORT=ON bench_shortint
|
||||
|
||||
- name: Parse results
|
||||
run: |
|
||||
@@ -74,24 +73,8 @@ jobs:
|
||||
--commit-date "${COMMIT_DATE}" \
|
||||
--bench-date "${{ env.BENCH_DATE }}" \
|
||||
--walk-subdirs \
|
||||
--throughput
|
||||
|
||||
- name: Remove previous raw results
|
||||
run: |
|
||||
rm -rf target/criterion
|
||||
|
||||
- name: Run benchmarks with AVX512
|
||||
run: |
|
||||
make AVX512_SUPPORT=ON bench_shortint
|
||||
|
||||
- name: Parse AVX512 results
|
||||
run: |
|
||||
python3 ./ci/benchmark_parser.py target/criterion ${{ env.RESULTS_FILENAME }} \
|
||||
--hardware ${{ inputs.instance_type }} \
|
||||
--walk-subdirs \
|
||||
--name-suffix avx512 \
|
||||
--throughput \
|
||||
--append-results
|
||||
--throughput
|
||||
|
||||
- name: Measure key sizes
|
||||
run: |
|
||||
@@ -110,7 +93,7 @@ jobs:
|
||||
path: ${{ env.RESULTS_FILENAME }}
|
||||
|
||||
- name: Checkout Slab repo
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
repository: zama-ai/slab
|
||||
path: slab
|
||||
|
||||
2
.github/workflows/start_benchmarks.yml
vendored
2
.github/workflows/start_benchmarks.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Slab repo
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
repository: zama-ai/slab
|
||||
path: slab
|
||||
|
||||
2
.github/workflows/sync_on_push.yml
vendored
2
.github/workflows/sync_on_push.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Save repo
|
||||
|
||||
@@ -58,7 +58,7 @@ tfhe = { version = "*", features = ["boolean", "shortint", "integer", "x86_64"]
|
||||
Note: aarch64-based machines are not yet supported for Windows as it's currently missing an entropy source to be able to seed the [CSPRNGs](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) used in TFHE-rs
|
||||
|
||||
Note that 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 performances possible,
|
||||
to run in release mode with cargo's `--release` flag to have the best performances possible,
|
||||
eg: `cargo run --release`.
|
||||
|
||||
Here is a full example evaluating a Boolean circuit:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tfhe"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
readme = "../README.md"
|
||||
keywords = ["fully", "homomorphic", "encryption", "fhe", "cryptography"]
|
||||
|
||||
@@ -32,6 +32,34 @@ int uint128_client_key(const ClientKey *client_key) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
int uint128_encrypt_trivial(const ClientKey *client_key) {
|
||||
int ok;
|
||||
FheUint128 *lhs = NULL;
|
||||
FheUint128 *rhs = NULL;
|
||||
FheUint128 *result = NULL;
|
||||
|
||||
ok = fhe_uint128_try_encrypt_trivial_u128(10, 20, &lhs);
|
||||
assert(ok == 0);
|
||||
|
||||
ok = fhe_uint128_try_encrypt_trivial_u128(1, 2, &rhs);
|
||||
assert(ok == 0);
|
||||
|
||||
ok = fhe_uint128_sub(lhs, rhs, &result);
|
||||
assert(ok == 0);
|
||||
|
||||
uint64_t w0, w1;
|
||||
ok = fhe_uint128_decrypt(result, client_key, &w0, &w1);
|
||||
assert(ok == 0);
|
||||
|
||||
assert(w0 == 9);
|
||||
assert(w1 == 18);
|
||||
|
||||
fhe_uint128_destroy(lhs);
|
||||
fhe_uint128_destroy(rhs);
|
||||
fhe_uint128_destroy(result);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int uint128_public_key(const ClientKey *client_key, const PublicKey *public_key) {
|
||||
int ok;
|
||||
FheUint128 *lhs = NULL;
|
||||
@@ -79,6 +107,7 @@ int main(void) {
|
||||
set_server_key(server_key);
|
||||
|
||||
uint128_client_key(client_key);
|
||||
uint128_encrypt_trivial(client_key);
|
||||
uint128_public_key(client_key, public_key);
|
||||
|
||||
client_key_destroy(client_key);
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int uint256_client_key(const ClientKey *client_key) {
|
||||
int ok;
|
||||
FheUint256 *lhs = NULL;
|
||||
@@ -49,6 +48,50 @@ int uint256_client_key(const ClientKey *client_key) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
int uint256_encrypt_trivial(const ClientKey *client_key) {
|
||||
int ok;
|
||||
FheUint256 *lhs = NULL;
|
||||
FheUint256 *rhs = NULL;
|
||||
FheUint256 *result = NULL;
|
||||
U256 *lhs_clear = NULL;
|
||||
U256 *rhs_clear = NULL;
|
||||
U256 *result_clear = NULL;
|
||||
|
||||
ok = u256_from_u64_words(1, 2, 3, 4, &lhs_clear);
|
||||
assert(ok == 0);
|
||||
ok = u256_from_u64_words(5, 6, 7, 8, &rhs_clear);
|
||||
assert(ok == 0);
|
||||
|
||||
ok = fhe_uint256_try_encrypt_trivial_u256(lhs_clear, &lhs);
|
||||
assert(ok == 0);
|
||||
|
||||
ok = fhe_uint256_try_encrypt_trivial_u256(rhs_clear, &rhs);
|
||||
assert(ok == 0);
|
||||
|
||||
ok = fhe_uint256_add(lhs, rhs, &result);
|
||||
assert(ok == 0);
|
||||
|
||||
ok = fhe_uint256_decrypt(result, client_key, &result_clear);
|
||||
assert(ok == 0);
|
||||
|
||||
uint64_t w0, w1, w2, w3;
|
||||
ok = u256_to_u64_words(result_clear, &w0, &w1, &w2, &w3);
|
||||
assert(ok == 0);
|
||||
|
||||
assert(w0 == 6);
|
||||
assert(w1 == 8);
|
||||
assert(w2 == 10);
|
||||
assert(w3 == 12);
|
||||
|
||||
u256_destroy(lhs_clear);
|
||||
u256_destroy(rhs_clear);
|
||||
u256_destroy(result_clear);
|
||||
fhe_uint256_destroy(lhs);
|
||||
fhe_uint256_destroy(rhs);
|
||||
fhe_uint256_destroy(result);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int uint256_public_key(const ClientKey *client_key, const PublicKey *public_key) {
|
||||
int ok;
|
||||
FheUint256 *lhs = NULL;
|
||||
@@ -112,6 +155,7 @@ int main(void) {
|
||||
set_server_key(server_key);
|
||||
|
||||
uint256_client_key(client_key);
|
||||
uint256_encrypt_trivial(client_key);
|
||||
uint256_public_key(client_key, public_key);
|
||||
|
||||
client_key_destroy(client_key);
|
||||
|
||||
@@ -67,6 +67,37 @@ int public_key_test(const ClientKey *client_key, const PublicKey *public_key) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
int trivial_encrypt_test(const ClientKey *client_key) {
|
||||
int ok;
|
||||
FheBool *lhs = NULL;
|
||||
FheBool *rhs = NULL;
|
||||
FheBool *result = NULL;
|
||||
|
||||
bool lhs_clear = 0;
|
||||
bool rhs_clear = 1;
|
||||
|
||||
ok = fhe_bool_try_encrypt_trivial_bool(lhs_clear, &lhs);
|
||||
assert(ok == 0);
|
||||
|
||||
ok = fhe_bool_try_encrypt_trivial_bool(rhs_clear, &rhs);
|
||||
assert(ok == 0);
|
||||
|
||||
ok = fhe_bool_bitand(lhs, rhs, &result);
|
||||
assert(ok == 0);
|
||||
|
||||
bool clear;
|
||||
ok = fhe_bool_decrypt(result, client_key, &clear);
|
||||
assert(ok == 0);
|
||||
|
||||
assert(clear == (lhs_clear & rhs_clear));
|
||||
|
||||
fhe_bool_destroy(lhs);
|
||||
fhe_bool_destroy(rhs);
|
||||
fhe_bool_destroy(result);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
@@ -88,6 +119,7 @@ int main(void)
|
||||
|
||||
client_key_test(client_key);
|
||||
public_key_test(client_key, public_key);
|
||||
trivial_encrypt_test(client_key);
|
||||
|
||||
client_key_destroy(client_key);
|
||||
public_key_destroy(public_key);
|
||||
|
||||
@@ -9,7 +9,7 @@ Welcome to this tutorial about TFHE-rs `core_crypto` module.
|
||||
To use `TFHE-rs`, first it has to be added as a dependency in the `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
tfhe = { version = "0.2.0", features = [ "x86_64-unix" ] }
|
||||
tfhe = { version = "0.2.1", 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.2.0", features = ["x86_64-unix"] }
|
||||
tfhe = { version = "0.2.1", features = ["x86_64-unix"] }
|
||||
```
|
||||
|
||||
For Apple Silicon or aarch64-based machines running Unix-like OSes:
|
||||
|
||||
```toml
|
||||
tfhe = { version = "0.2.0", features = ["aarch64-unix"] }
|
||||
tfhe = { version = "0.2.1", features = ["aarch64-unix"] }
|
||||
```
|
||||
|
||||
For x86\_64-based machines with the [`rdseed instruction`](https://en.wikipedia.org/wiki/RDRAND) running Windows:
|
||||
|
||||
```toml
|
||||
tfhe = { version = "0.2.0", features = ["x86_64"] }
|
||||
tfhe = { version = "0.2.1", features = ["x86_64"] }
|
||||
```
|
||||
|
||||
### Commented code to double a 2-bits message in a leveled fashion and using a PBS with the `core_crypto` module.
|
||||
|
||||
@@ -59,10 +59,10 @@ To ensure predictable timings, the operation flavor is the `default` one: a carr
|
||||
|
||||
| Plaintext size | add | mul | greater\_than (gt) | min |
|
||||
| -------------------| -------------- | ------------------- | --------- | ------- |
|
||||
| 8 bits | 129.0 ms | 178.2 ms | 111.9 ms | 287.7 ms |
|
||||
| 16 bits | 256.3 ms | 328.0 ms | 145.3 ms | 437.4 ms |
|
||||
| 32 bits | 469.4 ms | 645.5 ms | 192.0 ms | 776.4 ms |
|
||||
| 40 bits | 608.0 ms | 849.3 ms | 228.4 ms | 953.5 ms |
|
||||
| 64 bits | 959.9 ms | 1.49 s | 249.0 ms | 1.36 s |
|
||||
| 128 bits | 1.88 s | 3.25 s | 294.7 ms | 2.37 s |
|
||||
| 256 bits | 3.66 s | 8.38 s | 361.8 ms | 4.51 s |
|
||||
| 8 bits | 129.0 ms | 227.2 ms | 111.9 ms | 186.8 ms |
|
||||
| 16 bits | 256.3 ms | 756.0 ms | 145.3 ms | 233.1 ms |
|
||||
| 32 bits | 469.4 ms | 2.10 s | 192.0 ms | 282.9 ms |
|
||||
| 40 bits | 608.0 ms | 3.37 s | 228.4 ms | 318.6 ms |
|
||||
| 64 bits | 959.9 ms | 5.53 s | 249.0 ms | 336.5 ms |
|
||||
| 128 bits | 1.88 s | 14.1 s | 294.7 ms | 398.6 ms |
|
||||
| 256 bits | 3.66 s | 29.2 s | 361.8 ms | 509.1 ms |
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
To use `TFHE-rs` in your project, you first need to add it as a dependency in your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
tfhe = { version = "0.2.0", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
|
||||
tfhe = { version = "0.2.1", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
|
||||
```
|
||||
|
||||
{% hint style="info" %}
|
||||
|
||||
@@ -11,7 +11,7 @@ To serialize our data, a [data format](https://serde.rs/#data-formats) should be
|
||||
|
||||
[dependencies]
|
||||
# ...
|
||||
tfhe = { version = "0.2.0", features = ["integer"]}
|
||||
tfhe = { version = "0.2.1", features = ["integer","x86_64-unix"]}
|
||||
bincode = "1.3.3"
|
||||
```
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ The basic steps for using the high-level API of TFHE-rs are:
|
||||
3. Client-side: Encrypting data;
|
||||
4. Server-side: Setting the server key;
|
||||
5. Server-side: Computing over encrypted data;
|
||||
6. Client-side: Encrypting data.
|
||||
6. Client-side: Decrypting data.
|
||||
|
||||
Here is the full example (mixing client and server parts):
|
||||
|
||||
@@ -44,10 +44,13 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Default configuration for x86 Unix machines:
|
||||
```toml
|
||||
tfhe = { version = "0.2.0", features = ["integer"]}
|
||||
tfhe = { version = "0.2.1", features = ["integer", "x86_64-unix"]}
|
||||
```
|
||||
|
||||
Other configurations can be found [here](../getting_started/installation.md).
|
||||
|
||||
### Imports.
|
||||
|
||||
`tfhe` uses `traits` to have a consistent API for creating FHE types and enable users to write generic functions. To be able to use associated functions and methods of a trait, the trait has to be in scope.
|
||||
@@ -64,13 +67,8 @@ The first step is the creation of the configuration. The configuration is used t
|
||||
|
||||
Creating a configuration is done using the ConfigBuilder type.
|
||||
|
||||
In this example, 8-bit unsigned integers with default parameters are used. The `integers` feature must also be enabled, as per the table on the Getting Started page.
|
||||
|
||||
{% hint style="info" %}
|
||||
```toml
|
||||
tfhe = { version = "0.2.0", features = ["integer"]}
|
||||
```
|
||||
{% endhint %}
|
||||
In this example, 8-bit unsigned integers with default parameters are used. The `integers`
|
||||
feature must also be enabled, as per the table on the [Getting Started page](../getting_started/installation.md).
|
||||
|
||||
The config is done by first creating a builder with all types deactivated. Then, the `uint8` type with default parameters is activated.
|
||||
|
||||
@@ -191,10 +189,13 @@ To use the `FheUint8` type, the `integer` feature must be activated:
|
||||
# Cargo.toml
|
||||
|
||||
[dependencies]
|
||||
# ...
|
||||
tfhe = { version = "0.2.0", features = ["integer"]}
|
||||
# Default configuration for x86 Unix machines:
|
||||
tfhe = { version = "0.2.1", features = ["integer", "x86_64-unix"]}
|
||||
```
|
||||
|
||||
Other configurations can be found [here](../getting_started/installation.md).
|
||||
|
||||
|
||||
```rust
|
||||
use tfhe::{FheUint8, ConfigBuilder, generate_keys, set_server_key, ClientKey};
|
||||
use tfhe::prelude::*;
|
||||
@@ -317,11 +318,13 @@ To use Booleans, the `booleans` feature in our Cargo.toml must be enabled:
|
||||
```toml
|
||||
# Cargo.toml
|
||||
|
||||
[dependencies]
|
||||
# ...
|
||||
tfhe = { version = "0.2.0", features = ["booleans"]}
|
||||
# Default configuration for x86 Unix machines:
|
||||
tfhe = { version = "0.2.1", features = ["boolean", "x86_64-unix"]}
|
||||
```
|
||||
|
||||
Other configurations can be found [here](../getting_started/installation.md).
|
||||
|
||||
|
||||
#### function definition
|
||||
|
||||
First, the verification function is defined.
|
||||
@@ -461,7 +464,7 @@ To make the `compute_parity_bit` function compatible with both `FheBool` and `bo
|
||||
|
||||
Writing a generic function that accepts `FHE` types as well as clear types can help test the function to see if it is correct. If the function is generic, it can run with clear data, allowing the use of print-debugging or a debugger to spot errors.
|
||||
|
||||
Writing generic functions that use operator overloading for our FHE types can be trickier than normal, since, as explained in [Generic Bounds How To](../how\_to/generic\_bounds.md), `FHE` types are not copy. So using the reference `&` is mandatory, even though this is not the case when using native types, which are all `Copy`.
|
||||
Writing generic functions that use operator overloading for our FHE types can be trickier than normal, since `FHE` types are not copy. So using the reference `&` is mandatory, even though this is not the case when using native types, which are all `Copy`.
|
||||
|
||||
This will make the generic bounds trickier at first.
|
||||
|
||||
@@ -549,7 +552,7 @@ help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
```
|
||||
|
||||
The way to fix this is to use `Higher-Rank Trait Bounds`, as shown in the [Generic Bounds How To](../how\_to/generic\_bounds.md):
|
||||
The way to fix this is to use `Higher-Rank Trait Bounds`:
|
||||
|
||||
```Rust
|
||||
where
|
||||
|
||||
@@ -11,6 +11,7 @@ impl_binary_fn_on_type!(FheBool => bitand, bitor, bitxor);
|
||||
impl_unary_fn_on_type!(FheBool => not);
|
||||
|
||||
impl_decrypt_on_type!(FheBool, bool);
|
||||
impl_try_encrypt_trivial_on_type!(FheBool{crate::high_level_api::FheBool}, bool);
|
||||
impl_try_encrypt_with_client_key_on_type!(FheBool{crate::high_level_api::FheBool}, bool);
|
||||
impl_try_encrypt_with_public_key_on_type!(FheBool{crate::high_level_api::FheBool}, bool);
|
||||
|
||||
|
||||
@@ -81,40 +81,62 @@ create_integer_wrapper_type!(name: FheUint128, clear_scalar_type: u64);
|
||||
create_integer_wrapper_type!(name: FheUint256, clear_scalar_type: u64);
|
||||
|
||||
impl_decrypt_on_type!(FheUint8, u8);
|
||||
impl_try_encrypt_trivial_on_type!(FheUint8{crate::high_level_api::FheUint8}, u8);
|
||||
impl_try_encrypt_with_client_key_on_type!(FheUint8{crate::high_level_api::FheUint8}, u8);
|
||||
impl_try_encrypt_with_public_key_on_type!(FheUint8{crate::high_level_api::FheUint8}, u8);
|
||||
impl_try_encrypt_with_client_key_on_type!(CompressedFheUint8{crate::high_level_api::CompressedFheUint8}, u8);
|
||||
|
||||
impl_decrypt_on_type!(FheUint10, u16);
|
||||
impl_try_encrypt_trivial_on_type!(FheUint10{crate::high_level_api::FheUint10}, u16);
|
||||
impl_try_encrypt_with_client_key_on_type!(FheUint10{crate::high_level_api::FheUint10}, u16);
|
||||
impl_try_encrypt_with_public_key_on_type!(FheUint10{crate::high_level_api::FheUint10}, u16);
|
||||
impl_try_encrypt_with_client_key_on_type!(CompressedFheUint10{crate::high_level_api::CompressedFheUint10}, u16);
|
||||
|
||||
impl_decrypt_on_type!(FheUint12, u16);
|
||||
impl_try_encrypt_trivial_on_type!(FheUint12{crate::high_level_api::FheUint12}, u16);
|
||||
impl_try_encrypt_with_client_key_on_type!(FheUint12{crate::high_level_api::FheUint12}, u16);
|
||||
impl_try_encrypt_with_public_key_on_type!(FheUint12{crate::high_level_api::FheUint12}, u16);
|
||||
impl_try_encrypt_with_client_key_on_type!(CompressedFheUint12{crate::high_level_api::CompressedFheUint12}, u16);
|
||||
|
||||
impl_decrypt_on_type!(FheUint14, u16);
|
||||
impl_try_encrypt_trivial_on_type!(FheUint14{crate::high_level_api::FheUint14}, u16);
|
||||
impl_try_encrypt_with_client_key_on_type!(FheUint14{crate::high_level_api::FheUint14}, u16);
|
||||
impl_try_encrypt_with_public_key_on_type!(FheUint14{crate::high_level_api::FheUint14}, u16);
|
||||
impl_try_encrypt_with_client_key_on_type!(CompressedFheUint14{crate::high_level_api::CompressedFheUint14}, u16);
|
||||
|
||||
impl_decrypt_on_type!(FheUint16, u16);
|
||||
impl_try_encrypt_trivial_on_type!(FheUint16{crate::high_level_api::FheUint16}, u16);
|
||||
impl_try_encrypt_with_client_key_on_type!(FheUint16{crate::high_level_api::FheUint16}, u16);
|
||||
impl_try_encrypt_with_public_key_on_type!(FheUint16{crate::high_level_api::FheUint16}, u16);
|
||||
impl_try_encrypt_with_client_key_on_type!(CompressedFheUint16{crate::high_level_api::CompressedFheUint16}, u16);
|
||||
|
||||
impl_decrypt_on_type!(FheUint32, u32);
|
||||
impl_try_encrypt_trivial_on_type!(FheUint32{crate::high_level_api::FheUint32}, u32);
|
||||
impl_try_encrypt_with_client_key_on_type!(FheUint32{crate::high_level_api::FheUint32}, u32);
|
||||
impl_try_encrypt_with_public_key_on_type!(FheUint32{crate::high_level_api::FheUint32}, u32);
|
||||
impl_try_encrypt_with_client_key_on_type!(CompressedFheUint32{crate::high_level_api::CompressedFheUint32}, u32);
|
||||
|
||||
impl_decrypt_on_type!(FheUint64, u64);
|
||||
impl_try_encrypt_trivial_on_type!(FheUint64{crate::high_level_api::FheUint64}, u64);
|
||||
impl_try_encrypt_with_client_key_on_type!(FheUint64{crate::high_level_api::FheUint64}, u64);
|
||||
impl_try_encrypt_with_public_key_on_type!(FheUint64{crate::high_level_api::FheUint64}, u64);
|
||||
impl_try_encrypt_with_client_key_on_type!(CompressedFheUint64{crate::high_level_api::CompressedFheUint64}, u64);
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fhe_uint128_try_encrypt_trivial_u128(
|
||||
low_word: u64,
|
||||
high_word: u64,
|
||||
result: *mut *mut FheUint128,
|
||||
) -> c_int {
|
||||
catch_panic(|| {
|
||||
let value = ((high_word as u128) << 64u128) | low_word as u128;
|
||||
|
||||
let inner = <crate::high_level_api::FheUint128>::try_encrypt_trivial(value).unwrap();
|
||||
|
||||
*result = Box::into_raw(Box::new(FheUint128(inner)));
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fhe_uint128_try_encrypt_with_client_key_u128(
|
||||
low_word: u64,
|
||||
@@ -189,6 +211,18 @@ pub unsafe extern "C" fn fhe_uint128_decrypt(
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fhe_uint256_try_encrypt_trivial_u256(
|
||||
value: *const U256,
|
||||
result: *mut *mut FheUint256,
|
||||
) -> c_int {
|
||||
catch_panic(|| {
|
||||
let inner = <crate::high_level_api::FheUint256>::try_encrypt_trivial((*value).0).unwrap();
|
||||
|
||||
*result = Box::into_raw(Box::new(FheUint256(inner)));
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fhe_uint256_try_encrypt_with_client_key_u256(
|
||||
value: *const U256,
|
||||
|
||||
@@ -59,6 +59,23 @@ macro_rules! impl_try_encrypt_with_public_key_on_type {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_try_encrypt_trivial_on_type {
|
||||
($wrapper_type:ty{$wrapped_type:ty}, $input_type:ty) => {
|
||||
::paste::paste! {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [<$wrapper_type:snake _try_encrypt_trivial_ $input_type:snake>](
|
||||
value: $input_type,
|
||||
result: *mut *mut $wrapper_type,
|
||||
) -> ::std::os::raw::c_int {
|
||||
$crate::c_api::utils::catch_panic(|| {
|
||||
let inner = <$wrapped_type>::try_encrypt_trivial(value).unwrap();
|
||||
|
||||
*result = Box::into_raw(Box::new($wrapper_type(inner)));
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_decrypt_on_type {
|
||||
($wrapper_type:ty, $output_type:ty) => {
|
||||
::paste::paste! {
|
||||
|
||||
@@ -190,3 +190,14 @@ fn test_compressed_bool() {
|
||||
assert_eq!(a.decrypt(&keys), true);
|
||||
assert_eq!(b.decrypt(&keys), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trivial_bool() {
|
||||
let keys = setup_static_default();
|
||||
|
||||
let a = FheBool::encrypt_trivial(true);
|
||||
let b = FheBool::encrypt_trivial(false);
|
||||
|
||||
assert_eq!(a.decrypt(&keys), true);
|
||||
assert_eq!(b.decrypt(&keys), false);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::marker::PhantomData;
|
||||
|
||||
use crate::high_level_api::integers::parameters::EvaluationIntegerKey;
|
||||
|
||||
use super::client_key::GenericIntegerClientKey;
|
||||
use super::client_key::{GenericIntegerClientKey, RadixClientKey};
|
||||
use super::parameters::IntegerParameter;
|
||||
|
||||
use crate::integer::wopbs::WopbsKey;
|
||||
@@ -11,12 +11,16 @@ use crate::integer::wopbs::WopbsKey;
|
||||
pub struct GenericIntegerServerKey<P: IntegerParameter> {
|
||||
pub(in crate::high_level_api::integers) inner: P::InnerServerKey,
|
||||
pub(in crate::high_level_api::integers) wopbs_key: WopbsKey,
|
||||
// To know if we have to encrypt into a big or small when trivial encrypting
|
||||
pub(in crate::high_level_api::integers) pbs_order: crate::shortint::PBSOrder,
|
||||
// To know the num block when trivial encrypting
|
||||
pub(in crate::high_level_api::integers) num_block: usize,
|
||||
_marker: PhantomData<P>,
|
||||
}
|
||||
|
||||
impl<P> GenericIntegerServerKey<P>
|
||||
where
|
||||
P: IntegerParameter,
|
||||
P: IntegerParameter<InnerClientKey = RadixClientKey>,
|
||||
P::InnerServerKey: EvaluationIntegerKey<P::InnerClientKey>,
|
||||
{
|
||||
pub(super) fn new(client_key: &GenericIntegerClientKey<P>) -> Self {
|
||||
@@ -29,6 +33,8 @@ where
|
||||
Self {
|
||||
inner,
|
||||
wopbs_key,
|
||||
pbs_order: client_key.inner.pbs_order,
|
||||
num_block: client_key.inner.inner.num_blocks(),
|
||||
_marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,3 +201,39 @@ fn test_integer_compressed_public_key() {
|
||||
let clear: u8 = a.decrypt(&client_key);
|
||||
assert_eq!(clear, 213u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trivial_fhe_uint8() {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_uint8().build();
|
||||
let (client_key, sks) = generate_keys(config);
|
||||
|
||||
set_server_key(sks);
|
||||
|
||||
let a = FheUint8::try_encrypt_trivial(234u8).unwrap();
|
||||
assert!(matches!(
|
||||
&*a.ciphertext.borrow(),
|
||||
crate::high_level_api::integers::server_key::RadixCiphertextDyn::Big(_)
|
||||
));
|
||||
|
||||
let clear: u8 = a.decrypt(&client_key);
|
||||
assert_eq!(clear, 234);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trivial_fhe_uint256_small() {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_uint256_small()
|
||||
.build();
|
||||
let (client_key, sks) = generate_keys(config);
|
||||
|
||||
set_server_key(sks);
|
||||
|
||||
let clear_a = U256::from(u128::MAX);
|
||||
let a = FheUint256::try_encrypt_trivial(clear_a).unwrap();
|
||||
assert!(matches!(
|
||||
&*a.ciphertext.borrow(),
|
||||
crate::high_level_api::integers::server_key::RadixCiphertextDyn::Small(_)
|
||||
));
|
||||
let clear: U256 = a.decrypt(&client_key);
|
||||
assert_eq!(clear, clear_a);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ use crate::high_level_api::keys::{
|
||||
CompressedPublicKey, RefKeyFromCompressedPublicKeyChain, RefKeyFromKeyChain,
|
||||
RefKeyFromPublicKeyChain,
|
||||
};
|
||||
use crate::high_level_api::traits::{FheBootstrap, FheDecrypt, FheEq, FheOrd, FheTryEncrypt};
|
||||
use crate::high_level_api::traits::{
|
||||
FheBootstrap, FheDecrypt, FheEq, FheOrd, FheTrivialEncrypt, FheTryEncrypt, FheTryTrivialEncrypt,
|
||||
};
|
||||
use crate::high_level_api::{ClientKey, PublicKey};
|
||||
use crate::integer::U256;
|
||||
|
||||
@@ -166,6 +168,47 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<P, T> FheTryTrivialEncrypt<T> for GenericInteger<P>
|
||||
where
|
||||
T: Into<U256>,
|
||||
P: IntegerParameter<
|
||||
InnerCiphertext = RadixCiphertextDyn,
|
||||
InnerServerKey = crate::integer::ServerKey,
|
||||
>,
|
||||
P::Id: WithGlobalKey<Key = GenericIntegerServerKey<P>> + Default,
|
||||
{
|
||||
type Error = crate::high_level_api::errors::Error;
|
||||
|
||||
fn try_encrypt_trivial(value: T) -> Result<Self, Self::Error> {
|
||||
let value = value.into();
|
||||
let id = P::Id::default();
|
||||
let ciphertext = id.with_global(|key| match key.pbs_order {
|
||||
crate::shortint::PBSOrder::KeyswitchBootstrap => {
|
||||
RadixCiphertextDyn::Big(key.inner.create_trivial_radix(value, key.num_block))
|
||||
}
|
||||
crate::shortint::PBSOrder::BootstrapKeyswitch => {
|
||||
RadixCiphertextDyn::Small(key.inner.create_trivial_radix(value, key.num_block))
|
||||
}
|
||||
})?;
|
||||
Ok(Self::new(ciphertext, id))
|
||||
}
|
||||
}
|
||||
|
||||
impl<P, T> FheTrivialEncrypt<T> for GenericInteger<P>
|
||||
where
|
||||
T: Into<U256>,
|
||||
P: IntegerParameter<
|
||||
InnerCiphertext = RadixCiphertextDyn,
|
||||
InnerServerKey = crate::integer::ServerKey,
|
||||
>,
|
||||
P::Id: WithGlobalKey<Key = GenericIntegerServerKey<P>> + Default,
|
||||
{
|
||||
#[track_caller]
|
||||
fn encrypt_trivial(value: T) -> Self {
|
||||
Self::try_encrypt_trivial(value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> GenericInteger<P>
|
||||
where
|
||||
P: IntegerParameter,
|
||||
|
||||
@@ -413,7 +413,7 @@ static_int_type! {
|
||||
parameters: Radix {
|
||||
big_block_parameters: crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2,
|
||||
small_block_parameters: crate::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2,
|
||||
num_block: 32,
|
||||
num_block: 16,
|
||||
wopbs_block_parameters: crate::shortint::parameters::parameters_wopbs_message_carry::WOPBS_PARAM_MESSAGE_2_CARRY_2,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::high_level_api::prelude::*;
|
||||
use crate::high_level_api::{generate_keys, CompressedFheUint2, ConfigBuilder, FheUint2};
|
||||
use crate::high_level_api::{
|
||||
generate_keys, set_server_key, CompressedFheUint2, ConfigBuilder, FheUint2,
|
||||
};
|
||||
use crate::CompressedPublicKey;
|
||||
|
||||
#[test]
|
||||
@@ -24,3 +26,15 @@ fn test_shortint_compressed_public_key() {
|
||||
let clear = a.decrypt(&client_key);
|
||||
assert_eq!(clear, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trivial_shortint() {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_uint2().build();
|
||||
let (client_key, sks) = generate_keys(config);
|
||||
|
||||
set_server_key(sks);
|
||||
|
||||
let a = FheUint2::try_encrypt_trivial(2).unwrap();
|
||||
let clear = a.decrypt(&client_key);
|
||||
assert_eq!(clear, 2);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ use crate::high_level_api::keys::{
|
||||
};
|
||||
use crate::high_level_api::shortints::public_key::compressed::GenericShortIntCompressedPublicKey;
|
||||
use crate::high_level_api::traits::{
|
||||
FheBootstrap, FheDecrypt, FheEq, FheNumberConstant, FheOrd, FheTryEncrypt, FheTryTrivialEncrypt,
|
||||
FheBootstrap, FheDecrypt, FheEq, FheNumberConstant, FheOrd, FheTrivialEncrypt, FheTryEncrypt,
|
||||
FheTryTrivialEncrypt,
|
||||
};
|
||||
use crate::high_level_api::PublicKey;
|
||||
|
||||
@@ -311,6 +312,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Clear, P> FheTrivialEncrypt<Clear> for GenericShortInt<P>
|
||||
where
|
||||
Clear: TryInto<u8>,
|
||||
P: StaticShortIntegerParameter,
|
||||
P::Id: Default + WithGlobalKey<Key = GenericShortIntServerKey<P>>,
|
||||
{
|
||||
#[track_caller]
|
||||
fn encrypt_trivial(value: Clear) -> Self {
|
||||
Self::try_encrypt_trivial(value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> GenericShortInt<P>
|
||||
where
|
||||
P: ShortIntegerParameter,
|
||||
|
||||
@@ -109,29 +109,35 @@ impl AsLittleEndianWords for U256 {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait BlockEncryptionKey {
|
||||
fn parameters(&self) -> &crate::shortint::Parameters;
|
||||
pub(crate) trait KnowsMessageModulus {
|
||||
fn message_modulus(&self) -> MessageModulus;
|
||||
}
|
||||
|
||||
impl BlockEncryptionKey for crate::shortint::ClientKey {
|
||||
fn parameters(&self) -> &crate::shortint::Parameters {
|
||||
&self.parameters
|
||||
impl KnowsMessageModulus for crate::shortint::ClientKey {
|
||||
fn message_modulus(&self) -> MessageModulus {
|
||||
self.parameters.message_modulus
|
||||
}
|
||||
}
|
||||
|
||||
impl<OpOrder: crate::shortint::PBSOrderMarker> BlockEncryptionKey
|
||||
impl<OpOrder: crate::shortint::PBSOrderMarker> KnowsMessageModulus
|
||||
for crate::shortint::PublicKeyBase<OpOrder>
|
||||
{
|
||||
fn parameters(&self) -> &crate::shortint::Parameters {
|
||||
&self.parameters
|
||||
fn message_modulus(&self) -> MessageModulus {
|
||||
self.parameters.message_modulus
|
||||
}
|
||||
}
|
||||
|
||||
impl<OpOrder: crate::shortint::PBSOrderMarker> BlockEncryptionKey
|
||||
impl<OpOrder: crate::shortint::PBSOrderMarker> KnowsMessageModulus
|
||||
for crate::shortint::CompressedPublicKeyBase<OpOrder>
|
||||
{
|
||||
fn parameters(&self) -> &crate::shortint::Parameters {
|
||||
&self.parameters
|
||||
fn message_modulus(&self) -> MessageModulus {
|
||||
self.parameters.message_modulus
|
||||
}
|
||||
}
|
||||
|
||||
impl KnowsMessageModulus for crate::shortint::ServerKey {
|
||||
fn message_modulus(&self) -> MessageModulus {
|
||||
self.message_modulus
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +157,7 @@ pub(crate) fn encrypt_words_radix_impl<BlockKey, Block, RadixCiphertextType, T,
|
||||
) -> RadixCiphertextType
|
||||
where
|
||||
T: AsLittleEndianWords,
|
||||
BlockKey: BlockEncryptionKey,
|
||||
BlockKey: KnowsMessageModulus,
|
||||
F: Fn(&BlockKey, u64) -> Block,
|
||||
RadixCiphertextType: From<Vec<Block>>,
|
||||
{
|
||||
@@ -165,8 +171,8 @@ where
|
||||
// | bit values are not valid and should not be encrypted)
|
||||
// |-> current_power (start of next block of bits to encrypt (inclusive))
|
||||
|
||||
let mask = (encrypting_key.parameters().message_modulus.0 - 1) as u128;
|
||||
let block_modulus = encrypting_key.parameters().message_modulus.0 as u128;
|
||||
let mask = (encrypting_key.message_modulus().0 - 1) as u128;
|
||||
let block_modulus = encrypting_key.message_modulus().0 as u128;
|
||||
|
||||
let mut blocks = Vec::with_capacity(num_blocks);
|
||||
|
||||
|
||||
@@ -1107,7 +1107,9 @@ impl<'a> Comparator<'a> {
|
||||
};
|
||||
|
||||
let mut res = self.unchecked_max_parallelized(lhs, rhs);
|
||||
self.server_key.full_propagate_parallelized(&mut res);
|
||||
res.blocks
|
||||
.par_iter_mut()
|
||||
.for_each(|block| self.server_key.key.message_extract_assign(block));
|
||||
res
|
||||
}
|
||||
|
||||
@@ -1143,7 +1145,9 @@ impl<'a> Comparator<'a> {
|
||||
};
|
||||
|
||||
let mut res = self.unchecked_min_parallelized(lhs, rhs);
|
||||
self.server_key.full_propagate_parallelized(&mut res);
|
||||
res.blocks
|
||||
.par_iter_mut()
|
||||
.for_each(|block| self.server_key.key.message_extract_assign(block));
|
||||
res
|
||||
}
|
||||
}
|
||||
@@ -1333,7 +1337,7 @@ mod tests {
|
||||
assert!(super::has_non_zero_carries(&ct_0));
|
||||
assert!(super::has_non_zero_carries(&ct_1));
|
||||
let encrypted_result = default_comparator_method(&comparator, &ct_0, &ct_1);
|
||||
// assert!(!super::has_non_zero_carries(&encrypted_result));
|
||||
assert!(!super::has_non_zero_carries(&encrypted_result));
|
||||
|
||||
// Sanity decryption checks
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@ mod sub;
|
||||
use super::ServerKey;
|
||||
|
||||
use crate::integer::ciphertext::RadixCiphertext;
|
||||
use crate::integer::encryption::{encrypt_words_radix_impl, AsLittleEndianWords};
|
||||
use crate::shortint::PBSOrderMarker;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -49,6 +50,44 @@ impl ServerKey {
|
||||
RadixCiphertext::from(vec_res)
|
||||
}
|
||||
|
||||
/// Create a trivial radix ciphertext
|
||||
///
|
||||
/// Trivial means that the value is not encrypted
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use tfhe::integer::{gen_keys_radix, RadixCiphertextBig};
|
||||
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
|
||||
///
|
||||
/// let num_blocks = 4;
|
||||
///
|
||||
/// // Generate the client key and the server key:
|
||||
/// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, num_blocks);
|
||||
///
|
||||
/// let ctxt: RadixCiphertextBig = sks.create_trivial_radix(212u64, num_blocks);
|
||||
///
|
||||
/// // Decrypt:
|
||||
/// let dec: u64 = cks.decrypt(&ctxt);
|
||||
/// assert_eq!(212, dec);
|
||||
/// ```
|
||||
pub fn create_trivial_radix<T, PBSOrder>(
|
||||
&self,
|
||||
value: T,
|
||||
num_blocks: usize,
|
||||
) -> RadixCiphertext<PBSOrder>
|
||||
where
|
||||
PBSOrder: PBSOrderMarker,
|
||||
T: AsLittleEndianWords,
|
||||
{
|
||||
encrypt_words_radix_impl(
|
||||
&self.key,
|
||||
value,
|
||||
num_blocks,
|
||||
crate::shortint::ServerKey::create_trivial,
|
||||
)
|
||||
}
|
||||
|
||||
/// Propagate the carry of the 'index' block to the next one.
|
||||
///
|
||||
/// # Example
|
||||
|
||||
@@ -342,10 +342,10 @@ impl ServerKey {
|
||||
terms.lock().unwrap().push(term);
|
||||
});
|
||||
|
||||
let terms = terms.into_inner().unwrap();
|
||||
let mut terms = terms.into_inner().unwrap();
|
||||
|
||||
for term in terms {
|
||||
self.unchecked_add_assign(&mut result, &term);
|
||||
for term in terms.iter_mut() {
|
||||
self.smart_add_assign(&mut result, term);
|
||||
}
|
||||
|
||||
result
|
||||
@@ -495,7 +495,20 @@ impl ServerKey {
|
||||
(ct1, &tmp_rhs)
|
||||
}
|
||||
};
|
||||
self.unchecked_mul_assign_parallelized(lhs, rhs);
|
||||
|
||||
let num_blocks = lhs.blocks.len();
|
||||
let mut terms = vec![self.create_trivial_zero_radix(num_blocks); num_blocks];
|
||||
terms
|
||||
.par_iter_mut()
|
||||
.zip(rhs.blocks.par_iter().enumerate())
|
||||
.for_each(|(term, (i, rhs_i))| {
|
||||
*term = self.unchecked_block_mul_parallelized(lhs, rhs_i, i);
|
||||
});
|
||||
|
||||
*lhs = self
|
||||
.smart_binary_op_seq_parallelized(&mut terms, ServerKey::smart_add_parallelized)
|
||||
.unwrap_or_else(|| self.create_trivial_zero_radix(num_blocks));
|
||||
|
||||
self.full_propagate_parallelized(lhs);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user