Compare commits

...

25 Commits
cm ... tmp_ccs

Author SHA1 Message Date
Loris
03635afa8f toolchain changed 2024-05-16 11:36:40 +02:00
J-B Orfila
4c659b5c70 Artifacts CCS2024 2024-04-23 11:00:00 +02:00
Arthur Meyre
b80e09f9d2 chore(tfhe): bump version 2024-02-29 09:28:28 +01:00
Arthur Meyre
aae5b45047 chore(tfhe): update toolchain to avoid SIMD breakage, fix lints 2024-02-29 09:28:28 +01:00
tmontaigu
c0240af4ca 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
2024-02-28 14:59:13 +01:00
Arthur Meyre
0578c2ab1d chore(ci): fix doctest by using parameters with enough precision 2024-02-28 14:59:13 +01:00
Arthur Meyre
d1abdc081d chore(ci): fix test runs by moving panic to its own test file
- investigate what goes wrong in the panic hook leading to multiple use of
the same object from the js side
2024-02-28 14:59:13 +01:00
Arthur Meyre
44ff195704 chore(tfhe): bump version to 0.4.3 2024-02-28 14:59:13 +01:00
Arthur Meyre
1fb65f1f6e fix(shortint): use proper noise value during compact list encryption 2024-02-28 14:59:13 +01:00
Arthur Meyre
e1f54981bf chore(tfhe): pin bytemuck to avoid nightly stdsimd breakage 2024-02-28 14:59:13 +01:00
Arthur Meyre
621cbcb14a chore(doc): correct some typos and wrong phrasing on data migration 2024-01-24 19:46:00 +01:00
Arthur Meyre
0898268733 chore(tfhe): bump version to 0.4.2 2024-01-23 19:48:36 +01:00
Arthur Meyre
6ec7f7e405 feat(forward_compatibility): add code to upgrade to TFHE-rs 0.5
- add tfhe-c-api-dynamic-buffer to be able to work with 0.5 buffers
- add a script to symlink the dependency lib to a fixed name
- the rust build system adds a fingerprint to the lib name which is not
practical when we are linking our C test executable
- link the most recent artifacts corresponding to the dependency we have
2024-01-23 19:48:36 +01:00
tmontaigu
16ad67ace3 chore(wasm): update dependencies of wasm tests 2024-01-23 19:48:36 +01:00
Arthur Meyre
c949256323 doc(data_migration): add documentation on how to migrate data for TFHE-rs
co-authored-by: jborfila
2024-01-22 13:43:10 +01:00
Arthur Meyre
7ae5f65909 feat(boolean): add raw parts methods to the ClientKey
- into_raw_parts allows to deconstruct a ClientKey
- new_from_raw_parts allows to construct a ClientKey
2024-01-08 17:17:27 +01:00
Arthur Meyre
4a2e9e5064 chore(c_api): add the c_api code from the docs as a test 2024-01-03 14:26:57 +01:00
Arthur Meyre
3ae27e79d0 doc(c_api): Add an output for the users compiling the C API example 2024-01-03 14:26:57 +01:00
tmontaigu
2332f89aa0 docs(capi): fix C API example 2024-01-03 14:26:57 +01:00
Arthur Meyre
3f9603a75c chore(ci): fix trivium clippy target 2023-11-28 19:23:29 +01:00
Arthur Meyre
848cc37300 chore(ci): update Makefile for semver trick 2023-11-28 19:23:29 +01:00
tmontaigu
2f4d00b13a chore(tfhe): bump version to 0.4.1 2023-10-23 15:00:39 +02:00
tmontaigu
2f295ea467 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-23 15:00:39 +02:00
tmontaigu
fa54a02c01 chore(ci): set node version 2023-10-23 15:00:39 +02:00
tmontaigu
646b644728 chore(ci): tell nvm to use node version 20 in wasm parallel tests 2023-10-23 15:00:39 +02:00
182 changed files with 17116 additions and 1922 deletions

View File

@@ -114,6 +114,10 @@ jobs:
run: |
make test_safe_deserialization
- name: Run forward compatibility tests
run: |
make test_forward_compatibility
- name: Slack Notification
if: ${{ always() }}
continue-on-error: true

View File

@@ -81,6 +81,10 @@ jobs:
run: |
make test_c_api
- name: Run C API tests with forward_compatibility
run: |
FORWARD_COMPAT=ON make test_c_api
- name: Run user docs tests
run: |
make test_user_doc

View File

@@ -66,9 +66,17 @@ jobs:
toolchain: nightly
override: true
- name: Run benchmarks with AVX512
- name: bench_ac2023_CJP
run: |
make AVX512_SUPPORT=ON bench_pbs
make AVX512_SUPPORT=ON bench_ac2023_CJP
- name: bench_ac2023_stairKS
run: |
make AVX512_SUPPORT=ON bench_ac2023_stairKS
- name: bench_ac2023_fastKS
run: |
make AVX512_SUPPORT=ON bench_ac2023_fastKS
- name: Parse results
run: |

189
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,6 +16,12 @@ PARSE_INTEGER_BENCH_CSV_FILE?=tfhe_rs_integer_benches.csv
FAST_TESTS?=FALSE
FAST_BENCH?=FALSE
BENCH_OP_FLAVOR?=DEFAULT
NODE_VERSION=20
FORWARD_COMPAT?=OFF
TFHE_CURRENT_VERSION:=$(shell grep '^version[[:space:]]*=' tfhe/Cargo.toml | 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
@@ -38,6 +44,12 @@ else
COVERAGE_ONLY=
endif
ifeq ($(FORWARD_COMPAT),ON)
FORWARD_COMPAT_FEATURE=forward_compatibility
else
FORWARD_COMPAT_FEATURE=
endif
# Variables used only for regex_engine example
REGEX_STRING?=''
REGEX_PATTERN?=''
@@ -99,7 +111,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
@@ -142,46 +154,52 @@ check_newline: check_linelint_installed
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
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
--features=$(TARGET_ARCH_FEATURE),nightly-avx512 \
-p $(TFHE_SPEC) -- --no-deps -D warnings
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
--features=$(TARGET_ARCH_FEATURE),experimental,nightly-avx512 \
-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:
@@ -190,15 +208,20 @@ clippy_tasks:
.PHONY: clippy_trivium # Run clippy lints on Trivium app
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
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
-p tfhe-trivium -- --no-deps -D warnings
.PHONY: clippy_all_targets # Run clippy lints on all targets (benches, examples, etc.)
clippy_all_targets:
clippy_all_targets: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,safe-deserialization \
-p tfhe -- --no-deps -D warnings
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_all_targets_forward_compatibility # Run clippy lints on all targets (benches, examples, etc.)
clippy_all_targets_forward_compatibility: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,safe-deserialization,forward_compatibility \
-p $(TFHE_SPEC) -- --no-deps -D warnings
.PHONY: clippy_concrete_csprng # Run clippy lints on concrete-csprng
clippy_concrete_csprng:
@@ -208,7 +231,8 @@ clippy_concrete_csprng:
.PHONY: clippy_all # Run all clippy targets
clippy_all: clippy clippy_boolean clippy_shortint clippy_integer clippy_all_targets clippy_c_api \
clippy_js_wasm_api clippy_tasks clippy_core clippy_concrete_csprng clippy_trivium
clippy_js_wasm_api clippy_tasks clippy_core clippy_concrete_csprng clippy_trivium \
clippy_all_targets_forward_compatibility
.PHONY: clippy_fast # Run main clippy targets
clippy_fast: clippy clippy_all_targets clippy_c_api clippy_js_wasm_api clippy_tasks clippy_core \
@@ -218,58 +242,66 @@ 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: symlink_c_libs_without_fingerprint # Link the .a and .so files without the changing hash part in target
symlink_c_libs_without_fingerprint:
@./scripts/symlink_c_libs_without_fingerprint.sh \
--cargo-profile "$(CARGO_PROFILE)" \
--lib-name tfhe-c-api-dynamic-buffer
.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,safe-deserialization \
-p tfhe
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api,safe-deserialization,$(FORWARD_COMPAT_FEATURE) \
-p $(TFHE_SPEC)
@"$(MAKE)" symlink_c_libs_without_fingerprint
.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,safe-deserialization,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,$(FORWARD_COMPAT_FEATURE) \
-p $(TFHE_SPEC)
@"$(MAKE)" symlink_c_libs_without_fingerprint
.PHONY: build_web_js_api # Build the js API targeting the web browser
build_web_js_api: install_rs_build_toolchain install_wasm_pack
@@ -302,16 +334,34 @@ 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_ccs_2024_stair_ks # Run the tests of the core_crypto module including experimental ones
test_ccs_2024_stair_ks: 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_SPEC) -- core_crypto::algorithms::test::lwe_stair_keyswitch
@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_SPEC) -- core_crypto::algorithms::test::lwe_stair_keyswitch; \
fi
.PHONY: test_ccs_2024_fft_shrinking_ks # Run the tests of the core_crypto module including experimental ones
test_ccs_2024_fft_shrinking_ks: 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_SPEC) -- core_crypto::algorithms::test::lwe_fast_keyswitch
@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_SPEC) -- core_crypto::algorithms::test::lwe_fast_keyswitch; \
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
@@ -319,18 +369,18 @@ test_boolean_cov: install_rs_check_toolchain install_tarpaulin
--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,safe-deserialization \
-p tfhe \
-p $(TFHE_SPEC) \
c_api
.PHONY: test_c_api_c # Run the C tests for the C API
test_c_api_c: build_c_api
./scripts/c_api_tests.sh
./scripts/c_api_tests.sh --forward-compat "$(FORWARD_COMPAT)"
.PHONY: test_c_api # Run all the tests for the C API
test_c_api: test_c_api_rs test_c_api_c
@@ -340,19 +390,19 @@ test_shortint_ci: install_rs_build_toolchain install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/shortint-tests.sh --rust-toolchain $(CARGO_RS_BUILD_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)"
--cargo-profile "$(CARGO_PROFILE)" --tfhe-package "$(TFHE_SPEC)"
.PHONY: test_shortint_multi_bit_ci # Run the tests for shortint ci running only multibit tests
test_shortint_multi_bit_ci: install_rs_build_toolchain install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/shortint-tests.sh --rust-toolchain $(CARGO_RS_BUILD_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)" --multi-bit
--cargo-profile "$(CARGO_PROFILE)" --multi-bit --tfhe-package "$(TFHE_SPEC)"
.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
@@ -360,42 +410,48 @@ test_shortint_cov: install_rs_check_toolchain install_tarpaulin
--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
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_BUILD_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)"
--cargo-profile "$(CARGO_PROFILE)" --tfhe-package "$(TFHE_SPEC)"
.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
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
--cargo-profile "$(CARGO_PROFILE)" --multi-bit --tfhe-package "$(TFHE_SPEC)"
.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 -- safe_deserialization::
--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_forward_compatibility # Run forward compatibility tests
test_forward_compatibility: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --tests --profile $(CARGO_PROFILE) \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,forward_compatibility,internal-keycache -p $(TFHE_SPEC) \
-- forward_compatibility::
.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
@@ -459,17 +515,19 @@ format_doc_latex:
check_compile_tests:
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --no-run \
--features=$(TARGET_ARCH_FEATURE),experimental,boolean,shortint,integer,internal-keycache,safe-deserialization \
-p tfhe
-p $(TFHE_SPEC)
@if [[ "$(OS)" == "Linux" || "$(OS)" == "Darwin" ]]; then \
"$(MAKE)" build_c_api; \
./scripts/c_api_tests.sh --build-only; \
"$(MAKE)" build_c_api && \
./scripts/c_api_tests.sh --build-only --forward-compat "$(FORWARD_COMPAT)" && \
FORWARD_COMPAT=ON "$(MAKE)" build_c_api && \
./scripts/c_api_tests.sh --build-only --forward-compat "$(FORWARD_COMPAT)"; \
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
@@ -493,7 +551,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
@@ -517,7 +576,7 @@ 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
bench_integer_multi_bit: install_rs_check_toolchain
@@ -525,14 +584,14 @@ bench_integer_multi_bit: install_rs_check_toolchain
__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_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
@@ -540,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
@@ -565,6 +624,24 @@ ci_bench_web_js_api_parallel: build_web_js_api_parallel
nvm use node && \
$(MAKE) -C tfhe/web_wasm_parallel_tests bench-ci
.PHONY: bench_ccs_2024_cjp # Run benchmarks for PBS
bench_ccs_2024_cjp: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench ccs-2024-cjp \
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC)
.PHONY: bench_ccs_2024_fft_shrinking_ks # Run benchmarks for PBS
bench_ccs_2024_fft_shrinking_ks: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench ccs-2024-fft-shrinking-ks \
--features=$(TARGET_ARCH_FEATURE),internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC)
.PHONY: bench_ccs_2024_stair_ks # Run benchmarks for PBS
bench_ccs_2024_stair_ks: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
--bench ccs-2024-stair-ks \
--features=$(TARGET_ARCH_FEATURE),internal-keycache,$(AVX512_FEATURE) -p $(TFHE_SPEC)
#
# Utility tools
#

84
README_CCS.md Normal file
View File

@@ -0,0 +1,84 @@
# Description
In what follows, we provide instructions on how to run benchmarks from the paper entitled "New Secret Keys for Enhanced Performance in (T)FHE". In particular, Table 2 and Figure 4 (in the Appendix) can be easily reproduced using this code.
The implementation of the techniques from the aforementioned paper has been integrated into the TFHE-rs library, version 0.4.
Modified or added source files are located in `tfhe/src/core_crypto/`:
- `algorithms/pseudo_ggsw_encryption.rs`
- `algorithms/pseudo_ggsw_conversion.rs`
- `algorithms/lwe_shrinking_keyswitch_key_generation.rs`
- `algorithms/lwe_shrinking_keyswitch.rs`
- `algorithms/lwe_secret_key_generation.rs`
- `algorithms/lwe_partial_secret_key_generation.rs`
- `algorithms/lwe_fast_keyswitch_key_generation.rs`
- `algorithms/lwe_fast_keyswitch.rs`
- `algorithms/glwe_secret_key_generation.rs`
- `algorithms/glwe_partial_secret_key_generation.rs`
- `algorithms/glwe_partial_sample_extraction.rs`
Test files are located in `tfhe/src/core_crypto/algorithms/test`:
- `lwe_stair_keyswitch.rs`
- `lwe_fast_keyswitch.rs`
Benchmarks are located in `tfhe/benches/core_crypto`:
- `ccs_2024_cjp.rs`
- `ccs_2024_fft_shrinking_ks.rs`
- `ccs_2024_stair_ks.rs`
# Dependencies
Tested on Linux and Mac OS with Rust >= 1.75 (see [here](https://www.rust-lang.org/tools/install) a guide to install Rust).
# How to run benchmarks
At the root of the project (i.e., in the TFHE-rs folder), enter the following commands to run the benchmarks:
- `make bench_ccs_2024_cjp`: Returns the timings associated with the CJP-based bootstrapping (Table 2, Line 1 + Figure 4, blue line);
- `make bench_ccs_2024_stair_ks`: Returns the timings associated with the "All+Stair-KS"-based bootstrapping (Table 2, Line 2 + Figure 4, red line);
- `make bench_ccs_2024_fft_shrinking_ks`: Returns the timings associated with the "All+FFT Shrinking-KS"-based bootstrapping (Table 2, Line 3 + Figure 4, green line);
This outputs the timings depending on the input precision.
Since large precision (>= 6 bits) might be long to execute, particularly on a laptop, these are disable by default. To choose which precision to launch, please uncomment lines associated to the parameter names into the `param_vec` variable, inside the `criterion_bench` function inside one of the benchmark files.
For instance, to launch only the precision 7 of the stair-KS benchmark, the correct `param_vec` variable (line 353 of `ccs_2024_stair_ks.rs`) looks like:
```rust
let param_vec = [
// PRECISION_1_STAIR,
// PRECISION_2_STAIR,
// PRECISION_3_STAIR,
// PRECISION_4_STAIR,
// PRECISION_5_STAIR,
// PRECISION_6_STAIR,
PRECISION_7_STAIR
// PRECISION_8_STAIR,
// PRECISION_9_STAIR,
// PRECISION_10_STAIR,
// PRECISION_11_STAIR,
];
```
Running the command `make bench_ccs_2024_stair_ks`will give the correct benchmark.
# How to run the tests
At the root of the project (i.e., in the TFHE-rs folder), enter the following commands to run the tests:
- `make test_ccs_2024_stair_ks`: Returns the timings associated with the "All+Stair-KS"-based bootstrapping (Table 2, Line 2 + Figure 4, red line);
- `make test_ccs_2024_fft_shrinking_ks`: Returns the timings associated with the "All+FFT Shrinking-KS"-based bootstrapping (Table 2, Line 3 + Figure 4, green line);
As for the benchmarks, all precision are not enabled by default. To add precision in the test, associated parameters must be uncommented in the macro `create_parametrized_test!` (located at the end of each test file)
For instance, in the file `lwe_fast_keyswitch.rs`, testing only the precision will look like this:
```rust
create_parametrized_test!(lwe_encrypt_fast_ks_decrypt_custom_mod {
PRECISION_1_FAST_KS,
PRECISION_2_FAST_KS,
PRECISION_3_FAST_KS,
PRECISION_4_FAST_KS,
PRECISION_5_FAST_KS,
PRECISION_6_FAST_KS,
PRECISION_7_FAST_KS,
PRECISION_8_FAST_KS,
// PRECISION_9_FAST_KS,
PRECISION_10_FAST_KS
// PRECISION_11_FAST_KS
});
```
Please note that the last parameter MUST NOT be followed by a comma `,` to correctly compile.

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

@@ -7,10 +7,12 @@ function usage() {
echo
echo "--help Print this message"
echo "--build-only Pass to only build the tests without running them"
echo "--forward-compat Indicate if we have forward compatibility enabled"
echo
}
BUILD_ONLY=0
forward_compat="OFF"
while [ -n "$1" ]
do
@@ -24,6 +26,11 @@ do
BUILD_ONLY=1
;;
"--forward-compat" )
shift
forward_compat="$1"
;;
*)
echo "Unknown param : $1"
exit 1
@@ -35,12 +42,18 @@ done
CURR_DIR="$(dirname "$0")"
REPO_ROOT="${CURR_DIR}/.."
TFHE_BUILD_DIR="${REPO_ROOT}/tfhe/build/"
DEFINE_FORWARD_COMPAT="OFF"
if [[ "${forward_compat}" == "ON" ]]; then
DEFINE_FORWARD_COMPAT="ON"
fi
mkdir -p "${TFHE_BUILD_DIR}"
cd "${TFHE_BUILD_DIR}"
cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DCARGO_PROFILE="${CARGO_PROFILE}"
cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DCARGO_PROFILE="${CARGO_PROFILE}" \
"-DWITH_FORWARD_COMPATIBILITY=${DEFINE_FORWARD_COMPAT}"
make -j

View File

@@ -3,12 +3,13 @@
set -e
function usage() {
echo "$0: shortint test runner"
echo "$0: integer test runner"
echo
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 "--cargo-profile The cargo profile used to build tests"
echo "--tfhe-package The package spec like tfhe@0.4.2, default=tfhe"
echo
}
@@ -16,6 +17,7 @@ RUST_TOOLCHAIN="+stable"
multi_bit=""
not_multi_bit="_multi_bit"
cargo_profile="release"
tfhe_package="tfhe"
while [ -n "$1" ]
do
@@ -40,6 +42,11 @@ do
cargo_profile="$1"
;;
"--tfhe-package" )
shift
tfhe_package="$1"
;;
*)
echo "Unknown param : $1"
exit 1
@@ -102,7 +109,7 @@ and not test(/.*default_add_sequence_multi_thread_param_message_3_carry_3_ks_pbs
cargo "${RUST_TOOLCHAIN}" nextest run \
--tests \
--cargo-profile "${cargo_profile}" \
--package tfhe \
--package "${tfhe_package}" \
--profile ci \
--features="${ARCH_FEATURE}",integer,internal-keycache \
--test-threads "${n_threads}" \
@@ -111,7 +118,7 @@ and not test(/.*default_add_sequence_multi_thread_param_message_3_carry_3_ks_pbs
if [[ "${multi_bit}" == "" ]]; then
cargo "${RUST_TOOLCHAIN}" test \
--profile "${cargo_profile}" \
--package tfhe \
--package "${tfhe_package}" \
--features="${ARCH_FEATURE}",integer,internal-keycache \
--doc \
-- integer::
@@ -146,7 +153,7 @@ and not test(/.*default_add_sequence_multi_thread_param_message_3_carry_3_ks_pbs
cargo "${RUST_TOOLCHAIN}" nextest run \
--tests \
--cargo-profile "${cargo_profile}" \
--package tfhe \
--package "${tfhe_package}" \
--profile ci \
--features="${ARCH_FEATURE}",integer,internal-keycache \
--test-threads $num_threads \
@@ -155,7 +162,7 @@ and not test(/.*default_add_sequence_multi_thread_param_message_3_carry_3_ks_pbs
if [[ "${multi_bit}" == "" ]]; then
cargo "${RUST_TOOLCHAIN}" test \
--profile "${cargo_profile}" \
--package tfhe \
--package "${tfhe_package}" \
--features="${ARCH_FEATURE}",integer,internal-keycache \
--doc \
-- --test-threads="$(${nproc_bin})" integer::

View File

@@ -9,12 +9,14 @@ function usage() {
echo "--rust-toolchain The toolchain to run the tests with default: stable"
echo "--multi-bit Run multi-bit tests only: default off"
echo "--cargo-profile The cargo profile used to build tests"
echo "--tfhe-package The package spec like tfhe@0.4.2, default=tfhe"
echo
}
RUST_TOOLCHAIN="+stable"
multi_bit=""
cargo_profile="release"
tfhe_package="tfhe"
while [ -n "$1" ]
do
@@ -38,6 +40,11 @@ do
cargo_profile="$1"
;;
"--tfhe-package" )
shift
tfhe_package="$1"
;;
*)
echo "Unknown param : $1"
exit 1
@@ -110,7 +117,7 @@ and not test(~smart_add_and_mul)""" # This test is too slow
cargo "${RUST_TOOLCHAIN}" nextest run \
--tests \
--cargo-profile "${cargo_profile}" \
--package tfhe \
--package "${tfhe_package}" \
--profile ci \
--features="${ARCH_FEATURE}",shortint,internal-keycache \
--test-threads "${n_threads_small}" \
@@ -127,7 +134,7 @@ and not test(~smart_add_and_mul)"""
cargo "${RUST_TOOLCHAIN}" nextest run \
--tests \
--cargo-profile "${cargo_profile}" \
--package tfhe \
--package "${tfhe_package}" \
--profile ci \
--features="${ARCH_FEATURE}",shortint,internal-keycache \
--test-threads "${n_threads_big}" \
@@ -136,7 +143,7 @@ and not test(~smart_add_and_mul)"""
if [[ "${multi_bit}" == "" ]]; then
cargo "${RUST_TOOLCHAIN}" test \
--profile "${cargo_profile}" \
--package tfhe \
--package "${tfhe_package}" \
--features="${ARCH_FEATURE}",shortint,internal-keycache \
--doc \
-- shortint::
@@ -175,7 +182,7 @@ and not test(~smart_add_and_mul)""" # This test is too slow
cargo "${RUST_TOOLCHAIN}" nextest run \
--tests \
--cargo-profile "${cargo_profile}" \
--package tfhe \
--package "${tfhe_package}" \
--profile ci \
--features="${ARCH_FEATURE}",shortint,internal-keycache \
--test-threads "$(${nproc_bin})" \
@@ -184,7 +191,7 @@ and not test(~smart_add_and_mul)""" # This test is too slow
if [[ "${multi_bit}" == "" ]]; then
cargo "${RUST_TOOLCHAIN}" test \
--profile "${cargo_profile}" \
--package tfhe \
--package "${tfhe_package}" \
--features="${ARCH_FEATURE}",shortint,internal-keycache \
--doc \
-- --test-threads="$(${nproc_bin})" shortint::

View File

@@ -0,0 +1,90 @@
#!/usr/bin/env bash
set -e
function usage() {
echo "$0: symlink C libs to names without the variable fingerprint part"
echo
echo "--help Print this message"
echo "--cargo-profile The cargo profile used"
echo "--lib-name The lib name without the lib prefix, '-' will be converted to '_'"
echo
}
CARGO_PROFILE=""
LIBNAME=""
while [ -n "$1" ]
do
case "$1" in
"--help" | "-h" )
usage
exit 0
;;
"--cargo-profile" )
shift
CARGO_PROFILE="$1"
;;
"--lib-name" )
shift
LIBNAME="$1"
;;
*)
echo "Unknown param : $1"
exit 1
;;
esac
shift
done
if [[ "${CARGO_PROFILE}" == "" ]]; then
echo "CARGO_PROFILE is not set, aborting."
exit 1
fi
UNAME="$(uname)"
if [[ "${UNAME}" != "Linux" && "${UNAME}" != "Darwin" ]]; then
echo "This script is compatible with Linux and macOS and may not work for your system"
fi
# Add the lib prefix
LIB_OF_INTEREST="lib${LIBNAME}"
LIB_OF_INTEREST_UNDERSCORE="${LIB_OF_INTEREST//-/_}"
CURR_DIR="$(dirname "$0")"
REPO_DIR="${CURR_DIR}/.."
OUTPUT_TARGET_DIR="${REPO_DIR}/target/${CARGO_PROFILE}"
OUTPUT_DEPS_DIR="${OUTPUT_TARGET_DIR}/deps"
cd "${OUTPUT_DEPS_DIR}"
echo "In ${PWD}"
# Find most recent file with similar name
MAYBE_STATIC_LIB="$(find . -maxdepth 1 -type f -name "${LIB_OF_INTEREST_UNDERSCORE}*.a")"
if [[ "${MAYBE_STATIC_LIB}" != "" ]]; then
STATIC_LIB="$(find . -maxdepth 1 -type f -name "${LIB_OF_INTEREST_UNDERSCORE}*.a" -print0 \
| xargs -0 ls -t | head -n 1)"
echo "Symlinking ${STATIC_LIB} to ${LIB_OF_INTEREST_UNDERSCORE}.a"
ln -snf "${STATIC_LIB}" "${LIB_OF_INTEREST_UNDERSCORE}.a"
else
echo "Could not find static lib that might correspond to $1, is there a typo in the lib name?"
fi
DYNAMIC_LIB_EXT="so"
if [[ "${UNAME}" == "Darwin" ]]; then
DYNAMIC_LIB_EXT="dylib"
fi
DYNAMIC_LIB_PATTERN="${LIB_OF_INTEREST_UNDERSCORE}*.${DYNAMIC_LIB_EXT}"
MAYBE_DYNAMIC_LIB="$(find . -maxdepth 1 -type f -name "${DYNAMIC_LIB_PATTERN}")"
if [[ "${MAYBE_DYNAMIC_LIB}" != "" ]]; then
DYNAMIC_LIB="$(find . -maxdepth 1 -type f -name "${DYNAMIC_LIB_PATTERN}" -print0 \
| xargs -0 ls -t | head -n 1)"
echo "Symlinking ${DYNAMIC_LIB} to ${LIB_OF_INTEREST_UNDERSCORE}.${DYNAMIC_LIB_EXT}"
ln -snf "${DYNAMIC_LIB}" "${LIB_OF_INTEREST_UNDERSCORE}.${DYNAMIC_LIB_EXT}"
else
echo "Could not find dynamic lib that might correspond to $1, is there a typo in the lib name?"
fi

View File

@@ -196,7 +196,7 @@ fn find_contiguous_doc_test<'a>(
fn find_contiguous_part_in_doc_test_or_comment(
part_is_code_block: bool,
full_doc_comment_content: &Vec<CommentContent>,
full_doc_comment_content: &[CommentContent],
part_start_idx: usize,
) -> (usize, usize) {
let mut next_line_idx = part_start_idx + 1;
@@ -348,7 +348,7 @@ fn process_doc_lines_until_impossible<'a>(
}
fn process_non_doc_lines_until_impossible(
lines: &Vec<&str>,
lines: &[&str],
rewritten_content: &mut String,
mut line_idx: usize,
) -> usize {

View File

@@ -1,6 +1,6 @@
[package]
name = "tfhe"
version = "0.4.0"
version = "0.4.4"
edition = "2021"
readme = "../README.md"
keywords = ["fully", "homomorphic", "encryption", "fhe", "cryptography"]
@@ -46,10 +46,10 @@ log = "0.4.19"
# End regex-engine deps
[build-dependencies]
cbindgen = { version = "0.26.0", optional = true }
cbindgen = { package = "tfhe-c-api-bindgen", version = "0.26.1", 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",
] }
@@ -57,14 +57,18 @@ lazy_static = { version = "1.4.0", optional = true }
serde = { version = "1.0", features = ["derive"] }
rayon = { version = "1.5.0" }
bincode = { version = "1.3.3", optional = true }
concrete-fft = { version = "0.3.0", features = ["serde", "fft128"] }
pulp = "0.13"
concrete-fft = { version = "0.4.0", features = ["serde", "fft128"] }
pulp = "0.18.8"
aligned-vec = { version = "0.5", features = ["serde"] }
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.11.0"
tfhe-c-api-dynamic-buffer = { version = "0.1.0", optional = true, features = [
"c_api",
] }
next_tfhe = { package = "tfhe", version = "0.5.0", optional = true }
# wasm deps
wasm-bindgen = { version = "0.2.86", features = [
@@ -75,32 +79,52 @@ js-sys = { version = "0.3", optional = true }
console_error_panic_hook = { version = "0.1.7", optional = true }
serde-wasm-bindgen = { version = "0.6.0", optional = true }
getrandom = { version = "0.2.8", optional = true }
bytemuck = "1.13.1"
bytemuck = "1.14.3"
[features]
forward_compatibility = [
"dep:bincode",
"dep:tfhe-c-api-dynamic-buffer",
"dep:next_tfhe",
"dep:paste",
]
# paste is used by the HL API
boolean = ["dep:paste"]
shortint = ["dep:paste"]
integer = ["shortint", "dep:paste"]
internal-keycache = ["lazy_static", "dep:fs2", "dep:bincode", "dep:paste"]
boolean = ["dep:paste", "next_tfhe?/boolean"]
shortint = ["dep:paste", "next_tfhe?/shortint"]
integer = ["shortint", "dep:paste", "next_tfhe?/integer"]
internal-keycache = [
"dep:lazy_static",
"dep:fs2",
"dep:bincode",
"dep:paste",
"next_tfhe?/internal-keycache",
]
safe-deserialization = ["dep:bincode"]
# Experimental section
experimental = []
experimental-force_fft_algo_dif4 = []
experimental = ["next_tfhe?/experimental"]
experimental-force_fft_algo_dif4 = [
"next_tfhe?/experimental-force_fft_algo_dif4",
]
# End experimental section
__c_api = ["cbindgen", "dep:bincode", "dep:paste"]
__c_api = [
"dep:cbindgen",
"dep:bincode",
"dep:paste",
"next_tfhe?/__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",
"dep:bincode",
"safe-deserialization",
@@ -109,34 +133,47 @@ 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"]
nightly-avx512 = [
"concrete-fft/nightly",
"pulp/nightly",
"next_tfhe?/nightly-avx512",
]
# Enable the x86_64 specific accelerated implementation of the random generator for the default
# backend
generator_x86_64_aesni = ["concrete-csprng/generator_x86_64_aesni"]
generator_x86_64_aesni = [
"concrete-csprng/generator_x86_64_aesni",
"next_tfhe?/generator_x86_64_aesni",
]
# Enable the aarch64 specific accelerated implementation of the random generator for the default
# backend
generator_aarch64_aes = ["concrete-csprng/generator_aarch64_aes"]
generator_aarch64_aes = [
"concrete-csprng/generator_aarch64_aes",
"next_tfhe?/generator_aarch64_aes",
]
# Private features
__profiling = []
__coverage = []
seeder_unix = ["concrete-csprng/seeder_unix"]
seeder_x86_64_rdseed = ["concrete-csprng/seeder_x86_64_rdseed"]
seeder_unix = ["concrete-csprng/seeder_unix", "next_tfhe?/seeder_unix"]
seeder_x86_64_rdseed = [
"concrete-csprng/seeder_x86_64_rdseed",
"next_tfhe?/seeder_x86_64_rdseed",
]
# These target_arch features enable a set of public features for tfhe if users want a known
# good/working configuration for tfhe.
# For a target_arch that does not yet have such a feature, one can still enable features manually or
# create a feature for said target_arch to make its use simpler.
x86_64 = ["generator_x86_64_aesni", "seeder_x86_64_rdseed"]
x86_64-unix = ["x86_64", "seeder_unix"]
x86_64 = ["generator_x86_64_aesni", "seeder_x86_64_rdseed", "next_tfhe?/x86_64"]
x86_64-unix = ["x86_64", "seeder_unix", "next_tfhe?/x86_64-unix"]
aarch64 = ["generator_aarch64_aes"]
aarch64-unix = ["aarch64", "seeder_unix"]
aarch64 = ["generator_aarch64_aes", "next_tfhe?/aarch64"]
aarch64-unix = ["aarch64", "seeder_unix", "next_tfhe?/aarch64-unix"]
[package.metadata.docs.rs]
# TODO: manage builds for docs.rs based on their documentation https://docs.rs/about
@@ -148,6 +185,23 @@ rustdoc-args = ["--html-in-header", "katex-header.html"]
# Benches #
# #
###########
[[bench]]
name = "ccs-2024-fft-shrinking-ks"
path = "benches/core_crypto/ccs_2024_fft_shrinking_ks.rs"
harness = false
required-features = ["internal-keycache"]
[[bench]]
name = "ccs-2024-cjp"
path = "benches/core_crypto/ccs_2024_cjp.rs"
harness = false
required-features = ["internal-keycache"]
[[bench]]
name = "ccs-2024-stair-ks"
path = "benches/core_crypto/ccs_2024_stair_ks.rs"
harness = false
required-features = ["internal-keycache"]
[[bench]]
name = "pbs-bench"

View File

@@ -0,0 +1,445 @@
use criterion::{criterion_group, criterion_main, Criterion};
use tfhe::core_crypto::prelude::*;
use tfhe::keycache::NamedParam;
use tfhe::named_params_impl;
fn generate_accumulator<F, Scalar: UnsignedTorus + CastFrom<usize>>(
polynomial_size: PolynomialSize,
glwe_size: GlweSize,
message_modulus: usize,
ciphertext_modulus: CiphertextModulus<Scalar>,
delta: Scalar,
f: F,
) -> GlweCiphertextOwned<Scalar>
where
F: Fn(Scalar) -> Scalar,
{
// N/(p/2) = size of each block, to correct noise from the input we introduce the
// notion of box, which manages redundancy to yield a denoised value
// for several noisy values around a true input value.
let box_size = polynomial_size.0 / message_modulus;
// Create the accumulator
let mut accumulator_scalar = vec![Scalar::ZERO; polynomial_size.0];
// Fill each box with the encoded denoised value
for i in 0..message_modulus {
let index = i * box_size;
accumulator_scalar[index..index + box_size]
.iter_mut()
.for_each(|a| *a = f(Scalar::cast_from(i)) * delta);
}
let half_box_size = box_size / 2;
// Negate the first half_box_size coefficients to manage negacyclicity and rotate
for a_i in accumulator_scalar[0..half_box_size].iter_mut() {
*a_i = (*a_i).wrapping_neg();
}
// Rotate the accumulator
accumulator_scalar.rotate_left(half_box_size);
let accumulator_plaintext = PlaintextList::from_container(accumulator_scalar);
allocate_and_trivially_encrypt_new_glwe_ciphertext(
glwe_size,
&accumulator_plaintext,
ciphertext_modulus,
)
}
named_params_impl!(
CJPParam<u64> =>
PRECISION_1_CJP,
PRECISION_2_CJP,
PRECISION_3_CJP,
PRECISION_4_CJP,
PRECISION_5_CJP,
PRECISION_6_CJP,
PRECISION_7_CJP,
PRECISION_8_CJP,
PRECISION_9_CJP,
PRECISION_10_CJP,
PRECISION_11_CJP,
);
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct CJPParam<Scalar: UnsignedTorus> {
pub log_precision: usize,
pub _log_mu: usize,
pub glwe_dimension: GlweDimension,
pub polynomial_size: PolynomialSize,
pub std_dev_bsk: StandardDev,
pub lwe_dimension: LweDimension,
pub ks1_lwe_modular_std_dev: StandardDev,
pub pbs_level: DecompositionLevelCount,
pub pbs_base_log: DecompositionBaseLog,
pub ks1_level: DecompositionLevelCount,
pub ks1_base_log: DecompositionBaseLog,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
// CJP
// p,log(nu), k, N, stddev, n, stddev, br_l,br_b, ks_l,ks_b, cost
// 1, 1, 5, 8, -31.07, 588, -12.66, 1, 15, 3, 3, 31445684
// 2, 2, 6, 8, -37.88, 668, -14.79, 1, 18, 3, 4, 42387300
// 3, 3, 4, 9, -51.49, 720, -16.17, 1, 21, 3, 4, 63333680
// 4, 4, 2, 10, -51.49, 788, -17.98, 1, 23, 3, 4, 78607596
// 5, 5, 1, 11, -51.49, 840, -19.36, 1, 23, 6, 3, 118525112
// 6, 6, 1, 12, -62.00, 840, -19.36, 2, 14, 5, 3, 347139256
// 7, 7, 1, 13, -62.00, 896, -20.85, 2, 15, 6, 3, 797064320
// 8, 8, 1, 14, -62.00, 968, -22.77, 3, 11, 6, 3, 2351201336
// 9, 9, 1, 15, -62.00, 1024, -24.26, 4, 9, 7, 3, 6510246912
// 10, 10, 1, 16, -62.00, 1096, -26.17, 6, 6, 12, 2, 20813446072
// 11, 11, 1, 17, -62.00, 1132, -27.13, 20, 2, 13, 2, 128439942036
pub const PRECISION_1_CJP: CJPParam<u64> = CJPParam {
log_precision: 1,
_log_mu: 1,
glwe_dimension: GlweDimension(5),
polynomial_size: PolynomialSize(256),
std_dev_bsk: StandardDev(4.43606636507407e-10),
lwe_dimension: LweDimension(588),
ks1_lwe_modular_std_dev: StandardDev(0.000154511302974888),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(15),
ks1_level: DecompositionLevelCount(3),
ks1_base_log: DecompositionBaseLog(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 2, 2, 6, 8, -37.88, 668, -14.79, 1, 18, 3, 4, 42387300
pub const PRECISION_2_CJP: CJPParam<u64> = CJPParam {
log_precision: 2,
_log_mu: 2,
glwe_dimension: GlweDimension(6),
polynomial_size: PolynomialSize(256),
std_dev_bsk: StandardDev(3.95351839879752e-12),
lwe_dimension: LweDimension(668),
ks1_lwe_modular_std_dev: StandardDev(0.0000352993220185940),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(18),
ks1_level: DecompositionLevelCount(3),
ks1_base_log: DecompositionBaseLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 3, 3, 4, 9, -51.49, 720, -16.17, 1, 21, 3, 4, 63333680
pub const PRECISION_3_CJP: CJPParam<u64> = CJPParam {
log_precision: 3,
_log_mu: 3,
glwe_dimension: GlweDimension(4),
polynomial_size: PolynomialSize(512),
std_dev_bsk: StandardDev(3.16202663074765e-16),
lwe_dimension: LweDimension(720),
ks1_lwe_modular_std_dev: StandardDev(0.0000135626629816676),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(21),
ks1_level: DecompositionLevelCount(3),
ks1_base_log: DecompositionBaseLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 4, 4, 2, 10, -51.49, 788, -17.98, 1, 23, 3, 4, 78607596
pub const PRECISION_4_CJP: CJPParam<u64> = CJPParam {
log_precision: 4,
_log_mu: 4,
glwe_dimension: GlweDimension(2),
polynomial_size: PolynomialSize(1024),
std_dev_bsk: StandardDev(3.16202663074765e-16),
lwe_dimension: LweDimension(788),
ks1_lwe_modular_std_dev: StandardDev(3.86794845500957e-6),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(23),
ks1_level: DecompositionLevelCount(3),
ks1_base_log: DecompositionBaseLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 5, 5, 1, 11, -51.49, 840, -19.36, 1, 23, 6, 3, 118525112
pub const PRECISION_5_CJP: CJPParam<u64> = CJPParam {
log_precision: 5,
_log_mu: 5,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
std_dev_bsk: StandardDev(3.16202663074765e-16),
lwe_dimension: LweDimension(840),
ks1_lwe_modular_std_dev: StandardDev(1.48613849575138e-6),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(23),
ks1_level: DecompositionLevelCount(6),
ks1_base_log: DecompositionBaseLog(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 6, 6, 1, 12, -62.00, 840, -19.36, 2, 14, 5, 3, 347139256
pub const PRECISION_6_CJP: CJPParam<u64> = CJPParam {
log_precision: 6,
_log_mu: 6,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(4096),
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(840),
ks1_lwe_modular_std_dev: StandardDev(1.48613849575138e-6),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(14),
ks1_level: DecompositionLevelCount(5),
ks1_base_log: DecompositionBaseLog(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 7, 7, 1, 13, -62.00, 896, -20.85, 2, 15, 6, 3, 797064320
pub const PRECISION_7_CJP: CJPParam<u64> = CJPParam {
log_precision: 7,
_log_mu: 7,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(8192),
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(896),
ks1_lwe_modular_std_dev: StandardDev(5.29083953889772e-7),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(15),
ks1_level: DecompositionLevelCount(6),
ks1_base_log: DecompositionBaseLog(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 8, 8, 1, 14, -62.00, 968, -22.77, 3, 11, 6, 3, 2351201336
pub const PRECISION_8_CJP: CJPParam<u64> = CJPParam {
log_precision: 8,
_log_mu: 8,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(16384),
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(968),
ks1_lwe_modular_std_dev: StandardDev(1.39812821058259e-7),
pbs_level: DecompositionLevelCount(3),
pbs_base_log: DecompositionBaseLog(11),
ks1_level: DecompositionLevelCount(6),
ks1_base_log: DecompositionBaseLog(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 9, 9, 1, 15, -62.00, 1024, -24.26, 4, 9, 7, 3, 6510246912
pub const PRECISION_9_CJP: CJPParam<u64> = CJPParam {
log_precision: 9,
_log_mu: 9,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(32768),
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(1024),
ks1_lwe_modular_std_dev: StandardDev(4.97751187937479e-8),
pbs_level: DecompositionLevelCount(4),
pbs_base_log: DecompositionBaseLog(9),
ks1_level: DecompositionLevelCount(7),
ks1_base_log: DecompositionBaseLog(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 10, 10, 1, 16, -62.00, 1096, -26.17, 6, 6, 12, 2, 20813446072
pub const PRECISION_10_CJP: CJPParam<u64> = CJPParam {
log_precision: 10,
_log_mu: 10,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(65536),
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(1096),
ks1_lwe_modular_std_dev: StandardDev(1.32447880680348e-8),
pbs_level: DecompositionLevelCount(6),
pbs_base_log: DecompositionBaseLog(6),
ks1_level: DecompositionLevelCount(12),
ks1_base_log: DecompositionBaseLog(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
// 11, 11, 1, 17, -62.00, 1132, -27.13, 20, 2, 13, 2, 128439942036
pub const PRECISION_11_CJP: CJPParam<u64> = CJPParam {
log_precision: 11,
_log_mu: 11,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(131072),
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(1132),
ks1_lwe_modular_std_dev: StandardDev(6.80857487193794e-9),
pbs_level: DecompositionLevelCount(20),
pbs_base_log: DecompositionBaseLog(2),
ks1_level: DecompositionLevelCount(13),
ks1_base_log: DecompositionBaseLog(2),
ciphertext_modulus: CiphertextModulus::new_native(),
};
fn criterion_bench(c: &mut Criterion) {
let param_vec = [
PRECISION_1_CJP,
PRECISION_2_CJP,
PRECISION_3_CJP,
PRECISION_4_CJP,
PRECISION_5_CJP,
PRECISION_6_CJP,
PRECISION_7_CJP,
PRECISION_8_CJP,
PRECISION_9_CJP,
PRECISION_10_CJP,
PRECISION_11_CJP,
];
for params in param_vec {
let log_precision = params.log_precision;
let _log_mu = params._log_mu;
let glwe_dimension = params.glwe_dimension;
let polynomial_size = params.polynomial_size;
let std_dev_bsk = params.std_dev_bsk;
let lwe_dimension = params.lwe_dimension;
let ks1_lwe_modular_std_dev = params.ks1_lwe_modular_std_dev;
let pbs_level = params.pbs_level;
let pbs_base_mpg = params.pbs_base_log;
let ks1_level = params.ks1_level;
let ks1_base_log = params.ks1_base_log;
let ciphertext_modulus = params.ciphertext_modulus;
let precision = 1 << (log_precision);
// let mu = 1<< _log_mu;
// let carry = (mu*(precision -1) +1)/precision;
// let log_carry = ((carry as f32).log2().ceil()) as usize;
// let delta_log = 63 - (log_precision + log_carry);
//println!("Delta log = {:?}", delta_log);
let delta_log = 63 - log_precision;
//TODO: to randomize
let msg = 1;
let pt = Plaintext(msg << delta_log);
// Create the PRNG
let mut seeder = new_seeder();
let seeder = seeder.as_mut();
let mut encryption_generator =
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
let mut secret_generator =
SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
let small_lwe_secret_key =
allocate_and_generate_new_binary_lwe_secret_key(lwe_dimension, &mut secret_generator);
let large_glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key(
glwe_dimension,
polynomial_size,
&mut secret_generator,
);
let large_lwe_secret_key = large_glwe_secret_key.clone().into_lwe_secret_key();
//KSK Generation
let ksk_large_to_small = allocate_and_generate_new_lwe_keyswitch_key(
&large_lwe_secret_key,
&small_lwe_secret_key,
ks1_base_log,
ks1_level,
ks1_lwe_modular_std_dev,
ciphertext_modulus,
&mut encryption_generator,
);
//Encryption
let mut large_lwe = LweCiphertext::new(
0u64,
large_lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
encrypt_lwe_ciphertext(
&large_lwe_secret_key,
&mut large_lwe,
pt,
std_dev_bsk,
&mut encryption_generator,
);
//KS
let mut small_lwe =
LweCiphertext::new(0u64, lwe_dimension.to_lwe_size(), ciphertext_modulus);
//PBS PART
let mut bsk = LweBootstrapKey::new(
0,
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_mpg,
pbs_level,
lwe_dimension,
ciphertext_modulus,
);
par_generate_lwe_bootstrap_key(
&small_lwe_secret_key,
&large_glwe_secret_key,
&mut bsk,
std_dev_bsk,
&mut encryption_generator,
);
let mut fbsk = FourierLweBootstrapKey::new(
small_lwe_secret_key.lwe_dimension(),
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_mpg,
pbs_level,
);
convert_standard_lwe_bootstrap_key_to_fourier(&bsk, &mut fbsk);
drop(bsk);
let accumulator = generate_accumulator(
polynomial_size,
glwe_dimension.to_glwe_size(),
precision,
ciphertext_modulus,
1 << delta_log,
|x| x & 1,
);
let mut out_pbs_ct = LweCiphertext::new(
0u64,
large_lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
let bench_id = format!("CJP::{}", params.name());
c.bench_function(&bench_id, |b| {
b.iter(|| {
keyswitch_lwe_ciphertext(&ksk_large_to_small, &large_lwe, &mut small_lwe);
programmable_bootstrap_lwe_ciphertext(
&small_lwe,
&mut out_pbs_ct,
&accumulator,
&fbsk,
);
})
});
}
}
criterion_group!(benches, criterion_bench);
criterion_main!(benches);
// #[test]
// fn test_CJP() {
// let param_vec = [
// PRECISION_1_CJP,
// PRECISION_2_CJP,
// PRECISION_3_CJP,
// PRECISION_4_CJP,
// PRECISION_5_CJP,
// // PRECISION_6_CJP,
// // PRECISION_7_CJP,
// // PRECISION_8_CJP,
// // PRECISION_9_CJP,
// // PRECISION_10_CJP,
// // PRECISION_11_CJP,
// ];
// for params in param_vec {
// to_gen_test_CJP(params);
// }
// }

View File

@@ -0,0 +1,581 @@
#![allow(clippy::excessive_precision)]
use criterion::{criterion_group, criterion_main, Criterion};
use tfhe::core_crypto::prelude::*;
use tfhe::keycache::NamedParam;
use tfhe::named_params_impl;
fn generate_accumulator<F, Scalar: UnsignedTorus + CastFrom<usize>>(
polynomial_size: PolynomialSize,
glwe_size: GlweSize,
message_modulus: usize,
ciphertext_modulus: CiphertextModulus<Scalar>,
delta: Scalar,
f: F,
) -> GlweCiphertextOwned<Scalar>
where
F: Fn(Scalar) -> Scalar,
{
// N/(p/2) = size of each block, to correct noise from the input we introduce the
// notion of box, which manages redundancy to yield a denoised value
// for several noisy values around a true input value.
let box_size = polynomial_size.0 / message_modulus;
// Create the accumulator
let mut accumulator_scalar = vec![Scalar::ZERO; polynomial_size.0];
// Fill each box with the encoded denoised value
for i in 0..message_modulus {
let index = i * box_size;
accumulator_scalar[index..index + box_size]
.iter_mut()
.for_each(|a| *a = f(Scalar::cast_from(i)) * delta);
}
let half_box_size = box_size / 2;
// Negate the first half_box_size coefficients to manage negacyclicity and rotate
for a_i in accumulator_scalar[0..half_box_size].iter_mut() {
*a_i = (*a_i).wrapping_neg();
}
// Rotate the accumulator
accumulator_scalar.rotate_left(half_box_size);
let accumulator_plaintext = PlaintextList::from_container(accumulator_scalar);
allocate_and_trivially_encrypt_new_glwe_ciphertext(
glwe_size,
&accumulator_plaintext,
ciphertext_modulus,
)
}
named_params_impl!(
FastKSParam<u64> =>
PRECISION_1_FAST_KS,
PRECISION_2_FAST_KS,
PRECISION_3_FAST_KS,
PRECISION_4_FAST_KS,
PRECISION_5_FAST_KS,
PRECISION_6_FAST_KS,
PRECISION_7_FAST_KS,
PRECISION_8_FAST_KS,
PRECISION_9_FAST_KS,
PRECISION_10_FAST_KS,
PRECISION_11_FAST_KS
);
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct FastKSParam<Scalar: UnsignedTorus> {
pub log_precision: usize,
pub _log_mu: usize,
pub glwe_dimension: GlweDimension,
pub polynomial_size: PolynomialSize,
pub phi_bsk: usize,
pub std_dev_bsk: StandardDev,
pub lwe_dimension: LweDimension,
pub ks1_lwe_modular_std_dev: StandardDev,
pub pbs_level: DecompositionLevelCount,
pub pbs_base_log: DecompositionBaseLog,
pub ks1_level: DecompositionLevelCount,
pub ks1_base_log: DecompositionBaseLog,
pub ks1_polynomial_size: PolynomialSize,
pub ks_in_glwe_dimension: GlweDimension,
pub phi_in: usize,
pub ks_out_glwe_dimension: GlweDimension,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
pub const PRECISION_1_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 1,
_log_mu: 1,
glwe_dimension: GlweDimension(5),
polynomial_size: PolynomialSize(256),
phi_bsk: 1280,
std_dev_bsk: StandardDev(4.436066365074074e-10),
lwe_dimension: LweDimension(534),
ks1_lwe_modular_std_dev: StandardDev(0.0004192214045106218),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(15),
ks1_level: DecompositionLevelCount(9),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(256),
ks_in_glwe_dimension: GlweDimension(3),
phi_in: 746,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_2_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 2,
_log_mu: 2,
glwe_dimension: GlweDimension(6),
polynomial_size: PolynomialSize(256),
phi_bsk: 1536,
std_dev_bsk: StandardDev(3.953518398797519e-12),
lwe_dimension: LweDimension(590),
ks1_lwe_modular_std_dev: StandardDev(0.0001492480807729575),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(18),
ks1_level: DecompositionLevelCount(11),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(1024),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 946,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_3_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 3,
_log_mu: 3,
glwe_dimension: GlweDimension(3),
polynomial_size: PolynomialSize(512),
phi_bsk: 1536,
std_dev_bsk: StandardDev(3.953518398797519e-12),
lwe_dimension: LweDimension(686),
ks1_lwe_modular_std_dev: StandardDev(2.5308824029981747e-05),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(18),
ks1_level: DecompositionLevelCount(13),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(1024),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 850,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_4_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 4,
_log_mu: 4,
glwe_dimension: GlweDimension(2),
polynomial_size: PolynomialSize(1024),
phi_bsk: 2048,
std_dev_bsk: StandardDev(3.162026630747649e-16),
lwe_dimension: LweDimension(682),
ks1_lwe_modular_std_dev: StandardDev(2.7313997525878062e-05),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(23),
ks1_level: DecompositionLevelCount(14),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(512),
ks_in_glwe_dimension: GlweDimension(3),
phi_in: 1366,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_5_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 5,
_log_mu: 5,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
phi_bsk: 2048,
std_dev_bsk: StandardDev(3.162026630747649e-16),
lwe_dimension: LweDimension(766),
ks1_lwe_modular_std_dev: StandardDev(5.822216831056818e-06),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(23),
ks1_level: DecompositionLevelCount(15),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(512),
ks_in_glwe_dimension: GlweDimension(3),
phi_in: 1282,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_6_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 6,
_log_mu: 6,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(4096),
phi_bsk: 2443,
std_dev_bsk: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(774),
ks1_lwe_modular_std_dev: StandardDev(4.998754134591537e-06),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(14),
ks1_level: DecompositionLevelCount(15),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(2048),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 1669,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_7_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 7,
_log_mu: 7,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(8192),
phi_bsk: 2443,
std_dev_bsk: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(818),
ks1_lwe_modular_std_dev: StandardDev(2.2215530137414073e-06),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(14),
ks1_level: DecompositionLevelCount(16),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(2048),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 1625,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_8_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 8,
_log_mu: 8,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(16384),
phi_bsk: 2443,
std_dev_bsk: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(854),
ks1_lwe_modular_std_dev: StandardDev(1.1499479557902908e-06),
pbs_level: DecompositionLevelCount(3),
pbs_base_log: DecompositionBaseLog(11),
ks1_level: DecompositionLevelCount(18),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(2048),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 1589,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_9_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 9,
_log_mu: 9,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(32768),
phi_bsk: 2443,
std_dev_bsk: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(902),
ks1_lwe_modular_std_dev: StandardDev(4.7354340335704556e-07),
pbs_level: DecompositionLevelCount(4),
pbs_base_log: DecompositionBaseLog(8),
ks1_level: DecompositionLevelCount(18),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(2048),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 1541,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_10_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 10,
_log_mu: 10,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(65536),
phi_bsk: 2443,
std_dev_bsk: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(938),
ks1_lwe_modular_std_dev: StandardDev(2.434282602565751e-07),
pbs_level: DecompositionLevelCount(6),
pbs_base_log: DecompositionBaseLog(6),
ks1_level: DecompositionLevelCount(20),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(512),
ks_in_glwe_dimension: GlweDimension(3),
phi_in: 1505,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_11_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: 11,
_log_mu: 11,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(131072),
phi_bsk: 2443,
std_dev_bsk: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(1018),
ks1_lwe_modular_std_dev: StandardDev(5.56131000242714e-08),
pbs_level: DecompositionLevelCount(13),
pbs_base_log: DecompositionBaseLog(3),
ks1_level: DecompositionLevelCount(22),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(512),
ks_in_glwe_dimension: GlweDimension(3),
phi_in: 1425,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
fn criterion_bench(c: &mut Criterion) {
let param_vec = [
PRECISION_1_FAST_KS,
PRECISION_2_FAST_KS,
PRECISION_3_FAST_KS,
PRECISION_4_FAST_KS,
PRECISION_5_FAST_KS,
PRECISION_6_FAST_KS,
PRECISION_7_FAST_KS,
PRECISION_8_FAST_KS,
PRECISION_9_FAST_KS,
PRECISION_10_FAST_KS,
PRECISION_11_FAST_KS,
];
for params in param_vec {
let log_precision = params.log_precision;
let _log_mu = params._log_mu;
let glwe_dimension = params.glwe_dimension;
let polynomial_size = params.polynomial_size;
let phi_bsk = params.phi_bsk;
let std_dev_bsk = params.std_dev_bsk;
let lwe_dimension = params.lwe_dimension;
let ks1_lwe_modular_std_dev = params.ks1_lwe_modular_std_dev;
let pbs_level = params.pbs_level;
let pbs_base_mpg = params.pbs_base_log;
let ks1_level = params.ks1_level;
let ks1_base_log = params.ks1_base_log;
let ks1_polynomial_size = params.ks1_polynomial_size;
let ks_in_glwe_dimension = params.ks_in_glwe_dimension;
let phi_in = params.phi_in;
let ks_out_glwe_dimension = params.ks_out_glwe_dimension;
let ciphertext_modulus = params.ciphertext_modulus;
let precision = 1 << (log_precision);
let delta_log = 63 - log_precision;
//TODO: to randomize
let msg = 1;
let pt = Plaintext(msg << delta_log);
// Create the PRNG
let mut seeder = new_seeder();
let seeder = seeder.as_mut();
let mut encryption_generator =
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
let mut secret_generator =
SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
//Shared and partial key generations
let glwe_secret_key = allocate_and_generate_new_binary_partial_glwe_secret_key(
glwe_dimension,
polynomial_size,
PartialGlweSecretKeyRandomCoefCount(phi_bsk),
&mut secret_generator,
);
let large_lwe_secret_key = glwe_secret_key.clone().into_lwe_secret_key();
let mut large_glwe_secret_key_without_shared =
GlweSecretKey::new_empty_key(0u64, ks_in_glwe_dimension, ks1_polynomial_size);
large_glwe_secret_key_without_shared.as_mut()[0..phi_bsk - lwe_dimension.0]
.copy_from_slice(&glwe_secret_key.as_ref()[lwe_dimension.0..phi_bsk]);
let small_glwe_secret_key =
allocate_and_generate_new_shared_glwe_secret_key_from_glwe_secret_key(
// large_glwe_secret_key_without_shared.clone(),
&glwe_secret_key,
ks_out_glwe_dimension,
lwe_dimension.0,
ks1_polynomial_size,
);
let mut ggsw = PseudoGgswCiphertext::new(
0u64,
ks_in_glwe_dimension.to_glwe_size(),
ks_out_glwe_dimension.to_glwe_size(),
ks1_polynomial_size,
ks1_base_log,
ks1_level,
ciphertext_modulus,
);
//Encryption
let mut large_lwe = LweCiphertext::new(
0u64,
large_lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
encrypt_lwe_ciphertext(
&large_lwe_secret_key,
&mut large_lwe,
pt,
std_dev_bsk,
&mut encryption_generator,
);
let mut split_large_lwe =
LweCiphertext::new(0u64, lwe_dimension.to_lwe_size(), ciphertext_modulus);
split_large_lwe.as_mut()[0..lwe_dimension.0]
.iter_mut()
.zip(large_lwe.as_ref()[0..lwe_dimension.0].iter())
.for_each(|(dst, &src)| *dst = src);
let body = split_large_lwe.get_mut_body().data;
*body = *large_lwe.get_body().data;
let mut split_large_lwe_to_ks = LweCiphertext::new(
0u64,
LweSize(phi_bsk - lwe_dimension.0 + 1),
ciphertext_modulus,
);
split_large_lwe_to_ks.as_mut()[0..phi_bsk - lwe_dimension.0]
.iter_mut()
.zip(large_lwe.as_ref()[lwe_dimension.0..phi_bsk].iter())
.for_each(|(dst, &src)| *dst = src);
let mut nks_kin_glwe = GlweCiphertext::new(
0u64,
ks_in_glwe_dimension.to_glwe_size(),
ks1_polynomial_size,
ciphertext_modulus,
);
encrypt_pseudo_ggsw_ciphertext(
&small_glwe_secret_key,
&large_glwe_secret_key_without_shared,
&mut ggsw,
ks1_lwe_modular_std_dev,
&mut encryption_generator,
);
//Memory stuff
let fft = Fft::new(ks1_polynomial_size);
let fft = fft.as_view();
let mut buffers = ComputationBuffers::new();
let buffer_size_req =
add_external_product_fast_keyswitch_assign_mem_optimized_requirement::<u64>(
small_glwe_secret_key.glwe_dimension(),
ks1_polynomial_size,
fft,
)
.unwrap()
.unaligned_bytes_required();
let buffer_size_req = buffer_size_req.max(
convert_standard_ggsw_ciphertext_to_fourier_mem_optimized_requirement(fft)
.unwrap()
.unaligned_bytes_required(),
);
buffers.resize(10 * buffer_size_req);
//To Fourier
let mut fourier_ggsw = PseudoFourierGgswCiphertext::new(
ks_in_glwe_dimension.to_glwe_size(),
ks_out_glwe_dimension.to_glwe_size(),
ks1_polynomial_size,
ks1_base_log,
ks1_level,
);
convert_standard_pseudo_ggsw_ciphertext_to_fourier_mem_optimized(
&ggsw,
&mut fourier_ggsw,
fft,
buffers.stack(),
);
let mut glwe_after_ks = GlweCiphertext::new(
0u64,
ks_out_glwe_dimension.to_glwe_size(),
ks1_polynomial_size,
ciphertext_modulus,
);
let mut small_lwe_secret_key = LweSecretKey::new_empty_key(0u64, lwe_dimension);
small_lwe_secret_key.as_mut()[0..lwe_dimension.0].copy_from_slice(
&glwe_secret_key.clone().into_lwe_secret_key().as_ref()[0..lwe_dimension.0],
);
let mut bsk = LweBootstrapKey::new(
0,
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_mpg,
pbs_level,
lwe_dimension,
ciphertext_modulus,
);
par_generate_lwe_bootstrap_key(
&small_lwe_secret_key,
&glwe_secret_key,
&mut bsk,
std_dev_bsk,
&mut encryption_generator,
);
let mut fbsk = FourierLweBootstrapKey::new(
small_lwe_secret_key.lwe_dimension(),
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_mpg,
pbs_level,
);
convert_standard_lwe_bootstrap_key_to_fourier(&bsk, &mut fbsk);
drop(bsk);
let accumulator = generate_accumulator(
polynomial_size,
glwe_dimension.to_glwe_size(),
precision,
ciphertext_modulus,
1 << delta_log,
|x| x,
);
let mut out_pbs_ct = LweCiphertext::new(
0u64,
large_lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
let bench_id = format!("FAST_KS::{}", params.name());
c.bench_function(&bench_id, |b| {
b.iter(|| {
partial_convert_lwe_ciphertext_into_constant_glwe_ciphertext(
&split_large_lwe_to_ks,
&mut nks_kin_glwe,
phi_in,
);
let large_glwe_without_shared = nks_kin_glwe.clone();
add_external_product_fast_keyswitch_assign_mem_optimized(
&mut glwe_after_ks,
&fourier_ggsw,
&large_glwe_without_shared,
fft,
buffers.stack(),
);
//Encryption
let mut lwe_after_partial_sample_extract =
LweCiphertext::new(0u64, lwe_dimension.to_lwe_size(), ciphertext_modulus);
partial_extract_lwe_sample_from_glwe_ciphertext(
&glwe_after_ks,
&mut lwe_after_partial_sample_extract,
MonomialDegree(0),
lwe_dimension.0,
);
//Sum with initial ct
lwe_after_partial_sample_extract.as_mut()[0..lwe_dimension.0]
.iter_mut()
.zip(split_large_lwe.as_ref()[0..lwe_dimension.0].iter())
.for_each(|(dst, &src)| *dst = dst.wrapping_add(src));
let body = lwe_after_partial_sample_extract.get_mut_body().data;
*body = body.wrapping_add(*split_large_lwe.get_body().data);
programmable_bootstrap_lwe_ciphertext(
&lwe_after_partial_sample_extract,
&mut out_pbs_ct,
&accumulator,
&fbsk,
);
})
});
}
}
criterion_group!(benches, criterion_bench);
criterion_main!(benches);

View File

@@ -0,0 +1,575 @@
#![allow(clippy::excessive_precision)]
use criterion::{criterion_group, criterion_main, Criterion};
use tfhe::core_crypto::prelude::*;
use tfhe::keycache::NamedParam;
use tfhe::named_params_impl;
fn generate_accumulator<F, Scalar: UnsignedTorus + CastFrom<usize>>(
polynomial_size: PolynomialSize,
glwe_size: GlweSize,
message_modulus: usize,
ciphertext_modulus: CiphertextModulus<Scalar>,
delta: Scalar,
f: F,
) -> GlweCiphertextOwned<Scalar>
where
F: Fn(Scalar) -> Scalar,
{
// N/(p/2) = size of each block, to correct noise from the input we introduce the
// notion of box, which manages redundancy to yield a denoised value
// for several noisy values around a true input value.
let box_size = polynomial_size.0 / message_modulus;
// Create the accumulator
let mut accumulator_scalar = vec![Scalar::ZERO; polynomial_size.0];
// Fill each box with the encoded denoised value
for i in 0..message_modulus {
let index = i * box_size;
accumulator_scalar[index..index + box_size]
.iter_mut()
.for_each(|a| *a = f(Scalar::cast_from(i)) * delta);
}
let half_box_size = box_size / 2;
// Negate the first half_box_size coefficients to manage negacyclicity and rotate
for a_i in accumulator_scalar[0..half_box_size].iter_mut() {
*a_i = (*a_i).wrapping_neg();
}
// Rotate the accumulator
accumulator_scalar.rotate_left(half_box_size);
let accumulator_plaintext = PlaintextList::from_container(accumulator_scalar);
allocate_and_trivially_encrypt_new_glwe_ciphertext(
glwe_size,
&accumulator_plaintext,
ciphertext_modulus,
)
}
named_params_impl!(
StairKSParam<u64> =>
PRECISION_1_STAIR,
PRECISION_2_STAIR,
PRECISION_3_STAIR,
PRECISION_4_STAIR,
PRECISION_5_STAIR,
PRECISION_6_STAIR,
PRECISION_7_STAIR,
PRECISION_8_STAIR,
PRECISION_9_STAIR,
PRECISION_10_STAIR,
PRECISION_11_STAIR,
);
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct StairKSParam<Scalar: UnsignedTorus> {
pub log_precision: usize,
pub _log_mu: usize,
pub glwe_dimension: GlweDimension,
pub polynomial_size: PolynomialSize,
pub phi: usize,
pub std_dev_bsk: StandardDev,
pub lwe_dimension: LweDimension,
pub ks1_lwe_modular_std_dev: StandardDev,
pub ks2_lwe_modular_std_dev: StandardDev,
pub pbs_level: DecompositionLevelCount,
pub pbs_base_log: DecompositionBaseLog,
pub ks1_level: DecompositionLevelCount,
pub ks1_base_log: DecompositionBaseLog,
pub ks2_level: DecompositionLevelCount,
pub ks2_base_log: DecompositionBaseLog,
pub size1: usize,
pub size2: usize,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 1, 1, 5, 8, 1280, -31.07, 532, -17.82, -11.17, 1, 15, 1, 9, 4,
// 2, 498, 250, 26700580
pub const PRECISION_1_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 1,
_log_mu: 1,
glwe_dimension: GlweDimension(5),
polynomial_size: PolynomialSize(256),
phi: 1280,
std_dev_bsk: StandardDev(4.43606636507407e-10),
lwe_dimension: LweDimension(532),
ks1_lwe_modular_std_dev: StandardDev(4.32160905950851e-6),
ks2_lwe_modular_std_dev: StandardDev(0.000434005215413364),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(15),
ks1_level: DecompositionLevelCount(1),
ks1_base_log: DecompositionBaseLog(9),
ks2_level: DecompositionLevelCount(4),
ks2_base_log: DecompositionBaseLog(2),
size1: 498,
size2: 250,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 2, 2, 6, 8, 1536, -37.88, 576, -20.85, -12.34, 1, 18, 1, 10, 5,
// 2, 640, 320, 35091584
pub const PRECISION_2_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 2,
_log_mu: 2,
glwe_dimension: GlweDimension(6),
polynomial_size: PolynomialSize(256),
phi: 1536,
std_dev_bsk: StandardDev(3.953518398797519e-12),
lwe_dimension: LweDimension(576),
ks1_lwe_modular_std_dev: StandardDev(5.290839538897724e-07),
ks2_lwe_modular_std_dev: StandardDev(0.00019288117965414483),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(18),
ks1_level: DecompositionLevelCount(1),
ks1_base_log: DecompositionBaseLog(10),
ks2_level: DecompositionLevelCount(5),
ks2_base_log: DecompositionBaseLog(2),
size1: 640,
size2: 320,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 3, 3, 3, 9, 1536, -37.88, 648, -22.13, -14.25, 1, 18, 2, 7, 6,
// 2, 592, 296, 42686328
pub const PRECISION_3_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 3,
_log_mu: 3,
glwe_dimension: GlweDimension(3),
polynomial_size: PolynomialSize(512),
phi: 1536,
std_dev_bsk: StandardDev(3.95351839879752e-12),
lwe_dimension: LweDimension(648),
ks1_lwe_modular_std_dev: StandardDev(2.17874395902014e-7),
ks2_lwe_modular_std_dev: StandardDev(5.132424409507535e-05),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(18),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(7),
ks2_level: DecompositionLevelCount(6),
ks2_base_log: DecompositionBaseLog(2),
size1: 592,
size2: 296,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 4, 4, 2, 10, 2048, -51.49, 664, -26.97, -14.68, 1, 22, 1, 13, 6,
// 2, 922, 462, 65150660
pub const PRECISION_4_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 4,
_log_mu: 4,
glwe_dimension: GlweDimension(2),
polynomial_size: PolynomialSize(1024),
phi: 2048,
std_dev_bsk: StandardDev(3.16202663074765e-16),
lwe_dimension: LweDimension(664),
ks1_lwe_modular_std_dev: StandardDev(7.60713313301797e-9),
ks2_lwe_modular_std_dev: StandardDev(0.0000380960250519291),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(22),
ks1_level: DecompositionLevelCount(1),
ks1_base_log: DecompositionBaseLog(13),
ks2_level: DecompositionLevelCount(6),
ks2_base_log: DecompositionBaseLog(2),
size1: 922,
size2: 462,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 5, 5, 1, 11, 2048, -51.49, 732, -28.17, -16.49, 1, 23, 2, 9, 7,
// 2, 877, 439, 94962998
pub const PRECISION_5_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 5,
_log_mu: 5,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
phi: 2048,
std_dev_bsk: StandardDev(3.16202663074765e-16),
lwe_dimension: LweDimension(732),
ks1_lwe_modular_std_dev: StandardDev(3.31119701700870e-9),
ks2_lwe_modular_std_dev: StandardDev(0.0000108646407745138),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(23),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(9),
ks2_level: DecompositionLevelCount(7),
ks2_base_log: DecompositionBaseLog(2),
size1: 877,
size2: 439,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 6, 6, 1, 12, 2443, -62.00, 748, -31.94, -16.91, 2, 14, 1, 16, 8,
// 2, 1130, 565, 283238205
pub const PRECISION_6_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 6,
_log_mu: 6,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(4096),
phi: 2443,
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(748),
ks1_lwe_modular_std_dev: StandardDev(2.42717974083759e-10),
ks2_lwe_modular_std_dev: StandardDev(8.12050004923523e-6),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(14),
ks1_level: DecompositionLevelCount(1),
ks1_base_log: DecompositionBaseLog(16),
ks2_level: DecompositionLevelCount(8),
ks2_base_log: DecompositionBaseLog(2),
size1: 1130,
size2: 565,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 7, 7, 1, 13, 2443, -62.00, 776, -32.45, -17.66, 2, 15, 2, 10, 16,
// 1, 1111, 556, 614607038
pub const PRECISION_7_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 7,
_log_mu: 7,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(8192),
phi: 2443,
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(776),
ks1_lwe_modular_std_dev: StandardDev(1.70442007475721e-10),
ks2_lwe_modular_std_dev: StandardDev(4.82847821796524e-6),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(15),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(10),
ks2_level: DecompositionLevelCount(16),
ks2_base_log: DecompositionBaseLog(1),
size1: 1111,
size2: 556,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 8, 8, 1, 14, 2443, -62.00, 816, -33.17, -18.72, 3, 11, 2, 9, 17,
// 1, 1084, 543, 1795749574
pub const PRECISION_8_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 8,
_log_mu: 8,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(16384),
phi: 2443,
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(816),
ks1_lwe_modular_std_dev: StandardDev(1.03474906781522e-10),
ks2_lwe_modular_std_dev: StandardDev(2.31589295271883e-6),
pbs_level: DecompositionLevelCount(3),
pbs_base_log: DecompositionBaseLog(11),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(9),
ks2_level: DecompositionLevelCount(17),
ks2_base_log: DecompositionBaseLog(1),
size1: 1084,
size2: 543,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 9, 9, 1, 15, 2443, -62.00, 860, -33.94, -19.89, 4, 8, 2, 10, 18,
// 1, 1055, 528, 4992007842
pub const PRECISION_9_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 9,
_log_mu: 9,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(32768),
phi: 2443,
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(860),
ks1_lwe_modular_std_dev: StandardDev(6.06794935209399e-11),
ks2_lwe_modular_std_dev: StandardDev(1.02923225069468e-6),
pbs_level: DecompositionLevelCount(4),
pbs_base_log: DecompositionBaseLog(8),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(10),
ks2_level: DecompositionLevelCount(18),
ks2_base_log: DecompositionBaseLog(1),
size1: 1055,
size2: 528,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 10, 10, 1, 16, 2443, -62.00, 904, -34.71, -21.06, 6, 6, 2, 11, 19,
// 1, 1026, 513, 15555548076
pub const PRECISION_10_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 10,
_log_mu: 10,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(65536),
phi: 2443,
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(904),
ks1_lwe_modular_std_dev: StandardDev(3.55835153515238e-11),
ks2_lwe_modular_std_dev: StandardDev(4.77994271508188e-14),
pbs_level: DecompositionLevelCount(6),
pbs_base_log: DecompositionBaseLog(6),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(11),
ks2_level: DecompositionLevelCount(19),
ks2_base_log: DecompositionBaseLog(1),
size1: 1026,
size2: 513,
ciphertext_modulus: CiphertextModulus::new_native(),
};
// p,log(nu), k, N, phi, stddev, n, stddev, stddev, br_l,br_b, ksl1,ksb1, ksl2,ksb2, size1,
// size2, cost 11, 11, 1, 17, 2443, -62.00, 984, -36.15, -23.19, 12, 3, 2, 11, 21,
// 1, 972, 487, 66586908138
pub const PRECISION_11_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: 11,
_log_mu: 11,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(131072),
phi: 2443,
std_dev_bsk: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(984),
ks1_lwe_modular_std_dev: StandardDev(1.31149203314392e-11),
ks2_lwe_modular_std_dev: StandardDev(1.04499545254235e-7),
pbs_level: DecompositionLevelCount(12),
pbs_base_log: DecompositionBaseLog(3),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(11),
ks2_level: DecompositionLevelCount(21),
ks2_base_log: DecompositionBaseLog(1),
size1: 972,
size2: 487,
ciphertext_modulus: CiphertextModulus::new_native(),
};
fn criterion_bench(c: &mut Criterion) {
let param_vec = [
PRECISION_1_STAIR,
PRECISION_2_STAIR,
PRECISION_3_STAIR,
PRECISION_4_STAIR,
PRECISION_5_STAIR,
PRECISION_6_STAIR,
PRECISION_7_STAIR,
PRECISION_8_STAIR,
PRECISION_9_STAIR,
PRECISION_10_STAIR,
PRECISION_11_STAIR,
];
for params in param_vec {
let log_precision = params.log_precision;
let _log_mu = params._log_mu;
let glwe_dimension = params.glwe_dimension;
let polynomial_size = params.polynomial_size;
let std_dev_bsk = params.std_dev_bsk;
let lwe_dimension = params.lwe_dimension;
let ks1_lwe_modular_std_dev = params.ks1_lwe_modular_std_dev;
let ks2_lwe_modular_std_dev = params.ks2_lwe_modular_std_dev;
let pbs_level = params.pbs_level;
let pbs_base_mpg = params.pbs_base_log;
let ks1_level = params.ks1_level;
let ks1_base_log = params.ks1_base_log;
let ks2_level = params.ks2_level;
let ks2_base_log = params.ks2_base_log;
let size1 = params.size1;
let size2 = params.size2;
let ciphertext_modulus = params.ciphertext_modulus;
let precision = 1 << (log_precision);
// let mu = 1<< _log_mu;
// let carry = (mu*(precision -1) +1)/precision;
// let log_carry = ((carry as f32).log2().ceil()) as usize;
// let delta_log = 63 - (log_precision + log_carry);
let delta_log = 63 - log_precision;
//TODO: to randomize
let msg = 1;
let pt = Plaintext(msg << delta_log);
// Create the PRNG
let mut seeder = new_seeder();
let seeder = seeder.as_mut();
let mut encryption_generator =
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
let mut secret_generator =
SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
//Shared and partial key generations
let large_lwe_dimension_phi = LweDimension(lwe_dimension.0 + size1 + size2);
let large_lwe_dimension = LweDimension(glwe_dimension.0 * polynomial_size.0);
let glwe_secret_key = allocate_and_generate_new_binary_partial_glwe_secret_key(
glwe_dimension,
polynomial_size,
PartialGlweSecretKeyRandomCoefCount(large_lwe_dimension_phi.0),
&mut secret_generator,
);
let large_lwe_secret_key = glwe_secret_key.clone().into_lwe_secret_key();
// let large_lwe_secret_key = allocate_and_generate_new_binary_lwe_partial_secret_key
// (large_lwe_dimension, &mut secret_generator, large_lwe_dimension_phi);
// large_lwe_dimension_phi - size1 == lwe_dimension.0 + size2
let inter_phi = lwe_dimension.0 + size2;
let inter_lwe_secret_key =
allocate_and_generate_new_shared_lwe_secret_key_from_lwe_secret_key(
&large_lwe_secret_key,
SharedLweSecretKeyCommonCoefCount(inter_phi),
);
let small_lwe_secret_key =
allocate_and_generate_new_shared_lwe_secret_key_from_lwe_secret_key(
&inter_lwe_secret_key,
SharedLweSecretKeyCommonCoefCount(lwe_dimension.0),
);
// println!("Large Key Dimension = {:?}",large_lwe_secret_key.lwe_dimension().0);
// println!("Inter Key Dimension = {:?}",inter_lwe_secret_key.lwe_dimension().0);
// println!("Small Key Dimension = {:?}",small_lwe_secret_key.lwe_dimension().0);
//
//
//
// println!("Large phi = {:?}",large_lwe_dimension_phi);
// println!("Inter phi = {:?}",inter_phi);
//Shrinking KSK generations
let ksk_large_to_inter = allocate_and_generate_new_lwe_shrinking_keyswitch_key(
&large_lwe_secret_key,
&inter_lwe_secret_key,
SharedLweSecretKeyCommonCoefCount(inter_phi),
ks1_base_log,
ks1_level,
ks1_lwe_modular_std_dev,
ciphertext_modulus,
&mut encryption_generator,
);
let ksk_inter_to_small = allocate_and_generate_new_lwe_shrinking_keyswitch_key(
&inter_lwe_secret_key,
&small_lwe_secret_key,
SharedLweSecretKeyCommonCoefCount(lwe_dimension.0),
ks2_base_log,
ks2_level,
ks2_lwe_modular_std_dev,
ciphertext_modulus,
&mut encryption_generator,
);
//Encryption
let mut large_lwe =
LweCiphertext::new(0u64, large_lwe_dimension.to_lwe_size(), ciphertext_modulus);
encrypt_lwe_ciphertext(
&large_lwe_secret_key,
&mut large_lwe,
pt,
std_dev_bsk,
&mut encryption_generator,
);
//Shrinking KS
let mut inter_lwe =
LweCiphertext::new(0, LweDimension(inter_phi).to_lwe_size(), ciphertext_modulus);
let mut small_lwe = LweCiphertext::new(0, lwe_dimension.to_lwe_size(), ciphertext_modulus);
//PBS PART
let mut bsk = LweBootstrapKey::new(
0,
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_mpg,
pbs_level,
lwe_dimension,
ciphertext_modulus,
);
par_generate_lwe_bootstrap_key(
&small_lwe_secret_key,
&glwe_secret_key,
&mut bsk,
std_dev_bsk,
&mut encryption_generator,
);
let mut fbsk = FourierLweBootstrapKey::new(
small_lwe_secret_key.lwe_dimension(),
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_mpg,
pbs_level,
);
convert_standard_lwe_bootstrap_key_to_fourier(&bsk, &mut fbsk);
drop(bsk);
let accumulator = generate_accumulator(
polynomial_size,
glwe_dimension.to_glwe_size(),
precision,
ciphertext_modulus,
1 << delta_log,
|x| x,
);
let mut out_pbs_ct = LweCiphertext::new(
0u64,
large_lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
let decomposer = SignedDecomposer::new(
DecompositionBaseLog(log_precision + 1),
DecompositionLevelCount(1),
);
shrinking_keyswitch_lwe_ciphertext(&ksk_large_to_inter, &large_lwe, &mut inter_lwe);
let dec_inter = decrypt_lwe_ciphertext(&inter_lwe_secret_key, &inter_lwe);
let decoded = decomposer.closest_representable(dec_inter.0) >> delta_log;
assert_eq!(decoded, msg, "Err after first shrinking KS");
shrinking_keyswitch_lwe_ciphertext(&ksk_inter_to_small, &inter_lwe, &mut small_lwe);
let dec_small = decrypt_lwe_ciphertext(&small_lwe_secret_key, &small_lwe);
let decoded = decomposer.closest_representable(dec_small.0) >> delta_log;
assert_eq!(decoded, msg, "Err after second shrinking KS");
programmable_bootstrap_lwe_ciphertext(&small_lwe, &mut out_pbs_ct, &accumulator, &fbsk);
let dec_large = decrypt_lwe_ciphertext(&large_lwe_secret_key, &out_pbs_ct);
let decoded = decomposer.closest_representable(dec_large.0) >> delta_log;
assert_eq!(decoded, msg, "Err after PBS");
let bench_id = format!("stairKS::{}", params.name());
c.bench_function(&bench_id, |b| {
b.iter(|| {
shrinking_keyswitch_lwe_ciphertext(&ksk_large_to_inter, &large_lwe, &mut inter_lwe);
shrinking_keyswitch_lwe_ciphertext(&ksk_inter_to_small, &inter_lwe, &mut small_lwe);
programmable_bootstrap_lwe_ciphertext(
&small_lwe,
&mut out_pbs_ct,
&accumulator,
&fbsk,
);
})
});
}
}
criterion_group!(benches, criterion_bench);
criterion_main!(benches);

View File

@@ -393,7 +393,7 @@ fn _bench_wopbs_param_message_8_norm2_5(c: &mut Criterion) {
let mut bench_group = c.benchmark_group("programmable_bootstrap");
let param = WOPBS_PARAM_MESSAGE_4_NORM2_6_KS_PBS;
let param_set: ShortintParameterSet = param.try_into().unwrap();
let param_set: ShortintParameterSet = param.into();
let pbs_params = param_set.pbs_parameters().unwrap();
let keys = KEY_CACHE_WOPBS.get_from_param((pbs_params, param));

View File

@@ -32,12 +32,9 @@ 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![
#[cfg(feature = "__c_api")]
@@ -54,6 +51,8 @@ fn gen_c_api() {
"shortint",
#[cfg(feature = "integer")]
"integer",
#[cfg(feature = "forward_compatibility")]
"forward_compatibility",
];
let parse_expand_vec = if parse_expand_features_vec.is_empty() {
@@ -62,14 +61,16 @@ fn gen_c_api() {
vec![package_name.as_str()]
};
cbindgen::Builder::new()
.with_crate(crate_dir.clone())
.with_config(cbindgen::Config::from_root_or_default(crate_dir))
let builder = cbindgen::Builder::new()
.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()
.unwrap()
.write_to_file(output_file);
.with_parse_expand_features(&parse_expand_features_vec);
#[cfg(feature = "forward_compatibility")]
let builder = builder.with_include("tfhe-c-api-dynamic-buffer.h");
builder.generate().unwrap().write_to_file(output_file);
}
fn main() {

View File

@@ -8,8 +8,14 @@ endif()
set(TFHE_C_API_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../target/${CARGO_PROFILE}")
include_directories(${TFHE_C_API_RELEASE})
include_directories(${TFHE_C_API_RELEASE}/deps)
add_library(Tfhe STATIC IMPORTED)
set_target_properties(Tfhe PROPERTIES IMPORTED_LOCATION ${TFHE_C_API_RELEASE}/libtfhe.a)
if("${WITH_FORWARD_COMPATIBILITY}" STREQUAL "ON")
add_definitions(-DWITH_FORWARD_COMPATIBILITY)
add_library(TfheDynamicBuffer STATIC IMPORTED)
set_target_properties(TfheDynamicBuffer PROPERTIES IMPORTED_LOCATION ${TFHE_C_API_RELEASE}/deps/libtfhe_c_api_dynamic_buffer.a)
endif()
if(APPLE)
find_library(SECURITY_FRAMEWORK Security)
@@ -30,6 +36,9 @@ foreach (testsourcefile ${TEST_CASES})
)
target_include_directories(${testname} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${testname} LINK_PUBLIC Tfhe m pthread dl)
if("${WITH_FORWARD_COMPATIBILITY}" STREQUAL "ON")
target_link_libraries(${testname} LINK_PUBLIC TfheDynamicBuffer)
endif()
if(APPLE)
target_link_libraries(${testname} LINK_PUBLIC ${SECURITY_FRAMEWORK})
endif()

View File

@@ -0,0 +1,68 @@
// If this test break the c_api doc needs to be updated
#include <tfhe.h>
#include <assert.h>
#include <stdio.h>
int main(void)
{
int ok = 0;
// Prepare the config builder for the high level API and choose which types to enable
ConfigBuilder *builder;
Config *config;
// Put the builder in a default state without any types enabled
config_builder_all_disabled(&builder);
// Enable the uint128 type using the small LWE key for encryption
config_builder_enable_default_integers_small(&builder);
// Populate the config
config_builder_build(builder, &config);
ClientKey *client_key = NULL;
ServerKey *server_key = NULL;
// Generate the keys using the config
generate_keys(config, &client_key, &server_key);
// Set the server key for the current thread
set_server_key(server_key);
FheUint128 *lhs = NULL;
FheUint128 *rhs = NULL;
FheUint128 *result = NULL;
// A 128-bit unsigned integer containing value: 20 << 64 | 10
U128 clear_lhs = { .w0 = 10, .w1 = 20 };
// A 128-bit unsigned integer containing value: 2 << 64 | 1
U128 clear_rhs = { .w0 = 1, .w1 = 2 };
ok = fhe_uint128_try_encrypt_with_client_key_u128(clear_lhs, client_key, &lhs);
assert(ok == 0);
ok = fhe_uint128_try_encrypt_with_client_key_u128(clear_rhs, client_key, &rhs);
assert(ok == 0);
// Compute the subtraction
ok = fhe_uint128_sub(lhs, rhs, &result);
assert(ok == 0);
U128 clear_result;
// Decrypt
ok = fhe_uint128_decrypt(result, client_key, &clear_result);
assert(ok == 0);
// Here the subtraction allows us to compare each word
assert(clear_result.w0 == 9);
assert(clear_result.w1 == 18);
// Destroy the ciphertexts
fhe_uint128_destroy(lhs);
fhe_uint128_destroy(rhs);
fhe_uint128_destroy(result);
// Destroy the keys
client_key_destroy(client_key);
server_key_destroy(server_key);
printf("FHE computation successful!\n");
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,120 @@
#include <tfhe.h>
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#ifdef WITH_FORWARD_COMPATIBILITY
int uint8_format_update(const ClientKey *client_key, const ServerKey *server_key) {
int ok;
FheUint8 *lhs = NULL;
FheUint8 *deserialized_lhs = NULL;
FheUint8 *result = NULL;
Buffer value_buffer = {.pointer = NULL, .length = 0};
Buffer conformant_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;
DynamicBuffer out_buffer = {.pointer = NULL, .length = 0};
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_update_serialization_from_0_4_to_0_5(deser_view, &out_buffer);
assert(ok == 0);
destroy_dynamic_buffer(&out_buffer);
deser_view.pointer = cks_buffer.pointer;
deser_view.length = cks_buffer.length;
ok = client_key_deserialize(deser_view, &deserialized_client_key);
assert(ok == 0);
ok = fhe_uint8_try_encrypt_with_client_key_u8(lhs_clear, deserialized_client_key, &lhs);
assert(ok == 0);
ok = fhe_uint8_serialize(lhs, &value_buffer);
assert(ok == 0);
deser_view.pointer = value_buffer.pointer;
deser_view.length = value_buffer.length;
ok = fhe_uint8_update_serialization_from_0_4_to_0_5(deser_view, &out_buffer);
assert(ok == 0);
destroy_dynamic_buffer(&out_buffer);
ok = fhe_uint8_safe_serialize(lhs, &conformant_value_buffer, max_serialization_size);
assert(ok == 0);
deser_view.pointer = conformant_value_buffer.pointer;
deser_view.length = conformant_value_buffer.length;
ok = fhe_uint8_safe_update_serialization_conformant_from_0_4_to_0_5(
deser_view, max_serialization_size, server_key, &out_buffer);
assert(ok == 0);
destroy_dynamic_buffer(&out_buffer);
deser_view.pointer = value_buffer.pointer;
deser_view.length = value_buffer.length;
ok = fhe_uint8_deserialize(deser_view, &deserialized_lhs);
assert(ok == 0);
uint8_t clear;
ok = fhe_uint8_decrypt(deserialized_lhs, deserialized_client_key, &clear);
assert(ok == 0);
assert(clear == lhs_clear);
if (value_buffer.pointer != NULL) {
destroy_buffer(&value_buffer);
}
if (conformant_value_buffer.pointer != NULL) {
destroy_buffer(&conformant_value_buffer);
}
fhe_uint8_destroy(lhs);
fhe_uint8_destroy(deserialized_lhs);
fhe_uint8_destroy(result);
return ok;
}
#endif
int main(void) {
int ok = 0;
#ifdef WITH_FORWARD_COMPATIBILITY
{
ConfigBuilder *builder;
Config *config;
ok = config_builder_all_disabled(&builder);
assert(ok == 0);
ok = config_builder_enable_default_integers(&builder);
assert(ok == 0);
ok = config_builder_build(builder, &config);
assert(ok == 0);
ClientKey *client_key = NULL;
ServerKey *server_key = NULL;
PublicKey *public_key = NULL;
ok = generate_keys(config, &client_key, &server_key);
assert(ok == 0);
ok = uint8_format_update(client_key, server_key);
client_key_destroy(client_key);
public_key_destroy(public_key);
server_key_destroy(server_key);
}
#endif
return ok;
}

View File

@@ -46,6 +46,7 @@ usize_is_size_t = true
[defines]
# "target_os = freebsd" = "DEFINE_FREEBSD"
# "feature = serde" = "DEFINE_SERDE"
"feature = forward_compatibility" = "WITH_FORWARD_COMPATIBILITY"
[export]
@@ -114,8 +115,8 @@ 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 = []

View File

@@ -16,6 +16,7 @@
## How To
* [Configure Rust](how_to/rust_configuration.md)
* [Serialize/Deserialize](how_to/serialization.md)
* [Migrate Data to Newer Versions of TFHE-rs](how_to/migrate_data.md)
* [Compress Ciphertexts/Keys](how_to/compress.md)
* [Use Public Key Encryption](how_to/public_key.md)
* [Use Trivial Ciphertext](how_to/trivial_ciphertext.md)

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.4.4", 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.4.4", 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.4.4", 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.4.4", features = ["x86_64"] }
```
### Commented code to double a 2-bit message in a leveled fashion and using a PBS with the `core_crypto` module.

View File

@@ -8,12 +8,12 @@ To use `TFHE-rs` in your project, you first need to add it as a dependency in yo
If you are using an `x86` machine:
```toml
tfhe = { version = "0.4.0", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
tfhe = { version = "0.4.4", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
```
If you are using an `ARM` machine:
```toml
tfhe = { version = "0.4.0", features = [ "boolean", "shortint", "integer", "aarch64-unix" ] }
tfhe = { version = "0.4.4", features = [ "boolean", "shortint", "integer", "aarch64-unix" ] }
```
{% hint style="info" %}

View File

@@ -46,7 +46,7 @@ fn main() {
The default configuration for x86 Unix machines:
```toml
tfhe = { version = "0.4.0", features = ["integer", "x86_64-unix"]}
tfhe = { version = "0.4.4", 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).

View File

@@ -68,7 +68,7 @@ $ cmake .. -DCMAKE_BUILD_TYPE=RELEASE
$ make
...
$ ./my-executable
Result: 2
FHE computation successful!
$
```
@@ -76,7 +76,6 @@ $
#include <tfhe.h>
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
int main(void)
@@ -89,7 +88,7 @@ int main(void)
// Put the builder in a default state without any types enabled
config_builder_all_disabled(&builder);
// Enable the uint128 type using the small LWE key for encryption
config_builder_enable_default_uint128_small(&builder);
config_builder_enable_default_integers_small(&builder);
// Populate the config
config_builder_build(builder, &config);
@@ -104,27 +103,29 @@ int main(void)
FheUint128 *lhs = NULL;
FheUint128 *rhs = NULL;
FheUint128 *result = NULL;
// A 128-bit unsigned integer containing value: 20 << 64 | 10
U128 clear_lhs = { .w0 = 10, .w1 = 20 };
// A 128-bit unsigned integer containing value: 2 << 64 | 1
U128 clear_rhs = { .w0 = 1, .w1 = 2 };
// Encrypt a u128 using 64 bits words, we encrypt 20 << 64 | 10
ok = fhe_uint128_try_encrypt_with_client_key_u128(10, 20, client_key, &lhs);
ok = fhe_uint128_try_encrypt_with_client_key_u128(clear_lhs, client_key, &lhs);
assert(ok == 0);
// Encrypt a u128 using words, we encrypt 2 << 64 | 1
ok = fhe_uint128_try_encrypt_with_client_key_u128(1, 2, client_key, &rhs);
ok = fhe_uint128_try_encrypt_with_client_key_u128(clear_rhs, client_key, &rhs);
assert(ok == 0);
// Compute the subtraction
ok = fhe_uint128_sub(lhs, rhs, &result);
assert(ok == 0);
uint64_t w0, w1;
U128 clear_result;
// Decrypt
ok = fhe_uint128_decrypt(result, client_key, &w0, &w1);
ok = fhe_uint128_decrypt(result, client_key, &clear_result);
assert(ok == 0);
// Here the subtraction allows us to compare each word
assert(w0 == 9);
assert(w1 == 18);
assert(clear_result.w0 == 9);
assert(clear_result.w1 == 18);
// Destroy the ciphertexts
fhe_uint128_destroy(lhs);
@@ -134,6 +135,8 @@ int main(void)
// Destroy the keys
client_key_destroy(client_key);
server_key_destroy(server_key);
printf("FHE computation successful!\n");
return EXIT_SUCCESS;
}
```

View File

@@ -0,0 +1,142 @@
# Managing Data Through Various TFHE-rs Versions
In what follows, the process to manage data when upgrading the TFHE-rs version (starting from the 0.4.4 release) is given. This page details the methods to make data, which have initially been generated with an older version of TFHE-rs, usable with a newer version.
## Forward Compatibility Strategy
The current strategy that has been adopted for TFHE-rs is the following:
- TFHE-rs has a global `SERIALIZATION_VERSION` constant;
- When breaking serialization changes are introduced, this global version is bumped;
- Safe serialization primitives check this constant upon deserialization, if the data is incompatible, these primitives return an error.
To be able to use older serialized data with newer versions, the following is done on new major TFHE-rs releases:
- A minor update is done to the previously released branch to add the new release as an optional dependency;
- Conversion code is added to the previous branch to be able to load old data and convert it to the new data format.
In practice, if we take the 0.5 release as a concrete example, here is what will happen:
- 0.5.0 is released with breaking changes to the serialization;
- 0.4.4 has tfhe@0.5.0 as optional dependency gated by the `forward_compatibility` feature;
- Conversion code is added to 0.4.4, if possible without any user input, but some data migration will likely require some information to be provided by the developer writing the migration code;
- 0.4.4 is released.
{% hint style="info" %}
Note that if you do not need forward compatibility 0.4.4 will be equivalent to 0.4.1 from a usability perspective and you can safely update.
Note also that the 0.5.0 has no knowledge of previous releases.
{% endhint %}
## What it means from a developer perspective
A set of generic tooling is given to allow migrating data by using several workflows. The data migration is considered to be an application/protocol layer concern to avoid imposing design choices.
Examples to migrate data:
An `Application` uses TFHE-rs 0.4.1 and needs/wants to upgrade to 0.5.0 to benefit from various improvements.
Example timeline of the data migration or `Bulk Data Migration`:
- A new transition version of the `Application` is compiled with the 0.4.4 release of TFHE-rs;
- The transition version of the `Application` adds code to read previously stored data, convert it to the proper format for 0.5.0 and save it back to disk;
- The service enters a maintenance period (if relevant);
- Migration of data from 0.4.4 to 0.5.0 is done with the transition version of the `Application`, note that depending on the volume of data this transition can take a significant amount of time;
- The updated version of the `Application` is compiled with the 0.5.0 release of TFHE-rs and put in production;
- Service is resumed with the updated `Application` (if relevant).
The above case is describing a simple use case, where only a single version of data has to be managed. Moreover, the above strategy is not relevant in the case where the data is so large that migrating it in one go is not doable, or if the service cannot suffer any interruption.
In order to manage more complicated cases, another method called `Migrate On Read` can be used.
Here is an example timeline where data is migrated only as needed with the `Migrate On Read` approach:
- A new version of the `Application` is compiled, it has tfhe@0.4.4 as dependency (the dependency will have to be renamed to avoid conflicts, a possible name is to use the major version like `tfhe_0_4`) and tfhe@0.5.0 which will not be renamed and can be accessed as `tfhe`
- Code to manage reading the data is added to the `Application`:
- The code determines whether the data was saved with the 0.4 `Application` or the 0.5 `Application`, if the data is already up to date with the 0.5 format it can be loaded right away, if it's in the 0.4 format the `Application` can check if an updated version of the data is already available in the 0.5 format and loads that if it's available, otherwise it converts the data to 0.5, saves the converted data to avoid having to convert it every time it is accessed and continue processing with the 0.5 data
The above is more complicated to manage as data will be present on disk with several versions, however it allows to run the service continuously or near-continuously once the new `Application` is deployed (it will require careful routing or error handling as nodes with outdated `Application` won't be able to process the 0.5 data).
Also, if required, several version of TFHE-rs can be "chained" to upgrade very old data to newer formats.
The above pattern can be extended to have `tfhe_0_4` (tfhe@0.4.4 renamed), `tfhe_0_5` (tfhe@0.5.0 renamed) and `tfhe` being tfhe@0.6.0, this will require special handling from the developers so that their protocol can handle data from 0.4.4, 0.5.0 and 0.6.0 using all the conversion tooling from the relevant version.
E.g., if some computation requires data from version 0.4.4 a conversion function could be called `upgrade_data_from_0_4_to_0_6` and do:
- read data from 0.4.4
- convert to 0.5.0 format using `tfhe_0_4`
- convert to 0.6.0 format using `tfhe_0_5`
- save to disk in 0.6.0 format
- process 0.6.0 data with `tfhe` which is tfhe@0.6.0
## A concrete example for shortint
The following very small sample project shows how some data can be migrated in a project following the pattern explained above:
Cargo.toml:
```toml
[package]
name = "data_migration_tfhe"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# The project used tfhe 0.4.1, it now depends on the 0.4.4 with the forward compatibility code
tfhe_0_4 = { package = "tfhe", version = "0.4.4", features = [
"x86_64-unix",
"boolean",
"shortint",
"integer",
"forward_compatibility",
] }
# The project now uses tfhe 0.5.0 as it's "normal/default" tfhe version for all processing except
# data upgrade, as only old versions will be retrofitted with code to migrate code to newer versions
tfhe = { version = "0.5", features = [
"x86_64-unix",
"boolean",
"shortint",
"integer",
] }
```
src/main.rs:
```rust
fn old_tfhe_data_generation() -> tfhe_0_4::shortint::Ciphertext {
use tfhe_0_4::shortint::gen_keys;
use tfhe_0_4::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let ct = cks.encrypt(2);
ct
}
fn data_migration(old_ciphertext: tfhe_0_4::shortint::Ciphertext) {
use tfhe::shortint::Ciphertext;
use tfhe_0_4::forward_compatibility::ConvertInto;
// Here as tfhe_0_4 depends on tfhe 0.5.0 and tfhe 0.5.0 is a dependency of our project the
// forward compatibility works out of the box using tfhe types and the tfhe_0_4 conversion code
let new_ct: Ciphertext = old_ciphertext.convert_into();
println!("{:?}", new_ct.noise_level())
}
fn main() {
data_migration(old_tfhe_data_generation())
}
```
This will output:
```console
NoiseLevel(18446744073709551615)
```
The noise level here is set at `usize::MAX` on a 64 bits system, it corresponds to the constant `NoiseLevel::UNKNOWN` from shortint, as the noise level was not a value that was directly tracked in TFHE-rs the noise level is set to this unknown constant when migrating the ciphertext. It is recommended to first apply a PBS to reset the noise level to a known nominal level as some algorithms will always clean ciphertexts which are not at the nominal noise level.
## Breaking changes and additional migration information
The main breaking change going from 0.4.4 to 0.5.0 with respect to data migration is that the High Level API dropped support for `shortint`. The `boolean` format has changed to use `integer`'s `BooleanBlock` under the hood.
This means that any data coming from the High Level API which previously used `boolean` or `shortint` is not supported for the data migration.

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.4.4", features = ["integer","x86_64-unix"]}
bincode = "1.3.3"
```

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.4.4", features = ["integer", "x86_64-unix"]}
```
Other configurations can be found [here](../getting_started/installation.md).

View File

@@ -21,7 +21,7 @@ To use Booleans, the `booleans` feature in our Cargo.toml must be enabled:
# Cargo.toml
# Default configuration for x86 Unix machines:
tfhe = { version = "0.4.0", features = ["boolean", "x86_64-unix"]}
tfhe = { version = "0.4.4", features = ["boolean", "x86_64-unix"]}
```
Other configurations can be found [here](../getting_started/installation.md).

View File

@@ -19,7 +19,7 @@ pub fn has_match(
let res = if branches.len() <= 1 {
branches
.get(0)
.first()
.map_or(exec.ct_false(), |branch| branch(&mut exec))
.0
} else {

View File

@@ -0,0 +1,43 @@
const test = require('node:test');
const assert = require('node:assert').strict;
const {
init_panic_hook,
TfheClientKey,
TfheConfigBuilder,
FheUint8,
} = require("../pkg/tfhe.js");
const U256_MAX = BigInt("115792089237316195423570985008687907853269984665640564039457584007913129639935");
const U128_MAX = BigInt("340282366920938463463374607431768211455");
const U32_MAX = 4294967295;
// This is useful to debug test
//
// Note that the test hlapi_panic
// purposefully creates a panic, to some panic message
// will be printed and tess will be ok
init_panic_hook();
// Here integers are not enabled
// but we try to use them, so an error should be returned
// as the underlying panic should have been trapped
// Put in its own file as some async access is causing panics, to be investigated
test('hlapi_panic', (t) => {
let config = TfheConfigBuilder.all_disabled()
.build();
let clientKey = TfheClientKey.generate(config);
let clear = 73;
console.log("\nThe following log is an expected error log:\n=======================\n")
try {
let _ = FheUint8.encrypt_with_client_key(clear, clientKey);
assert(false);
} catch (e) {
assert(true);
}
});

View File

@@ -36,27 +36,6 @@ const U32_MAX = 4294967295;
// will be printed and tess will be ok
init_panic_hook();
// Here integers are not enabled
// but we try to use them, so an error should be returned
// as the underlying panic should have been trapped
test('hlapi_panic', (t) => {
let config = TfheConfigBuilder.all_disabled()
.build();
let clientKey = TfheClientKey.generate(config);
let clear = 73;
console.log("\nThe following log is an expected error log:\n=======================\n")
try {
let _ = FheUint8.encrypt_with_client_key(clear, clientKey);
assert(false);
} catch (e) {
assert(true);
}
});
test('hlapi_key_gen_big', (t) => {
let config = TfheConfigBuilder.all_disabled()
.enable_default_integers()

View File

@@ -134,4 +134,92 @@ impl ClientKey {
pub fn new(parameter_set: &BooleanParameters) -> ClientKey {
BooleanEngine::with_thread_local_mut(|engine| engine.create_client_key(*parameter_set))
}
/// Deconstruct a [`ClientKey`] into its constituants.
///
/// # Example
///
/// ```rust
/// # fn main() {
/// use tfhe::boolean::client_key::ClientKey;
/// use tfhe::boolean::parameters::PARAMETERS_ERROR_PROB_2_POW_MINUS_165;
/// use tfhe::boolean::prelude::*;
///
/// // Generate the client key:
/// let cks = ClientKey::new(&PARAMETERS_ERROR_PROB_2_POW_MINUS_165);
/// let raw_parts = cks.into_raw_parts();
/// # }
/// ```
pub fn into_raw_parts(
self,
) -> (
LweSecretKeyOwned<u32>,
GlweSecretKeyOwned<u32>,
BooleanParameters,
) {
let Self {
lwe_secret_key,
glwe_secret_key,
parameters,
} = self;
(lwe_secret_key, glwe_secret_key, parameters)
}
/// Construct a [`ClientKey`] from its constituants.
///
/// # Panics
///
/// Panics if the provided raw parts are not compatible with the provided parameters.
///
/// # Example
///
/// ```rust
/// # fn main() {
/// use tfhe::boolean::client_key::ClientKey;
/// use tfhe::boolean::parameters::PARAMETERS_ERROR_PROB_2_POW_MINUS_165;
/// use tfhe::boolean::prelude::*;
///
/// // Generate the client key:
/// let cks = ClientKey::new(&PARAMETERS_ERROR_PROB_2_POW_MINUS_165);
/// let (lwe_secret_key, glwe_secret_key, parameters) = cks.into_raw_parts();
/// let reconstructed_cks = ClientKey::new_from_raw_parts(lwe_secret_key, glwe_secret_key, parameters);
/// # }
pub fn new_from_raw_parts(
lwe_secret_key: LweSecretKeyOwned<u32>,
glwe_secret_key: GlweSecretKeyOwned<u32>,
parameters: BooleanParameters,
) -> Self {
assert_eq!(
lwe_secret_key.lwe_dimension(),
parameters.lwe_dimension,
"Mismatch between the LweSecretKey LweDimension ({:?}) \
and the parameters LweDimension ({:?})",
lwe_secret_key.lwe_dimension(),
parameters.lwe_dimension
);
assert_eq!(
glwe_secret_key.glwe_dimension(),
parameters.glwe_dimension,
"Mismatch between the GlweSecretKey GlweDimension ({:?}) \
and the parameters GlweDimension ({:?})",
glwe_secret_key.glwe_dimension(),
parameters.glwe_dimension
);
assert_eq!(
glwe_secret_key.polynomial_size(),
parameters.polynomial_size,
"Mismatch between the GlweSecretKey PolynomialSize ({:?}) \
and the parameters PolynomialSize ({:?})",
glwe_secret_key.polynomial_size(),
parameters.polynomial_size
);
Self {
lwe_secret_key,
glwe_secret_key,
parameters,
}
}
}

View File

@@ -229,7 +229,6 @@ macro_rules! create_integer_wrapper_type {
impl_safe_deserialize_conformant_integer!($name, crate::high_level_api::safe_deserialize_conformant_integer);
// The compressed version of the ciphertext type
::paste::paste! {
pub struct [<Compressed $name>]($crate::high_level_api::[<Compressed $name>]);
@@ -357,6 +356,257 @@ create_integer_wrapper_type!(name: FheUint64, clear_scalar_type: u64);
create_integer_wrapper_type!(name: FheUint128, clear_scalar_type: U128);
create_integer_wrapper_type!(name: FheUint256, clear_scalar_type: U256);
#[cfg(feature = "forward_compatibility")]
pub mod forward_compatibility {
use super::*;
// FheInt don't have the 10, 12, 14 variants so we define the impl here
impl_update_serialization_format_on_type!(FheUint8);
impl_update_serialization_format_on_type!(FheUint10);
impl_update_serialization_format_on_type!(FheUint12);
impl_update_serialization_format_on_type!(FheUint14);
impl_update_serialization_format_on_type!(FheUint16);
impl_update_serialization_format_on_type!(FheUint32);
impl_update_serialization_format_on_type!(FheUint64);
impl_update_serialization_format_on_type!(FheUint128);
impl_update_serialization_format_on_type!(FheUint256);
impl_update_serialization_format_on_type!(CompressedFheUint8);
impl_update_serialization_format_on_type!(CompressedFheUint10);
impl_update_serialization_format_on_type!(CompressedFheUint12);
impl_update_serialization_format_on_type!(CompressedFheUint14);
impl_update_serialization_format_on_type!(CompressedFheUint16);
impl_update_serialization_format_on_type!(CompressedFheUint32);
impl_update_serialization_format_on_type!(CompressedFheUint64);
impl_update_serialization_format_on_type!(CompressedFheUint128);
impl_update_serialization_format_on_type!(CompressedFheUint256);
impl_update_serialization_format_on_type!(CompactFheUint8);
impl_update_serialization_format_on_type!(CompactFheUint10);
impl_update_serialization_format_on_type!(CompactFheUint12);
impl_update_serialization_format_on_type!(CompactFheUint14);
impl_update_serialization_format_on_type!(CompactFheUint16);
impl_update_serialization_format_on_type!(CompactFheUint32);
impl_update_serialization_format_on_type!(CompactFheUint64);
impl_update_serialization_format_on_type!(CompactFheUint128);
impl_update_serialization_format_on_type!(CompactFheUint256);
impl_update_serialization_format_on_type!(CompactFheUint8List);
impl_update_serialization_format_on_type!(CompactFheUint10List);
impl_update_serialization_format_on_type!(CompactFheUint12List);
impl_update_serialization_format_on_type!(CompactFheUint14List);
impl_update_serialization_format_on_type!(CompactFheUint16List);
impl_update_serialization_format_on_type!(CompactFheUint32List);
impl_update_serialization_format_on_type!(CompactFheUint64List);
impl_update_serialization_format_on_type!(CompactFheUint128List);
impl_update_serialization_format_on_type!(CompactFheUint256List);
impl_safe_update_serialization_format_conformant_on_type!(
FheUint8,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheUint10,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheUint12,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheUint14,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheUint16,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheUint32,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheUint64,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheUint128,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheUint256,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheUint8,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheUint10,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheUint12,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheUint14,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheUint16,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheUint32,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheUint64,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheUint128,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheUint256,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheUint8,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheUint10,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheUint12,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheUint14,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheUint16,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheUint32,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheUint64,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheUint128,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheUint256,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
// FheInt don't have the 10, 12, 14 variants so we define the impl here
impl_update_serialization_format_on_type!(FheInt8);
impl_update_serialization_format_on_type!(FheInt16);
impl_update_serialization_format_on_type!(FheInt32);
impl_update_serialization_format_on_type!(FheInt64);
impl_update_serialization_format_on_type!(FheInt128);
impl_update_serialization_format_on_type!(FheInt256);
impl_update_serialization_format_on_type!(CompressedFheInt8);
impl_update_serialization_format_on_type!(CompressedFheInt16);
impl_update_serialization_format_on_type!(CompressedFheInt32);
impl_update_serialization_format_on_type!(CompressedFheInt64);
impl_update_serialization_format_on_type!(CompressedFheInt128);
impl_update_serialization_format_on_type!(CompressedFheInt256);
impl_update_serialization_format_on_type!(CompactFheInt8);
impl_update_serialization_format_on_type!(CompactFheInt16);
impl_update_serialization_format_on_type!(CompactFheInt32);
impl_update_serialization_format_on_type!(CompactFheInt64);
impl_update_serialization_format_on_type!(CompactFheInt128);
impl_update_serialization_format_on_type!(CompactFheInt256);
impl_update_serialization_format_on_type!(CompactFheInt8List);
impl_update_serialization_format_on_type!(CompactFheInt16List);
impl_update_serialization_format_on_type!(CompactFheInt32List);
impl_update_serialization_format_on_type!(CompactFheInt64List);
impl_update_serialization_format_on_type!(CompactFheInt128List);
impl_update_serialization_format_on_type!(CompactFheInt256List);
impl_safe_update_serialization_format_conformant_on_type!(
FheInt8,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheInt16,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheInt32,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheInt64,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheInt128,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
FheInt256,
crate::high_level_api::safe_deserialize_conformant_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheInt8,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheInt16,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheInt32,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheInt64,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheInt128,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompressedFheInt256,
crate::high_level_api::safe_deserialize_conformant_compressed_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheInt8,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheInt16,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheInt32,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheInt64,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheInt128,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
impl_safe_update_serialization_format_conformant_on_type!(
CompactFheInt256,
crate::high_level_api::safe_deserialize_conformant_compact_integer
);
}
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);

View File

@@ -19,6 +19,17 @@ impl_serialize_deserialize_on_type!(CompactPublicKey);
impl_serialize_deserialize_on_type!(CompressedCompactPublicKey);
impl_serialize_deserialize_on_type!(ServerKey);
#[cfg(feature = "forward_compatibility")]
mod forward_compatibility {
use super::*;
impl_update_serialization_format_on_type!(ClientKey);
impl_update_serialization_format_on_type!(PublicKey);
impl_update_serialization_format_on_type!(CompactPublicKey);
impl_update_serialization_format_on_type!(CompressedCompactPublicKey);
impl_update_serialization_format_on_type!(ServerKey);
}
#[no_mangle]
pub unsafe extern "C" fn generate_keys(
config: *mut super::config::Config,

View File

@@ -326,6 +326,69 @@ macro_rules! impl_safe_deserialize_conformant_integer {
};
}
#[cfg(feature = "forward_compatibility")]
macro_rules! impl_update_serialization_format_on_type {
($wrapper_type:ty) => {
::paste::paste! {
#[no_mangle]
pub unsafe extern "C" fn [<$wrapper_type:snake _update_serialization_from_0_4_to_0_5>](
buffer_view: crate::c_api::buffer::BufferView,
result: *mut tfhe_c_api_dynamic_buffer::DynamicBuffer,
) -> ::std::os::raw::c_int {
use crate::forward_compatibility::ConvertInto;
crate::c_api::utils::catch_panic(|| {
let object: $wrapper_type = $wrapper_type(bincode::deserialize(buffer_view.into()).unwrap());
let next_object: next_tfhe::$wrapper_type = (object.0).convert_into();
let buffer = bincode::serialize(&next_object).unwrap();
*result = buffer.into();
})
}
}
};
}
#[cfg(feature = "forward_compatibility")]
macro_rules! impl_safe_update_serialization_format_conformant_on_type {
($wrapper_type:ty, $function_name:path) => {
::paste::paste! {
#[no_mangle]
pub unsafe extern "C" fn [<$wrapper_type:snake _safe_update_serialization_conformant_from_0_4_to_0_5>](
buffer_view: crate::c_api::buffer::BufferView,
serialized_size_limit: u64,
server_key: *const crate::c_api::high_level_api::keys::ServerKey,
result: *mut tfhe_c_api_dynamic_buffer::DynamicBuffer,
) -> ::std::os::raw::c_int {
crate::c_api::utils::catch_panic(|| {
use crate::forward_compatibility::ConvertInto;
crate::c_api::utils::check_ptr_is_non_null_and_aligned(result).unwrap();
let sk = crate::c_api::utils::get_ref_checked(server_key).unwrap();
let buffer_view: &[u8] = buffer_view.into();
let object: $wrapper_type = $wrapper_type(
$function_name(
buffer_view,
serialized_size_limit,
&sk.0,
)
.unwrap(),
);
let next_object: next_tfhe::$wrapper_type = (object.0).convert_into();
let buffer = bincode::serialize(&next_object).unwrap();
*result = buffer.into();
})
}
}
};
}
macro_rules! impl_binary_fn_on_type {
// More general binary fn case,
// where the type of the left-hand side can be different

View File

@@ -853,3 +853,302 @@ where
Plaintext(decoded)
}
// /// Encrypt a plaintext in a [`GGSW ciphertext`](`GgswCiphertext`) in the constant coefficient.
// ///
// /// See the [`GGSW ciphertext formal definition`](`GgswCiphertext#ggsw-encryption`) for the
// /// definition of the encryption algorithm.
// ///
// /// ```
// /// use tfhe::core_crypto::prelude::*;
// ///
// /// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
// /// // computations
// /// // Define parameters for GgswCiphertext creation
// /// let glwe_size = GlweSize(2);
// /// let polynomial_size = PolynomialSize(1024);
// /// let decomp_base_log = DecompositionBaseLog(8);
// /// let decomp_level_count = DecompositionLevelCount(3);
// /// let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
// /// let ciphertext_modulus = CiphertextModulus::new_native();
// ///
// /// // Create the PRNG
// /// let mut seeder = new_seeder();
// /// let seeder = seeder.as_mut();
// /// let mut encryption_generator =
// /// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
// /// let mut secret_generator =
// /// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
// ///
// /// // Create the GlweSecretKey
// /// let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key(
// /// glwe_size.to_glwe_dimension(),
// /// polynomial_size,
// /// &mut secret_generator,
// /// );
// ///
// /// // Create the plaintext
// /// let plaintext = Plaintext(3u64);
// ///
// /// // Create a new GgswCiphertext
// /// let mut ggsw = GgswCiphertext::new(
// /// 0u64,
// /// glwe_size,
// /// polynomial_size,
// /// decomp_base_log,
// /// decomp_level_count,
// /// ciphertext_modulus,
// /// );
// ///
// /// encrypt_constant_ggsw_ciphertext(
// /// &glwe_secret_key,
// /// &mut ggsw,
// /// plaintext,
// /// glwe_modular_std_dev,
// /// &mut encryption_generator,
// /// );
// ///
// /// let decrypted = decrypt_constant_ggsw_ciphertext(&glwe_secret_key, &ggsw);
// /// assert_eq!(decrypted, plaintext);
// /// ```
// pub fn encrypt_polynomial_ggsw_ciphertext<Scalar, KeyCont, OutputCont, Gen, PlainCont>(
// glwe_secret_key: &GlweSecretKey<KeyCont>,
// output: &mut GgswCiphertext<OutputCont>,
// encoded: &mut PlaintextList<PlainCont>,
// noise_parameters: impl DispersionParameter,
// generator: &mut EncryptionRandomGenerator<Gen>,
// ) where Scalar: UnsignedTorus, KeyCont: Container<Element = Scalar>, PlainCont:
// ContainerMut<Element = Scalar>, OutputCont: ContainerMut<Element = Scalar>, Gen:
// ByteRandomGenerator,
// {
// assert!(
// output.polynomial_size() == glwe_secret_key.polynomial_size(),
// "Mismatch between polynomial sizes of output ciphertexts and input secret key. \
// Got {:?} in output, and {:?} in secret key.",
// output.polynomial_size(),
// glwe_secret_key.polynomial_size()
// );
//
// assert!(
// output.glwe_size().to_glwe_dimension() == glwe_secret_key.glwe_dimension(),
// "Mismatch between GlweDimension of output ciphertexts and input secret key. \
// Got {:?} in output, and {:?} in secret key.",
// output.glwe_size().to_glwe_dimension(),
// glwe_secret_key.glwe_dimension()
// );
//
// // Generators used to have same sequential and parallel key generation
// let gen_iter = generator
// .fork_ggsw_to_ggsw_levels::<Scalar>(
// output.decomposition_level_count(),
// output.glwe_size(),
// output.polynomial_size(),
// )
// .expect("Failed to split generator into ggsw levels");
//
// let output_glwe_size = output.glwe_size();
// let output_polynomial_size = output.polynomial_size();
// let decomp_base_log = output.decomposition_base_log();
// let ciphertext_modulus = output.ciphertext_modulus();
//
// for (level_index, (mut level_matrix, mut generator)) in
// output.iter_mut().zip(gen_iter).enumerate()
// {
// let decomp_level = DecompositionLevel(level_index + 1);
// // We scale the factor down from the native torus to whatever our torus is, the
// // encryption process will scale it back up
// let one= Scalar::ONE;
// let factor = one
// .wrapping_neg()
// .wrapping_mul(Scalar::ONE << (Scalar::BITS - (decomp_base_log.0 * decomp_level.0)))
// .wrapping_div(ciphertext_modulus.get_power_of_two_scaling_to_native_torus());
//
// slice_wrapping_scalar_mul_assign(encoded.as_mut_polynomial().into_container(),
// factor);
//
// // We iterate over the rows of the level matrix, the last row needs special treatment
// let gen_iter = generator
// .fork_ggsw_level_to_glwe::<Scalar>(output_glwe_size, output_polynomial_size)
// .expect("Failed to split generator into glwe");
//
// let last_row_index = level_matrix.glwe_size().0 - 1;
//
// for ((row_index, mut row_as_glwe), mut generator) in level_matrix
// .as_mut_glwe_list()
// .iter_mut()
// .enumerate()
// .zip(gen_iter)
// {
// encrypt_polynomial_ggsw_level_matrix_row(
// glwe_secret_key,
// (row_index, last_row_index),
// &polynomial,
// &mut row_as_glwe,
// noise_parameters,
// &mut generator,
// );
// }
// }
// }
//
// /// Convenience function to encrypt a row of a [`GgswLevelMatrix`] irrespective of the current
// row /// being encrypted. Allows to share code between sequential
// ([`encrypt_constant_ggsw_ciphertext`]) /// and parallel
// ([`par_encrypt_constant_ggsw_ciphertext`]) variants of the GGSW ciphertext /// encryption.
// ///
// /// You probably don't want to use this function directly.
// fn encrypt_polynomial_ggsw_level_matrix_row<Scalar, KeyCont, OutputCont, Gen>(
// glwe_secret_key: &GlweSecretKey<KeyCont>,
// (row_index, last_row_index): (usize, usize),
// factor: &Polynomial<InCount>,
// row_as_glwe: &mut GlweCiphertext<OutputCont>,
// noise_parameters: impl DispersionParameter,
// generator: &mut EncryptionRandomGenerator<Gen>,
// ) where Scalar: UnsignedTorus, KeyCont: Container<Element = Scalar>, OutputCont:
// ContainerMut<Element = Scalar>, Gen: ByteRandomGenerator,
// {
// if row_index < last_row_index {
// // Not the last row
// let sk_poly_list = glwe_secret_key.as_polynomial_list();
// let sk_poly = sk_poly_list.get(row_index);
//
// // Copy the key polynomial to the output body, to avoid allocating a temporary buffer
// let mut body = row_as_glwe.get_mut_body();
// body.as_mut().copy_from_slice(sk_poly.as_ref());
//
// // slice_wrapping_scalar_mul_assign(body.as_mut(), factor);
// let mut tmp_body = Polynomial::new(Scalar::ZERO, glwe_secret_key.polynomial_size());
// tmp_body.as_mut().copy_from_slice(body.as_ref());
// polynomial_karatsuba_wrapping_mul(&mut body.as_mut_polynomial(), &tmp_body, factor);
//
// encrypt_glwe_ciphertext_assign(glwe_secret_key, row_as_glwe, noise_parameters,
// generator); } else {
// // The last row needs a slightly different treatment
// let mut body = row_as_glwe.get_mut_body();
//
// body.as_mut().fill(Scalar::ZERO);
// body.as_mut()[0] = factor.wrapping_neg();
//
// encrypt_glwe_ciphertext_assign(glwe_secret_key, row_as_glwe, noise_parameters,
// generator); }
// }
//
// /// Decrypt a [`GGSW ciphertext`](`GgswCiphertext`) only yielding the plaintext from the constant
// /// term of the polynomial.
// ///
// /// # Example
// ///
// /// ```
// /// use tfhe::core_crypto::prelude::*;
// ///
// /// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
// /// // computations
// /// // Define parameters for GgswCiphertext creation
// /// let glwe_size = GlweSize(2);
// /// let polynomial_size = PolynomialSize(4);
// /// let decomp_base_log = DecompositionBaseLog(8);
// /// let decomp_level_count = DecompositionLevelCount(3);
// /// let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
// /// let ciphertext_modulus = CiphertextModulus::new_native();
// ///
// /// // Create the PRNG
// /// let mut seeder = new_seeder();
// /// let seeder = seeder.as_mut();
// /// let mut encryption_generator =
// /// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
// /// let mut secret_generator =
// /// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
// ///
// /// // Create the GlweSecretKey
// /// let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key(
// /// glwe_size.to_glwe_dimension(),
// /// polynomial_size,
// /// &mut secret_generator,
// /// );
// ///
// /// // Create the plaintext
// /// let plaintext = PlaintextList::new(3u64, PlaintextCount(4));
// ///
// /// // Create a new GgswCiphertext
// /// let mut ggsw = GgswCiphertext::new(
// /// 0u64,
// /// glwe_size,
// /// polynomial_size,
// /// decomp_base_log,
// /// decomp_level_count,
// /// ciphertext_modulus,
// /// );
// ///
// /// encrypt_polynomial_ggsw_ciphertext(
// /// &glwe_secret_key,
// /// &mut ggsw,
// /// &plaintext,
// /// glwe_modular_std_dev,
// /// &mut encryption_generator,
// /// );
// ///
// ///
// /// let mut decrypted = PlaintextList::new(0u64, PlaintextCount(polynomial_size.0));
// /// decrypt_polynomial_ggsw_ciphertext(&glwe_secret_key, &ggsw, &mut decrypted);
// /// assert_eq!(decrypted, plaintext);
// /// ```
// pub fn decrypt_polynomial_ggsw_ciphertext<Scalar, KeyCont, InputCont, OutputCont>(
// glwe_secret_key: &GlweSecretKey<KeyCont>,
// ggsw_ciphertext: &GgswCiphertext<InputCont>,
// output_plaintext_list: &mut PlaintextList<OutputCont>,
// )
// where
// Scalar: UnsignedTorus,
// KeyCont: Container<Element = Scalar>,
// InputCont: Container<Element = Scalar>,
// OutputCont: ContainerMut<Element = Scalar>,
//
// {
// assert!(
// ggsw_ciphertext.polynomial_size() == glwe_secret_key.polynomial_size(),
// "Mismatch between polynomial sizes of input ciphertext and input secret key. \
// Got {:?} in output, and {:?} in secret key.",
// ggsw_ciphertext.polynomial_size(),
// glwe_secret_key.polynomial_size()
// );
//
// assert!(
// ggsw_ciphertext.glwe_size().to_glwe_dimension() == glwe_secret_key.glwe_dimension(),
// "Mismatch between GlweDimension of input ciphertext and input secret key. \
// Got {:?} in output, and {:?} in secret key.",
// ggsw_ciphertext.glwe_size().to_glwe_dimension(),
// glwe_secret_key.glwe_dimension()
// );
//
// let level_matrix = ggsw_ciphertext.last().unwrap();
// let level_matrix_as_glwe_list = level_matrix.as_glwe_list();
// let last_row = level_matrix_as_glwe_list.last().unwrap();
// let decomp_level = ggsw_ciphertext.decomposition_level_count();
//
//
// decrypt_glwe_ciphertext(glwe_secret_key, &last_row, output_plaintext_list);
//
// let decomp_base_log = ggsw_ciphertext.decomposition_base_log();
//
// let decomposer = SignedDecomposer::new(decomp_base_log, decomp_level);
// let mut decoded = PlaintextList::new(Scalar::ZERO, PlaintextCount(ggsw_ciphertext
// .polynomial_size().0));
//
//
// for (plaintext_ref, mut decoded_ref) in output_plaintext_list.iter().zip(decoded.iter_mut
// ()) {
// //let plaintext_ref = decrypted_plaintext_list.get(0);
//
// // Glwe decryption maps to a smaller torus potentially, map back to the native torus
// let rounded = decomposer.closest_representable(
// (*plaintext_ref.0).wrapping_mul(
// ggsw_ciphertext
// .ciphertext_modulus()
// .get_power_of_two_scaling_to_native_torus(),
// ),
// );
// decoded_ref = PlaintextRefMut(& mut rounded.wrapping_div(Scalar::ONE << (Scalar::BITS -
// (decomp_base_log.0 *
// decomp_level.0))));
// }
// }

View File

@@ -0,0 +1,311 @@
//! Module containing primitives pertaining to the operation usually referred to as a
//! _sample extract_ in the literature. Allowing to extract a single
//! [`LWE Ciphertext`](`LweCiphertext`) from a given [`GLWE ciphertext`](`GlweCiphertext`).
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::parameters::MonomialDegree;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
/// Extract the nth coefficient from the body of a [`GLWE Ciphertext`](`GlweCiphertext`) as an
/// [`LWE ciphertext`](`LweCiphertext`).
///
/// # Formal definition
///
/// This operation is usually referred to as a _sample extract_ in the literature.
///
/// # Example
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for GlweCiphertext creation
/// let glwe_size = GlweSize(2);
/// let polynomial_size = PolynomialSize(8);
/// let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
/// let ciphertext_modulus = CiphertextModulus::new_native();
/// let phi = PartialGlweSecretKeyRandomCoefCount(
/// glwe_size.to_glwe_dimension().0 * polynomial_size.0 - 4,
/// );
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut encryption_generator =
/// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// // Create the GlweSecretKey
/// let glwe_secret_key = allocate_and_generate_new_binary_partial_glwe_secret_key(
/// glwe_size.to_glwe_dimension(),
/// polynomial_size,
/// phi,
/// &mut secret_generator,
/// );
///
/// // Create the plaintext
/// let msg = 3u64;
/// let encoded_msg = msg << 60;
/// let mut plaintext_list = PlaintextList::new(encoded_msg, PlaintextCount(polynomial_size.0));
///
/// let special_value = 15;
/// *plaintext_list.get_mut(0).0 = 15 << 60;
///
/// // Create a new GlweCiphertext
/// let mut glwe = GlweCiphertext::new(0u64, glwe_size, polynomial_size, ciphertext_modulus);
///
/// encrypt_glwe_ciphertext(
/// &glwe_secret_key,
/// &mut glwe,
/// &plaintext_list,
/// glwe_modular_std_dev,
/// &mut encryption_generator,
/// );
///
/// // Now we get the equivalent LweSecretKey from the GlweSecretKey
/// let equivalent_lwe_sk = glwe_secret_key.clone().into_lwe_secret_key();
///
/// let mut extracted_sample = LweCiphertext::new(
/// 0u64,
/// equivalent_lwe_sk.lwe_dimension().to_lwe_size(),
/// ciphertext_modulus,
/// );
///
/// partial_extract_lwe_sample_from_glwe_ciphertext(
/// &glwe,
/// &mut extracted_sample,
/// MonomialDegree(0),
/// phi.0,
/// );
///
/// let decrypted_plaintext = decrypt_lwe_ciphertext(&equivalent_lwe_sk, &extracted_sample);
///
/// // Round and remove encoding
/// // First create a decomposer working on the high 4 bits corresponding to our encoding.
/// let decomposer = SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
///
/// let recovered_message = decomposer.closest_representable(decrypted_plaintext.0) >> 60;
///
/// // We check we recover our special value instead of the 3 stored in all other slots of the
/// // GlweCiphertext
/// assert_eq!(special_value, recovered_message);
/// ```
pub fn partial_extract_lwe_sample_from_glwe_ciphertext<Scalar, InputCont, OutputCont>(
input_glwe: &GlweCiphertext<InputCont>,
output_lwe: &mut LweCiphertext<OutputCont>,
nth: MonomialDegree,
phi: usize,
) where
Scalar: UnsignedInteger,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
// assert!(
// input_glwe.glwe_size().to_glwe_dimension().0 * input_glwe.polynomial_size().0
// == output_lwe.lwe_size().to_lwe_dimension().0,
// "Mismatch between equivalent LweDimension of input ciphertext and output ciphertext. \
// Got {:?} for input and {:?} for output.",
// LweDimension(input_glwe.glwe_size().to_glwe_dimension().0 *
// input_glwe.polynomial_size().0), output_lwe.lwe_size().to_lwe_dimension(),
// );
//
// assert_eq!(
// input_glwe.ciphertext_modulus(),
// output_lwe.ciphertext_modulus(),
// "Mismatched moduli between input_glwe ({:?}) and output_lwe ({:?})",
// input_glwe.ciphertext_modulus(),
// output_lwe.ciphertext_modulus()
// );
output_lwe.as_mut().fill(Scalar::ZERO);
// // We retrieve the bodies and masks of the two ciphertexts.
let (mut lwe_mask, lwe_body) = output_lwe.get_mut_mask_and_body();
let (glwe_mask, glwe_body) = input_glwe.get_mask_and_body();
//
// // We copy the body
*lwe_body.data = glwe_body.as_ref()[nth.0];
//
//We copy the mask (each polynomial is in the wrong order)
lwe_mask.as_mut()[0..phi].copy_from_slice(&glwe_mask.as_ref()[0..phi]);
//
//
// // We compute the number of elements which must be
// // turned into their opposite
// let opposite_count = input_glwe.polynomial_size().0 - nth.0 - 1;
//
// // We loop through the polynomials
// for lwe_mask_poly in lwe_mask
// .as_mut()
// .chunks_exact_mut(input_glwe.polynomial_size().0).filter(|x| x != 0)
// {
// // We reverse the polynomial
// lwe_mask_poly.reverse();
// // We compute the opposite of the proper coefficients
// slice_wrapping_opposite_assign(&mut lwe_mask_poly[0..opposite_count]);
// // We rotate the polynomial properly
// lwe_mask_poly.rotate_left(opposite_count);
// }
// println!("GLWE MASK = {:?}", glwe_mask);
let big_n = input_glwe.polynomial_size().0;
//let lwe_mask_out = LweMask::from_container(vec![0; phi], input_glwe.ciphertext_modulus());
for i in 0..phi {
let alpha = i / big_n;
let beta = big_n.wrapping_sub(i) % big_n;
//let gamma:u32 = (1 - ((beta == 0) as u32)) as u32;
lwe_mask.as_mut()[i] = glwe_mask.as_polynomial_list().get(alpha)[beta];
// let mut mask_coef = glwe_mask.as_polynomial_list().as_view().get
// (alpha as usize).get(beta as usize).unwrap().to_owned();
if beta != 0 {
// println!("### IN LOOP BEFORE mask_coef = {:?}", mask_coef);
// mask_coef = mask_coef.wrapping_neg();
lwe_mask.as_mut()[i] = lwe_mask.as_mut()[i].wrapping_neg()
// println!("### IN LOOP AFTER mask_coef = {:?}", mask_coef);
}
// container_mask_out[i] = mask_coef;
}
// println!("container_mask_out = {:?}", container_mask_out);
// lwe_mask.as_mut().iter_mut().zip(container_mask_out.iter()).for_each(|(dst, &src)|
// *dst = src);
// println!("LWE MASK OUTPUT = {:?}", lwe_mask);
// println!("OUTPUT = {:?}", output_lwe.get_mask_and_body());
}
/// This operation does the opposite of
/// [`extract_lwe_sample_from_glwe_ciphertext`](`super::extract_lwe_sample_from_glwe_ciphertext`)
/// and inserts the body of [`an LWE ciphertext`](`LweCiphertext`) in the first coefficient of
/// [`a GLWE ciphertext`](`GlweCiphertext`) and fills the mask to have a valid GLWE ciphertext. The
/// rest of the mask and body are filled with zeros.
///
/// For an `input_lwe` encrypted under [`an LWE secret key`](`super::super::entities::LweSecretKey`)
/// that shares `phi` coefficients with [`an output GLWE secret
/// key`](`super::super::entities::GlweSecretKey`), it only requires on the order of `phi`
/// computations instead of `k * N` computations where `phi` is smaller than `k * N` (hence the
/// partial name). The `output_glwe` can be decrypted with the output GLWE secret key which shares
/// parts of its coefficients with the input LWE secret key.
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for GlweCiphertext creation
/// let glwe_size = GlweSize(2);
/// let polynomial_size = PolynomialSize(8);
/// let lwe_dimension = LweDimension(glwe_size.to_glwe_dimension().0 * polynomial_size.0);
/// let lwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
/// let ciphertext_modulus = CiphertextModulus::new_native();
/// let phi = PartialGlweSecretKeyRandomCoefCount(2);
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut encryption_generator =
/// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// // Create the GlweSecretKey
/// let glwe_secret_key = allocate_and_generate_new_binary_partial_glwe_secret_key(
/// glwe_size.to_glwe_dimension(),
/// polynomial_size,
/// phi,
/// &mut secret_generator,
/// );
///
/// println!("PARTIAL GLWE secret key = {:?}", glwe_secret_key);
///
/// let lwe_secret_key = glwe_secret_key.clone().into_lwe_secret_key();
///
/// println!("PARTIAL LWE secret key = {:?}", lwe_secret_key);
///
/// // Create the plaintext
/// let msg = 3u64;
/// let encoded_msg = msg << 60;
/// let mut plaintext = Plaintext(encoded_msg);
///
/// // Create a new LweCiphertext
/// let mut lwe = LweCiphertext::new(0u64, lwe_dimension.to_lwe_size(), ciphertext_modulus);
///
/// let mut glwe = GlweCiphertext::new(0u64, glwe_size, polynomial_size, ciphertext_modulus);
///
/// encrypt_lwe_ciphertext(
/// &lwe_secret_key,
/// &mut lwe,
/// plaintext,
/// lwe_modular_std_dev,
/// &mut encryption_generator,
/// );
///
/// partial_convert_lwe_ciphertext_into_constant_glwe_ciphertext(&lwe, &mut glwe, phi.0);
///
/// let mut output_plaintext_list = PlaintextList::new(0u64, PlaintextCount(polynomial_size.0));
///
/// decrypt_glwe_ciphertext(&glwe_secret_key, &glwe, &mut output_plaintext_list);
///
/// let decrypted_plaintext = output_plaintext_list.into_container()[0];
/// // Round and remove encoding
/// // First create a decomposer working on the high 4 bits corresponding to our encoding.
/// let decomposer = SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
///
/// let recovered_message = decomposer.closest_representable(decrypted_plaintext) >> 60;
///
/// // We check we recover our special value instead of the 3 stored in all other slots of the
/// // GlweCiphertext
/// assert_eq!(msg, recovered_message);
/// ```
pub fn partial_convert_lwe_ciphertext_into_constant_glwe_ciphertext<Scalar, InputCont, OutputCont>(
input_lwe: &LweCiphertext<InputCont>,
output_glwe: &mut GlweCiphertext<OutputCont>,
phi: usize,
) where
Scalar: UnsignedInteger,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
assert!(phi <= input_lwe.lwe_size().to_lwe_dimension().0);
assert!(phi <= output_glwe.get_mask().as_ref().len());
// B' is set to the LWE body only so the rest of the mask should be zeroed out
// if the index is greater than the shared dimension then the mask element is zeroed out as well
// So clear the output once and then run the algorithm
output_glwe.as_mut().fill(Scalar::ZERO);
let big_n = output_glwe.polynomial_size().0;
// We retrieve the bodies and masks of the two ciphertexts.
let (lwe_mask, lwe_body) = input_lwe.get_mask_and_body();
let (mut glwe_mask, mut glwe_body) = output_glwe.get_mut_mask_and_body();
// We copy the body
glwe_body.as_mut()[0] = *lwe_body.data;
let glwe_mask_slice = glwe_mask.as_mut();
for (i, &lwe_mask_element) in lwe_mask.as_ref()[..phi].iter().enumerate() {
// alpha = index of the current polynomial being considered
let alpha = i / big_n;
// beta = index in the polynomial = 0 if i is the first element of the output polynomial
// otherwise the end of the polynomial is reversed and negated
// Example with N = 512
// LWE: | 0 1 ... 511 | 512 513 ... 1023| ...
// | |
// | ________|
// v |
// GLWE: | 0 -511 ... -1 | 512 -1023 ... -513 | ...
let beta = big_n.wrapping_sub(i) % big_n;
if beta != 0 {
glwe_mask_slice[alpha * big_n + beta] = lwe_mask_element.wrapping_neg();
} else {
glwe_mask_slice[alpha * big_n + beta] = lwe_mask_element;
}
}
}

View File

@@ -0,0 +1,81 @@
//! Module containing primitives pertaining to the generation of
//! [`GLWE secret keys`](`GlweSecretKey`).
use crate::core_crypto::commons::generators::SecretRandomGenerator;
use crate::core_crypto::commons::math::random::{RandomGenerable, UniformBinary};
use crate::core_crypto::commons::numeric::Numeric;
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
/// Fill a [`GLWE secret key`](`GlweSecretKey`) with a predefined number of uniformly random binary
/// coefficients which can be smaller than the input key element count.
pub fn generate_binary_partial_glwe_secret_key<Scalar, KeyCont, Gen>(
glwe_secret_key: &mut GlweSecretKey<KeyCont>,
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount,
generator: &mut SecretRandomGenerator<Gen>,
) where
Scalar: RandomGenerable<UniformBinary> + Numeric,
KeyCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert!(
partial_glwe_secret_key_fill.0 <= glwe_secret_key.as_ref().len(),
"partial_glwe_secret_key_fill ({partial_glwe_secret_key_fill:?}) \
must be smaller than the total glwe_secret_key length ({}).",
glwe_secret_key.as_ref().len()
);
// Generate random coefficients to partially fill the key
generator.fill_slice_with_random_uniform_binary(
&mut glwe_secret_key.as_mut()[..partial_glwe_secret_key_fill.0],
);
}
/// Allocate a new [`GLWE secret key`](`GlweSecretKey`) and fill it with uniformly random binary
/// coefficients.
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// let glwe_size = GlweSize(2);
/// let polynomial_size = PolynomialSize(8);
/// let partial_glwe_secret_key_fill = PartialGlweSecretKeyRandomCoefCount(5);
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// let mut glwe_secret_key: GlweSecretKeyOwned<u64> =
/// allocate_and_generate_new_binary_partial_glwe_secret_key(
/// glwe_size.to_glwe_dimension(),
/// polynomial_size,
/// partial_glwe_secret_key_fill,
/// &mut secret_generator,
/// );
/// assert!(glwe_secret_key.as_ref()[partial_glwe_secret_key_fill.0..]
/// .iter()
/// .all(|x| *x == 0u64));
/// ```
pub fn allocate_and_generate_new_binary_partial_glwe_secret_key<Scalar, Gen>(
glwe_dimension: GlweDimension,
polynomial_size: PolynomialSize,
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount,
generator: &mut SecretRandomGenerator<Gen>,
) -> GlweSecretKeyOwned<Scalar>
where
Scalar: RandomGenerable<UniformBinary> + Numeric,
Gen: ByteRandomGenerator,
{
let mut glwe_secret_key =
GlweSecretKeyOwned::new_empty_key(Scalar::ZERO, glwe_dimension, polynomial_size);
generate_binary_partial_glwe_secret_key(
&mut glwe_secret_key,
partial_glwe_secret_key_fill,
generator,
);
glwe_secret_key
}

View File

@@ -25,8 +25,8 @@ use rayon::prelude::*;
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for GlweCiphertext creation
/// let glwe_size = GlweSize(2);
/// let polynomial_size = PolynomialSize(1024);
/// let glwe_size = GlweSize(4);
/// let polynomial_size = PolynomialSize(4);
/// let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
@@ -51,11 +51,10 @@ use rayon::prelude::*;
/// let mut plaintext_list = PlaintextList::new(encoded_msg, PlaintextCount(polynomial_size.0));
///
/// let special_value = 15;
/// *plaintext_list.get_mut(42).0 = 15 << 60;
/// *plaintext_list.get_mut(0).0 = 15 << 60;
///
/// // Create a new GlweCiphertext
/// let mut glwe = GlweCiphertext::new(0u64, glwe_size, polynomial_size, ciphertext_modulus);
///
/// encrypt_glwe_ciphertext(
/// &glwe_secret_key,
/// &mut glwe,
@@ -74,7 +73,7 @@ use rayon::prelude::*;
/// );
///
/// // Here we chose to extract sample at index 42 (corresponding to the MonomialDegree(42))
/// extract_lwe_sample_from_glwe_ciphertext(&glwe, &mut extracted_sample, MonomialDegree(42));
/// extract_lwe_sample_from_glwe_ciphertext(&glwe, &mut extracted_sample, MonomialDegree(0));
///
/// let decrypted_plaintext = decrypt_lwe_ciphertext(&equivalent_lwe_sk, &extracted_sample);
///

View File

@@ -69,3 +69,49 @@ pub fn generate_binary_glwe_secret_key<Scalar, InCont, Gen>(
{
generator.fill_slice_with_random_uniform_binary(glwe_secret_key.as_mut())
}
pub fn allocate_and_generate_new_binary_shared_glwe_secret_key<Scalar, Gen>(
glwe_dimension_large: GlweDimension,
glwe_dimension_small: GlweDimension,
polynomial_size: PolynomialSize,
generator: &mut SecretRandomGenerator<Gen>,
) -> (GlweSecretKeyOwned<Scalar>, GlweSecretKeyOwned<Scalar>)
where
Scalar: RandomGenerable<UniformBinary> + Numeric,
Gen: ByteRandomGenerator,
{
let mut large_glwe_secret_key =
GlweSecretKeyOwned::new_empty_key(Scalar::ZERO, glwe_dimension_large, polynomial_size);
generate_binary_glwe_secret_key(&mut large_glwe_secret_key, generator);
let mut small_glwe_secret_key =
GlweSecretKeyOwned::new_empty_key(Scalar::ZERO, glwe_dimension_small, polynomial_size);
small_glwe_secret_key
.as_mut()
.iter_mut()
.zip(large_glwe_secret_key.as_ref().iter())
.for_each(|(dst, &src)| *dst = src);
(large_glwe_secret_key, small_glwe_secret_key)
}
pub fn allocate_and_generate_new_shared_glwe_secret_key_from_glwe_secret_key<Scalar, InCont>(
in_large_glwe_key: &GlweSecretKey<InCont>,
glwe_dimension_out: GlweDimension,
phi: usize,
polynomial_size: PolynomialSize,
) -> GlweSecretKeyOwned<Scalar>
where
Scalar: RandomGenerable<UniformBinary> + Numeric,
InCont: Container<Element = Scalar>,
{
// let lwe_dimension_small = LweDimension(phi);
let mut small_glwe_secret_key =
GlweSecretKey::new_empty_key(Scalar::ZERO, glwe_dimension_out, polynomial_size);
small_glwe_secret_key.as_mut()[0..phi]
.iter_mut()
.zip(in_large_glwe_key.as_ref())
.for_each(|(dst, &src)| *dst = src);
small_glwe_secret_key
}

View File

@@ -0,0 +1,234 @@
// //! Module containing primitives pertaining to the [`LWE programmable
// //! bootstrap`](`LweBootstrapKey#programmable-bootstrapping`).
//
use crate::core_crypto::commons::math::decomposition::SignedDecomposer;
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
use crate::core_crypto::fft_impl::fft64::crypto::pseudo_ggsw::{
add_external_product_pseudo_ggsw_assign as impl_add_external_product_assign,
add_external_product_pseudo_ggsw_assign_scratch as impl_add_external_product_assign_scratch,
PseudoFourierGgswCiphertext,
};
use crate::core_crypto::fft_impl::fft64::math::fft::FftView;
use concrete_fft::c64;
use dyn_stack::{PodStack, SizeOverflow, StackReq};
//
//
// /// Memory optimized version of [`add_external_product_assign`], the caller must provide a
// properly /// configured [`FftView`] object and a `PodStack` used as a memory buffer having a
// capacity at /// least as large as the result of
// [`add_external_product_assign_mem_optimized_requirement`]. ///
// /// Compute the external product of `ggsw` and `glwe`, and add the result to `out`.
// ///
// /// Strictly speaking this function computes:
// ///
// /// ```text
// /// out <- out + glwe * ggsw
// /// ```
// ///
/// # Example
///
/// ```
/// use tfhe::core_crypto::prelude::*;
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for GgswCiphertext creation
/// let glwe_size_out = GlweSize(2);
/// let glwe_size_in = GlweSize(2);
/// let polynomial_size = PolynomialSize(1024);
/// let decomp_base_log = DecompositionBaseLog(8);
/// let decomp_level_count = DecompositionLevelCount(2);
/// let glwe_modular_std_dev = StandardDev(5.96046447753906e-25);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut encryption_generator =
/// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// // Create the GlweSecretKey
/// let glwe_secret_key_out = allocate_and_generate_new_binary_glwe_secret_key(
/// glwe_size_out.to_glwe_dimension(),
/// polynomial_size,
/// &mut secret_generator,
/// );
/// //let glwe_secret_key_out = GlweSecretKey::new_empty_key(0u64, glwe_size_out
/// //.to_glwe_dimension(),
/// //polynomial_size);
///
/// // Create the GlweSecretKey
/// let glwe_secret_key_in = allocate_and_generate_new_binary_glwe_secret_key(
/// glwe_size_in.to_glwe_dimension(),
/// polynomial_size,
/// &mut secret_generator,
/// );
/// //let mut cont = vec![0u64; polynomial_size.0*glwe_size_in.to_glwe_dimension().0];
/// // cont[0] = 1;
/// //let glwe_secret_key_in = GlweSecretKey::from_container(cont,polynomial_size);
///
/// // Create a new GgswCiphertext
/// let mut ggsw = PseudoGgswCiphertext::new(
/// 0u64,
/// glwe_size_in,
/// glwe_size_out,
/// polynomial_size,
/// decomp_base_log,
/// decomp_level_count,
/// ciphertext_modulus,
/// );
///
/// encrypt_pseudo_ggsw_ciphertext(
/// &glwe_secret_key_out,
/// &glwe_secret_key_in,
/// &mut ggsw,
/// glwe_modular_std_dev,
/// &mut encryption_generator,
/// );
///
/// let ct_plaintext = Plaintext(3 << 60);
///
/// let ct_plaintexts = PlaintextList::new(ct_plaintext.0, PlaintextCount(polynomial_size.0));
/// //let ct_cont = vec![0_u64; polynomial_size.0*glwe_size_in.0];
/// //let mut ct = GlweCiphertext::from_container(ct_cont, polynomial_size, ciphertext_modulus);
/// //ct.get_mut_body().as_mut_polynomial()[0] = 1<<60;
/// let mut ct = GlweCiphertext::new(0u64, glwe_size_in, polynomial_size, ciphertext_modulus);
///
/// //trivially_encrypt_glwe_ciphertext(&mut ct, &ct_plaintexts);
/// encrypt_glwe_ciphertext(
/// &glwe_secret_key_in,
/// &mut ct,
/// &ct_plaintexts,
/// glwe_modular_std_dev,
/// &mut encryption_generator,
/// );
///
/// let fft = Fft::new(polynomial_size);
/// let fft = fft.as_view();
/// let mut buffers = ComputationBuffers::new();
///
/// let buffer_size_req =
/// add_external_product_fast_keyswitch_assign_mem_optimized_requirement::<u64>(
/// glwe_size_out.to_glwe_dimension(),
/// polynomial_size,
/// fft,
/// )
/// .unwrap()
/// .unaligned_bytes_required();
///
/// let buffer_size_req = buffer_size_req.max(
/// convert_standard_ggsw_ciphertext_to_fourier_mem_optimized_requirement(fft)
/// .unwrap()
/// .unaligned_bytes_required(),
/// );
///
/// buffers.resize(10 * buffer_size_req);
///
/// let mut fourier_ggsw = PseudoFourierGgswCiphertext::new(
/// glwe_size_in,
/// glwe_size_out,
/// polynomial_size,
/// decomp_base_log,
/// decomp_level_count,
/// );
///
/// convert_standard_pseudo_ggsw_ciphertext_to_fourier_mem_optimized(
/// &ggsw,
/// &mut fourier_ggsw,
/// fft,
/// buffers.stack(),
/// );
///
/// //println!("Fourier GGSW = {:?}", fourier_ggsw);
///
/// let mut ct_out = GlweCiphertext::new(0u64, glwe_size_out, polynomial_size, ciphertext_modulus);
///
/// println!("Input Secret Key: {:?}\n", glwe_secret_key_in);
/// println!("Ouput Secret Key: {:?}\n", glwe_secret_key_out);
/// println!("Ct IN = {:?}\n", ct);
/// println!("GGSW = {:?}\n", ggsw);
/// println!("GGSW Fourier = {:?}\n", fourier_ggsw);
///
/// add_external_product_fast_keyswitch_assign_mem_optimized(
/// &mut ct_out,
/// &fourier_ggsw,
/// &ct,
/// fft,
/// buffers.stack(),
/// );
///
/// println!("Ct OUT = {:?}\n", ct_out);
///
/// let mut output_plaintext_list = PlaintextList::new(0u64, ct_plaintexts.plaintext_count());
///
/// decrypt_glwe_ciphertext(&glwe_secret_key_out, &ct_out, &mut output_plaintext_list);
///
/// let signed_decomposer =
/// SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
///
/// output_plaintext_list
/// .iter_mut()
/// .for_each(|x| *x.0 = signed_decomposer.closest_representable(*x.0));
///
/// println!("PlaintextList OUT = {:?}\n", output_plaintext_list);
///
/// // As we cloned the input ciphertext for the output, the external product result is added to the
/// // originally contained value, hence why we expect ct_plaintext + ct_plaintext * msg_ggsw
/// //assert!(output_plaintext_list
/// // .iter()
/// // .all(|x| *x.0 == ct_plaintext.0), "{:?}", output_plaintext_list);
/// assert_eq!(output_plaintext_list.into_container()[0], ct_plaintext.0);
/// ```
pub fn add_external_product_fast_keyswitch_assign_mem_optimized<
Scalar,
OutputGlweCont,
InputGlweCont,
GgswCont,
>(
out: &mut GlweCiphertext<OutputGlweCont>,
ggsw: &PseudoFourierGgswCiphertext<GgswCont>,
glwe: &GlweCiphertext<InputGlweCont>,
fft: FftView<'_>,
stack: PodStack<'_>,
) where
Scalar: UnsignedTorus,
OutputGlweCont: ContainerMut<Element = Scalar>,
GgswCont: Container<Element = c64>,
InputGlweCont: Container<Element = Scalar>,
{
assert_eq!(out.ciphertext_modulus(), glwe.ciphertext_modulus());
impl_add_external_product_assign(out.as_mut_view(), ggsw.as_view(), glwe, fft, stack);
let ciphertext_modulus = out.ciphertext_modulus();
if !ciphertext_modulus.is_native_modulus() {
// When we convert back from the fourier domain, integer values will contain up to 53
// MSBs with information. In our representation of power of 2 moduli < native modulus we
// fill the MSBs and leave the LSBs empty, this usage of the signed decomposer allows to
// round while keeping the data in the MSBs
let signed_decomposer = SignedDecomposer::new(
DecompositionBaseLog(ciphertext_modulus.get_custom_modulus().ilog2() as usize),
DecompositionLevelCount(1),
);
out.as_mut()
.iter_mut()
.for_each(|x| *x = signed_decomposer.closest_representable(*x));
}
}
/// Return the required memory for [`add_external_product_fast_keyswitch_assign_mem_optimized`].
pub fn add_external_product_fast_keyswitch_assign_mem_optimized_requirement<Scalar>(
glwe_dimension: GlweDimension,
polynomial_size: PolynomialSize,
fft: FftView<'_>,
) -> Result<StackReq, SizeOverflow> {
//Trick to rebrand the dimension as a size to avoid code duplication
impl_add_external_product_assign_scratch::<Scalar>(
glwe_dimension.to_glwe_size(),
polynomial_size,
fft,
)
}

View File

@@ -0,0 +1,588 @@
// use crate::core_crypto::algorithms::*;
// use crate::core_crypto::commons::dispersion::DispersionParameter;
// use crate::core_crypto::commons::generators::EncryptionRandomGenerator;
// use crate::core_crypto::commons::math::random::ActivatedRandomGenerator;
// use crate::core_crypto::commons::parameters::*;
// use crate::core_crypto::commons::traits::*;
// use crate::core_crypto::entities::*;
// use rayon::prelude::*;
//
// /// Fill an [`LWE bootstrap key`](`LweBootstrapKey`) with an actual bootstrapping key constructed
// /// from an input key [`LWE secret key`](`LweSecretKey`) and an output key
// /// [`GLWE secret key`](`GlweSecretKey`)
// ///
// /// Consider using [`par_generate_lwe_bootstrap_key`] for better key generation times.
// ///
// /// ```
// /// use tfhe::core_crypto::prelude::*;
// ///
// /// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
// /// // computations
// /// // Define parameters for LweBootstrapKey creation
// /// let input_lwe_dimension = LweDimension(742);
// /// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
// /// let output_lwe_dimension = LweDimension(2048);
// /// let decomp_base_log = DecompositionBaseLog(3);
// /// let decomp_level_count = DecompositionLevelCount(5);
// /// let glwe_dimension = GlweDimension(1);
// /// let polynomial_size = PolynomialSize(1024);
// /// let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
// /// let ciphertext_modulus = CiphertextModulus::new_native();
// ///
// /// // Create the PRNG
// /// let mut seeder = new_seeder();
// /// let seeder = seeder.as_mut();
// /// let mut encryption_generator =
// /// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
// /// let mut secret_generator =
// /// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
// ///
// /// // Create the LweSecretKey
// /// let input_lwe_secret_key =
// /// allocate_and_generate_new_binary_lwe_secret_key(input_lwe_dimension, &mut
// secret_generator); /// let output_glwe_secret_key =
// allocate_and_generate_new_binary_glwe_secret_key( /// glwe_dimension,
// /// polynomial_size,
// /// &mut secret_generator,
// /// );
// ///
// /// let mut bsk = LweBootstrapKey::new(
// /// 0u64,
// /// glwe_dimension.to_glwe_size(),
// /// polynomial_size,
// /// decomp_base_log,
// /// decomp_level_count,
// /// input_lwe_dimension,
// /// ciphertext_modulus,
// /// );
// ///
// /// generate_lwe_bootstrap_key(
// /// &input_lwe_secret_key,
// /// &output_glwe_secret_key,
// /// &mut bsk,
// /// glwe_modular_std_dev,
// /// &mut encryption_generator,
// /// );
// ///
// /// for (ggsw, &input_key_bit) in bsk.iter().zip(input_lwe_secret_key.as_ref()) {
// /// let decrypted_ggsw = decrypt_constant_ggsw_ciphertext(&output_glwe_secret_key, &ggsw);
// /// assert_eq!(decrypted_ggsw.0, input_key_bit)
// /// }
// /// ```
// pub fn generate_glwe_fast_keyswitch_key<Scalar, InputKeyCont, OutputKeyCont, OutputCont, Gen>(
// input_lwe_secret_key: &GlweSecretKey<InputKeyCont>,
// output_glwe_secret_key: &GlweSecretKey<OutputKeyCont>,
// output: &mut LweBootstrapKey<OutputCont>,
// noise_parameters: impl DispersionParameter,
// generator: &mut EncryptionRandomGenerator<Gen>,
// ) where Scalar: UnsignedTorus, InputKeyCont: Container<Element = Scalar>, OutputKeyCont:
// Container<Element = Scalar>, OutputCont: ContainerMut<Element = Scalar>, Gen:
// ByteRandomGenerator,
// {
// // assert!(
// // output.input_lwe_dimension() == input_lwe_secret_key.lwe_dimension(),
// // "Mismatched LweDimension between input LWE secret key and LWE bootstrap key. \
// // Input LWE secret key LweDimension: {:?}, LWE bootstrap key input LweDimension {:?}.",
// // input_lwe_secret_key.lwe_dimension(),
// // output.input_lwe_dimension()
// // );
// //
// // assert!(
// // output.glwe_size() == output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // "Mismatched GlweSize between output GLWE secret key and LWE bootstrap key. \
// // Output GLWE secret key GlweSize: {:?}, LWE bootstrap key GlweSize {:?}.",
// // output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // output.glwe_size()
// // );
// //
// // assert!(
// // output.polynomial_size() == output_glwe_secret_key.polynomial_size(),
// // "Mismatched PolynomialSize between output GLWE secret key and LWE bootstrap key. \
// // Output GLWE secret key PolynomialSize: {:?}, LWE bootstrap key PolynomialSize {:?}.",
// // output_glwe_secret_key.polynomial_size(),
// // output.polynomial_size()
// // );
//
// let gen_iter = generator
// .fork_bsk_to_ggsw::<Scalar>(
// output.input_lwe_dimension(),
// output.decomposition_level_count(),
// output.glwe_size(),
// output.polynomial_size(),
// )
// .unwrap();
//
// for ((mut ggsw, input_key_element), mut generator) in output
// .iter_mut()
// .zip(input_lwe_secret_key.as_polynomial_list().as_view().iter())
// .zip(gen_iter)
// {
// let key = &GlweSecretKey::from_container(input_key_element.into_container(),
// input_lwe_secret_key.polynomial_size());
// encrypt_pseudo_ggsw_ciphertext(
// output_glwe_secret_key,
// key,
// &mut ggsw,
// noise_parameters,
// &mut generator,
// );
// }
// }
//
//
//
//
//
//
//
//
//
// //
// // /// Allocate a new [`LWE bootstrap key`](`LweBootstrapKey`) and fill it with an actual
// bootstrapping // /// key constructed from an input key [`LWE secret key`](`LweSecretKey`) and an
// output key // /// [`GLWE secret key`](`GlweSecretKey`).
// // ///
// // /// Consider using [`par_allocate_and_generate_new_lwe_bootstrap_key`] for better key
// generation // /// times.
// // pub fn allocate_and_generate_new_glwe_fast_keyswitch_key<Scalar, InputKeyCont, OutputKeyCont,
// Gen>( // input_lwe_secret_key: &GlweSecretKey<InputKeyCont>,
// // output_glwe_secret_key: &GlweSecretKey<OutputKeyCont>,
// // decomp_base_log: DecompositionBaseLog,
// // decomp_level_count: DecompositionLevelCount,
// // noise_parameters: impl DispersionParameter,
// // ciphertext_modulus: CiphertextModulus<Scalar>,
// // generator: &mut EncryptionRandomGenerator<Gen>,
// // ) -> LweBootstrapKeyOwned<Scalar>
// // where
// // Scalar: UnsignedTorus,
// // InputKeyCont: Container<Element = Scalar>,
// // OutputKeyCont: Container<Element = Scalar>,
// // Gen: ByteRandomGenerator,
// // {
// // let mut bsk = LweBootstrapKeyOwned::new(
// // Scalar::ZERO,
// // output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // output_glwe_secret_key.polynomial_size(),
// // decomp_base_log,
// // decomp_level_count,
// // LweDimension(input_lwe_secret_key.glwe_dimension().0 * input_lwe_secret_key
// // .polynomial_size().0),
// // ciphertext_modulus,
// // );
// //
// // generate_glwe_fast_keyswitch_key(
// // input_lwe_secret_key,
// // output_glwe_secret_key,
// // &mut bsk,
// // noise_parameters,
// // generator,
// // );
// //
// // bsk
// // }
// //
// // // /// Parallel variant of [`generate_lwe_bootstrap_key`], it is recommended to use this
// function for // // /// better key generation times as LWE bootstrapping keys can be quite large.
// // // ///
// // // /// # Example
// // // ///
// // // /// ```
// // // /// use tfhe::core_crypto::prelude::*;
// // // ///
// // // /// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield
// correct // // /// // computations
// // // /// // Define parameters for LweBootstrapKey creation
// // // /// let input_lwe_dimension = LweDimension(742);
// // // /// let lwe_modular_std_dev = StandardDev(0.000007069849454709433);
// // // /// let output_lwe_dimension = LweDimension(2048);
// // // /// let decomp_base_log = DecompositionBaseLog(3);
// // // /// let decomp_level_count = DecompositionLevelCount(5);
// // // /// let glwe_dimension = GlweDimension(1);
// // // /// let polynomial_size = PolynomialSize(1024);
// // // /// let glwe_modular_std_dev = StandardDev(0.00000000000000029403601535432533);
// // // /// let ciphertext_modulus = CiphertextModulus::new_native();
// // // ///
// // // /// // Create the PRNG
// // // /// let mut seeder = new_seeder();
// // // /// let seeder = seeder.as_mut();
// // // /// let mut encryption_generator =
// // // /// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
// // // /// let mut secret_generator =
// // // /// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
// // // ///
// // // /// // Create the LweSecretKey
// // // /// let input_lwe_secret_key =
// // // /// allocate_and_generate_new_binary_lwe_secret_key(input_lwe_dimension, &mut
// secret_generator); // // /// let output_glwe_secret_key =
// allocate_and_generate_new_binary_glwe_secret_key( // // /// glwe_dimension,
// // // /// polynomial_size,
// // // /// &mut secret_generator,
// // // /// );
// // // ///
// // // /// let mut bsk = LweBootstrapKey::new(
// // // /// 0u64,
// // // /// glwe_dimension.to_glwe_size(),
// // // /// polynomial_size,
// // // /// decomp_base_log,
// // // /// decomp_level_count,
// // // /// input_lwe_dimension,
// // // /// ciphertext_modulus,
// // // /// );
// // // ///
// // // /// par_generate_lwe_bootstrap_key(
// // // /// &input_lwe_secret_key,
// // // /// &output_glwe_secret_key,
// // // /// &mut bsk,
// // // /// glwe_modular_std_dev,
// // // /// &mut encryption_generator,
// // // /// );
// // // ///
// // // /// assert!(bsk.as_ref().iter().all(|&x| x == 0) == false);
// // // /// ```
// // // pub fn par_generate_lwe_bootstrap_key<Scalar, InputKeyCont, OutputKeyCont, OutputCont,
// Gen>( // // input_lwe_secret_key: &LweSecretKey<InputKeyCont>,
// // // output_glwe_secret_key: &GlweSecretKey<OutputKeyCont>,
// // // output: &mut LweBootstrapKey<OutputCont>,
// // // noise_parameters: impl DispersionParameter + Sync,
// // // generator: &mut EncryptionRandomGenerator<Gen>,
// // // ) where
// // // Scalar: UnsignedTorus + Sync + Send,
// // // InputKeyCont: Container<Element = Scalar>,
// // // OutputKeyCont: Container<Element = Scalar> + Sync,
// // // OutputCont: ContainerMut<Element = Scalar>,
// // // Gen: ParallelByteRandomGenerator,
// // // {
// // // assert!(
// // // output.input_lwe_dimension() == input_lwe_secret_key.lwe_dimension(),
// // // "Mismatched LweDimension between input LWE secret key and LWE bootstrap key. \
// // // Input LWE secret key LweDimension: {:?}, LWE bootstrap key input LweDimension
// {:?}.", // // input_lwe_secret_key.lwe_dimension(),
// // // output.input_lwe_dimension()
// // // );
// // //
// // // assert!(
// // // output.glwe_size() == output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // // "Mismatched GlweSize between output GLWE secret key and LWE bootstrap key. \
// // // Output GLWE secret key GlweSize: {:?}, LWE bootstrap key GlweSize {:?}.",
// // // output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // // output.glwe_size()
// // // );
// // //
// // // assert!(
// // // output.polynomial_size() == output_glwe_secret_key.polynomial_size(),
// // // "Mismatched PolynomialSize between output GLWE secret key and LWE bootstrap key. \
// // // Output GLWE secret key PolynomialSize: {:?}, LWE bootstrap key PolynomialSize
// {:?}.", // // output_glwe_secret_key.polynomial_size(),
// // // output.polynomial_size()
// // // );
// // //
// // // let gen_iter = generator
// // // .par_fork_bsk_to_ggsw::<Scalar>(
// // // output.input_lwe_dimension(),
// // // output.decomposition_level_count(),
// // // output.glwe_size(),
// // // output.polynomial_size(),
// // // )
// // // .unwrap();
// // //
// // // output
// // // .par_iter_mut()
// // // .zip(input_lwe_secret_key.as_ref().par_iter())
// // // .zip(gen_iter)
// // // .for_each(|((mut ggsw, &input_key_element), mut generator)| {
// // // par_encrypt_constant_ggsw_ciphertext(
// // // output_glwe_secret_key,
// // // &mut ggsw,
// // // Plaintext(input_key_element),
// // // noise_parameters,
// // // &mut generator,
// // // );
// // // });
// // // }
// // //
// // // /// Parallel variant of [`allocate_and_generate_new_lwe_bootstrap_key`], it is recommended
// to use // // /// this function for better key generation times as LWE bootstrapping keys can be
// quite large. // // ///
// // // /// See [`programmable_bootstrap_lwe_ciphertext`] for usage.
// // // pub fn par_allocate_and_generate_new_lwe_bootstrap_key<Scalar, InputKeyCont, OutputKeyCont,
// Gen>( // // input_lwe_secret_key: &LweSecretKey<InputKeyCont>,
// // // output_glwe_secret_key: &GlweSecretKey<OutputKeyCont>,
// // // decomp_base_log: DecompositionBaseLog,
// // // decomp_level_count: DecompositionLevelCount,
// // // noise_parameters: impl DispersionParameter + Sync,
// // // ciphertext_modulus: CiphertextModulus<Scalar>,
// // // generator: &mut EncryptionRandomGenerator<Gen>,
// // // ) -> LweBootstrapKeyOwned<Scalar>
// // // where
// // // Scalar: UnsignedTorus + Sync + Send,
// // // InputKeyCont: Container<Element = Scalar>,
// // // OutputKeyCont: Container<Element = Scalar> + Sync,
// // // Gen: ParallelByteRandomGenerator,
// // // {
// // // let mut bsk = LweBootstrapKeyOwned::new(
// // // Scalar::ZERO,
// // // output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // // output_glwe_secret_key.polynomial_size(),
// // // decomp_base_log,
// // // decomp_level_count,
// // // input_lwe_secret_key.lwe_dimension(),
// // // ciphertext_modulus,
// // // );
// // //
// // // par_generate_lwe_bootstrap_key(
// // // input_lwe_secret_key,
// // // output_glwe_secret_key,
// // // &mut bsk,
// // // noise_parameters,
// // // generator,
// // // );
// // //
// // // bsk
// // // }
// // //
// // // /// Fill a [`seeded LWE bootstrap key`](`SeededLweBootstrapKey`) with an actual seeded
// bootstrapping // // /// key constructed from an input key [`LWE secret key`](`LweSecretKey`) and
// an output key // // /// [`GLWE secret key`](`GlweSecretKey`)
// // // ///
// // // /// Consider using [`par_generate_seeded_lwe_bootstrap_key`] for better key generation
// times. // // pub fn generate_seeded_lwe_bootstrap_key<
// // // Scalar,
// // // InputKeyCont,
// // // OutputKeyCont,
// // // OutputCont,
// // // NoiseSeeder,
// // // >(
// // // input_lwe_secret_key: &LweSecretKey<InputKeyCont>,
// // // output_glwe_secret_key: &GlweSecretKey<OutputKeyCont>,
// // // output: &mut SeededLweBootstrapKey<OutputCont>,
// // // noise_parameters: impl DispersionParameter,
// // // noise_seeder: &mut NoiseSeeder,
// // // ) where
// // // Scalar: UnsignedTorus,
// // // InputKeyCont: Container<Element = Scalar>,
// // // OutputKeyCont: Container<Element = Scalar>,
// // // OutputCont: ContainerMut<Element = Scalar>,
// // // // Maybe Sized allows to pass Box<dyn Seeder>.
// // // NoiseSeeder: Seeder + ?Sized,
// // // {
// // // assert!(
// // // output.input_lwe_dimension() == input_lwe_secret_key.lwe_dimension(),
// // // "Mismatched LweDimension between input LWE secret key and LWE bootstrap key. \
// // // Input LWE secret key LweDimension: {:?}, LWE bootstrap key input LweDimension
// {:?}.", // // input_lwe_secret_key.lwe_dimension(),
// // // output.input_lwe_dimension()
// // // );
// // //
// // // assert!(
// // // output.glwe_size() == output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // // "Mismatched GlweSize between output GLWE secret key and LWE bootstrap key. \
// // // Output GLWE secret key GlweSize: {:?}, LWE bootstrap key GlweSize {:?}.",
// // // output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // // output.glwe_size()
// // // );
// // //
// // // assert!(
// // // output.polynomial_size() == output_glwe_secret_key.polynomial_size(),
// // // "Mismatched PolynomialSize between output GLWE secret key and LWE bootstrap key. \
// // // Output GLWE secret key PolynomialSize: {:?}, LWE bootstrap key PolynomialSize
// {:?}.", // // output_glwe_secret_key.polynomial_size(),
// // // output.polynomial_size()
// // // );
// // //
// // // let mut generator = EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(
// // // output.compression_seed().seed,
// // // noise_seeder,
// // // );
// // //
// // // let gen_iter = generator
// // // .fork_bsk_to_ggsw::<Scalar>(
// // // output.input_lwe_dimension(),
// // // output.decomposition_level_count(),
// // // output.glwe_size(),
// // // output.polynomial_size(),
// // // )
// // // .unwrap();
// // //
// // // for ((mut ggsw, &input_key_element), mut generator) in output
// // // .iter_mut()
// // // .zip(input_lwe_secret_key.as_ref())
// // // .zip(gen_iter)
// // // {
// // // encrypt_constant_seeded_ggsw_ciphertext_with_existing_generator(
// // // output_glwe_secret_key,
// // // &mut ggsw,
// // // Plaintext(input_key_element),
// // // noise_parameters,
// // // &mut generator,
// // // );
// // // }
// // // }
// // //
// // // /// Allocate a new [`seeded LWE bootstrap key`](`SeededLweBootstrapKey`) and fill it with
// an actual // // /// seeded bootstrapping key constructed from an input key [`LWE secret
// key`](`LweSecretKey`) and an // // /// output key [`GLWE secret key`](`GlweSecretKey`)
// // // ///
// // // /// Consider using [`par_allocate_and_generate_new_seeded_lwe_bootstrap_key`] for better
// key // // /// generation times.
// // // pub fn allocate_and_generate_new_seeded_lwe_bootstrap_key<
// // // Scalar,
// // // InputKeyCont,
// // // OutputKeyCont,
// // // NoiseSeeder,
// // // >(
// // // input_lwe_secret_key: &LweSecretKey<InputKeyCont>,
// // // output_glwe_secret_key: &GlweSecretKey<OutputKeyCont>,
// // // decomp_base_log: DecompositionBaseLog,
// // // decomp_level_count: DecompositionLevelCount,
// // // noise_parameters: impl DispersionParameter,
// // // ciphertext_modulus: CiphertextModulus<Scalar>,
// // // noise_seeder: &mut NoiseSeeder,
// // // ) -> SeededLweBootstrapKeyOwned<Scalar>
// // // where
// // // Scalar: UnsignedTorus,
// // // InputKeyCont: Container<Element = Scalar>,
// // // OutputKeyCont: Container<Element = Scalar>,
// // // // Maybe Sized allows to pass Box<dyn Seeder>.
// // // NoiseSeeder: Seeder + ?Sized,
// // // {
// // // let mut bsk = SeededLweBootstrapKeyOwned::new(
// // // Scalar::ZERO,
// // // output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // // output_glwe_secret_key.polynomial_size(),
// // // decomp_base_log,
// // // decomp_level_count,
// // // input_lwe_secret_key.lwe_dimension(),
// // // noise_seeder.seed().into(),
// // // ciphertext_modulus,
// // // );
// // //
// // // generate_seeded_lwe_bootstrap_key(
// // // input_lwe_secret_key,
// // // output_glwe_secret_key,
// // // &mut bsk,
// // // noise_parameters,
// // // noise_seeder,
// // // );
// // //
// // // bsk
// // // }
// // //
// // // /// Parallel variant of [`generate_seeded_lwe_bootstrap_key`], it is recommended to use
// this // // /// function for better key generation times as LWE bootstrapping keys can be quite
// large. // // pub fn par_generate_seeded_lwe_bootstrap_key<
// // // Scalar,
// // // InputKeyCont,
// // // OutputKeyCont,
// // // OutputCont,
// // // NoiseSeeder,
// // // >(
// // // input_lwe_secret_key: &LweSecretKey<InputKeyCont>,
// // // output_glwe_secret_key: &GlweSecretKey<OutputKeyCont>,
// // // output: &mut SeededLweBootstrapKey<OutputCont>,
// // // noise_parameters: impl DispersionParameter + Sync,
// // // noise_seeder: &mut NoiseSeeder,
// // // ) where
// // // Scalar: UnsignedTorus + Sync + Send,
// // // InputKeyCont: Container<Element = Scalar>,
// // // OutputKeyCont: Container<Element = Scalar> + Sync,
// // // OutputCont: ContainerMut<Element = Scalar>,
// // // // Maybe Sized allows to pass Box<dyn Seeder>.
// // // NoiseSeeder: Seeder + ?Sized,
// // // {
// // // assert!(
// // // output.input_lwe_dimension() == input_lwe_secret_key.lwe_dimension(),
// // // "Mismatched LweDimension between input LWE secret key and LWE bootstrap key. \
// // // Input LWE secret key LweDimension: {:?}, LWE bootstrap key input LweDimension
// {:?}.", // // input_lwe_secret_key.lwe_dimension(),
// // // output.input_lwe_dimension()
// // // );
// // //
// // // assert!(
// // // output.glwe_size() == output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // // "Mismatched GlweSize between output GLWE secret key and LWE bootstrap key. \
// // // Output GLWE secret key GlweSize: {:?}, LWE bootstrap key GlweSize {:?}.",
// // // output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // // output.glwe_size()
// // // );
// // //
// // // assert!(
// // // output.polynomial_size() == output_glwe_secret_key.polynomial_size(),
// // // "Mismatched PolynomialSize between output GLWE secret key and LWE bootstrap key. \
// // // Output GLWE secret key PolynomialSize: {:?}, LWE bootstrap key PolynomialSize
// {:?}.", // // output_glwe_secret_key.polynomial_size(),
// // // output.polynomial_size()
// // // );
// // //
// // // let mut generator = EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(
// // // output.compression_seed().seed,
// // // noise_seeder,
// // // );
// // //
// // // let gen_iter = generator
// // // .par_fork_bsk_to_ggsw::<Scalar>(
// // // output.input_lwe_dimension(),
// // // output.decomposition_level_count(),
// // // output.glwe_size(),
// // // output.polynomial_size(),
// // // )
// // // .unwrap();
// // //
// // // output
// // // .par_iter_mut()
// // // .zip(input_lwe_secret_key.as_ref().par_iter())
// // // .zip(gen_iter)
// // // .for_each(|((mut ggsw, &input_key_element), mut generator)| {
// // // par_encrypt_constant_seeded_ggsw_ciphertext_with_existing_generator(
// // // output_glwe_secret_key,
// // // &mut ggsw,
// // // Plaintext(input_key_element),
// // // noise_parameters,
// // // &mut generator,
// // // );
// // // })
// // // }
// // //
// // // /// Parallel variant of [`allocate_and_generate_new_seeded_lwe_bootstrap_key`], it is
// recommended to // // /// use this function for better key generation times as LWE bootstrapping
// keys can be quite large. // // pub fn par_allocate_and_generate_new_seeded_lwe_bootstrap_key<
// // // Scalar,
// // // InputKeyCont,
// // // OutputKeyCont,
// // // NoiseSeeder,
// // // >(
// // // input_lwe_secret_key: &LweSecretKey<InputKeyCont>,
// // // output_glwe_secret_key: &GlweSecretKey<OutputKeyCont>,
// // // decomp_base_log: DecompositionBaseLog,
// // // decomp_level_count: DecompositionLevelCount,
// // // noise_parameters: impl DispersionParameter + Sync,
// // // ciphertext_modulus: CiphertextModulus<Scalar>,
// // // noise_seeder: &mut NoiseSeeder,
// // // ) -> SeededLweBootstrapKeyOwned<Scalar>
// // // where
// // // Scalar: UnsignedTorus + Sync + Send,
// // // InputKeyCont: Container<Element = Scalar>,
// // // OutputKeyCont: Container<Element = Scalar> + Sync,
// // // // Maybe Sized allows to pass Box<dyn Seeder>.
// // // NoiseSeeder: Seeder + ?Sized,
// // // {
// // // let mut bsk = SeededLweBootstrapKeyOwned::new(
// // // Scalar::ZERO,
// // // output_glwe_secret_key.glwe_dimension().to_glwe_size(),
// // // output_glwe_secret_key.polynomial_size(),
// // // decomp_base_log,
// // // decomp_level_count,
// // // input_lwe_secret_key.lwe_dimension(),
// // // noise_seeder.seed().into(),
// // // ciphertext_modulus,
// // // );
// // //
// // // par_generate_seeded_lwe_bootstrap_key(
// // // input_lwe_secret_key,
// // // output_glwe_secret_key,
// // // &mut bsk,
// // // noise_parameters,
// // // noise_seeder,
// // // );
// // //
// // // bsk
// // // }

View File

@@ -0,0 +1,68 @@
//! Module containing primitives pertaining to the generation of
//! [`LWE secret keys`](`LweSecretKey`).
use crate::core_crypto::commons::generators::SecretRandomGenerator;
use crate::core_crypto::commons::math::random::{RandomGenerable, UniformBinary};
use crate::core_crypto::commons::numeric::Numeric;
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
use crate::core_crypto::prelude::generate_binary_lwe_secret_key;
/// Allocate a new [`LWE secret key`](`LweSecretKey`) and fill it with uniformly random binary
/// coefficients.
/// phi: the number of non-zero coefficients
/// See [`encrypt_lwe_ciphertext`](`super::lwe_encryption::encrypt_lwe_ciphertext`) for usage.
///
/// /// Fill an [`LWE secret key`](`LweSecretKey`) with uniformly random binary coefficients.
///
/// # Example
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(20);
/// let phi = LweDimension(15);
///
/// // Create the PRNG20
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// let mut lwe_secret_key: LweSecretKeyOwned<u64> =
/// allocate_and_generate_new_binary_lwe_partial_secret_key(
/// lwe_dimension,
/// &mut secret_generator,
/// phi,
/// );
/// // Check all coefficients are not zero as we just generated a new key
/// // Note probability of this assert failing is (1/2)^lwe_dimension or ~4.3 * 10^-224 for an LWE
/// // dimension of 742.
/// assert!(lwe_secret_key.as_ref().iter().all(|&elt| elt == 0) == false);
/// ```
pub fn allocate_and_generate_new_binary_lwe_partial_secret_key<Scalar, Gen>(
lwe_dimension: LweDimension,
generator: &mut SecretRandomGenerator<Gen>,
phi: LweDimension,
) -> LweSecretKeyOwned<Scalar>
where
Scalar: RandomGenerable<UniformBinary> + Numeric,
Gen: ByteRandomGenerator,
{
let mut lwe_secret_key = LweSecretKeyOwned::new_empty_key(Scalar::ZERO, phi);
generate_binary_lwe_secret_key(&mut lwe_secret_key, generator);
let mut lwe_secret_key_out = LweSecretKeyOwned::new_empty_key(Scalar::ZERO, lwe_dimension);
lwe_secret_key_out
.as_mut()
.iter_mut()
.zip(lwe_secret_key.as_ref().iter())
.for_each(|(dst, &src)| *dst = src);
//println!("Input Key = {:?}", lwe_secret_key.into_container().to_vec());
//println!("Ouput Key = {:?}", lwe_secret_key_out.clone().into_container().to_vec());
lwe_secret_key_out
}

View File

@@ -64,3 +64,45 @@ pub fn generate_binary_lwe_secret_key<Scalar, InCont, Gen>(
{
generator.fill_slice_with_random_uniform_binary(lwe_secret_key.as_mut())
}
pub fn allocate_and_generate_new_binary_shared_lwe_secret_key<Scalar, Gen>(
lwe_dimension_large: LweDimension,
lwe_dimension_small: LweDimension,
generator: &mut SecretRandomGenerator<Gen>,
) -> (LweSecretKeyOwned<Scalar>, LweSecretKeyOwned<Scalar>)
where
Scalar: RandomGenerable<UniformBinary> + Numeric,
Gen: ByteRandomGenerator,
{
let mut large_lwe_secret_key =
LweSecretKeyOwned::new_empty_key(Scalar::ZERO, lwe_dimension_large);
generate_binary_lwe_secret_key(&mut large_lwe_secret_key, generator);
let mut small_lwe_secret_key = LweSecretKey::new_empty_key(Scalar::ZERO, lwe_dimension_small);
small_lwe_secret_key
.as_mut()
.iter_mut()
.zip(large_lwe_secret_key.as_ref().iter())
.for_each(|(dst, &src)| *dst = src);
(large_lwe_secret_key, small_lwe_secret_key)
}
pub fn allocate_and_generate_new_shared_lwe_secret_key_from_lwe_secret_key<Scalar, InCont>(
in_large_lwe_key: &LweSecretKey<InCont>,
shared_lwe_dimension: SharedLweSecretKeyCommonCoefCount,
) -> LweSecretKeyOwned<Scalar>
where
Scalar: RandomGenerable<UniformBinary> + Numeric,
InCont: Container<Element = Scalar>,
{
assert!(
shared_lwe_dimension.0 <= in_large_lwe_key.lwe_dimension().0,
"shared_lwe_dimension ({shared_lwe_dimension:?}) \
must be smaller than the total in_large_lwe_key length ({:?}).",
in_large_lwe_key.lwe_dimension()
);
let lwe_dimension_small = LweDimension(shared_lwe_dimension.0);
LweSecretKey::from_container(in_large_lwe_key.as_ref()[..lwe_dimension_small.0].to_vec())
}

View File

@@ -0,0 +1,150 @@
//! Module containing primitives pertaining to [`LWE ciphertext
//! keyswitch`](`LweKeyswitchKey#lwe-keyswitch`).
use crate::core_crypto::algorithms::slice_algorithms::*;
use crate::core_crypto::commons::math::decomposition::SignedDecomposer;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
// From ct_1 to ct_0 with n_1 > n_0 and shared randomness
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for LweShrinkingKeyswitchKey creation
/// let large_lwe_dimension = LweDimension(10);
/// let lwe_modular_std_dev = StandardDev(0.0000000000000000000000000000000007069849454709433);
/// let small_lwe_dimension = LweDimension(5);
/// let decomp_base_log = DecompositionBaseLog(30);
/// let decomp_level_count = DecompositionLevelCount(1);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut encryption_generator =
/// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// let shared_randomness_dimension = LweDimension(large_lwe_dimension.0 - small_lwe_dimension.0);
/// // Create the LweSecretKey
/// let large_lwe_secret_key =
/// allocate_and_generate_new_binary_lwe_secret_key(large_lwe_dimension, &mut secret_generator);
/// let mut small_lwe_secret_key = LweSecretKey::new_empty_key(0_u64, small_lwe_dimension);
/// small_lwe_secret_key
/// .as_mut()
/// .iter_mut()
/// .zip(large_lwe_secret_key.as_ref().iter())
/// .for_each(|(dst, &src)| *dst = src);
///
/// let ksk = allocate_and_generate_new_lwe_shrinking_keyswitch_key(
/// &large_lwe_secret_key,
/// &small_lwe_secret_key,
/// shared_randomness_dimension,
/// decomp_base_log,
/// decomp_level_count,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
/// // Create the plaintext
/// let msg = 3u64;
/// let plaintext = Plaintext(msg << 60);
///
/// // Create a new LweCiphertext
/// let input_lwe = allocate_and_encrypt_new_lwe_ciphertext(
/// &large_lwe_secret_key,
/// plaintext,
/// lwe_modular_std_dev,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
/// let mut output_lwe = LweCiphertext::new(
/// 0,
/// small_lwe_secret_key.lwe_dimension().to_lwe_size(),
/// ciphertext_modulus,
/// );
///
/// shrinking_keyswitch_lwe_ciphertext(&ksk, &input_lwe, &mut output_lwe);
///
/// let decrypted_plaintext = decrypt_lwe_ciphertext(&small_lwe_secret_key, &output_lwe);
///
/// // Round and remove encoding
/// // First create a decomposer working on the high 4 bits corresponding to our encoding.
/// let decomposer = SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
///
/// let rounded = decomposer.closest_representable(decrypted_plaintext.0);
///
/// // Remove the encoding
/// let cleartext = rounded >> 60;
///
/// // Check we recovered the original message
/// assert_eq!(cleartext, msg);
/// ```
pub fn shrinking_keyswitch_lwe_ciphertext<Scalar, KSKCont, InputCont, OutputCont>(
lwe_shrinking_keyswitch_key: &LweShrinkingKeyswitchKey<KSKCont>,
input_lwe_ciphertext: &LweCiphertext<InputCont>,
output_lwe_ciphertext: &mut LweCiphertext<OutputCont>,
) where
Scalar: UnsignedInteger,
KSKCont: Container<Element = Scalar>,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
{
assert_eq!(
input_lwe_ciphertext.lwe_size().to_lwe_dimension(),
LweDimension(
output_lwe_ciphertext.lwe_size().to_lwe_dimension().0
+ lwe_shrinking_keyswitch_key
.unshared_randomness_lwe_dimension()
.0
)
);
// Clear the output ciphertext, as it will get updated gradually
output_lwe_ciphertext.as_mut().fill(Scalar::ZERO);
// Copy the input body to the output ciphertext
*output_lwe_ciphertext.get_mut_body().data = *input_lwe_ciphertext.get_body().data;
let shared_randomness_lwe_dimension =
lwe_shrinking_keyswitch_key.shared_randomness_lwe_dimension();
let input_lwe_ciphertext_mask = input_lwe_ciphertext.get_mask();
let (input_shared_mask_slice, input_unshared_mask_slice) = input_lwe_ciphertext_mask
.as_ref()
.split_at(shared_randomness_lwe_dimension.0);
// Copy the shared elements of the mask
output_lwe_ciphertext.get_mut_mask().as_mut()[0..shared_randomness_lwe_dimension.0]
.copy_from_slice(input_shared_mask_slice);
// We instantiate a decomposer
let decomposer = SignedDecomposer::new(
lwe_shrinking_keyswitch_key.decomposition_base_log(),
lwe_shrinking_keyswitch_key.decomposition_level_count(),
);
for (keyswitch_key_block, &input_mask_element) in lwe_shrinking_keyswitch_key
.as_lwe_keyswitch_key()
.iter()
.zip(input_unshared_mask_slice.iter())
{
let decomposition_iter = decomposer.decompose(input_mask_element);
// Loop over the levels
for (level_key_ciphertext, decomposed) in keyswitch_key_block.iter().zip(decomposition_iter)
{
slice_wrapping_sub_scalar_mul_assign(
output_lwe_ciphertext.as_mut(),
level_key_ciphertext.as_ref(),
decomposed.value(),
);
}
}
}

View File

@@ -0,0 +1,100 @@
//! Module containing primitives pertaining to [`LWE shrinking keyswitch keys
//! generation`](`LweKeyswitchKey#key-switching-key`) and [`seeded LWE shrinking keyswitch keys
//! generation`](`SeededLweKeyswitchKey`).
//TODO: Seeded part not done
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::dispersion::DispersionParameter;
use crate::core_crypto::commons::generators::EncryptionRandomGenerator;
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
pub fn generate_lwe_shrinking_keyswitch_key<Scalar, InputKeyCont, OutputKeyCont, KSKeyCont, Gen>(
input_lwe_sk: &LweSecretKey<InputKeyCont>,
output_lwe_sk: &LweSecretKey<OutputKeyCont>,
lwe_keyswitch_key: &mut LweShrinkingKeyswitchKey<KSKeyCont>,
noise_parameters: impl DispersionParameter,
generator: &mut EncryptionRandomGenerator<Gen>,
) where
Scalar: UnsignedTorus,
InputKeyCont: Container<Element = Scalar>,
OutputKeyCont: Container<Element = Scalar>,
KSKeyCont: ContainerMut<Element = Scalar> + std::fmt::Debug,
Gen: ByteRandomGenerator,
{
let unshared_randomness_lwe_dimension = lwe_keyswitch_key.unshared_randomness_lwe_dimension();
assert!(
lwe_keyswitch_key.output_key_lwe_dimension() == output_lwe_sk.lwe_dimension(),
"The destination LweKeyswitchKey output LweDimension is not equal \
to the output LweSecretKey LweDimension. Destination: {:?}, output: {:?}",
lwe_keyswitch_key.output_key_lwe_dimension(),
output_lwe_sk.lwe_dimension()
);
assert_eq!(
input_lwe_sk.lwe_dimension().0,
output_lwe_sk.lwe_dimension().0 + unshared_randomness_lwe_dimension.0
);
let shared_randomness_lwe_dimension = lwe_keyswitch_key.shared_randomness_lwe_dimension();
let shrunk_input_lwe_secret_key =
LweSecretKey::from_container(&input_lwe_sk.as_ref()[shared_randomness_lwe_dimension.0..]);
generate_lwe_keyswitch_key(
&shrunk_input_lwe_secret_key,
output_lwe_sk,
&mut lwe_keyswitch_key.as_mut_lwe_keyswitch_key(),
noise_parameters,
generator,
)
}
/// Allocate a new [`LWE keyswitch key`](`LweKeyswitchKey`) and fill it with an actual keyswitching
/// key constructed from an input and an output key [`LWE secret key`](`LweSecretKey`).
///
/// See [`shrinking_keyswitch_lwe_ciphertext`] for usage.
#[allow(clippy::too_many_arguments)]
pub fn allocate_and_generate_new_lwe_shrinking_keyswitch_key<
Scalar,
InputKeyCont,
OutputKeyCont,
Gen,
>(
input_lwe_sk: &LweSecretKey<InputKeyCont>,
output_lwe_sk: &LweSecretKey<OutputKeyCont>,
shared_randomness_coef_count: SharedLweSecretKeyCommonCoefCount,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
noise_parameters: impl DispersionParameter,
ciphertext_modulus: CiphertextModulus<Scalar>,
generator: &mut EncryptionRandomGenerator<Gen>,
) -> LweShrinkingKeyswitchKeyOwned<Scalar>
where
Scalar: UnsignedTorus,
InputKeyCont: Container<Element = Scalar>,
OutputKeyCont: Container<Element = Scalar>,
Gen: ByteRandomGenerator,
{
let mut new_lwe_keyswitch_key = LweShrinkingKeyswitchKeyOwned::new(
Scalar::ZERO,
decomp_base_log,
decomp_level_count,
input_lwe_sk.lwe_dimension(),
output_lwe_sk.lwe_dimension(),
shared_randomness_coef_count,
ciphertext_modulus,
);
generate_lwe_shrinking_keyswitch_key(
input_lwe_sk,
output_lwe_sk,
&mut new_lwe_keyswitch_key,
noise_parameters,
generator,
);
new_lwe_keyswitch_key
}

View File

@@ -6,6 +6,8 @@ pub mod ggsw_conversion;
pub mod ggsw_encryption;
pub mod glwe_encryption;
pub mod glwe_linear_algebra;
pub mod glwe_partial_sample_extraction;
pub mod glwe_partial_secret_key_generation;
pub mod glwe_sample_extraction;
pub mod glwe_secret_key_generation;
pub mod lwe_bootstrap_key_conversion;
@@ -13,6 +15,8 @@ pub mod lwe_bootstrap_key_generation;
pub mod lwe_compact_ciphertext_list_expansion;
pub mod lwe_compact_public_key_generation;
pub mod lwe_encryption;
pub mod lwe_fast_keyswitch;
pub mod lwe_fast_keyswitch_key_generation;
pub mod lwe_keyswitch;
pub mod lwe_keyswitch_key_generation;
pub mod lwe_linear_algebra;
@@ -21,14 +25,19 @@ pub mod lwe_multi_bit_bootstrap_key_generation;
pub mod lwe_multi_bit_programmable_bootstrapping;
pub mod lwe_packing_keyswitch;
pub mod lwe_packing_keyswitch_key_generation;
pub mod lwe_partial_secret_key_generation;
pub mod lwe_private_functional_packing_keyswitch;
pub mod lwe_private_functional_packing_keyswitch_key_generation;
pub mod lwe_programmable_bootstrapping;
pub mod lwe_public_key_generation;
pub mod lwe_secret_key_generation;
pub mod lwe_shrinking_keyswitch;
pub mod lwe_shrinking_keyswitch_key_generation;
pub mod lwe_wopbs;
pub mod misc;
pub mod polynomial_algorithms;
pub mod pseudo_ggsw_conversion;
pub mod pseudo_ggsw_encryption;
pub mod seeded_ggsw_ciphertext_decompression;
pub mod seeded_ggsw_ciphertext_list_decompression;
pub mod seeded_glwe_ciphertext_decompression;
@@ -52,6 +61,8 @@ pub use ggsw_conversion::*;
pub use ggsw_encryption::*;
pub use glwe_encryption::*;
pub use glwe_linear_algebra::*;
pub use glwe_partial_sample_extraction::*;
pub use glwe_partial_secret_key_generation::*;
pub use glwe_sample_extraction::*;
pub use glwe_secret_key_generation::*;
pub use lwe_bootstrap_key_conversion::*;
@@ -59,6 +70,9 @@ pub use lwe_bootstrap_key_generation::*;
pub use lwe_compact_ciphertext_list_expansion::*;
pub use lwe_compact_public_key_generation::*;
pub use lwe_encryption::*;
pub use lwe_fast_keyswitch::*;
// TODO: the key gen was simplified and the code was left in a half done state
// pub use lwe_fast_keyswitch_key_generation::*;
pub use lwe_keyswitch::*;
pub use lwe_keyswitch_key_generation::*;
pub use lwe_linear_algebra::*;
@@ -67,12 +81,17 @@ pub use lwe_multi_bit_bootstrap_key_generation::*;
pub use lwe_multi_bit_programmable_bootstrapping::*;
pub use lwe_packing_keyswitch::*;
pub use lwe_packing_keyswitch_key_generation::*;
pub use lwe_partial_secret_key_generation::*;
pub use lwe_private_functional_packing_keyswitch::*;
pub use lwe_private_functional_packing_keyswitch_key_generation::*;
pub use lwe_programmable_bootstrapping::*;
pub use lwe_public_key_generation::*;
pub use lwe_secret_key_generation::*;
pub use lwe_shrinking_keyswitch::*;
pub use lwe_shrinking_keyswitch_key_generation::*;
pub use lwe_wopbs::*;
pub use pseudo_ggsw_conversion::*;
pub use pseudo_ggsw_encryption::*;
pub use seeded_ggsw_ciphertext_decompression::*;
pub use seeded_ggsw_ciphertext_list_decompression::*;
pub use seeded_glwe_ciphertext_decompression::*;

View File

@@ -0,0 +1,74 @@
//! Module containing primitives pertaining to the conversion of
//! [`standard GGSW ciphertexts`](`GgswCiphertext`) to various representations/numerical domains
//! like the Fourier domain.
use crate::core_crypto::commons::computation_buffers::ComputationBuffers;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
use crate::core_crypto::fft_impl::fft64::crypto::pseudo_ggsw::{
fill_with_forward_fourier_scratch, PseudoFourierGgswCiphertext,
};
use crate::core_crypto::fft_impl::fft64::math::fft::{Fft, FftView};
use concrete_fft::c64;
use dyn_stack::{PodStack, SizeOverflow, StackReq};
/// Convert a [`GGSW ciphertext`](`GgswCiphertext`) with standard coefficients to the Fourier
/// domain.
///
/// If you want to manage the computation memory manually you can use
/// [`convert_standard_pseudo_ggsw_ciphertext_to_fourier_mem_optimized`].
pub fn convert_standard_pseudo_ggsw_ciphertext_to_fourier<Scalar, InputCont, OutputCont>(
input_ggsw: &PseudoGgswCiphertext<InputCont>,
output_ggsw: &mut PseudoFourierGgswCiphertext<OutputCont>,
) where
Scalar: UnsignedTorus,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = c64>,
{
let fft = Fft::new(output_ggsw.polynomial_size());
let fft = fft.as_view();
let mut buffers = ComputationBuffers::new();
buffers.resize(
convert_standard_pseudo_ggsw_ciphertext_to_fourier_mem_optimized_requirement(fft)
.unwrap()
.unaligned_bytes_required(),
);
convert_standard_pseudo_ggsw_ciphertext_to_fourier_mem_optimized(
input_ggsw,
output_ggsw,
fft,
buffers.stack(),
);
}
/// Memory optimized version of [`convert_standard_pseudo_ggsw_ciphertext_to_fourier`].
///
/// See TODO for usage.
pub fn convert_standard_pseudo_ggsw_ciphertext_to_fourier_mem_optimized<
Scalar,
InputCont,
OutputCont,
>(
input_ggsw: &PseudoGgswCiphertext<InputCont>,
output_ggsw: &mut PseudoFourierGgswCiphertext<OutputCont>,
fft: FftView<'_>,
stack: PodStack<'_>,
) where
Scalar: UnsignedTorus,
InputCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = c64>,
{
output_ggsw
.as_mut_view()
.fill_with_forward_fourier(input_ggsw, fft, stack);
}
/// Return the required memory for
/// [`convert_standard_pseudo_ggsw_ciphertext_to_fourier_mem_optimized`].
pub fn convert_standard_pseudo_ggsw_ciphertext_to_fourier_mem_optimized_requirement(
fft: FftView<'_>,
) -> Result<StackReq, SizeOverflow> {
fill_with_forward_fourier_scratch(fft)
}

View File

@@ -0,0 +1,191 @@
use crate::core_crypto::algorithms::slice_algorithms::*;
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::dispersion::DispersionParameter;
use crate::core_crypto::commons::generators::EncryptionRandomGenerator;
use crate::core_crypto::commons::math::decomposition::DecompositionLevel;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
/// Encrypt a plaintext in a [`GGSW ciphertext`](`GgswCiphertext`) in the constant coefficient.
///
/// See the [`GGSW ciphertext formal definition`](`GgswCiphertext#ggsw-encryption`) for the
/// definition of the encryption algorithm.
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for GgswCiphertext creation
/// let glwe_size_out = GlweSize(2);
/// let polynomial_size = PolynomialSize(4);
/// let glwe_size_in = GlweSize(3);
/// let polynomial_size_to_encrypt = PolynomialSize(4);
/// let decomp_base_log = DecompositionBaseLog(8);
/// let decomp_level_count = DecompositionLevelCount(2);
/// let glwe_modular_std_dev =
/// StandardDev(0.00000000000000000000000000000000000000029403601535432533);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut encryption_generator =
/// EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
/// let mut secret_generator =
/// SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
///
/// // Create the GlweSecretKey
/// let glwe_secret_key = allocate_and_generate_new_binary_glwe_secret_key(
/// glwe_size_out.to_glwe_dimension(),
/// polynomial_size,
/// &mut secret_generator,
/// );
/// // Create the GlweSecretKey
/// let glwe_secret_key_to_encrypt = allocate_and_generate_new_binary_glwe_secret_key(
/// glwe_size_in.to_glwe_dimension(),
/// polynomial_size_to_encrypt,
/// &mut secret_generator,
/// );
///
/// // Create the plaintext
/// let plaintext = Plaintext(3u64);
///
/// // Create a new GgswCiphertext
/// let mut ggsw = PseudoGgswCiphertext::new(
/// 0u64,
/// glwe_size_in,
/// glwe_size_out,
/// polynomial_size,
/// decomp_base_log,
/// decomp_level_count,
/// ciphertext_modulus,
/// );
///
/// encrypt_pseudo_ggsw_ciphertext(
/// &glwe_secret_key,
/// &glwe_secret_key_to_encrypt,
/// &mut ggsw,
/// glwe_modular_std_dev,
/// &mut encryption_generator,
/// );
/// println!("GGSW = {:?}", ggsw);
/// let decrypted = decrypt_constant_ggsw_ciphertext(&glwe_secret_key, &ggsw);
/// assert_eq!(decrypted, plaintext);
/// ```
pub fn encrypt_pseudo_ggsw_ciphertext<Scalar, KeyCont, OutputCont, Gen>(
glwe_secret_key_out: &GlweSecretKey<KeyCont>,
glwe_secret_key_in: &GlweSecretKey<KeyCont>,
output: &mut PseudoGgswCiphertext<OutputCont>,
noise_parameters: impl DispersionParameter,
generator: &mut EncryptionRandomGenerator<Gen>,
) where
Scalar: UnsignedTorus,
KeyCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert!(
output.polynomial_size() == glwe_secret_key_out.polynomial_size(),
"Mismatch between polynomial sizes of output ciphertexts and input secret key. \
Got {:?} in output, and {:?} in secret key.",
output.polynomial_size(),
glwe_secret_key_out.polynomial_size()
);
// Generators used to have same sequential and parallel key generation
let gen_iter = generator
.fork_pseudo_ggsw_to_ggsw_levels::<Scalar>(
output.decomposition_level_count(),
output.glwe_size_in(),
output.glwe_size_out(),
output.polynomial_size(),
)
.expect("Failed to split generator into ggsw levels");
let output_glwe_size_in = output.glwe_size_in();
let ouptut_glwe_size_out = output.glwe_size_out();
let output_polynomial_size = output.polynomial_size();
let decomp_base_log = output.decomposition_base_log();
let ciphertext_modulus = output.ciphertext_modulus();
for (level_index, (mut level_matrix, mut generator)) in
output.iter_mut().zip(gen_iter).enumerate()
{
let decomp_level = DecompositionLevel(level_index + 1);
// We scale the factor down from the native torus to whatever our torus is, the
// encryption process will scale it back up
let encoded = Scalar::ONE;
let factor = encoded
.wrapping_neg()
.wrapping_mul(Scalar::ONE << (Scalar::BITS - (decomp_base_log.0 * decomp_level.0)))
.wrapping_div(ciphertext_modulus.get_power_of_two_scaling_to_native_torus());
// We iterate over the rows of the level matrix, the last row needs special treatment
let gen_iter = generator
.fork_pseudo_ggsw_level_to_glwe::<Scalar>(
output_glwe_size_in,
ouptut_glwe_size_out,
output_polynomial_size,
)
.expect("Failed to split generator into glwe");
for ((row_index, mut row_as_glwe), mut generator) in level_matrix
.as_mut_glwe_list()
.iter_mut()
.enumerate()
.zip(gen_iter)
{
encrypt_pseudo_ggsw_level_matrix_row(
glwe_secret_key_out,
glwe_secret_key_in,
row_index,
factor,
&mut row_as_glwe,
noise_parameters,
&mut generator,
);
}
}
}
fn encrypt_pseudo_ggsw_level_matrix_row<Scalar, KeyCont, OutputCont, Gen>(
glwe_secret_key: &GlweSecretKey<KeyCont>,
glwe_secret_key_to_encrypt: &GlweSecretKey<KeyCont>,
row_index: usize,
factor: Scalar,
row_as_glwe: &mut GlweCiphertext<OutputCont>,
noise_parameters: impl DispersionParameter,
generator: &mut EncryptionRandomGenerator<Gen>,
) where
Scalar: UnsignedTorus,
KeyCont: Container<Element = Scalar>,
OutputCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
let sk_poly_list = glwe_secret_key_to_encrypt.as_polynomial_list();
let sk_poly = sk_poly_list.get(row_index);
// let poly_size = row_as_glwe.polynomial_size();
// let ct_mod = row_as_glwe.ciphertext_modulus();
// let glwe_size = row_as_glwe.glwe_size();
// Copy the key polynomial to the output body, to avoid allocating a temporary buffer
let mut body = row_as_glwe.get_mut_body();
body.as_mut().copy_from_slice(sk_poly.as_ref());
slice_wrapping_scalar_mul_assign(body.as_mut(), factor);
//println!("[ggsw_encryption_row] KEY VALUE = {:?}", body.as_ref());
encrypt_glwe_ciphertext_assign(glwe_secret_key, row_as_glwe, noise_parameters, generator);
// let mut ct = GlweCiphertext::new(Scalar::ZERO, glwe_size, poly_size,
// ct_mod);
// trivially_encrypt_glwe_ciphertext(&mut ct,
// &PlaintextList::from_container(body.as_polynomial ().into_container()));
//TODO: to remove for tests
// let mut pt = PlaintextList::new(Scalar::ZERO, PlaintextCount(glwe_secret_key
// .polynomial_size().0 * glwe_secret_key.glwe_dimension().0));
// decrypt_glwe_ciphertext(glwe_secret_key, &row_as_glwe, &mut pt);
// println!("[ggsw_encryption_row] DECRYTPTED GLWE ROW = {:?}", pt);
}

View File

@@ -0,0 +1,617 @@
use super::*;
use crate::core_crypto::algorithms::test::MessageModulusLog;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct FastKSParam<Scalar: UnsignedInteger> {
pub log_precision: MessageModulusLog,
/// This value is unused but allows to identify the parameter optimization that was done
pub _log_mu: usize,
pub glwe_dimension: GlweDimension,
pub polynomial_size: PolynomialSize,
// phi_bsk = number of coefficients != 0 in a given key for partial keys
// this is the general phi_bsk for a GLWE secret key, which saturates to 2443 according to the
// paper
pub bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount,
pub bsk_glwe_std_dev: StandardDev,
pub lwe_dimension: LweDimension,
pub ks1_lwe_modular_std_dev: StandardDev,
pub pbs_level: DecompositionLevelCount,
pub pbs_base_log: DecompositionBaseLog,
pub ks1_level: DecompositionLevelCount,
pub ks1_base_log: DecompositionBaseLog,
pub ks1_polynomial_size: PolynomialSize,
pub ks_in_glwe_dimension: GlweDimension,
pub phi_in: usize,
pub ks_out_glwe_dimension: GlweDimension,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
#[allow(dead_code)]
pub const PRECISION_1_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(1),
_log_mu: 1,
glwe_dimension: GlweDimension(5),
polynomial_size: PolynomialSize(256),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(1280),
bsk_glwe_std_dev: StandardDev(4.436066365074074e-10),
lwe_dimension: LweDimension(534),
ks1_lwe_modular_std_dev: StandardDev(0.0004192214045106218),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(15),
ks1_level: DecompositionLevelCount(9),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(256),
ks_in_glwe_dimension: GlweDimension(3),
phi_in: 746,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_2_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(2),
_log_mu: 2,
glwe_dimension: GlweDimension(6),
polynomial_size: PolynomialSize(256),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(1536),
bsk_glwe_std_dev: StandardDev(3.953518398797519e-12),
lwe_dimension: LweDimension(590),
ks1_lwe_modular_std_dev: StandardDev(0.0001492480807729575),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(18),
ks1_level: DecompositionLevelCount(11),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(1024),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 946,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_3_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(3),
_log_mu: 3,
glwe_dimension: GlweDimension(3),
polynomial_size: PolynomialSize(512),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(1536),
bsk_glwe_std_dev: StandardDev(3.953518398797519e-12),
lwe_dimension: LweDimension(686),
ks1_lwe_modular_std_dev: StandardDev(2.5308824029981747e-5),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(18),
ks1_level: DecompositionLevelCount(13),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(1024),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 850,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_4_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(4),
_log_mu: 4,
glwe_dimension: GlweDimension(2),
polynomial_size: PolynomialSize(1024),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2048),
bsk_glwe_std_dev: StandardDev(3.162026630747649e-16),
lwe_dimension: LweDimension(682),
ks1_lwe_modular_std_dev: StandardDev(2.7313997525878062e-5),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(23),
ks1_level: DecompositionLevelCount(14),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(512),
ks_in_glwe_dimension: GlweDimension(3), // Original value
// ks_in_glwe_dimension: GlweDimension(4), // Test non square pseudo GGSWs
phi_in: 1366,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_5_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(5),
_log_mu: 5,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2048),
bsk_glwe_std_dev: StandardDev(3.162026630747649e-16),
lwe_dimension: LweDimension(766),
ks1_lwe_modular_std_dev: StandardDev(5.822216831056818e-06),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(23),
ks1_level: DecompositionLevelCount(15),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(512),
ks_in_glwe_dimension: GlweDimension(3),
phi_in: 1282,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_6_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(6),
_log_mu: 6,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(4096),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_std_dev: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(774),
ks1_lwe_modular_std_dev: StandardDev(4.998754134591537e-06),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(14),
ks1_level: DecompositionLevelCount(15),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(2048),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 1669,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_7_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(7),
_log_mu: 7,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(8192),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_std_dev: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(818),
ks1_lwe_modular_std_dev: StandardDev(2.2215530137414073e-06),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(14),
ks1_level: DecompositionLevelCount(16),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(2048),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 1625,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_8_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(8),
_log_mu: 8,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(16384),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_std_dev: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(854),
ks1_lwe_modular_std_dev: StandardDev(1.1499479557902908e-06),
pbs_level: DecompositionLevelCount(3),
pbs_base_log: DecompositionBaseLog(11),
ks1_level: DecompositionLevelCount(18),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(2048),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 1589,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_9_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(9),
_log_mu: 9,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(32768),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_std_dev: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(902),
ks1_lwe_modular_std_dev: StandardDev(4.7354340335704556e-07),
pbs_level: DecompositionLevelCount(4),
pbs_base_log: DecompositionBaseLog(8),
ks1_level: DecompositionLevelCount(18),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(2048),
ks_in_glwe_dimension: GlweDimension(1),
phi_in: 1541,
ks_out_glwe_dimension: GlweDimension(1),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_10_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(10),
_log_mu: 10,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(65536),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_std_dev: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(938),
ks1_lwe_modular_std_dev: StandardDev(2.434282602565751e-07),
pbs_level: DecompositionLevelCount(6),
pbs_base_log: DecompositionBaseLog(6),
ks1_level: DecompositionLevelCount(20),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(512),
ks_in_glwe_dimension: GlweDimension(3),
phi_in: 1505,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
#[allow(dead_code)]
pub const PRECISION_11_FAST_KS: FastKSParam<u64> = FastKSParam {
log_precision: MessageModulusLog(11),
_log_mu: 11,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(131072),
bsk_partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_std_dev: StandardDev(2.168404344971009e-19),
lwe_dimension: LweDimension(1018),
ks1_lwe_modular_std_dev: StandardDev(5.56131000242714e-08),
pbs_level: DecompositionLevelCount(13),
pbs_base_log: DecompositionBaseLog(3),
ks1_level: DecompositionLevelCount(22),
ks1_base_log: DecompositionBaseLog(1),
ks1_polynomial_size: PolynomialSize(512),
ks_in_glwe_dimension: GlweDimension(3),
phi_in: 1425,
ks_out_glwe_dimension: GlweDimension(3),
ciphertext_modulus: CiphertextModulus::new_native(),
};
fn lwe_encrypt_fast_ks_decrypt_custom_mod<
Scalar: UnsignedTorus + CastFrom<usize> + CastInto<usize> + Sync + Send,
>(
params: FastKSParam<Scalar>,
) {
let log_precision = params.log_precision;
let glwe_dimension = params.glwe_dimension;
let polynomial_size = params.polynomial_size;
let bsk_partial_glwe_secret_key_fill = params.bsk_partial_glwe_secret_key_fill;
let bsk_glwe_std_dev = params.bsk_glwe_std_dev;
let lwe_dimension = params.lwe_dimension;
let ks1_lwe_modular_std_dev = params.ks1_lwe_modular_std_dev;
let pbs_level = params.pbs_level;
let pbs_base_log = params.pbs_base_log;
let ks1_level = params.ks1_level;
let ks1_base_log = params.ks1_base_log;
let ks1_polynomial_size = params.ks1_polynomial_size;
let ks_in_glwe_dimension = params.ks_in_glwe_dimension;
let phi_in = params.phi_in;
let ks_out_glwe_dimension = params.ks_out_glwe_dimension;
let ciphertext_modulus = params.ciphertext_modulus;
let msg_modulus = Scalar::ONE.shl(log_precision.0);
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let mut msg = msg_modulus;
let delta: Scalar = encoding_with_padding / msg_modulus;
let f = |x| x;
// Shared and partial key generations
let glwe_secret_key = allocate_and_generate_new_binary_partial_glwe_secret_key(
glwe_dimension,
polynomial_size,
bsk_partial_glwe_secret_key_fill,
&mut rsc.secret_random_generator,
);
let large_lwe_secret_key = glwe_secret_key.clone().into_lwe_secret_key();
// Shared small lwe secret key sharing lwe_dimension coeffs with the glwe_secret_key
let mut small_lwe_secret_key = LweSecretKey::new_empty_key(Scalar::ZERO, lwe_dimension);
small_lwe_secret_key.as_mut()[0..lwe_dimension.0]
.copy_from_slice(&glwe_secret_key.as_ref()[0..lwe_dimension.0]);
// Corresponds to the small LWE sk with only lwe_dimension coeffs that are non zero and
// shared with the glwe_secret_key
let small_glwe_secret_key =
allocate_and_generate_new_shared_glwe_secret_key_from_glwe_secret_key(
&glwe_secret_key,
ks_out_glwe_dimension,
lwe_dimension.0,
ks1_polynomial_size,
);
let mut large_glwe_secret_key_unshared =
GlweSecretKey::new_empty_key(Scalar::ZERO, ks_in_glwe_dimension, ks1_polynomial_size);
// Get the unshared coefficients in the large glwe secret key which is used for the input of
// the KS
large_glwe_secret_key_unshared.as_mut()
[0..bsk_partial_glwe_secret_key_fill.0 - lwe_dimension.0]
.copy_from_slice(
&glwe_secret_key.as_ref()[lwe_dimension.0..bsk_partial_glwe_secret_key_fill.0],
);
//Memory stuff
let fft_ks = Fft::new(ks1_polynomial_size);
let fft_ks = fft_ks.as_view();
let mut ks_buffers = ComputationBuffers::new();
let mut pbs_buffers = ComputationBuffers::new();
let fft_pbs = Fft::new(polynomial_size);
let fft_pbs = fft_pbs.as_view();
let ks_buffer_size_req =
add_external_product_fast_keyswitch_assign_mem_optimized_requirement::<Scalar>(
small_glwe_secret_key.glwe_dimension(),
ks1_polynomial_size,
fft_ks,
)
.unwrap()
.try_unaligned_bytes_required()
.unwrap();
let ks_buffer_size_req = ks_buffer_size_req.max(
convert_standard_ggsw_ciphertext_to_fourier_mem_optimized_requirement(fft_ks)
.unwrap()
.unaligned_bytes_required(),
);
let pbs_buffer_size_req = programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement::<
Scalar,
>(glwe_dimension.to_glwe_size(), polynomial_size, fft_pbs)
.unwrap()
.try_unaligned_bytes_required()
.unwrap();
ks_buffers.resize(ks_buffer_size_req);
pbs_buffers.resize(pbs_buffer_size_req);
let mut bsk = LweBootstrapKey::new(
Scalar::ZERO,
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_log,
pbs_level,
lwe_dimension,
ciphertext_modulus,
);
par_generate_lwe_bootstrap_key(
&small_lwe_secret_key,
&glwe_secret_key,
&mut bsk,
bsk_glwe_std_dev,
&mut rsc.encryption_random_generator,
);
let mut fbsk = FourierLweBootstrapKey::new(
small_lwe_secret_key.lwe_dimension(),
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_log,
pbs_level,
);
convert_standard_lwe_bootstrap_key_to_fourier_mem_optimized(
&bsk,
&mut fbsk,
fft_pbs,
pbs_buffers.stack(),
);
drop(bsk);
let accumulator = generate_accumulator(
polynomial_size,
glwe_dimension.to_glwe_size(),
msg_modulus.cast_into(),
ciphertext_modulus,
delta,
f,
);
let mut ggsw = PseudoGgswCiphertext::new(
Scalar::ZERO,
ks_in_glwe_dimension.to_glwe_size(),
ks_out_glwe_dimension.to_glwe_size(),
ks1_polynomial_size,
ks1_base_log,
ks1_level,
ciphertext_modulus,
);
encrypt_pseudo_ggsw_ciphertext(
&small_glwe_secret_key,
&large_glwe_secret_key_unshared,
&mut ggsw,
ks1_lwe_modular_std_dev,
&mut rsc.encryption_random_generator,
);
//To Fourier
let mut fourier_ggsw = PseudoFourierGgswCiphertext::new(
ks_in_glwe_dimension.to_glwe_size(),
ks_out_glwe_dimension.to_glwe_size(),
ks1_polynomial_size,
ks1_base_log,
ks1_level,
);
convert_standard_pseudo_ggsw_ciphertext_to_fourier_mem_optimized(
&ggsw,
&mut fourier_ggsw,
fft_ks,
ks_buffers.stack(),
);
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
println!("msg={msg}");
for test_iteration in 0..NB_TESTS {
println!("test_iteration={test_iteration}");
let plaintext = Plaintext(msg * delta);
let mut large_lwe_ciphertext_ap_input = allocate_and_encrypt_new_lwe_ciphertext(
&large_lwe_secret_key,
plaintext,
bsk_glwe_std_dev,
ciphertext_modulus,
&mut rsc.encryption_random_generator,
);
let mut large_lwe_shared_part = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let mut large_lwe_unshared_part_requires_keyswitch = LweCiphertext::new(
Scalar::ZERO,
LweSize(bsk_partial_glwe_secret_key_fill.0 - lwe_dimension.0 + 1),
ciphertext_modulus,
);
let mut large_glwe_unshared_requires_keyswitch = GlweCiphertext::new(
Scalar::ZERO,
ks_in_glwe_dimension.to_glwe_size(),
ks1_polynomial_size,
ciphertext_modulus,
);
let mut glwe_unshared_after_ks = GlweCiphertext::new(
Scalar::ZERO,
ks_out_glwe_dimension.to_glwe_size(),
ks1_polynomial_size,
ciphertext_modulus,
);
let mut small_lwe_unshared_after_ks = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
// Check the AP works for several iterations
for ap_iteration in 0..NB_TESTS {
println!("ap_iteration={ap_iteration}");
let decrypted =
decrypt_lwe_ciphertext(&large_lwe_secret_key, &large_lwe_ciphertext_ap_input);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(decoded, f(msg));
// Copy the shared part in the smaller ciphertext
large_lwe_shared_part
.get_mut_mask()
.as_mut()
.copy_from_slice(
&large_lwe_ciphertext_ap_input.get_mask().as_ref()[..lwe_dimension.0],
);
*large_lwe_shared_part.get_mut_body().data =
*large_lwe_ciphertext_ap_input.get_body().data;
// Copy the unshared part to be keyswitched
large_lwe_unshared_part_requires_keyswitch
.get_mut_mask()
.as_mut()
.copy_from_slice(
&large_lwe_ciphertext_ap_input.get_mask().as_ref()
[lwe_dimension.0..bsk_partial_glwe_secret_key_fill.0],
);
partial_convert_lwe_ciphertext_into_constant_glwe_ciphertext(
&large_lwe_unshared_part_requires_keyswitch,
&mut large_glwe_unshared_requires_keyswitch,
phi_in,
);
glwe_unshared_after_ks.as_mut().fill(Scalar::ZERO);
add_external_product_fast_keyswitch_assign_mem_optimized(
&mut glwe_unshared_after_ks,
&fourier_ggsw,
&large_glwe_unshared_requires_keyswitch,
fft_ks,
ks_buffers.stack(),
);
partial_extract_lwe_sample_from_glwe_ciphertext(
&glwe_unshared_after_ks,
&mut small_lwe_unshared_after_ks,
MonomialDegree(0),
lwe_dimension.0,
);
// Sum with initial ct's shared part
small_lwe_unshared_after_ks
.get_mut_mask()
.as_mut()
.iter_mut()
.zip(large_lwe_shared_part.as_ref()[0..lwe_dimension.0].iter())
.for_each(|(dst, &src)| *dst = dst.wrapping_add(src));
// Sum the body
let body = small_lwe_unshared_after_ks.get_mut_body().data;
*body = (*body).wrapping_add(*large_lwe_shared_part.get_body().data);
let decrypted =
decrypt_lwe_ciphertext(&small_lwe_secret_key, &small_lwe_unshared_after_ks);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(decoded, f(msg));
programmable_bootstrap_lwe_ciphertext_mem_optimized(
&small_lwe_unshared_after_ks,
&mut large_lwe_ciphertext_ap_input,
&accumulator,
&fbsk,
fft_pbs,
pbs_buffers.stack(),
);
let decrypted =
decrypt_lwe_ciphertext(&large_lwe_secret_key, &large_lwe_ciphertext_ap_input);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(decoded, f(msg));
////////////
// Remove the input message to get 0
lwe_ciphertext_plaintext_sub_assign(&mut large_lwe_ciphertext_ap_input, plaintext);
let decrypted =
decrypt_lwe_ciphertext(&large_lwe_secret_key, &large_lwe_ciphertext_ap_input);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(Scalar::ZERO, decoded, "Error after sub");
////////////
// multiply by a cleartext, will still output 0 but is the biggest noise growth
// possible
lwe_ciphertext_cleartext_mul_assign(
&mut large_lwe_ciphertext_ap_input,
Cleartext(msg_modulus),
);
let decrypted =
decrypt_lwe_ciphertext(&large_lwe_secret_key, &large_lwe_ciphertext_ap_input);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(Scalar::ZERO, decoded, "Error after mul");
////////////
// Add back the input plaintext to still be doing an overall identity computation
lwe_ciphertext_plaintext_add_assign(&mut large_lwe_ciphertext_ap_input, plaintext);
let decrypted =
decrypt_lwe_ciphertext(&large_lwe_secret_key, &large_lwe_ciphertext_ap_input);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(msg, decoded, "Error after add");
////////////
}
}
}
}
create_parametrized_test!(lwe_encrypt_fast_ks_decrypt_custom_mod {
PRECISION_1_FAST_KS,
PRECISION_2_FAST_KS,
PRECISION_3_FAST_KS,
PRECISION_4_FAST_KS,
PRECISION_5_FAST_KS,
PRECISION_6_FAST_KS
// PRECISION_7_FAST_KS,
// PRECISION_8_FAST_KS
// PRECISION_9_FAST_KS,
// PRECISION_10_FAST_KS,
// PRECISION_11_FAST_KS
});

View File

@@ -144,7 +144,7 @@ pub const TEST_PARAMS_4_BITS_NATIVE_U128: TestParams<u128> = TestParams {
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(4),
message_modulus_log: MessageModulusLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
@@ -163,7 +163,7 @@ pub const TEST_PARAMS_3_BITS_127_U128: TestParams<u128> = TestParams {
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(3),
message_modulus_log: MessageModulusLog(3),
ciphertext_modulus: CiphertextModulus::new(1 << 127),
};

View File

@@ -0,0 +1,495 @@
use super::*;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct StairKSParam<Scalar: UnsignedInteger> {
pub log_precision: MessageModulusLog,
/// This value is unused but allows to identify the parameter optimization that was done
pub _log_mu: usize,
pub glwe_dimension: GlweDimension,
pub polynomial_size: PolynomialSize,
// phi = number of coefficients != 0 in a given key for partial keys
// this is the general phi for a GLWE secret key, which saturates to 2443 according to the
// paper
// phi == lwe_dimension + ks1_unshared_coeff_count + ks2_unshared_coeff_count
pub partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount,
pub bsk_glwe_modular_std_dev: StandardDev,
pub lwe_dimension: LweDimension,
pub ks1_lwe_modular_std_dev: StandardDev,
pub ks2_lwe_modular_std_dev: StandardDev,
pub pbs_level: DecompositionLevelCount,
pub pbs_base_log: DecompositionBaseLog,
pub ks1_level: DecompositionLevelCount,
pub ks1_base_log: DecompositionBaseLog,
pub ks2_level: DecompositionLevelCount,
pub ks2_base_log: DecompositionBaseLog,
/// The number of elements being dropped when going from the large key to the inter key
pub ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount,
/// The number of elements being dropped when going from the inter key to the small key
pub ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
pub const PRECISION_1_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(1),
_log_mu: 1,
glwe_dimension: GlweDimension(5),
polynomial_size: PolynomialSize(256),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(1280),
bsk_glwe_modular_std_dev: StandardDev(4.43606636507407e-10),
lwe_dimension: LweDimension(532),
ks1_lwe_modular_std_dev: StandardDev(4.32160905950851e-6),
ks2_lwe_modular_std_dev: StandardDev(0.000434005215413364),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(15),
ks1_level: DecompositionLevelCount(1),
ks1_base_log: DecompositionBaseLog(9),
ks2_level: DecompositionLevelCount(4),
ks2_base_log: DecompositionBaseLog(2),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(498),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(250),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_2_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(2),
_log_mu: 2,
glwe_dimension: GlweDimension(6),
polynomial_size: PolynomialSize(256),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(1536),
bsk_glwe_modular_std_dev: StandardDev(3.953518398797519e-12),
lwe_dimension: LweDimension(576),
ks1_lwe_modular_std_dev: StandardDev(5.290839538897724e-07),
ks2_lwe_modular_std_dev: StandardDev(0.00019288117965414483),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(18),
ks1_level: DecompositionLevelCount(1),
ks1_base_log: DecompositionBaseLog(10),
ks2_level: DecompositionLevelCount(5),
ks2_base_log: DecompositionBaseLog(2),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(640),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(320),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_3_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(3),
_log_mu: 3,
glwe_dimension: GlweDimension(3),
polynomial_size: PolynomialSize(512),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(1536),
bsk_glwe_modular_std_dev: StandardDev(3.95351839879752e-12),
lwe_dimension: LweDimension(648),
ks1_lwe_modular_std_dev: StandardDev(2.17874395902014e-7),
ks2_lwe_modular_std_dev: StandardDev(5.132424409507535e-05),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(18),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(7),
ks2_level: DecompositionLevelCount(6),
ks2_base_log: DecompositionBaseLog(2),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(592),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(296),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_4_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(4),
_log_mu: 4,
glwe_dimension: GlweDimension(2),
polynomial_size: PolynomialSize(1024),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2048),
bsk_glwe_modular_std_dev: StandardDev(3.16202663074765e-16),
lwe_dimension: LweDimension(664),
ks1_lwe_modular_std_dev: StandardDev(7.60713313301797e-9),
ks2_lwe_modular_std_dev: StandardDev(0.0000380960250519291),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(22),
ks1_level: DecompositionLevelCount(1),
ks1_base_log: DecompositionBaseLog(13),
ks2_level: DecompositionLevelCount(6),
ks2_base_log: DecompositionBaseLog(2),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(922),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(462),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_5_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(5),
_log_mu: 5,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2048),
bsk_glwe_modular_std_dev: StandardDev(3.16202663074765e-16),
lwe_dimension: LweDimension(732),
ks1_lwe_modular_std_dev: StandardDev(3.31119701700870e-9),
ks2_lwe_modular_std_dev: StandardDev(0.0000108646407745138),
pbs_level: DecompositionLevelCount(1),
pbs_base_log: DecompositionBaseLog(23),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(9),
ks2_level: DecompositionLevelCount(7),
ks2_base_log: DecompositionBaseLog(2),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(877),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(439),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_6_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(6),
_log_mu: 6,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(4096),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_modular_std_dev: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(748),
ks1_lwe_modular_std_dev: StandardDev(2.42717974083759e-10),
ks2_lwe_modular_std_dev: StandardDev(8.12050004923523e-6),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(14),
ks1_level: DecompositionLevelCount(1),
ks1_base_log: DecompositionBaseLog(16),
ks2_level: DecompositionLevelCount(8),
ks2_base_log: DecompositionBaseLog(2),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(1130),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(565),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_7_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(7),
_log_mu: 7,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(8192),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_modular_std_dev: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(776),
ks1_lwe_modular_std_dev: StandardDev(1.70442007475721e-10),
ks2_lwe_modular_std_dev: StandardDev(4.82847821796524e-6),
pbs_level: DecompositionLevelCount(2),
pbs_base_log: DecompositionBaseLog(15),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(10),
ks2_level: DecompositionLevelCount(16),
ks2_base_log: DecompositionBaseLog(1),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(1111),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(556),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_8_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(8),
_log_mu: 8,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(16384),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_modular_std_dev: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(816),
ks1_lwe_modular_std_dev: StandardDev(1.03474906781522e-10),
ks2_lwe_modular_std_dev: StandardDev(2.31589295271883e-6),
pbs_level: DecompositionLevelCount(3),
pbs_base_log: DecompositionBaseLog(11),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(9),
ks2_level: DecompositionLevelCount(17),
ks2_base_log: DecompositionBaseLog(1),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(1084),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(543),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_9_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(9),
_log_mu: 9,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(32768),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_modular_std_dev: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(860),
ks1_lwe_modular_std_dev: StandardDev(6.06794935209399e-11),
ks2_lwe_modular_std_dev: StandardDev(1.02923225069468e-6),
pbs_level: DecompositionLevelCount(4),
pbs_base_log: DecompositionBaseLog(8),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(10),
ks2_level: DecompositionLevelCount(18),
ks2_base_log: DecompositionBaseLog(1),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(1055),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(528),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_10_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(10),
_log_mu: 10,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(65536),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_modular_std_dev: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(904),
ks1_lwe_modular_std_dev: StandardDev(3.55835153515238e-11),
ks2_lwe_modular_std_dev: StandardDev(4.77994271508188e-14),
pbs_level: DecompositionLevelCount(6),
pbs_base_log: DecompositionBaseLog(6),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(11),
ks2_level: DecompositionLevelCount(19),
ks2_base_log: DecompositionBaseLog(1),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(1026),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(513),
ciphertext_modulus: CiphertextModulus::new_native(),
};
pub const PRECISION_11_STAIR: StairKSParam<u64> = StairKSParam {
log_precision: MessageModulusLog(11),
_log_mu: 11,
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(131072),
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2443),
bsk_glwe_modular_std_dev: StandardDev(2.16840434497101e-19),
lwe_dimension: LweDimension(984),
ks1_lwe_modular_std_dev: StandardDev(1.31149203314392e-11),
ks2_lwe_modular_std_dev: StandardDev(1.04499545254235e-7),
pbs_level: DecompositionLevelCount(12),
pbs_base_log: DecompositionBaseLog(3),
ks1_level: DecompositionLevelCount(2),
ks1_base_log: DecompositionBaseLog(11),
ks2_level: DecompositionLevelCount(21),
ks2_base_log: DecompositionBaseLog(1),
ks1_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(972),
ks2_unshared_coeff_count: SharedLweSecretKeyDifferingCoefCount(487),
ciphertext_modulus: CiphertextModulus::new_native(),
};
fn lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod<
Scalar: UnsignedTorus + Send + Sync + CastFrom<usize> + CastInto<usize>,
>(
params: StairKSParam<Scalar>,
) {
let log_precision = params.log_precision;
let glwe_dimension = params.glwe_dimension;
let polynomial_size = params.polynomial_size;
let partial_glwe_secret_key_fill = params.partial_glwe_secret_key_fill;
let std_dev_bsk = params.bsk_glwe_modular_std_dev;
let lwe_dimension = params.lwe_dimension;
let ks1_lwe_modular_std_dev = params.ks1_lwe_modular_std_dev;
let ks2_lwe_modular_std_dev = params.ks2_lwe_modular_std_dev;
let pbs_level = params.pbs_level;
let pbs_base_mpg = params.pbs_base_log;
let ks1_level = params.ks1_level;
let ks1_base_log = params.ks1_base_log;
let ks2_level = params.ks2_level;
let ks2_base_log = params.ks2_base_log;
let ks1_unshared_coeff_count = params.ks1_unshared_coeff_count;
let ks2_unshared_coeff_count = params.ks2_unshared_coeff_count;
let ciphertext_modulus = params.ciphertext_modulus;
let msg_modulus = Scalar::ONE.shl(log_precision.0);
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let mut rsc = TestResources::new();
const NB_TESTS: usize = 10;
let mut msg = msg_modulus;
let delta: Scalar = encoding_with_padding / msg_modulus;
let large_lwe_dimension = LweDimension(glwe_dimension.0 * polynomial_size.0);
// Our algorithm is set up so that this equality holds, but in practice it could be more generic
// if we had an intermediate LweDimension being defined
assert_eq!(
partial_glwe_secret_key_fill.0,
lwe_dimension.0 + ks1_unshared_coeff_count.0 + ks2_unshared_coeff_count.0
);
while msg != Scalar::ZERO {
msg = msg.wrapping_sub(Scalar::ONE);
let glwe_secret_key = allocate_and_generate_new_binary_partial_glwe_secret_key(
glwe_dimension,
polynomial_size,
partial_glwe_secret_key_fill,
&mut rsc.secret_random_generator,
);
let large_lwe_secret_key = glwe_secret_key.clone().into_lwe_secret_key();
let large_lwe_dimension_without_zeros = LweDimension(partial_glwe_secret_key_fill.0);
let inter_shared_coef_count =
large_lwe_dimension_without_zeros.shared_coef_count_from(ks1_unshared_coeff_count);
let inter_lwe_secret_key =
allocate_and_generate_new_shared_lwe_secret_key_from_lwe_secret_key(
&large_lwe_secret_key,
inter_shared_coef_count,
);
let small_shared_coef_count =
inter_shared_coef_count.shared_coef_count_from(ks2_unshared_coeff_count);
let small_lwe_secret_key =
allocate_and_generate_new_shared_lwe_secret_key_from_lwe_secret_key(
&inter_lwe_secret_key,
small_shared_coef_count,
);
//Shrinking KSK generations
let ksk_large_to_inter = allocate_and_generate_new_lwe_shrinking_keyswitch_key(
&large_lwe_secret_key,
&inter_lwe_secret_key,
inter_shared_coef_count,
ks1_base_log,
ks1_level,
ks1_lwe_modular_std_dev,
ciphertext_modulus,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(
&ksk_large_to_inter,
ciphertext_modulus
));
let ksk_inter_to_small = allocate_and_generate_new_lwe_shrinking_keyswitch_key(
&inter_lwe_secret_key,
&small_lwe_secret_key,
small_shared_coef_count,
ks2_base_log,
ks2_level,
ks2_lwe_modular_std_dev,
ciphertext_modulus,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(
&ksk_inter_to_small,
ciphertext_modulus
));
//PBS PART
let mut bsk = LweBootstrapKey::new(
Scalar::ZERO,
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_mpg,
pbs_level,
lwe_dimension,
ciphertext_modulus,
);
par_generate_lwe_bootstrap_key(
&small_lwe_secret_key,
&glwe_secret_key,
&mut bsk,
std_dev_bsk,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&*bsk, ciphertext_modulus));
let mut fbsk = FourierLweBootstrapKey::new(
small_lwe_secret_key.lwe_dimension(),
glwe_dimension.to_glwe_size(),
polynomial_size,
pbs_base_mpg,
pbs_level,
);
convert_standard_lwe_bootstrap_key_to_fourier(&bsk, &mut fbsk);
drop(bsk);
let accumulator = generate_accumulator(
polynomial_size,
glwe_dimension.to_glwe_size(),
msg_modulus.cast_into(),
ciphertext_modulus,
delta,
|x| x,
);
for _ in 0..NB_TESTS {
let plaintext = Plaintext(msg * delta);
//Encryption
let mut large_lwe = LweCiphertext::new(
Scalar::ZERO,
large_lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
encrypt_lwe_ciphertext(
&large_lwe_secret_key,
&mut large_lwe,
plaintext,
std_dev_bsk,
&mut rsc.encryption_random_generator,
);
assert!(check_content_respects_mod(&large_lwe, ciphertext_modulus));
//Shrinking KS
let mut inter_lwe = LweCiphertext::new(
Scalar::ZERO,
inter_lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
let mut small_lwe = LweCiphertext::new(
Scalar::ZERO,
lwe_dimension.to_lwe_size(),
ciphertext_modulus,
);
let mut out_pbs_ct = LweCiphertext::new(
Scalar::ZERO,
large_lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
// Check the AP works for several iterations
for _ in 0..NB_TESTS {
shrinking_keyswitch_lwe_ciphertext(&ksk_large_to_inter, &large_lwe, &mut inter_lwe);
assert!(check_content_respects_mod(&inter_lwe, ciphertext_modulus));
let dec_inter = decrypt_lwe_ciphertext(&inter_lwe_secret_key, &inter_lwe);
let decoded = round_decode(dec_inter.0, delta) % msg_modulus;
assert_eq!(decoded, msg, "Err after first shrinking KS");
shrinking_keyswitch_lwe_ciphertext(&ksk_inter_to_small, &inter_lwe, &mut small_lwe);
assert!(check_content_respects_mod(&small_lwe, ciphertext_modulus));
let dec_small = decrypt_lwe_ciphertext(&small_lwe_secret_key, &small_lwe);
let decoded = round_decode(dec_small.0, delta) % msg_modulus;
assert_eq!(decoded, msg, "Err after second shrinking KS");
programmable_bootstrap_lwe_ciphertext(
&small_lwe,
&mut out_pbs_ct,
&accumulator,
&fbsk,
);
assert!(check_content_respects_mod(&out_pbs_ct, ciphertext_modulus));
let dec_large = decrypt_lwe_ciphertext(&large_lwe_secret_key, &out_pbs_ct);
let decoded = round_decode(dec_large.0, delta) % msg_modulus;
assert_eq!(decoded, msg, "Err after PBS");
}
}
}
}
// #[test]
// fn lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod_params_stair_4() {
// lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod(PRECISION_4_STAIR)
// }
create_parametrized_test!(lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod{
PRECISION_1_STAIR,
PRECISION_2_STAIR,
PRECISION_3_STAIR,
PRECISION_4_STAIR,
PRECISION_5_STAIR,
PRECISION_6_STAIR
// PRECISION_7_STAIR,
// PRECISION_8_STAIR
// PRECISION_9_STAIR,
// PRECISION_10_STAIR,
// PRECISION_11_STAIR
});

View File

@@ -9,6 +9,7 @@ mod glwe_sample_extraction;
mod lwe_bootstrap_key_generation;
mod lwe_compact_public_key_generation;
mod lwe_encryption;
mod lwe_fast_keyswitch;
mod lwe_keyswitch;
mod lwe_keyswitch_key_generation;
mod lwe_linear_algebra;
@@ -17,7 +18,8 @@ mod lwe_multi_bit_programmable_bootstrapping;
mod lwe_packing_keyswitch;
mod lwe_packing_keyswitch_key_generation;
mod lwe_private_functional_packing_keyswitch;
mod lwe_programmable_bootstrapping;
pub(crate) mod lwe_programmable_bootstrapping;
mod lwe_stair_keyswitch;
mod noise_distribution;
pub struct TestResources {
@@ -26,6 +28,9 @@ pub struct TestResources {
pub secret_random_generator: SecretRandomGenerator<ActivatedRandomGenerator>,
}
#[derive(Debug, PartialEq, Eq, Copy, Clone, serde::Serialize, serde::Deserialize)]
pub struct MessageModulusLog(pub usize);
impl TestResources {
pub fn new() -> Self {
let mut seeder = new_seeder();
@@ -56,7 +61,7 @@ pub struct TestParams<Scalar: UnsignedTorus> {
pub pfks_modular_std_dev: StandardDev,
pub cbs_level: DecompositionLevelCount,
pub cbs_base_log: DecompositionBaseLog,
pub message_modulus_log: CiphertextModulusLog,
pub message_modulus_log: MessageModulusLog,
pub ciphertext_modulus: CiphertextModulus<Scalar>,
}
@@ -76,7 +81,7 @@ pub const TEST_PARAMS_4_BITS_NATIVE_U64: TestParams<u64> = TestParams {
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(4),
message_modulus_log: MessageModulusLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
@@ -95,7 +100,7 @@ pub const TEST_PARAMS_3_BITS_63_U64: TestParams<u64> = TestParams {
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(3),
message_modulus_log: MessageModulusLog(3),
ciphertext_modulus: CiphertextModulus::new(1 << 63),
};
@@ -114,7 +119,7 @@ pub const DUMMY_NATIVE_U32: TestParams<u32> = TestParams {
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(4),
message_modulus_log: MessageModulusLog(4),
ciphertext_modulus: CiphertextModulus::new_native(),
};
@@ -133,7 +138,7 @@ pub const DUMMY_31_U32: TestParams<u32> = TestParams {
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus_log: CiphertextModulusLog(3),
message_modulus_log: MessageModulusLog(3),
ciphertext_modulus: CiphertextModulus::new(1 << 31),
};

View File

@@ -125,6 +125,31 @@ impl<G: ByteRandomGenerator> MaskRandomGenerator<G> {
self.try_fork(glwe_size.0, mask_bytes)
}
// Forks the generator, when splitting a ggsw into level matrices.
pub(crate) fn fork_pseudo_ggsw_to_ggsw_levels<T: UnsignedInteger>(
&mut self,
level: DecompositionLevelCount,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
) -> Result<impl Iterator<Item = Self>, ForkError> {
let mask_bytes =
mask_bytes_per_pseudo_ggsw_level::<T>(glwe_size_in, glwe_size_out, polynomial_size);
self.try_fork(level.0, mask_bytes)
}
// Forks the generator, when splitting a pseudo ggsw level matrix to glwe.
pub(crate) fn fork_pseudo_ggsw_level_to_glwe<T: UnsignedInteger>(
&mut self,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
) -> Result<impl Iterator<Item = Self>, ForkError> {
let mask_bytes =
mask_bytes_per_glwe::<T>(glwe_size_out.to_glwe_dimension(), polynomial_size);
self.try_fork(glwe_size_in.to_glwe_dimension().0, mask_bytes)
}
// Forks the generator, when splitting a ggsw into level matrices.
pub(crate) fn fork_gsw_to_gsw_levels<T: UnsignedInteger>(
&mut self,
@@ -392,6 +417,15 @@ fn mask_bytes_per_ggsw<T: UnsignedInteger>(
level.0 * mask_bytes_per_ggsw_level::<T>(glwe_size, poly_size)
}
fn mask_bytes_per_pseudo_ggsw_level<T: UnsignedInteger>(
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
poly_size: PolynomialSize,
) -> usize {
glwe_size_in.to_glwe_dimension().0
* mask_bytes_per_glwe::<T>(glwe_size_out.to_glwe_dimension(), poly_size)
}
fn mask_bytes_per_pfpksk_chunk<T: UnsignedInteger>(
level: DecompositionLevelCount,
glwe_size: GlweSize,

View File

@@ -149,6 +149,44 @@ impl<G: ByteRandomGenerator> EncryptionRandomGenerator<G> {
self.map_to_encryption_generator(mask_iter, noise_iter)
}
// Forks the generator, when splitting a ggsw into level matrices.
pub(crate) fn fork_pseudo_ggsw_to_ggsw_levels<T: UnsignedInteger>(
&mut self,
level: DecompositionLevelCount,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
) -> Result<impl Iterator<Item = Self>, ForkError> {
let mask_iter = self.mask.fork_pseudo_ggsw_to_ggsw_levels::<T>(
level,
glwe_size_in,
glwe_size_out,
polynomial_size,
)?;
let noise_iter =
self.noise
.fork_pseudo_ggsw_to_ggsw_levels(level, glwe_size_in, polynomial_size)?;
self.map_to_encryption_generator(mask_iter, noise_iter)
}
// Forks the generator, when splitting a pseudo ggsw level matrix to glwe.
pub(crate) fn fork_pseudo_ggsw_level_to_glwe<T: UnsignedInteger>(
&mut self,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
) -> Result<impl Iterator<Item = Self>, ForkError> {
let mask_iter = self.mask.fork_pseudo_ggsw_level_to_glwe::<T>(
glwe_size_in,
glwe_size_out,
polynomial_size,
)?;
let noise_iter = self
.noise
.fork_pseudo_ggsw_level_to_glwe(glwe_size_in, polynomial_size)?;
self.map_to_encryption_generator(mask_iter, noise_iter)
}
// Forks the generator, when splitting a ggsw into level matrices.
pub(crate) fn fork_gsw_to_gsw_levels<T: UnsignedInteger>(
&mut self,

View File

@@ -211,6 +211,27 @@ impl<G: ByteRandomGenerator> NoiseRandomGenerator<G> {
self.try_fork(glwe_size.0, noise_bytes)
}
// Forks the generator, when splitting a ggsw into level matrices.
pub(crate) fn fork_pseudo_ggsw_to_ggsw_levels(
&mut self,
level: DecompositionLevelCount,
glwe_size_in: GlweSize,
polynomial_size: PolynomialSize,
) -> Result<impl Iterator<Item = Self>, ForkError> {
let noise_bytes = noise_bytes_per_ggsw_level(GlweSize(glwe_size_in.0 - 1), polynomial_size);
self.try_fork(level.0, noise_bytes)
}
// Forks the generator, when splitting a pseudo ggsw level matrix to glwe.
pub(crate) fn fork_pseudo_ggsw_level_to_glwe(
&mut self,
glwe_size_in: GlweSize,
polynomial_size: PolynomialSize,
) -> Result<impl Iterator<Item = Self>, ForkError> {
let noise_bytes = noise_bytes_per_glwe(polynomial_size);
self.try_fork(glwe_size_in.to_glwe_dimension().0, noise_bytes)
}
// Forks the generator, when splitting a ggsw into level matrices.
pub(crate) fn fork_gsw_to_gsw_levels(
&mut self,

View File

@@ -73,6 +73,32 @@ impl LweDimension {
pub fn to_lwe_size(&self) -> LweSize {
LweSize(self.0 + 1)
}
#[track_caller]
pub fn shared_coef_count_from(
&self,
unshared_coef_count: SharedLweSecretKeyDifferingCoefCount,
) -> SharedLweSecretKeyCommonCoefCount {
assert!(
unshared_coef_count.0 <= self.0,
"unshared_coef_count {unshared_coef_count:?} must be smaller than self {:?}",
*self
);
SharedLweSecretKeyCommonCoefCount(self.0 - unshared_coef_count.0)
}
#[track_caller]
pub fn unshared_coef_count_from(
&self,
shared_coef_count: SharedLweSecretKeyCommonCoefCount,
) -> SharedLweSecretKeyDifferingCoefCount {
assert!(
shared_coef_count.0 <= self.0,
"shared_coef_count {shared_coef_count:?} must be smaller than self {:?}",
*self
);
SharedLweSecretKeyDifferingCoefCount(self.0 - shared_coef_count.0)
}
}
/// The number of LWE encryptions of 0 in an LWE public key.
@@ -265,3 +291,34 @@ pub enum PBSOrder {
/// key realm.
BootstrapKeyswitch = 1,
}
/// The number of non zero elements in a partial GLWE secret key
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
pub struct PartialGlweSecretKeyRandomCoefCount(pub usize);
/// The number of zero elements completing a partial GLWE secret key
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
pub struct PartialGlweSecretKeyZeroCoefCount(pub usize);
/// The number of shared elements between two LWE secret keys
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
pub struct SharedLweSecretKeyCommonCoefCount(pub usize);
impl SharedLweSecretKeyCommonCoefCount {
#[track_caller]
pub fn shared_coef_count_from(
&self,
unshared_coef_count: SharedLweSecretKeyDifferingCoefCount,
) -> Self {
assert!(
unshared_coef_count.0 <= self.0,
"unshared_lwe_dimension {unshared_coef_count:?} must be smaller than self {:?}",
*self
);
Self(self.0 - unshared_coef_count.0)
}
}
/// The number of non shared elements between two LWE secret keys
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
pub struct SharedLweSecretKeyDifferingCoefCount(pub usize);

View File

@@ -0,0 +1,266 @@
//! Module containing the definition of the [`LweShrinkingKeyswitchKey`].
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
/// An [`LWE shrinking keyswitch key`](`LweShrinkingKeyswitchKey`) is an [`LWE keyswitch
/// key`](`LweKeyswitchKey`) where the input and output key share a part of their randomness.
///
/// See [`the formal definition of an LWE keyswitch key`](`LweKeyswitchKey#formal-definition`).
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct LweShrinkingKeyswitchKey<C: Container>
where
C::Element: UnsignedInteger,
{
lwe_ksk: LweKeyswitchKey<C>,
input_key_lwe_dimension: LweDimension,
}
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for LweShrinkingKeyswitchKey<C> {
fn as_ref(&self) -> &[T] {
self.lwe_ksk.as_ref()
}
}
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for LweShrinkingKeyswitchKey<C> {
fn as_mut(&mut self) -> &mut [T] {
self.lwe_ksk.as_mut()
}
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> LweShrinkingKeyswitchKey<C> {
/// Create an [`LweShrinkingKeyswitchKey`] from an existing container.
///
/// # Note
///
/// This function only wraps a container in the appropriate type. If you want to generate an LWE
/// shrinking keyswitch key you need to use
/// [`crate::core_crypto::algorithms::generate_lwe_shrinking_keyswitch_key`] using this key as
/// output.
///
/// This docstring exhibits [`LweShrinkingKeyswitchKey`] primitives usage.
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// todo!();
/// ```
pub fn from_container(
container: C,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
input_key_lwe_dimension: LweDimension,
output_lwe_size: LweSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
let lwe_ksk = LweKeyswitchKey::from_container(
container,
decomp_base_log,
decomp_level_count,
output_lwe_size,
ciphertext_modulus,
);
let output_key_lwe_dimension = lwe_ksk.output_key_lwe_dimension();
let unshared_randomness_coef_count =
SharedLweSecretKeyDifferingCoefCount(lwe_ksk.input_key_lwe_dimension().0);
let shared_randomness_coef_count =
input_key_lwe_dimension.shared_coef_count_from(unshared_randomness_coef_count);
assert_eq!(
input_key_lwe_dimension.0,
output_key_lwe_dimension.0 + unshared_randomness_coef_count.0
);
assert!(
output_key_lwe_dimension.0 <= input_key_lwe_dimension.0,
"The output LweDimension ({output_key_lwe_dimension:?}) \
must be smaller than the input LweDimension ({input_key_lwe_dimension:?}) \
for an LweShrinkingKeyswitchKey."
);
assert!(
shared_randomness_coef_count.0 <= output_key_lwe_dimension.0,
"The shared randomness coefficient count ({shared_randomness_coef_count:?}) \
must be smaller than the output LweDimension ({output_key_lwe_dimension:?}) \
for an LweShrinkingKeyswitchKey."
);
Self {
lwe_ksk,
input_key_lwe_dimension,
}
}
pub fn as_lwe_keyswitch_key(&self) -> LweKeyswitchKey<&'_ [Scalar]> {
self.lwe_ksk.as_view()
}
/// Return the [`DecompositionBaseLog`] of the [`LweShrinkingKeyswitchKey`].
///
/// See [`LweShrinkingKeyswitchKey::from_container`] for usage.
pub fn decomposition_base_log(&self) -> DecompositionBaseLog {
self.lwe_ksk.decomposition_base_log()
}
/// Return the [`DecompositionLevelCount`] of the [`LweShrinkingKeyswitchKey`].
///
/// See [`LweShrinkingKeyswitchKey::from_container`] for usage.
pub fn decomposition_level_count(&self) -> DecompositionLevelCount {
self.lwe_ksk.decomposition_level_count()
}
/// Return the input [`LweDimension`] of the [`LweShrinkingKeyswitchKey`].
///
/// See [`LweShrinkingKeyswitchKey::from_container`] for usage.
pub fn input_key_lwe_dimension(&self) -> LweDimension {
self.input_key_lwe_dimension
}
/// Return the output [`LweDimension`] of the [`LweShrinkingKeyswitchKey`].
///
/// See [`LweShrinkingKeyswitchKey::from_container`] for usage.
pub fn output_key_lwe_dimension(&self) -> LweDimension {
self.output_lwe_size().to_lwe_dimension()
}
/// Return the output [`LweSize`] of the [`LweShrinkingKeyswitchKey`].
///
/// See [`LweShrinkingKeyswitchKey::from_container`] for usage.
pub fn output_lwe_size(&self) -> LweSize {
self.lwe_ksk.output_lwe_size()
}
/// Return the unshared [`SharedLweSecretKeyDifferingCoefCount`] of randomness of the input and
/// output [`LweSecretKey`] used to build this [`LweShrinkingKeyswitchKey`].
///
/// See [`LweShrinkingKeyswitchKey::from_container`] for usage.
pub fn unshared_randomness_lwe_dimension(&self) -> SharedLweSecretKeyDifferingCoefCount {
SharedLweSecretKeyDifferingCoefCount(self.lwe_ksk.input_key_lwe_dimension().0)
}
/// Return the shared [`SharedLweSecretKeyCommonCoefCount`] of randomness of the input and
/// output [`LweSecretKey`] used to build this [`LweShrinkingKeyswitchKey`].
///
/// See [`LweShrinkingKeyswitchKey::from_container`] for usage.
pub fn shared_randomness_lwe_dimension(&self) -> SharedLweSecretKeyCommonCoefCount {
self.input_key_lwe_dimension()
.shared_coef_count_from(self.unshared_randomness_lwe_dimension())
}
/// Return the number of elements in an encryption of an input [`LweSecretKey`] element of the
/// current [`LweShrinkingKeyswitchKey`].
pub fn input_key_element_encrypted_size(&self) -> usize {
self.lwe_ksk.input_key_element_encrypted_size()
}
/// Consume the entity and return its underlying container.
///
/// See [`LweShrinkingKeyswitchKey::from_container`] for usage.
pub fn into_container(self) -> C {
self.lwe_ksk.into_container()
}
pub fn ciphertext_modulus(&self) -> CiphertextModulus<Scalar> {
self.lwe_ksk.ciphertext_modulus()
}
/// Return a view of the [`LweShrinkingKeyswitchKey`]. This is useful if an algorithm takes a
/// view by value.
pub fn as_view(&self) -> LweShrinkingKeyswitchKey<&'_ [Scalar]> {
LweShrinkingKeyswitchKey::from_container(
self.as_ref(),
self.decomposition_base_log(),
self.decomposition_level_count(),
self.input_key_lwe_dimension(),
self.output_lwe_size(),
self.ciphertext_modulus(),
)
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> LweShrinkingKeyswitchKey<C> {
pub fn as_mut_lwe_keyswitch_key(&mut self) -> LweKeyswitchKey<&'_ mut [Scalar]> {
self.lwe_ksk.as_mut_view()
}
/// Mutable variant of [`LweShrinkingKeyswitchKey::as_view`].
pub fn as_mut_view(&mut self) -> LweShrinkingKeyswitchKey<&'_ mut [Scalar]> {
let decomposition_base_log = self.decomposition_base_log();
let decomposition_level_count = self.decomposition_level_count();
let input_key_lwe_dimension = self.input_key_lwe_dimension();
let output_lwe_size = self.output_lwe_size();
let ciphertext_modulus = self.ciphertext_modulus();
LweShrinkingKeyswitchKey::from_container(
self.as_mut(),
decomposition_base_log,
decomposition_level_count,
input_key_lwe_dimension,
output_lwe_size,
ciphertext_modulus,
)
}
}
/// An [`LweShrinkingKeyswitchKey`] owning the memory for its own storage.
pub type LweShrinkingKeyswitchKeyOwned<Scalar> = LweShrinkingKeyswitchKey<Vec<Scalar>>;
/// A [`LweShrinkingKeyswitchKey`] immutably borrowing memory for its own storage.
pub type LweShrinkingKeyswitchKeyView<'data, Scalar> = LweShrinkingKeyswitchKey<&'data [Scalar]>;
/// A [`LweShrinkingKeyswitchKey`] mutably borrowing memory for its own storage.
pub type LweShrinkingKeyswitchKeyMutView<'data, Scalar> =
LweShrinkingKeyswitchKey<&'data mut [Scalar]>;
impl<Scalar: UnsignedInteger> LweShrinkingKeyswitchKeyOwned<Scalar> {
/// Allocate memory and create a new owned [`LweShrinkingKeyswitchKey`].
///
/// # Note
///
/// This function allocates a vector of the appropriate size and wraps it in the appropriate
/// type. If you want to generate an LWE shrinking keysiwtch key you need to use
/// [`crate::core_crypto::algorithms::generate_lwe_shrinking_keyswitch_key`] using this key as
/// output.
///
/// See [`LweShrinkingKeyswitchKey::from_container`] for usage.
pub fn new(
fill_with: Scalar,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
input_key_lwe_dimension: LweDimension,
output_key_lwe_dimension: LweDimension,
shared_randomness_coef_count: SharedLweSecretKeyCommonCoefCount,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> Self {
assert!(
output_key_lwe_dimension.0 <= input_key_lwe_dimension.0,
"The output LweDimension ({output_key_lwe_dimension:?}) \
must be smaller than the input LweDimension ({input_key_lwe_dimension:?}) \
for an LweShrinkingKeyswitchKey."
);
assert!(
shared_randomness_coef_count.0 <= output_key_lwe_dimension.0,
"The shared randomness coefficient count ({shared_randomness_coef_count:?}) \
must be smaller than the output LweDimension ({output_key_lwe_dimension:?}) \
for an LweShrinkingKeyswitchKey."
);
let unshared_randomness_coef_count =
input_key_lwe_dimension.unshared_coef_count_from(shared_randomness_coef_count);
assert_eq!(
input_key_lwe_dimension.0,
output_key_lwe_dimension.0 + unshared_randomness_coef_count.0
);
Self {
lwe_ksk: LweKeyswitchKey::new(
fill_with,
decomp_base_log,
decomp_level_count,
LweDimension(unshared_randomness_coef_count.0),
output_key_lwe_dimension,
ciphertext_modulus,
),
input_key_lwe_dimension,
}
}
}

View File

@@ -22,10 +22,12 @@ pub mod lwe_private_functional_packing_keyswitch_key;
pub mod lwe_private_functional_packing_keyswitch_key_list;
pub mod lwe_public_key;
pub mod lwe_secret_key;
pub mod lwe_shrinking_keyswitch_key;
pub mod plaintext;
pub mod plaintext_list;
pub mod polynomial;
pub mod polynomial_list;
pub mod pseudo_ggsw_ciphertext;
pub mod seeded_ggsw_ciphertext;
pub mod seeded_ggsw_ciphertext_list;
pub mod seeded_glwe_ciphertext;
@@ -51,6 +53,10 @@ pub use crate::core_crypto::fft_impl::fft64::crypto::bootstrap::{
pub use crate::core_crypto::fft_impl::fft64::crypto::ggsw::{
FourierGgswCiphertext, FourierGgswCiphertextList, FourierGgswLevelMatrix, FourierGgswLevelRow,
};
pub use crate::core_crypto::fft_impl::fft64::crypto::pseudo_ggsw::{
PseudoFourierGgswCiphertext, PseudoFourierGgswLevelMatrix, PseudoFourierGgswLevelRow,
};
pub use crate::core_crypto::fft_impl::fft64::math::polynomial::FourierPolynomial;
pub use cleartext::*;
pub use ggsw_ciphertext::*;
@@ -71,10 +77,12 @@ pub use lwe_private_functional_packing_keyswitch_key::*;
pub use lwe_private_functional_packing_keyswitch_key_list::*;
pub use lwe_public_key::*;
pub use lwe_secret_key::*;
pub use lwe_shrinking_keyswitch_key::*;
pub use plaintext::*;
pub use plaintext_list::*;
pub use polynomial::*;
pub use polynomial_list::*;
pub use pseudo_ggsw_ciphertext::*;
pub use seeded_ggsw_ciphertext::*;
pub use seeded_ggsw_ciphertext_list::*;
pub use seeded_glwe_ciphertext::*;

View File

@@ -0,0 +1,571 @@
//! Module containing the definition of the PseudoGgswCiphertext.
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct PseudoGgswCiphertext<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
decomp_base_log: DecompositionBaseLog,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<T: UnsignedInteger, C: Container<Element = T>> AsRef<[T]> for PseudoGgswCiphertext<C> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T: UnsignedInteger, C: ContainerMut<Element = T>> AsMut<[T]> for PseudoGgswCiphertext<C> {
fn as_mut(&mut self) -> &mut [T] {
self.data.as_mut()
}
}
/// Return the number of elements in a [`PseudoGgswCiphertext`] given a [`GlweSize`],
/// [`PolynomialSize`] and [`DecompositionLevelCount`].
pub fn pseudo_ggsw_ciphertext_size(
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
decomp_level_count: DecompositionLevelCount,
) -> usize {
decomp_level_count.0
* pseudo_ggsw_level_matrix_size(glwe_size_in, glwe_size_out, polynomial_size)
}
/// Return the number of elements in a [`GgswLevelMatrix`] given a [`GlweSize`] and
/// [`PolynomialSize`].
pub fn pseudo_ggsw_level_matrix_size(
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
) -> usize {
glwe_size_in.to_glwe_dimension().0 * glwe_size_out.0 * polynomial_size.0
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> PseudoGgswCiphertext<C> {
/// Create a [`PseudoGgswCiphertext`] from an existing container.
///
/// # Note
///
/// This function only wraps a container in the appropriate type. If you want to encrypt data
/// you need to use [`crate::core_crypto::algorithms::encrypt_constant_ggsw_ciphertext`] or its
/// parallel counterpart
/// [`crate::core_crypto::algorithms::par_encrypt_constant_ggsw_ciphertext`] using
/// this ciphertext as output.
///
/// This docstring exhibits [`PseudoGgswCiphertext`] primitives usage.
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for PseudoGgswCiphertext creation
/// let glwe_size_in = GlweSize(2);
/// let glwe_size_out = GlweSize(3);
/// let polynomial_size = PolynomialSize(1024);
/// let decomp_base_log = DecompositionBaseLog(8);
/// let decomp_level_count = DecompositionLevelCount(3);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create a new PseudoGgswCiphertext
/// let ggsw = PseudoGgswCiphertext::new(
/// 0u64,
/// glwe_size_in,
/// glwe_size_out,
/// polynomial_size,
/// decomp_base_log,
/// decomp_level_count,
/// ciphertext_modulus,
/// );
///
/// assert_eq!(ggsw.glwe_size_in(), glwe_size_in);
/// assert_eq!(ggsw.glwe_size_out(), glwe_size_out);
/// assert_eq!(ggsw.polynomial_size(), polynomial_size);
/// assert_eq!(ggsw.decomposition_base_log(), decomp_base_log);
/// assert_eq!(ggsw.decomposition_level_count(), decomp_level_count);
/// assert_eq!(ggsw.ciphertext_modulus(), ciphertext_modulus);
/// assert_eq!(
/// ggsw.pseudo_ggsw_level_matrix_size(),
/// pseudo_ggsw_level_matrix_size(glwe_size_in, glwe_size_out, polynomial_size)
/// );
///
/// // Demonstrate how to recover the allocated container
/// let underlying_container: Vec<u64> = ggsw.into_container();
///
/// // Recreate a ciphertext using from_container
/// let ggsw = PseudoGgswCiphertext::from_container(
/// underlying_container,
/// glwe_size_in,
/// glwe_size_out,
/// polynomial_size,
/// decomp_base_log,
/// ciphertext_modulus,
/// );
///
/// assert_eq!(ggsw.glwe_size_in(), glwe_size_in);
/// assert_eq!(ggsw.glwe_size_out(), glwe_size_out);
/// assert_eq!(ggsw.polynomial_size(), polynomial_size);
/// assert_eq!(ggsw.decomposition_base_log(), decomp_base_log);
/// assert_eq!(ggsw.decomposition_level_count(), decomp_level_count);
/// assert_eq!(ggsw.ciphertext_modulus(), ciphertext_modulus);
/// assert_eq!(
/// ggsw.pseudo_ggsw_level_matrix_size(),
/// pseudo_ggsw_level_matrix_size(glwe_size_in, glwe_size_out, polynomial_size)
/// );
/// ```
pub fn from_container(
container: C,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
decomp_base_log: DecompositionBaseLog,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
assert!(
container.container_len() > 0,
"Got an empty container to create a PseudoGgswCiphertext"
);
assert!(
container.container_len()
% (glwe_size_in.to_glwe_dimension().0 * glwe_size_out.0 * polynomial_size.0)
== 0,
"The provided container length is not valid. \
It needs to be dividable by glwe_dimension_in * glwe_size_out * polynomial_size: {}. \
Got container length: {} and glwe_dimension_in: {:?}, glwe_size_out: \
{glwe_size_out:?}\
polynomial_size: {polynomial_size:?}.",
glwe_size_in.0 * glwe_size_out.0 * polynomial_size.0,
container.container_len(),
glwe_size_in.to_glwe_dimension()
);
Self {
data: container,
glwe_size_in,
glwe_size_out,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
}
}
/// Return the [`PolynomialSize`] of the [`PseudoGgswCiphertext`].
///
/// See [`PseudoGgswCiphertext::from_container`] for usage.
pub fn polynomial_size(&self) -> PolynomialSize {
self.polynomial_size
}
/// Return the [`GlweSize`] of the [`PseudoGgswCiphertext`].
///
/// See [`PseudoGgswCiphertext::from_container`] for usage.
pub fn glwe_size_in(&self) -> GlweSize {
self.glwe_size_in
}
/// Return the [`GlweSize`] of the [`PseudoGgswCiphertext`].
///
/// See [`PseudoGgswCiphertext::from_container`] for usage.
pub fn glwe_size_out(&self) -> GlweSize {
self.glwe_size_out
}
/// Return the [`DecompositionBaseLog`] of the [`PseudoGgswCiphertext`].
///
/// See [`PseudoGgswCiphertext::from_container`] for usage.
pub fn decomposition_base_log(&self) -> DecompositionBaseLog {
self.decomp_base_log
}
/// Return the [`DecompositionLevelCount`] of the [`PseudoGgswCiphertext`].
///
/// See [`PseudoGgswCiphertext::from_container`] for usage.
pub fn decomposition_level_count(&self) -> DecompositionLevelCount {
DecompositionLevelCount(self.data.container_len() / self.pseudo_ggsw_level_matrix_size())
}
/// Return the [`CiphertextModulus`] of the [`PseudoGgswCiphertext`].
///
/// See [`PseudoGgswCiphertext::from_container`] for usage.
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
/// Return the size in number of elements of a single [`GgswLevelMatrix`] of the current
/// [`PseudoGgswCiphertext`].
///
/// See [`PseudoGgswCiphertext::from_container`] for usage.
pub fn pseudo_ggsw_level_matrix_size(&self) -> usize {
// GlweSize GlweCiphertext(glwe_size, polynomial_size) per level
pseudo_ggsw_level_matrix_size(self.glwe_size_in, self.glwe_size_out, self.polynomial_size)
}
/// Interpret the [`PseudoGgswCiphertext`] as a [`PolynomialList`].
pub fn as_polynomial_list(&self) -> PolynomialListView<'_, Scalar> {
PolynomialListView::from_container(self.as_ref(), self.polynomial_size)
}
/// Interpret the [`PseudoGgswCiphertext`] as a [`GlweCiphertextList`].
pub fn as_glwe_list(&self) -> GlweCiphertextListView<'_, Scalar> {
GlweCiphertextListView::from_container(
self.as_ref(),
self.glwe_size_out,
self.polynomial_size,
self.ciphertext_modulus,
)
}
/// Return a view of the [`PseudoGgswCiphertext`]. This is useful if an algorithm takes a view
/// by value.
pub fn as_view(&self) -> PseudoGgswCiphertextView<'_, Scalar> {
PseudoGgswCiphertextView::from_container(
self.as_ref(),
self.glwe_size_in(),
self.glwe_size_out(),
self.polynomial_size(),
self.decomposition_base_log(),
self.ciphertext_modulus(),
)
}
/// Consume the entity and return its underlying container.
///
/// See [`PseudoGgswCiphertext::from_container`] for usage.
pub fn into_container(self) -> C {
self.data
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> PseudoGgswCiphertext<C> {
/// Mutable variant of [`PseudoGgswCiphertext::as_polynomial_list`].
pub fn as_mut_polynomial_list(&mut self) -> PolynomialListMutView<'_, Scalar> {
let polynomial_size = self.polynomial_size;
PolynomialListMutView::from_container(self.as_mut(), polynomial_size)
}
/// Mutable variant of [`PseudoGgswCiphertext::as_glwe_list`].
pub fn as_mut_glwe_list(&mut self) -> GlweCiphertextListMutView<'_, Scalar> {
let polynomial_size = self.polynomial_size;
let glwe_size_out = self.glwe_size_out;
let ciphertext_modulus = self.ciphertext_modulus;
GlweCiphertextListMutView::from_container(
self.as_mut(),
glwe_size_out,
polynomial_size,
ciphertext_modulus,
)
}
/// Mutable variant of [`PseudoGgswCiphertext::as_view`].
pub fn as_mut_view(&mut self) -> PseudoGgswCiphertextMutView<'_, Scalar> {
let glwe_size_in = self.glwe_size_in();
let glwe_size_out = self.glwe_size_out();
let polynomial_size = self.polynomial_size();
let decomp_base_log = self.decomposition_base_log();
let ciphertext_modulus = self.ciphertext_modulus;
PseudoGgswCiphertextMutView::from_container(
self.as_mut(),
glwe_size_in,
glwe_size_out,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
)
}
}
/// A [`PseudoGgswCiphertext`] owning the memory for its own storage.
pub type PseudoGgswCiphertextOwned<Scalar> = PseudoGgswCiphertext<Vec<Scalar>>;
/// A [`PseudoGgswCiphertext`] immutably borrowing memory for its own storage.
pub type PseudoGgswCiphertextView<'data, Scalar> = PseudoGgswCiphertext<&'data [Scalar]>;
/// A [`PseudoGgswCiphertext`] immutably borrowing memory for its own storage.
pub type PseudoGgswCiphertextMutView<'data, Scalar> = PseudoGgswCiphertext<&'data mut [Scalar]>;
impl<Scalar: UnsignedInteger> PseudoGgswCiphertextOwned<Scalar> {
/// Allocate memory and create a new owned [`PseudoGgswCiphertext`].
///
/// # Note
///
/// This function allocates a vector of the appropriate size and wraps it in the appropriate
/// type. If you want to encrypt data you need to use
/// [`crate::core_crypto::algorithms::encrypt_constant_ggsw_ciphertext`] or its parallel
/// counterpart [`crate::core_crypto::algorithms::par_encrypt_constant_ggsw_ciphertext`]
/// using this ciphertext as output.
///
/// See [`PseudoGgswCiphertext::from_container`] for usage.
pub fn new(
fill_with: Scalar,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
decomp_base_log: DecompositionBaseLog,
decomp_level_count: DecompositionLevelCount,
ciphertext_modulus: CiphertextModulus<Scalar>,
) -> Self {
Self::from_container(
vec![
fill_with;
pseudo_ggsw_ciphertext_size(
glwe_size_in,
glwe_size_out,
polynomial_size,
decomp_level_count
)
],
glwe_size_in,
glwe_size_out,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
)
}
}
/// Metadata used in the [`CreateFrom`] implementation to create [`PseudoGgswCiphertext`] entities.
#[derive(Clone, Copy)]
pub struct PseudoGgswCiphertextCreationMetadata<Scalar: UnsignedInteger>(
pub GlweSize,
pub GlweSize,
pub PolynomialSize,
pub DecompositionBaseLog,
pub CiphertextModulus<Scalar>,
);
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C>
for PseudoGgswCiphertext<C>
{
type Metadata = PseudoGgswCiphertextCreationMetadata<Scalar>;
#[inline]
fn create_from(from: C, meta: Self::Metadata) -> Self {
let PseudoGgswCiphertextCreationMetadata(
glwe_size_in,
glwe_size_out,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
) = meta;
Self::from_container(
from,
glwe_size_in,
glwe_size_out,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
)
}
}
/// A convenience structure to more easily write iterators on a [`PseudoGgswCiphertext`] levels.
pub struct PseudoGgswLevelMatrix<C: Container>
where
C::Element: UnsignedInteger,
{
data: C,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> PseudoGgswLevelMatrix<C> {
/// Create a [`GgswLevelMatrix`] from an existing container.
///
/// # Note
///
/// This docstring exhibits [`GgswLevelMatrix`] primitives usage.
///
/// ```
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for GgswLevelMatrix creation
/// let glwe_size_in = GlweSize(3);
/// let glwe_size_out = GlweSize(2);
/// let polynomial_size = PolynomialSize(1024);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// let container =
/// vec![0u64; pseudo_ggsw_level_matrix_size(glwe_size_in, glwe_size_out, polynomial_size)];
///
/// // Create a new GgswLevelMatrix
/// let ggsw_level_matrix = PseudoGgswLevelMatrix::from_container(
/// container,
/// glwe_size_in,
/// glwe_size_out,
/// polynomial_size,
/// ciphertext_modulus,
/// );
///
/// assert_eq!(ggsw_level_matrix.glwe_size_in(), glwe_size_in);
/// assert_eq!(ggsw_level_matrix.glwe_size_out(), glwe_size_out);
/// assert_eq!(ggsw_level_matrix.polynomial_size(), polynomial_size);
/// assert_eq!(ggsw_level_matrix.ciphertext_modulus(), ciphertext_modulus);
/// ```
pub fn from_container(
container: C,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
ciphertext_modulus: CiphertextModulus<C::Element>,
) -> Self {
assert!(
container.container_len()
== pseudo_ggsw_level_matrix_size(glwe_size_in, glwe_size_out, polynomial_size),
"The provided container length is not valid. \
Expected length of {} (glwe_size * glwe_size * polynomial_size), got {}",
pseudo_ggsw_level_matrix_size(glwe_size_in, glwe_size_out, polynomial_size),
container.container_len(),
);
Self {
data: container,
glwe_size_in,
glwe_size_out,
polynomial_size,
ciphertext_modulus,
}
}
/// Return the [`GlweSize`] of the [`GgswLevelMatrix`].
///
/// See [`GgswLevelMatrix::from_container`] for usage.
pub fn glwe_size_in(&self) -> GlweSize {
self.glwe_size_in
}
pub fn glwe_size_out(&self) -> GlweSize {
self.glwe_size_out
}
/// Return the [`PolynomialSize`] of the [`GgswLevelMatrix`].
///
/// See [`GgswLevelMatrix::from_container`] for usage.
pub fn polynomial_size(&self) -> PolynomialSize {
self.polynomial_size
}
/// Return the [`CiphertextModulus`] of the [`GgswLevelMatrix`].
///
/// See [`GgswLevelMatrix::from_container`] for usage.
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
self.ciphertext_modulus
}
/// Interpret the [`GgswLevelMatrix`] as a [`GlweCiphertextList`].
pub fn as_glwe_list(&self) -> GlweCiphertextListView<'_, C::Element> {
GlweCiphertextListView::from_container(
self.data.as_ref(),
self.glwe_size_out,
self.polynomial_size,
self.ciphertext_modulus,
)
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> PseudoGgswLevelMatrix<C> {
/// Mutable variant of [`GgswLevelMatrix::as_glwe_list`]
pub fn as_mut_glwe_list(&mut self) -> GlweCiphertextListMutView<'_, C::Element> {
GlweCiphertextListMutView::from_container(
self.data.as_mut(),
self.glwe_size_out,
self.polynomial_size,
self.ciphertext_modulus,
)
}
}
/// Metadata used in the [`CreateFrom`] implementation to create [`GgswLevelMatrix`] entities.
#[derive(Clone, Copy)]
pub struct PseudoGgswLevelMatrixCreationMetadata<Scalar: UnsignedInteger>(
pub GlweSize,
pub GlweSize,
pub PolynomialSize,
pub CiphertextModulus<Scalar>,
);
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> CreateFrom<C>
for PseudoGgswLevelMatrix<C>
{
type Metadata = PseudoGgswLevelMatrixCreationMetadata<C::Element>;
#[inline]
fn create_from(from: C, meta: Self::Metadata) -> Self {
let PseudoGgswLevelMatrixCreationMetadata(
glwe_size_in,
glwe_size_out,
polynomial_size,
ciphertext_modulus,
) = meta;
Self::from_container(
from,
glwe_size_in,
glwe_size_out,
polynomial_size,
ciphertext_modulus,
)
}
}
impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> ContiguousEntityContainer
for PseudoGgswCiphertext<C>
{
type Element = C::Element;
type EntityViewMetadata = PseudoGgswLevelMatrixCreationMetadata<Self::Element>;
type EntityView<'this> = PseudoGgswLevelMatrix<&'this [Self::Element]>
where
Self: 'this;
type SelfViewMetadata = ();
type SelfView<'this> = DummyCreateFrom
where
Self: 'this;
fn get_entity_view_creation_metadata(&self) -> Self::EntityViewMetadata {
PseudoGgswLevelMatrixCreationMetadata(
self.glwe_size_in,
self.glwe_size_out,
self.polynomial_size,
self.ciphertext_modulus,
)
}
fn get_entity_view_pod_size(&self) -> usize {
self.pseudo_ggsw_level_matrix_size()
}
/// Unimplemented for [`PseudoGgswCiphertext`]. At the moment it does not make sense to
/// return "sub" PseudoGgswCiphertext.
fn get_self_view_creation_metadata(&self) -> Self::SelfViewMetadata {
unimplemented!(
"This function is not supported for PseudoGgswCiphertext. \
At the moment it does not make sense to return 'sub' PseudoGgswCiphertext."
)
}
}
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> ContiguousEntityContainerMut
for PseudoGgswCiphertext<C>
{
type EntityMutView<'this> = PseudoGgswLevelMatrix<&'this mut [Self::Element]>
where
Self: 'this;
type SelfMutView<'this> = DummyCreateFrom
where
Self: 'this;
}

View File

@@ -1,6 +1,7 @@
use dyn_stack::{GlobalPodBuffer, PodStack, ReborrowMut};
use super::super::super::{fft128, fft128_u128};
#[allow(unused_imports)]
use super::super::math::fft::{Fft128, Fft128View};
use crate::core_crypto::prelude::*;
use aligned_vec::CACHELINE_ALIGN;

View File

@@ -1,13 +1,14 @@
use crate::core_crypto::commons::utils::izip;
#[allow(unused_imports)]
pub use crate::core_crypto::fft_impl::fft128::math::fft::{Fft128, Fft128View};
use concrete_fft::fft128::f128;
use dyn_stack::PodStack;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use pulp::x86::{f64x4, u64x4, V3};
use pulp::{f64x4, u64x4, x86::V3};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[cfg(feature = "nightly-avx512")]
use pulp::x86::{f64x8, u64x8, V4};
use pulp::{f64x8, u64x8, x86::V4};
#[inline(always)]
pub fn zeroing_shl(x: u64, shift: u64) -> u64 {

View File

@@ -599,7 +599,7 @@ pub fn add_external_product_assign<Scalar, InputGlweCont>(
}
#[cfg_attr(__profiling, inline(never))]
fn collect_next_term<'a, Scalar: UnsignedTorus>(
pub(crate) fn collect_next_term<'a, Scalar: UnsignedTorus>(
decomposition: &mut TensorSignedDecompositionLendingIter<'_, Scalar>,
substack1: &'a mut PodStack,
align: usize,
@@ -671,7 +671,7 @@ pub(crate) fn update_with_fmadd(
let lhs = S::c64s_as_simd(ggsw_poly).0;
for (out, &lhs, &rhs) in izip!(out, lhs, rhs) {
*out = simd.c64s_mul_adde(lhs, rhs, *out);
*out = simd.c64s_mul_add_e(lhs, rhs, *out);
}
}
}
@@ -737,7 +737,7 @@ pub(crate) fn update_with_fmadd_factor(
} else {
for (out, &lhs, &rhs) in izip!(out, lhs, rhs) {
// NOTE: see above
*out = simd.c64s_mul_adde(factor, simd.c64s_mul(lhs, rhs), *out);
*out = simd.c64s_mul_add_e(factor, simd.c64s_mul(lhs, rhs), *out);
}
}
}

View File

@@ -1,5 +1,6 @@
pub mod bootstrap;
pub mod ggsw;
pub mod pseudo_ggsw;
pub mod wop_pbs;
#[cfg(test)]

View File

@@ -0,0 +1,501 @@
use super::super::math::decomposition::TensorSignedDecompositionLendingIter;
use super::super::math::fft::{FftView, FourierPolynomialList};
use super::super::math::polynomial::{FourierPolynomialMutView, FourierPolynomialView};
use crate::core_crypto::commons::math::decomposition::{DecompositionLevel, SignedDecomposer};
use crate::core_crypto::commons::math::torus::UnsignedTorus;
use crate::core_crypto::commons::parameters::{
DecompositionBaseLog, DecompositionLevelCount, GlweSize, PolynomialSize,
};
use crate::core_crypto::commons::traits::{
Container, ContiguousEntityContainer, ContiguousEntityContainerMut, IntoContainerOwned, Split,
};
use crate::core_crypto::commons::utils::izip;
use crate::core_crypto::entities::*;
use crate::core_crypto::fft_impl::fft64::crypto::ggsw::{collect_next_term, update_with_fmadd};
use aligned_vec::{avec, ABox, CACHELINE_ALIGN};
use concrete_fft::c64;
use dyn_stack::{PodStack, ReborrowMut, SizeOverflow, StackReq};
/// A GGSW ciphertext in the Fourier domain.
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(bound(deserialize = "C: IntoContainerOwned"))]
pub struct PseudoFourierGgswCiphertext<C: Container<Element = c64>> {
fourier: FourierPolynomialList<C>,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
decomposition_base_log: DecompositionBaseLog,
decomposition_level_count: DecompositionLevelCount,
}
/// A matrix containing a single level of gadget decomposition, in the Fourier domain.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PseudoFourierGgswLevelMatrix<C: Container<Element = c64>> {
data: C,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
row_count: usize,
decomposition_level: DecompositionLevel,
}
/// A row of a GGSW level matrix, in the Fourier domain.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PseudoFourierGgswLevelRow<C: Container<Element = c64>> {
data: C,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
decomposition_level: DecompositionLevel,
}
pub type PseudoFourierGgswCiphertextView<'a> = PseudoFourierGgswCiphertext<&'a [c64]>;
pub type PseudoFourierGgswCiphertextMutView<'a> = PseudoFourierGgswCiphertext<&'a mut [c64]>;
pub type PseudoFourierGgswLevelMatrixView<'a> = PseudoFourierGgswLevelMatrix<&'a [c64]>;
pub type PseudoFourierGgswLevelMatrixMutView<'a> = PseudoFourierGgswLevelMatrix<&'a mut [c64]>;
pub type PseudoFourierGgswLevelRowView<'a> = PseudoFourierGgswLevelRow<&'a [c64]>;
pub type PseudoFourierGgswLevelRowMutView<'a> = PseudoFourierGgswLevelRow<&'a mut [c64]>;
impl<C: Container<Element = c64>> PseudoFourierGgswCiphertext<C> {
pub fn from_container(
data: C,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
decomposition_base_log: DecompositionBaseLog,
decomposition_level_count: DecompositionLevelCount,
) -> Self {
assert_eq!(
data.container_len(),
polynomial_size.to_fourier_polynomial_size().0
* glwe_size_in.to_glwe_dimension().0
* glwe_size_out.0
* decomposition_level_count.0
);
Self {
fourier: FourierPolynomialList {
data,
polynomial_size,
},
glwe_size_in,
glwe_size_out,
decomposition_base_log,
decomposition_level_count,
}
}
pub fn polynomial_size(&self) -> PolynomialSize {
self.fourier.polynomial_size
}
pub fn glwe_size_in(&self) -> GlweSize {
self.glwe_size_in
}
pub fn glwe_size_out(&self) -> GlweSize {
// Le truc qui foire en k = 1 ? TODO
self.glwe_size_out
}
pub fn decomposition_base_log(&self) -> DecompositionBaseLog {
self.decomposition_base_log
}
pub fn decomposition_level_count(&self) -> DecompositionLevelCount {
self.decomposition_level_count
}
pub fn data(self) -> C {
self.fourier.data
}
pub fn as_view(&self) -> PseudoFourierGgswCiphertextView<'_>
where
C: AsRef<[c64]>,
{
PseudoFourierGgswCiphertextView {
fourier: FourierPolynomialList {
data: self.fourier.data.as_ref(),
polynomial_size: self.fourier.polynomial_size,
},
glwe_size_in: self.glwe_size_in,
glwe_size_out: self.glwe_size_out,
decomposition_base_log: self.decomposition_base_log,
decomposition_level_count: self.decomposition_level_count,
}
}
pub fn as_mut_view(&mut self) -> PseudoFourierGgswCiphertextMutView<'_>
where
C: AsMut<[c64]>,
{
PseudoFourierGgswCiphertextMutView {
fourier: FourierPolynomialList {
data: self.fourier.data.as_mut(),
polynomial_size: self.fourier.polynomial_size,
},
glwe_size_in: self.glwe_size_in,
glwe_size_out: self.glwe_size_out,
decomposition_base_log: self.decomposition_base_log,
decomposition_level_count: self.decomposition_level_count,
}
}
}
impl<C: Container<Element = c64>> PseudoFourierGgswLevelMatrix<C> {
pub fn new(
data: C,
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
row_count: usize,
decomposition_level: DecompositionLevel,
) -> Self {
assert_eq!(
data.container_len(),
polynomial_size.to_fourier_polynomial_size().0 * glwe_size_out.0 * row_count
);
Self {
data,
glwe_size_in,
glwe_size_out,
polynomial_size,
row_count,
decomposition_level,
}
}
/// Return an iterator over the rows of the level matrices.
pub fn into_rows(self) -> impl DoubleEndedIterator<Item = PseudoFourierGgswLevelRow<C>>
where
C: Split,
{
self.data
.split_into(self.row_count)
.map(move |slice| PseudoFourierGgswLevelRow {
data: slice,
polynomial_size: self.polynomial_size,
glwe_size_out: self.glwe_size_out,
decomposition_level: self.decomposition_level,
})
}
pub fn polynomial_size(&self) -> PolynomialSize {
self.polynomial_size
}
pub fn glwe_size_in(&self) -> GlweSize {
self.glwe_size_in
}
pub fn glwe_size_out(&self) -> GlweSize {
self.glwe_size_out
}
pub fn row_count(&self) -> usize {
self.row_count
}
pub fn decomposition_level(&self) -> DecompositionLevel {
self.decomposition_level
}
pub fn data(self) -> C {
self.data
}
}
impl<C: Container<Element = c64>> PseudoFourierGgswLevelRow<C> {
pub fn new(
data: C,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
decomposition_level: DecompositionLevel,
) -> Self {
assert_eq!(
data.container_len(),
polynomial_size.to_fourier_polynomial_size().0 * glwe_size_out.0
);
Self {
data,
glwe_size_out,
polynomial_size,
decomposition_level,
}
}
pub fn polynomial_size(&self) -> PolynomialSize {
self.polynomial_size
}
pub fn glwe_size_out(&self) -> GlweSize {
self.glwe_size_out
}
pub fn decomposition_level(&self) -> DecompositionLevel {
self.decomposition_level
}
pub fn data(self) -> C {
self.data
}
}
impl<'a> PseudoFourierGgswCiphertextView<'a> {
/// Return an iterator over the level matrices.
pub fn into_levels(
self,
) -> impl DoubleEndedIterator<Item = PseudoFourierGgswLevelMatrixView<'a>> {
self.fourier
.data
.split_into(self.decomposition_level_count.0)
.enumerate()
.map(move |(i, slice)| {
PseudoFourierGgswLevelMatrixView::new(
slice,
self.glwe_size_in,
self.glwe_size_out,
self.fourier.polynomial_size,
self.glwe_size_in.to_glwe_dimension().0,
DecompositionLevel(i + 1),
)
})
}
}
/// Return the required memory for
/// [`PseudoFourierGgswCiphertextMutView::fill_with_forward_fourier`].
pub fn fill_with_forward_fourier_scratch(fft: FftView<'_>) -> Result<StackReq, SizeOverflow> {
fft.forward_scratch()
}
impl<'a> PseudoFourierGgswCiphertextMutView<'a> {
/// Fill a GGSW ciphertext with the Fourier transform of a GGSW ciphertext in the standard
/// domain.
pub fn fill_with_forward_fourier<
Scalar: UnsignedTorus,
InputCont: Container<Element = Scalar>,
>(
self,
coef_ggsw: &PseudoGgswCiphertext<InputCont>,
fft: FftView<'_>,
mut stack: PodStack<'_>,
) {
debug_assert_eq!(coef_ggsw.polynomial_size(), self.polynomial_size());
let fourier_poly_size = coef_ggsw.polynomial_size().to_fourier_polynomial_size().0;
for (fourier_poly, coef_poly) in izip!(
self.data().into_chunks(fourier_poly_size),
coef_ggsw.as_polynomial_list().iter()
) {
fft.forward_as_torus(
FourierPolynomialMutView { data: fourier_poly },
coef_poly,
stack.rb_mut(),
);
}
}
}
#[allow(unused)]
type PseudoFourierGgswCiphertextOwned = PseudoFourierGgswCiphertext<ABox<[c64]>>;
impl PseudoFourierGgswCiphertext<ABox<[c64]>> {
pub fn new(
glwe_size_in: GlweSize,
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
decomposition_base_log: DecompositionBaseLog,
decomposition_level_count: DecompositionLevelCount,
) -> Self {
let boxed = avec![
c64::default();
polynomial_size.to_fourier_polynomial_size().0
* glwe_size_in.to_glwe_dimension().0
* glwe_size_out.0
* decomposition_level_count.0
]
.into_boxed_slice();
Self::from_container(
boxed,
glwe_size_in,
glwe_size_out,
polynomial_size,
decomposition_base_log,
decomposition_level_count,
)
}
}
/// Return the required memory for [`add_external_product_pseudo_ggsw_assign`].
pub fn add_external_product_pseudo_ggsw_assign_scratch<Scalar>(
glwe_size_out: GlweSize,
polynomial_size: PolynomialSize,
fft: FftView<'_>,
) -> Result<StackReq, SizeOverflow> {
let align = CACHELINE_ALIGN;
let standard_scratch =
StackReq::try_new_aligned::<Scalar>(glwe_size_out.0 * polynomial_size.0, align)?;
let fourier_polynomial_size = polynomial_size.to_fourier_polynomial_size().0;
let fourier_scratch =
StackReq::try_new_aligned::<c64>(glwe_size_out.0 * fourier_polynomial_size, align)?;
let fourier_scratch_single = StackReq::try_new_aligned::<c64>(fourier_polynomial_size, align)?;
let substack3 = fft.forward_scratch()?;
let substack2 = substack3.try_and(fourier_scratch_single)?;
let substack1 = substack2.try_and(standard_scratch)?;
let substack0 = StackReq::try_any_of([
substack1.try_and(standard_scratch)?,
fft.backward_scratch()?,
])?;
substack0.try_and(fourier_scratch)
}
/// Perform the external product of `ggsw` and `glwe`, and adds the result to `out`.
#[cfg_attr(__profiling, inline(never))]
pub fn add_external_product_pseudo_ggsw_assign<Scalar, InputGlweCont>(
mut out: GlweCiphertextMutView<'_, Scalar>,
ggsw: PseudoFourierGgswCiphertextView<'_>,
glwe: &GlweCiphertext<InputGlweCont>,
fft: FftView<'_>,
stack: PodStack<'_>,
) where
Scalar: UnsignedTorus,
InputGlweCont: Container<Element = Scalar>,
{
// we check that the polynomial sizes match
debug_assert_eq!(ggsw.polynomial_size(), glwe.polynomial_size());
debug_assert_eq!(ggsw.polynomial_size(), out.polynomial_size());
// we check that the glwe sizes match
debug_assert_eq!(ggsw.glwe_size_out(), out.glwe_size());
//println!("%%%%%% INSIDE EXTERNAL PRODUCT %%%%%%%%%%");
let align = CACHELINE_ALIGN;
let fourier_poly_size = ggsw.polynomial_size().to_fourier_polynomial_size().0;
// we round the input mask and body
let decomposer = SignedDecomposer::<Scalar>::new(
ggsw.decomposition_base_log(),
ggsw.decomposition_level_count(),
);
// println!("going in first substack");
let (mut output_fft_buffer, mut substack0) =
stack.make_aligned_raw::<c64>(fourier_poly_size * ggsw.glwe_size_out().0, align);
// println!("First substack done");
// output_fft_buffer is initially uninitialized, considered to be implicitly zero, to avoid
// the cost of filling it up with zeros. `is_output_uninit` is set to `false` once
// it has been fully initialized for the first time.
let output_fft_buffer = &mut *output_fft_buffer;
let mut is_output_uninit = true;
{
// ------------------------------------------------------ EXTERNAL PRODUCT IN FOURIER DOMAIN
// In this section, we perform the external product in the fourier domain, and accumulate
// the result in the output_fft_buffer variable.
let (mut decomposition, mut substack1) = TensorSignedDecompositionLendingIter::new(
glwe.as_ref()
.iter()
.map(|s| decomposer.closest_representable(*s)),
DecompositionBaseLog(decomposer.base_log),
DecompositionLevelCount(decomposer.level_count),
substack0.rb_mut(),
);
// We loop through the levels (we reverse to match the order of the decomposition iterator.)
ggsw.into_levels().rev().for_each(|ggsw_decomp_matrix| {
// We retrieve the decomposition of this level.
let (glwe_level, glwe_decomp_term, mut substack2) =
collect_next_term(&mut decomposition, &mut substack1, align);
let glwe_decomp_term = GlweCiphertextView::from_container(
&*glwe_decomp_term,
ggsw.polynomial_size(),
out.ciphertext_modulus(),
);
debug_assert_eq!(ggsw_decomp_matrix.decomposition_level(), glwe_level);
// For each level we have to add the result of the vector-matrix product between the
// decomposition of the glwe, and the ggsw level matrix to the output. To do so, we
// iteratively add to the output, the product between every line of the matrix, and
// the corresponding (scalar) polynomial in the glwe decomposition:
//
// ggsw_mat ggsw_mat
// glwe_dec | - - - - | < glwe_dec | - - - - |
// | - - - | x | - - - - | | - - - | x | - - - - | <
// ^ | - - - - | ^ | - - - - |
//
// t = 1 t = 2 ...
// println!("ggsw_decomp_matrix.into_rows() = {:?}\n ",ggsw_decomp_matrix);
// println!("glwe_decomp_term.as_poly = {:?}\n",glwe_decomp_term.as_polynomial_list());
izip!(
ggsw_decomp_matrix.into_rows(),
glwe_decomp_term.get_mask().as_polynomial_list().iter()
)
.for_each(|(ggsw_row, glwe_poly)| {
// println!("GGSW_ROW = {:?}\n", ggsw_row);
// println!("GLWE_POLY = {:?}\n", glwe_poly);
let (mut fourier, substack3) = substack2
.rb_mut()
.make_aligned_raw::<c64>(fourier_poly_size, align);
//println!("Second substack done");
// We perform the forward fft transform for the glwe polynomial
let fourier = fft
.forward_as_integer(
FourierPolynomialMutView { data: &mut fourier },
glwe_poly,
substack3,
)
.data;
// Now we loop through the polynomials of the output, and add the
// corresponding product of polynomials.
//println!("GLWE_POLY FOURIER = {:?}\n", fourier);
update_with_fmadd(
output_fft_buffer,
ggsw_row.data(),
fourier,
is_output_uninit,
fourier_poly_size,
);
// we initialized `output_fft_buffer, so we can set this to false
is_output_uninit = false;
});
});
}
//println!("Ouput FFT Buffer = {:?}\n", output_fft_buffer);
// -------------------------------------------- TRANSFORMATION OF RESULT TO STANDARD DOMAIN
// In this section, we bring the result from the fourier domain, back to the standard
// domain, and add it to the output.
//
// We iterate over the polynomials in the output.
if !is_output_uninit {
izip!(
out.as_mut_polynomial_list().iter_mut(),
output_fft_buffer
.into_chunks(fourier_poly_size)
.map(|slice| FourierPolynomialView { data: slice }),
)
.for_each(|(out, fourier)| {
fft.add_backward_as_torus(out, fourier, substack0.rb_mut());
});
}
//We copy the body
//as_mut().copy_from_slice(glwe.get_body().as_ref());
for (dst, src) in out
.get_mut_body()
.as_mut_polynomial()
.iter_mut()
.zip(glwe.get_body().as_polynomial().iter())
{
*dst = dst.wrapping_add(*src);
}
}

View File

@@ -0,0 +1,64 @@
use crate::forward_compatibility::ConvertInto;
use crate::boolean::ciphertext::CompressedCiphertext;
use next_tfhe::boolean::ciphertext::CompressedCiphertext as NextCompressedCiphertext;
impl crate::forward_compatibility::ConvertFrom<CompressedCiphertext> for NextCompressedCiphertext {
#[inline]
fn convert_from(value: CompressedCiphertext) -> Self {
let CompressedCiphertext { ciphertext } = value;
Self::from_raw_parts(ciphertext.convert_into())
}
}
use crate::boolean::ciphertext::Ciphertext;
use next_tfhe::boolean::ciphertext::Ciphertext as NextCiphertext;
impl crate::forward_compatibility::ConvertFrom<Ciphertext> for NextCiphertext {
#[inline]
fn convert_from(value: Ciphertext) -> Self {
match value {
Ciphertext::Encrypted(encrypted) => NextCiphertext::Encrypted(encrypted.convert_into()),
Ciphertext::Trivial(trivial) => NextCiphertext::Trivial(trivial),
}
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_ciphertext() {
use next_tfhe::boolean::ciphertext::Ciphertext as NextCiphertext;
use crate::boolean::gen_keys;
let (cks, sks) = gen_keys();
{
let tfhe_struct = cks.encrypt(true);
let _next_tfhe_struct: NextCiphertext = tfhe_struct.convert_into();
}
{
let tfhe_struct = sks.trivial_encrypt(true);
let _next_tfhe_struct: NextCiphertext = tfhe_struct.convert_into();
}
}
#[test]
fn test_conversion_compressed_ciphertext() {
use next_tfhe::boolean::ciphertext::CompressedCiphertext as NextCompressedCiphertext;
use crate::boolean::gen_keys;
let (cks, _sks) = gen_keys();
{
let tfhe_struct = cks.encrypt_compressed(true);
let _next_tfhe_struct: NextCompressedCiphertext = tfhe_struct.convert_into();
}
}
}

View File

@@ -0,0 +1,33 @@
use crate::forward_compatibility::ConvertInto;
use crate::boolean::client_key::ClientKey;
use next_tfhe::boolean::client_key::ClientKey as NextClientKey;
impl crate::forward_compatibility::ConvertFrom<ClientKey> for NextClientKey {
#[inline]
fn convert_from(value: ClientKey) -> Self {
let (lwe_secret_key, glwe_secret_key, parameters) = value.into_raw_parts();
Self::new_from_raw_parts(
lwe_secret_key.convert_into(),
glwe_secret_key.convert_into(),
parameters.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_client_key() {
use crate::boolean::client_key::ClientKey;
use next_tfhe::boolean::client_key::ClientKey as NextClientKey;
use crate::boolean::parameters::DEFAULT_PARAMETERS_KS_PBS;
let tfhe_struct = ClientKey::new(&DEFAULT_PARAMETERS_KS_PBS);
let _next_tfhe_struct: NextClientKey = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,69 @@
use crate::forward_compatibility::ConvertInto;
use crate::boolean::engine::bootstrapping::ServerKey;
use next_tfhe::boolean::engine::bootstrapping::ServerKey as NextServerKey;
impl crate::forward_compatibility::ConvertFrom<ServerKey> for NextServerKey {
#[inline]
fn convert_from(value: ServerKey) -> Self {
let ServerKey {
bootstrapping_key,
key_switching_key,
pbs_order,
} = value;
Self::from_raw_parts(
bootstrapping_key.convert_into(),
key_switching_key.convert_into(),
pbs_order.convert_into(),
)
}
}
use crate::boolean::engine::bootstrapping::CompressedServerKey;
use next_tfhe::boolean::engine::bootstrapping::CompressedServerKey as NextCompressedServerKey;
impl crate::forward_compatibility::ConvertFrom<CompressedServerKey> for NextCompressedServerKey {
#[inline]
fn convert_from(value: CompressedServerKey) -> Self {
let CompressedServerKey {
bootstrapping_key,
key_switching_key,
pbs_order,
} = value;
Self::from_raw_parts(
bootstrapping_key.convert_into(),
key_switching_key.convert_into(),
pbs_order.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_server_key() {
use next_tfhe::boolean::engine::bootstrapping::ServerKey as NextServerKey;
use crate::boolean::gen_keys;
let (_cks, tfhe_struct) = gen_keys();
let _next_tfhe_struct: NextServerKey = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_compressed_server_key() {
use crate::boolean::engine::bootstrapping::CompressedServerKey;
use next_tfhe::boolean::engine::bootstrapping::CompressedServerKey as NextCompressedServerKey;
use crate::boolean::client_key::ClientKey;
use crate::boolean::parameters::DEFAULT_PARAMETERS_KS_PBS;
let cks = ClientKey::new(&DEFAULT_PARAMETERS_KS_PBS);
let tfhe_struct = CompressedServerKey::new(&cks);
let _next_tfhe_struct: NextCompressedServerKey = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1 @@
pub mod bootstrapping;

View File

@@ -0,0 +1,38 @@
use crate::forward_compatibility::ConvertInto;
use crate::boolean::key_switching_key::KeySwitchingKey;
use next_tfhe::boolean::key_switching_key::KeySwitchingKey as NextKeySwitchingKey;
impl crate::forward_compatibility::ConvertFrom<KeySwitchingKey> for NextKeySwitchingKey {
#[inline]
fn convert_from(value: KeySwitchingKey) -> Self {
let KeySwitchingKey { key_switching_key } = value;
Self::from_raw_parts(key_switching_key.convert_into())
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_key_switching_key() {
use crate::boolean::key_switching_key::KeySwitchingKey;
use next_tfhe::boolean::key_switching_key::KeySwitchingKey as NextKeySwitchingKey;
use crate::boolean::gen_keys;
use crate::boolean::parameters::BooleanKeySwitchingParameters;
let (cks1, _sks1) = gen_keys();
let (cks2, _sks2) = gen_keys();
let ksk_params = BooleanKeySwitchingParameters::new(
cks2.parameters.ks_base_log,
cks2.parameters.ks_level,
);
let tfhe_struct = KeySwitchingKey::new(&cks1, &cks2, ksk_params);
let _next_tfhe_struct: NextKeySwitchingKey = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,6 @@
pub mod ciphertext;
pub mod client_key;
pub mod engine;
pub mod key_switching_key;
pub mod parameters;
pub mod public_key;

View File

@@ -0,0 +1,104 @@
use crate::boolean::parameters::BooleanParameters;
use crate::forward_compatibility::ConvertInto;
use next_tfhe::boolean::parameters::BooleanParameters as NextBooleanParameters;
impl crate::forward_compatibility::ConvertFrom<BooleanParameters> for NextBooleanParameters {
#[inline]
fn convert_from(value: BooleanParameters) -> Self {
let BooleanParameters {
lwe_dimension,
glwe_dimension,
polynomial_size,
lwe_modular_std_dev,
glwe_modular_std_dev,
pbs_base_log,
pbs_level,
ks_base_log,
ks_level,
encryption_key_choice,
} = value;
NextBooleanParameters {
lwe_dimension: lwe_dimension.convert_into(),
glwe_dimension: glwe_dimension.convert_into(),
polynomial_size: polynomial_size.convert_into(),
lwe_modular_std_dev: lwe_modular_std_dev.convert_into(),
glwe_modular_std_dev: glwe_modular_std_dev.convert_into(),
pbs_base_log: pbs_base_log.convert_into(),
pbs_level: pbs_level.convert_into(),
ks_base_log: ks_base_log.convert_into(),
ks_level: ks_level.convert_into(),
encryption_key_choice: encryption_key_choice.convert_into(),
}
}
}
use crate::boolean::parameters::BooleanKeySwitchingParameters;
use next_tfhe::boolean::parameters::BooleanKeySwitchingParameters as NextBooleanKeySwitchingParameters;
impl crate::forward_compatibility::ConvertFrom<BooleanKeySwitchingParameters>
for NextBooleanKeySwitchingParameters
{
#[inline]
fn convert_from(value: BooleanKeySwitchingParameters) -> Self {
let BooleanKeySwitchingParameters {
ks_base_log,
ks_level,
} = value;
NextBooleanKeySwitchingParameters {
ks_base_log: ks_base_log.convert_into(),
ks_level: ks_level.convert_into(),
}
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_boolean_parameters() {
use crate::boolean::parameters::BooleanParameters;
use crate::core_crypto::commons::dispersion::StandardDev;
use crate::core_crypto::commons::parameters::*;
use next_tfhe::boolean::parameters::BooleanParameters as NextBooleanParameters;
use rand::Rng;
let mut rng = rand::thread_rng();
for encryption_key_choice in [EncryptionKeyChoice::Big, EncryptionKeyChoice::Small] {
let tfhe_struct = BooleanParameters {
lwe_dimension: LweDimension(rng.gen()),
glwe_dimension: GlweDimension(rng.gen()),
polynomial_size: PolynomialSize(rng.gen()),
lwe_modular_std_dev: StandardDev(rng.gen()),
glwe_modular_std_dev: StandardDev(rng.gen()),
pbs_base_log: DecompositionBaseLog(rng.gen()),
pbs_level: DecompositionLevelCount(rng.gen()),
ks_base_log: DecompositionBaseLog(rng.gen()),
ks_level: DecompositionLevelCount(rng.gen()),
encryption_key_choice,
};
let _next_tfhe_struct: NextBooleanParameters = tfhe_struct.convert_into();
}
}
#[test]
fn test_conversion_boolean_key_switching_parameters() {
use crate::boolean::parameters::BooleanKeySwitchingParameters;
use crate::core_crypto::commons::parameters::*;
use next_tfhe::boolean::parameters::BooleanKeySwitchingParameters as NextBooleanKeySwitchingParameters;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = BooleanKeySwitchingParameters {
ks_base_log: DecompositionBaseLog(rng.gen()),
ks_level: DecompositionLevelCount(rng.gen()),
};
let _next_tfhe_struct: NextBooleanKeySwitchingParameters = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,65 @@
use crate::forward_compatibility::ConvertInto;
use crate::boolean::public_key::CompressedPublicKey;
use next_tfhe::boolean::public_key::CompressedPublicKey as NextCompressedPublicKey;
impl crate::forward_compatibility::ConvertFrom<CompressedPublicKey> for NextCompressedPublicKey {
#[inline]
fn convert_from(value: CompressedPublicKey) -> Self {
let CompressedPublicKey {
compressed_lwe_public_key,
parameters,
} = value;
Self::from_raw_parts(
compressed_lwe_public_key.convert_into(),
parameters.convert_into(),
)
}
}
use crate::boolean::public_key::PublicKey;
use next_tfhe::boolean::public_key::PublicKey as NextPublicKey;
impl crate::forward_compatibility::ConvertFrom<PublicKey> for NextPublicKey {
#[inline]
fn convert_from(value: PublicKey) -> Self {
let PublicKey {
lwe_public_key,
parameters,
} = value;
Self::from_raw_parts(lwe_public_key.convert_into(), parameters.convert_into())
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_compressed_public_key() {
use crate::boolean::public_key::CompressedPublicKey;
use next_tfhe::boolean::public_key::CompressedPublicKey as NextCompressedPublicKey;
use crate::boolean::client_key::ClientKey;
use crate::boolean::parameters::DEFAULT_PARAMETERS_KS_PBS;
let cks = ClientKey::new(&DEFAULT_PARAMETERS_KS_PBS);
let tfhe_struct = CompressedPublicKey::new(&cks);
let _next_tfhe_struct: NextCompressedPublicKey = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_public_key() {
use crate::boolean::public_key::PublicKey;
use next_tfhe::boolean::public_key::PublicKey as NextPublicKey;
use crate::boolean::client_key::ClientKey;
use crate::boolean::parameters::DEFAULT_PARAMETERS_KS_PBS;
let cks = ClientKey::new(&DEFAULT_PARAMETERS_KS_PBS);
let tfhe_struct = PublicKey::new(&cks);
let _next_tfhe_struct: NextPublicKey = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,41 @@
use crate::core_crypto::commons::ciphertext_modulus::CiphertextModulus;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use next_tfhe::core_crypto::commons::ciphertext_modulus::CiphertextModulus as NextCiphertextModulus;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
impl<Scalar> crate::forward_compatibility::ConvertFrom<CiphertextModulus<Scalar>>
for NextCiphertextModulus<Scalar>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
{
#[inline]
fn convert_from(value: CiphertextModulus<Scalar>) -> Self {
if value.is_native_modulus() {
Self::new_native()
} else {
Self::new(value.get_custom_modulus())
}
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_ciphertext_modulus() {
use crate::core_crypto::commons::ciphertext_modulus::CiphertextModulus;
use next_tfhe::core_crypto::commons::ciphertext_modulus::CiphertextModulus as NextCiphertextModulus;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = CiphertextModulus::new(0);
let _next_tfhe_struct: NextCiphertextModulus<u64> = tfhe_struct.convert_into();
let tfhe_struct = CiphertextModulus::new(rng.gen_range(0..=(1 << 64)));
let _next_tfhe_struct: NextCiphertextModulus<u64> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,27 @@
use crate::core_crypto::commons::dispersion::StandardDev;
use next_tfhe::core_crypto::commons::dispersion::StandardDev as NextStandardDev;
impl crate::forward_compatibility::ConvertFrom<StandardDev> for NextStandardDev {
#[inline]
fn convert_from(value: StandardDev) -> Self {
let StandardDev(field_0) = value;
NextStandardDev(field_0)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_standard_dev() {
use crate::core_crypto::commons::dispersion::StandardDev;
use next_tfhe::core_crypto::commons::dispersion::StandardDev as NextStandardDev;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = StandardDev(rng.gen());
let _next_tfhe_struct: NextStandardDev = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1 @@
pub mod random;

View File

@@ -0,0 +1,45 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::commons::math::random::Seed;
use next_tfhe::core_crypto::commons::math::random::Seed as NextSeed;
impl crate::forward_compatibility::ConvertFrom<Seed> for NextSeed {
#[inline]
fn convert_from(value: Seed) -> Self {
let Seed(seed) = value;
Self(seed)
}
}
use crate::core_crypto::commons::math::random::CompressionSeed;
use next_tfhe::core_crypto::commons::math::random::CompressionSeed as NextCompressionSeed;
impl crate::forward_compatibility::ConvertFrom<CompressionSeed> for NextCompressionSeed {
#[inline]
fn convert_from(value: CompressionSeed) -> Self {
let CompressionSeed { seed } = value;
NextCompressionSeed {
seed: seed.convert_into(),
}
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_compression_seed() {
use crate::core_crypto::commons::math::random::{CompressionSeed, Seed};
use next_tfhe::core_crypto::commons::math::random::CompressionSeed as NextCompressionSeed;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = CompressionSeed {
seed: Seed(rng.gen()),
};
let _next_tfhe_struct: NextCompressionSeed = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,4 @@
pub mod ciphertext_modulus;
pub mod dispersion;
pub mod math;
pub mod parameters;

View File

@@ -0,0 +1,790 @@
use crate::core_crypto::commons::parameters::PlaintextCount;
use next_tfhe::core_crypto::commons::parameters::PlaintextCount as NextPlaintextCount;
impl crate::forward_compatibility::ConvertFrom<PlaintextCount> for NextPlaintextCount {
#[inline]
fn convert_from(value: PlaintextCount) -> Self {
let PlaintextCount(field_0) = value;
NextPlaintextCount(field_0)
}
}
use crate::core_crypto::commons::parameters::CleartextCount;
use next_tfhe::core_crypto::commons::parameters::CleartextCount as NextCleartextCount;
impl crate::forward_compatibility::ConvertFrom<CleartextCount> for NextCleartextCount {
#[inline]
fn convert_from(value: CleartextCount) -> Self {
let CleartextCount(field_0) = value;
NextCleartextCount(field_0)
}
}
use crate::core_crypto::commons::parameters::CiphertextCount;
use next_tfhe::core_crypto::commons::parameters::CiphertextCount as NextCiphertextCount;
impl crate::forward_compatibility::ConvertFrom<CiphertextCount> for NextCiphertextCount {
#[inline]
fn convert_from(value: CiphertextCount) -> Self {
let CiphertextCount(field_0) = value;
NextCiphertextCount(field_0)
}
}
use crate::core_crypto::commons::parameters::LweCiphertextCount;
use next_tfhe::core_crypto::commons::parameters::LweCiphertextCount as NextLweCiphertextCount;
impl crate::forward_compatibility::ConvertFrom<LweCiphertextCount> for NextLweCiphertextCount {
#[inline]
fn convert_from(value: LweCiphertextCount) -> Self {
let LweCiphertextCount(field_0) = value;
NextLweCiphertextCount(field_0)
}
}
use crate::core_crypto::commons::parameters::GlweCiphertextCount;
use next_tfhe::core_crypto::commons::parameters::GlweCiphertextCount as NextGlweCiphertextCount;
impl crate::forward_compatibility::ConvertFrom<GlweCiphertextCount> for NextGlweCiphertextCount {
#[inline]
fn convert_from(value: GlweCiphertextCount) -> Self {
let GlweCiphertextCount(field_0) = value;
NextGlweCiphertextCount(field_0)
}
}
use crate::core_crypto::commons::parameters::GswCiphertextCount;
use next_tfhe::core_crypto::commons::parameters::GswCiphertextCount as NextGswCiphertextCount;
impl crate::forward_compatibility::ConvertFrom<GswCiphertextCount> for NextGswCiphertextCount {
#[inline]
fn convert_from(value: GswCiphertextCount) -> Self {
let GswCiphertextCount(field_0) = value;
NextGswCiphertextCount(field_0)
}
}
use crate::core_crypto::commons::parameters::GgswCiphertextCount;
use next_tfhe::core_crypto::commons::parameters::GgswCiphertextCount as NextGgswCiphertextCount;
impl crate::forward_compatibility::ConvertFrom<GgswCiphertextCount> for NextGgswCiphertextCount {
#[inline]
fn convert_from(value: GgswCiphertextCount) -> Self {
let GgswCiphertextCount(field_0) = value;
NextGgswCiphertextCount(field_0)
}
}
use crate::core_crypto::commons::parameters::LweSize;
use next_tfhe::core_crypto::commons::parameters::LweSize as NextLweSize;
impl crate::forward_compatibility::ConvertFrom<LweSize> for NextLweSize {
#[inline]
fn convert_from(value: LweSize) -> Self {
let LweSize(field_0) = value;
NextLweSize(field_0)
}
}
use crate::core_crypto::commons::parameters::LweDimension;
use next_tfhe::core_crypto::commons::parameters::LweDimension as NextLweDimension;
impl crate::forward_compatibility::ConvertFrom<LweDimension> for NextLweDimension {
#[inline]
fn convert_from(value: LweDimension) -> Self {
let LweDimension(field_0) = value;
NextLweDimension(field_0)
}
}
use crate::core_crypto::commons::parameters::LwePublicKeyZeroEncryptionCount;
use next_tfhe::core_crypto::commons::parameters::LwePublicKeyZeroEncryptionCount as NextLwePublicKeyZeroEncryptionCount;
impl crate::forward_compatibility::ConvertFrom<LwePublicKeyZeroEncryptionCount>
for NextLwePublicKeyZeroEncryptionCount
{
#[inline]
fn convert_from(value: LwePublicKeyZeroEncryptionCount) -> Self {
let LwePublicKeyZeroEncryptionCount(field_0) = value;
NextLwePublicKeyZeroEncryptionCount(field_0)
}
}
use crate::core_crypto::commons::parameters::LweMaskCount;
use next_tfhe::core_crypto::commons::parameters::LweMaskCount as NextLweMaskCount;
impl crate::forward_compatibility::ConvertFrom<LweMaskCount> for NextLweMaskCount {
#[inline]
fn convert_from(value: LweMaskCount) -> Self {
let LweMaskCount(field_0) = value;
NextLweMaskCount(field_0)
}
}
use crate::core_crypto::commons::parameters::LweBodyCount;
use next_tfhe::core_crypto::commons::parameters::LweBodyCount as NextLweBodyCount;
impl crate::forward_compatibility::ConvertFrom<LweBodyCount> for NextLweBodyCount {
#[inline]
fn convert_from(value: LweBodyCount) -> Self {
let LweBodyCount(field_0) = value;
NextLweBodyCount(field_0)
}
}
use crate::core_crypto::commons::parameters::GlweSize;
use next_tfhe::core_crypto::commons::parameters::GlweSize as NextGlweSize;
impl crate::forward_compatibility::ConvertFrom<GlweSize> for NextGlweSize {
#[inline]
fn convert_from(value: GlweSize) -> Self {
let GlweSize(field_0) = value;
NextGlweSize(field_0)
}
}
use crate::core_crypto::commons::parameters::GlweDimension;
use next_tfhe::core_crypto::commons::parameters::GlweDimension as NextGlweDimension;
impl crate::forward_compatibility::ConvertFrom<GlweDimension> for NextGlweDimension {
#[inline]
fn convert_from(value: GlweDimension) -> Self {
let GlweDimension(field_0) = value;
NextGlweDimension(field_0)
}
}
use crate::core_crypto::commons::parameters::PolynomialSize;
use next_tfhe::core_crypto::commons::parameters::PolynomialSize as NextPolynomialSize;
impl crate::forward_compatibility::ConvertFrom<PolynomialSize> for NextPolynomialSize {
#[inline]
fn convert_from(value: PolynomialSize) -> Self {
let PolynomialSize(field_0) = value;
NextPolynomialSize(field_0)
}
}
use crate::core_crypto::commons::parameters::FourierPolynomialSize;
use next_tfhe::core_crypto::commons::parameters::FourierPolynomialSize as NextFourierPolynomialSize;
impl crate::forward_compatibility::ConvertFrom<FourierPolynomialSize>
for NextFourierPolynomialSize
{
#[inline]
fn convert_from(value: FourierPolynomialSize) -> Self {
let FourierPolynomialSize(field_0) = value;
NextFourierPolynomialSize(field_0)
}
}
use crate::core_crypto::commons::parameters::PolynomialSizeLog;
use next_tfhe::core_crypto::commons::parameters::PolynomialSizeLog as NextPolynomialSizeLog;
impl crate::forward_compatibility::ConvertFrom<PolynomialSizeLog> for NextPolynomialSizeLog {
#[inline]
fn convert_from(value: PolynomialSizeLog) -> Self {
let PolynomialSizeLog(field_0) = value;
NextPolynomialSizeLog(field_0)
}
}
use crate::core_crypto::commons::parameters::PolynomialCount;
use next_tfhe::core_crypto::commons::parameters::PolynomialCount as NextPolynomialCount;
impl crate::forward_compatibility::ConvertFrom<PolynomialCount> for NextPolynomialCount {
#[inline]
fn convert_from(value: PolynomialCount) -> Self {
let PolynomialCount(field_0) = value;
NextPolynomialCount(field_0)
}
}
use crate::core_crypto::commons::parameters::MonomialDegree;
use next_tfhe::core_crypto::commons::parameters::MonomialDegree as NextMonomialDegree;
impl crate::forward_compatibility::ConvertFrom<MonomialDegree> for NextMonomialDegree {
#[inline]
fn convert_from(value: MonomialDegree) -> Self {
let MonomialDegree(field_0) = value;
NextMonomialDegree(field_0)
}
}
use crate::core_crypto::commons::parameters::DecompositionBaseLog;
use next_tfhe::core_crypto::commons::parameters::DecompositionBaseLog as NextDecompositionBaseLog;
impl crate::forward_compatibility::ConvertFrom<DecompositionBaseLog> for NextDecompositionBaseLog {
#[inline]
fn convert_from(value: DecompositionBaseLog) -> Self {
let DecompositionBaseLog(field_0) = value;
NextDecompositionBaseLog(field_0)
}
}
use crate::core_crypto::commons::parameters::DecompositionLevelCount;
use next_tfhe::core_crypto::commons::parameters::DecompositionLevelCount as NextDecompositionLevelCount;
impl crate::forward_compatibility::ConvertFrom<DecompositionLevelCount>
for NextDecompositionLevelCount
{
#[inline]
fn convert_from(value: DecompositionLevelCount) -> Self {
let DecompositionLevelCount(field_0) = value;
NextDecompositionLevelCount(field_0)
}
}
use crate::core_crypto::commons::parameters::LutCountLog;
use next_tfhe::core_crypto::commons::parameters::LutCountLog as NextLutCountLog;
impl crate::forward_compatibility::ConvertFrom<LutCountLog> for NextLutCountLog {
#[inline]
fn convert_from(value: LutCountLog) -> Self {
let LutCountLog(field_0) = value;
NextLutCountLog(field_0)
}
}
use crate::core_crypto::commons::parameters::ModulusSwitchOffset;
use next_tfhe::core_crypto::commons::parameters::ModulusSwitchOffset as NextModulusSwitchOffset;
impl crate::forward_compatibility::ConvertFrom<ModulusSwitchOffset> for NextModulusSwitchOffset {
#[inline]
fn convert_from(value: ModulusSwitchOffset) -> Self {
let ModulusSwitchOffset(field_0) = value;
NextModulusSwitchOffset(field_0)
}
}
use crate::core_crypto::commons::parameters::DeltaLog;
use next_tfhe::core_crypto::commons::parameters::DeltaLog as NextDeltaLog;
impl crate::forward_compatibility::ConvertFrom<DeltaLog> for NextDeltaLog {
#[inline]
fn convert_from(value: DeltaLog) -> Self {
let DeltaLog(field_0) = value;
NextDeltaLog(field_0)
}
}
use crate::core_crypto::commons::parameters::ExtractedBitsCount;
use next_tfhe::core_crypto::commons::parameters::ExtractedBitsCount as NextExtractedBitsCount;
impl crate::forward_compatibility::ConvertFrom<ExtractedBitsCount> for NextExtractedBitsCount {
#[inline]
fn convert_from(value: ExtractedBitsCount) -> Self {
let ExtractedBitsCount(field_0) = value;
NextExtractedBitsCount(field_0)
}
}
use crate::core_crypto::commons::parameters::FunctionalPackingKeyswitchKeyCount;
use next_tfhe::core_crypto::commons::parameters::FunctionalPackingKeyswitchKeyCount as NextFunctionalPackingKeyswitchKeyCount;
impl crate::forward_compatibility::ConvertFrom<FunctionalPackingKeyswitchKeyCount>
for NextFunctionalPackingKeyswitchKeyCount
{
#[inline]
fn convert_from(value: FunctionalPackingKeyswitchKeyCount) -> Self {
let FunctionalPackingKeyswitchKeyCount(field_0) = value;
NextFunctionalPackingKeyswitchKeyCount(field_0)
}
}
use crate::core_crypto::commons::parameters::CiphertextModulusLog;
use next_tfhe::core_crypto::commons::parameters::CiphertextModulusLog as NextCiphertextModulusLog;
impl crate::forward_compatibility::ConvertFrom<CiphertextModulusLog> for NextCiphertextModulusLog {
#[inline]
fn convert_from(value: CiphertextModulusLog) -> Self {
let CiphertextModulusLog(field_0) = value;
NextCiphertextModulusLog(field_0)
}
}
use crate::core_crypto::commons::parameters::ThreadCount;
use next_tfhe::core_crypto::commons::parameters::ThreadCount as NextThreadCount;
impl crate::forward_compatibility::ConvertFrom<ThreadCount> for NextThreadCount {
#[inline]
fn convert_from(value: ThreadCount) -> Self {
let ThreadCount(field_0) = value;
NextThreadCount(field_0)
}
}
use crate::core_crypto::commons::parameters::LweBskGroupingFactor;
use next_tfhe::core_crypto::commons::parameters::LweBskGroupingFactor as NextLweBskGroupingFactor;
impl crate::forward_compatibility::ConvertFrom<LweBskGroupingFactor> for NextLweBskGroupingFactor {
#[inline]
fn convert_from(value: LweBskGroupingFactor) -> Self {
let LweBskGroupingFactor(field_0) = value;
NextLweBskGroupingFactor(field_0)
}
}
use crate::core_crypto::commons::parameters::GgswPerLweMultiBitBskElement;
use next_tfhe::core_crypto::commons::parameters::GgswPerLweMultiBitBskElement as NextGgswPerLweMultiBitBskElement;
impl crate::forward_compatibility::ConvertFrom<GgswPerLweMultiBitBskElement>
for NextGgswPerLweMultiBitBskElement
{
#[inline]
fn convert_from(value: GgswPerLweMultiBitBskElement) -> Self {
let GgswPerLweMultiBitBskElement(field_0) = value;
NextGgswPerLweMultiBitBskElement(field_0)
}
}
use crate::core_crypto::commons::parameters::EncryptionKeyChoice;
use next_tfhe::core_crypto::commons::parameters::EncryptionKeyChoice as NextEncryptionKeyChoice;
impl crate::forward_compatibility::ConvertFrom<EncryptionKeyChoice> for NextEncryptionKeyChoice {
#[inline]
fn convert_from(value: EncryptionKeyChoice) -> Self {
match value {
EncryptionKeyChoice::Big => NextEncryptionKeyChoice::Big,
EncryptionKeyChoice::Small => NextEncryptionKeyChoice::Small,
}
}
}
use crate::core_crypto::commons::parameters::PBSOrder;
use next_tfhe::core_crypto::commons::parameters::PBSOrder as NextPBSOrder;
impl crate::forward_compatibility::ConvertFrom<PBSOrder> for NextPBSOrder {
#[inline]
fn convert_from(value: PBSOrder) -> Self {
match value {
PBSOrder::KeyswitchBootstrap => NextPBSOrder::KeyswitchBootstrap,
PBSOrder::BootstrapKeyswitch => NextPBSOrder::BootstrapKeyswitch,
}
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_plaintext_count() {
use crate::core_crypto::commons::parameters::PlaintextCount;
use next_tfhe::core_crypto::commons::parameters::PlaintextCount as NextPlaintextCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = PlaintextCount(rng.gen());
let _next_tfhe_struct: NextPlaintextCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_cleartext_count() {
use crate::core_crypto::commons::parameters::CleartextCount;
use next_tfhe::core_crypto::commons::parameters::CleartextCount as NextCleartextCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = CleartextCount(rng.gen());
let _next_tfhe_struct: NextCleartextCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_ciphertext_count() {
use crate::core_crypto::commons::parameters::CiphertextCount;
use next_tfhe::core_crypto::commons::parameters::CiphertextCount as NextCiphertextCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = CiphertextCount(rng.gen());
let _next_tfhe_struct: NextCiphertextCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_lwe_ciphertext_count() {
use crate::core_crypto::commons::parameters::LweCiphertextCount;
use next_tfhe::core_crypto::commons::parameters::LweCiphertextCount as NextLweCiphertextCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = LweCiphertextCount(rng.gen());
let _next_tfhe_struct: NextLweCiphertextCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_glwe_ciphertext_count() {
use crate::core_crypto::commons::parameters::GlweCiphertextCount;
use next_tfhe::core_crypto::commons::parameters::GlweCiphertextCount as NextGlweCiphertextCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = GlweCiphertextCount(rng.gen());
let _next_tfhe_struct: NextGlweCiphertextCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_gsw_ciphertext_count() {
use crate::core_crypto::commons::parameters::GswCiphertextCount;
use next_tfhe::core_crypto::commons::parameters::GswCiphertextCount as NextGswCiphertextCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = GswCiphertextCount(rng.gen());
let _next_tfhe_struct: NextGswCiphertextCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_ggsw_ciphertext_count() {
use crate::core_crypto::commons::parameters::GgswCiphertextCount;
use next_tfhe::core_crypto::commons::parameters::GgswCiphertextCount as NextGgswCiphertextCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = GgswCiphertextCount(rng.gen());
let _next_tfhe_struct: NextGgswCiphertextCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_lwe_size() {
use crate::core_crypto::commons::parameters::LweSize;
use next_tfhe::core_crypto::commons::parameters::LweSize as NextLweSize;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = LweSize(rng.gen());
let _next_tfhe_struct: NextLweSize = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_lwe_dimension() {
use crate::core_crypto::commons::parameters::LweDimension;
use next_tfhe::core_crypto::commons::parameters::LweDimension as NextLweDimension;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = LweDimension(rng.gen());
let _next_tfhe_struct: NextLweDimension = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_lwe_public_key_zero_encryption_count() {
use crate::core_crypto::commons::parameters::LwePublicKeyZeroEncryptionCount;
use next_tfhe::core_crypto::commons::parameters::LwePublicKeyZeroEncryptionCount as NextLwePublicKeyZeroEncryptionCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = LwePublicKeyZeroEncryptionCount(rng.gen());
let _next_tfhe_struct: NextLwePublicKeyZeroEncryptionCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_lwe_mask_count() {
use crate::core_crypto::commons::parameters::LweMaskCount;
use next_tfhe::core_crypto::commons::parameters::LweMaskCount as NextLweMaskCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = LweMaskCount(rng.gen());
let _next_tfhe_struct: NextLweMaskCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_lwe_body_count() {
use crate::core_crypto::commons::parameters::LweBodyCount;
use next_tfhe::core_crypto::commons::parameters::LweBodyCount as NextLweBodyCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = LweBodyCount(rng.gen());
let _next_tfhe_struct: NextLweBodyCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_glwe_size() {
use crate::core_crypto::commons::parameters::GlweSize;
use next_tfhe::core_crypto::commons::parameters::GlweSize as NextGlweSize;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = GlweSize(rng.gen());
let _next_tfhe_struct: NextGlweSize = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_glwe_dimension() {
use crate::core_crypto::commons::parameters::GlweDimension;
use next_tfhe::core_crypto::commons::parameters::GlweDimension as NextGlweDimension;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = GlweDimension(rng.gen());
let _next_tfhe_struct: NextGlweDimension = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_polynomial_size() {
use crate::core_crypto::commons::parameters::PolynomialSize;
use next_tfhe::core_crypto::commons::parameters::PolynomialSize as NextPolynomialSize;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = PolynomialSize(rng.gen());
let _next_tfhe_struct: NextPolynomialSize = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_fourier_polynomial_size() {
use crate::core_crypto::commons::parameters::FourierPolynomialSize;
use next_tfhe::core_crypto::commons::parameters::FourierPolynomialSize as NextFourierPolynomialSize;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = FourierPolynomialSize(rng.gen());
let _next_tfhe_struct: NextFourierPolynomialSize = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_polynomial_size_log() {
use crate::core_crypto::commons::parameters::PolynomialSizeLog;
use next_tfhe::core_crypto::commons::parameters::PolynomialSizeLog as NextPolynomialSizeLog;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = PolynomialSizeLog(rng.gen());
let _next_tfhe_struct: NextPolynomialSizeLog = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_polynomial_count() {
use crate::core_crypto::commons::parameters::PolynomialCount;
use next_tfhe::core_crypto::commons::parameters::PolynomialCount as NextPolynomialCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = PolynomialCount(rng.gen());
let _next_tfhe_struct: NextPolynomialCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_monomial_degree() {
use crate::core_crypto::commons::parameters::MonomialDegree;
use next_tfhe::core_crypto::commons::parameters::MonomialDegree as NextMonomialDegree;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = MonomialDegree(rng.gen());
let _next_tfhe_struct: NextMonomialDegree = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_decomposition_base_log() {
use crate::core_crypto::commons::parameters::DecompositionBaseLog;
use next_tfhe::core_crypto::commons::parameters::DecompositionBaseLog as NextDecompositionBaseLog;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = DecompositionBaseLog(rng.gen());
let _next_tfhe_struct: NextDecompositionBaseLog = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_decomposition_level_count() {
use crate::core_crypto::commons::parameters::DecompositionLevelCount;
use next_tfhe::core_crypto::commons::parameters::DecompositionLevelCount as NextDecompositionLevelCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = DecompositionLevelCount(rng.gen());
let _next_tfhe_struct: NextDecompositionLevelCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_lut_count_log() {
use crate::core_crypto::commons::parameters::LutCountLog;
use next_tfhe::core_crypto::commons::parameters::LutCountLog as NextLutCountLog;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = LutCountLog(rng.gen());
let _next_tfhe_struct: NextLutCountLog = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_modulus_switch_offset() {
use crate::core_crypto::commons::parameters::ModulusSwitchOffset;
use next_tfhe::core_crypto::commons::parameters::ModulusSwitchOffset as NextModulusSwitchOffset;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = ModulusSwitchOffset(rng.gen());
let _next_tfhe_struct: NextModulusSwitchOffset = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_delta_log() {
use crate::core_crypto::commons::parameters::DeltaLog;
use next_tfhe::core_crypto::commons::parameters::DeltaLog as NextDeltaLog;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = DeltaLog(rng.gen());
let _next_tfhe_struct: NextDeltaLog = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_extracted_bits_count() {
use crate::core_crypto::commons::parameters::ExtractedBitsCount;
use next_tfhe::core_crypto::commons::parameters::ExtractedBitsCount as NextExtractedBitsCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = ExtractedBitsCount(rng.gen());
let _next_tfhe_struct: NextExtractedBitsCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_functional_packing_keyswitch_key_count() {
use crate::core_crypto::commons::parameters::FunctionalPackingKeyswitchKeyCount;
use next_tfhe::core_crypto::commons::parameters::FunctionalPackingKeyswitchKeyCount as NextFunctionalPackingKeyswitchKeyCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = FunctionalPackingKeyswitchKeyCount(rng.gen());
let _next_tfhe_struct: NextFunctionalPackingKeyswitchKeyCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_ciphertext_modulus_log() {
use crate::core_crypto::commons::parameters::CiphertextModulusLog;
use next_tfhe::core_crypto::commons::parameters::CiphertextModulusLog as NextCiphertextModulusLog;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = CiphertextModulusLog(rng.gen());
let _next_tfhe_struct: NextCiphertextModulusLog = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_thread_count() {
use crate::core_crypto::commons::parameters::ThreadCount;
use next_tfhe::core_crypto::commons::parameters::ThreadCount as NextThreadCount;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = ThreadCount(rng.gen());
let _next_tfhe_struct: NextThreadCount = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_lwe_bsk_grouping_factor() {
use crate::core_crypto::commons::parameters::LweBskGroupingFactor;
use next_tfhe::core_crypto::commons::parameters::LweBskGroupingFactor as NextLweBskGroupingFactor;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = LweBskGroupingFactor(rng.gen());
let _next_tfhe_struct: NextLweBskGroupingFactor = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_ggsw_per_lwe_multi_bit_bsk_element() {
use crate::core_crypto::commons::parameters::GgswPerLweMultiBitBskElement;
use next_tfhe::core_crypto::commons::parameters::GgswPerLweMultiBitBskElement as NextGgswPerLweMultiBitBskElement;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = GgswPerLweMultiBitBskElement(rng.gen());
let _next_tfhe_struct: NextGgswPerLweMultiBitBskElement = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_encryption_key_choice() {
use crate::core_crypto::commons::parameters::EncryptionKeyChoice;
use next_tfhe::core_crypto::commons::parameters::EncryptionKeyChoice as NextEncryptionKeyChoice;
let enum_val_big = EncryptionKeyChoice::Big;
let enum_val_small = EncryptionKeyChoice::Small;
let next_enum_val_big: NextEncryptionKeyChoice = enum_val_big.convert_into();
let next_enum_val_small: NextEncryptionKeyChoice = enum_val_small.convert_into();
assert_eq!(next_enum_val_big, NextEncryptionKeyChoice::Big);
assert_eq!(next_enum_val_small, NextEncryptionKeyChoice::Small);
}
#[test]
fn test_conversion_pbs_order() {
use crate::core_crypto::commons::parameters::PBSOrder;
use next_tfhe::core_crypto::commons::parameters::PBSOrder as NextPBSOrder;
let enum_val_pbs_ks = PBSOrder::BootstrapKeyswitch;
let enum_val_ks_pbs = PBSOrder::KeyswitchBootstrap;
let next_enum_val_pbs_ks: NextPBSOrder = enum_val_pbs_ks.convert_into();
let next_enum_val_ls_pbs: NextPBSOrder = enum_val_ks_pbs.convert_into();
assert_eq!(next_enum_val_pbs_ks, NextPBSOrder::BootstrapKeyswitch);
assert_eq!(next_enum_val_ls_pbs, NextPBSOrder::KeyswitchBootstrap);
}
}

View File

@@ -0,0 +1,34 @@
use crate::core_crypto::entities::cleartext::Cleartext;
use next_tfhe::core_crypto::entities::cleartext::Cleartext as NextCleartext;
use crate::core_crypto::commons::numeric::Numeric;
use next_tfhe::core_crypto::commons::numeric::Numeric as NextNumeric;
impl<Scalar> crate::forward_compatibility::ConvertFrom<Cleartext<Scalar>> for NextCleartext<Scalar>
where
Scalar: Numeric + NextNumeric,
{
#[inline]
fn convert_from(value: Cleartext<Scalar>) -> Self {
let Cleartext(field_0) = value;
NextCleartext(field_0)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_cleartext() {
use crate::core_crypto::entities::cleartext::Cleartext;
use next_tfhe::core_crypto::entities::cleartext::Cleartext as NextCleartext;
use rand::Rng;
let mut rng = rand::thread_rng();
let tfhe_struct = Cleartext(rng.gen::<u64>());
let _next_tfhe_struct: NextCleartext<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,61 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::entities::ggsw_ciphertext::GgswCiphertext;
use next_tfhe::core_crypto::entities::ggsw_ciphertext::GgswCiphertext as NextGgswCiphertext;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<GgswCiphertext<C>>
for NextGgswCiphertext<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: GgswCiphertext<C>) -> Self {
let glwe_size = value.glwe_size();
let polynomial_size = value.polynomial_size();
let decomp_base_log = value.decomposition_base_log();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
NextGgswCiphertext::from_container(
container,
glwe_size.convert_into(),
polynomial_size.convert_into(),
decomp_base_log.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_ggsw_ciphertext() {
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::entities::ggsw_ciphertext::GgswCiphertext;
use next_tfhe::core_crypto::entities::ggsw_ciphertext::GgswCiphertext as NextGgswCiphertext;
let glwe_size = GlweSize(2);
let polynomial_size = PolynomialSize(2048);
let decomp_base_log = DecompositionBaseLog(23);
let container = vec![0u64; glwe_size.0 * glwe_size.0 * polynomial_size.0];
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct = GgswCiphertext::from_container(
container,
glwe_size,
polynomial_size,
decomp_base_log,
ciphertext_modulus,
);
let _next_tfhe_struct: NextGgswCiphertext<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,67 @@
use crate::core_crypto::entities::ggsw_ciphertext_list::GgswCiphertextList;
use crate::forward_compatibility::ConvertInto;
use next_tfhe::core_crypto::entities::ggsw_ciphertext_list::GgswCiphertextList as NextGgswCiphertextList;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<GgswCiphertextList<C>>
for NextGgswCiphertextList<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: GgswCiphertextList<C>) -> Self {
let glwe_size = value.glwe_size();
let polynomial_size = value.polynomial_size();
let decomp_base_log = value.decomposition_base_log();
let decomp_level_count = value.decomposition_level_count();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
glwe_size.convert_into(),
polynomial_size.convert_into(),
decomp_base_log.convert_into(),
decomp_level_count.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_ggsw_ciphertext_list() {
use crate::core_crypto::entities::ggsw_ciphertext_list::GgswCiphertextList;
use next_tfhe::core_crypto::entities::ggsw_ciphertext_list::GgswCiphertextList as NextGgswCiphertextList;
use crate::core_crypto::commons::parameters::*;
let glwe_size = GlweSize(2);
let polynomial_size = PolynomialSize(2048);
let decomp_base_log = DecompositionBaseLog(23);
let decomp_level_count = DecompositionLevelCount(1);
let ciphertext_count = GgswCiphertextCount(100);
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct = GgswCiphertextList::new(
0u64,
glwe_size,
polynomial_size,
decomp_base_log,
decomp_level_count,
ciphertext_count,
ciphertext_modulus,
);
let _next_tfhe_struct: NextGgswCiphertextList<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,50 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
use crate::core_crypto::entities::glwe_ciphertext::GlweCiphertext;
use next_tfhe::core_crypto::entities::glwe_ciphertext::GlweCiphertext as NextGlweCiphertext;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<GlweCiphertext<C>>
for NextGlweCiphertext<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: GlweCiphertext<C>) -> Self {
let polynomial_size = value.polynomial_size();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
polynomial_size.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_glwe_ciphertext() {
use crate::core_crypto::entities::glwe_ciphertext::GlweCiphertext;
use next_tfhe::core_crypto::entities::glwe_ciphertext::GlweCiphertext as NextGlweCiphertext;
use crate::core_crypto::commons::parameters::*;
let polynomial_size = PolynomialSize(2048);
let glwe_size = GlweSize(2);
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct = GlweCiphertext::new(0u64, glwe_size, polynomial_size, ciphertext_modulus);
let _next_tfhe_struct: NextGlweCiphertext<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,58 @@
use crate::core_crypto::entities::glwe_ciphertext_list::GlweCiphertextList;
use crate::forward_compatibility::ConvertInto;
use next_tfhe::core_crypto::entities::glwe_ciphertext_list::GlweCiphertextList as NextGlweCiphertextList;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<GlweCiphertextList<C>>
for NextGlweCiphertextList<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: GlweCiphertextList<C>) -> Self {
let glwe_size = value.glwe_size();
let polynomial_size = value.polynomial_size();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
glwe_size.convert_into(),
polynomial_size.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_glwe_ciphertext_list() {
use crate::core_crypto::entities::glwe_ciphertext_list::GlweCiphertextList;
use next_tfhe::core_crypto::entities::glwe_ciphertext_list::GlweCiphertextList as NextGlweCiphertextList;
use crate::core_crypto::commons::parameters::*;
let polynomial_size = PolynomialSize(2048);
let glwe_size = GlweSize(2);
let glwe_ciphertext_count = GlweCiphertextCount(10);
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct = GlweCiphertextList::new(
0u64,
glwe_size,
polynomial_size,
glwe_ciphertext_count,
ciphertext_modulus,
);
let _next_tfhe_struct: NextGlweCiphertextList<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,43 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::entities::glwe_secret_key::GlweSecretKey;
use next_tfhe::core_crypto::entities::glwe_secret_key::GlweSecretKey as NextGlweSecretKey;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<GlweSecretKey<C>> for NextGlweSecretKey<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: GlweSecretKey<C>) -> Self {
let polynomial_size = value.polynomial_size();
let container = value.into_container();
Self::from_container(container, polynomial_size.convert_into())
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_glwe_secret_key() {
use crate::core_crypto::entities::glwe_secret_key::GlweSecretKey;
use next_tfhe::core_crypto::entities::glwe_secret_key::GlweSecretKey as NextGlweSecretKey;
use crate::core_crypto::commons::parameters::*;
let polynomial_size = PolynomialSize(2048);
let glwe_dimension = GlweDimension(1);
let tfhe_struct = GlweSecretKey::new_empty_key(0u64, glwe_dimension, polynomial_size);
let _next_tfhe_struct: NextGlweSecretKey<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,66 @@
use crate::core_crypto::entities::lwe_bootstrap_key::LweBootstrapKey;
use crate::forward_compatibility::ConvertInto;
use next_tfhe::core_crypto::entities::lwe_bootstrap_key::LweBootstrapKey as NextLweBootstrapKey;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LweBootstrapKey<C>>
for NextLweBootstrapKey<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LweBootstrapKey<C>) -> Self {
let glwe_size = value.glwe_size();
let polynomial_size = value.polynomial_size();
let decomp_base_log = value.decomposition_base_log();
let decomp_level_count = value.decomposition_level_count();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
glwe_size.convert_into(),
polynomial_size.convert_into(),
decomp_base_log.convert_into(),
decomp_level_count.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_bootstrap_key() {
use crate::core_crypto::entities::lwe_bootstrap_key::LweBootstrapKey;
use next_tfhe::core_crypto::entities::lwe_bootstrap_key::LweBootstrapKey as NextLweBootstrapKey;
use crate::core_crypto::commons::parameters::*;
let input_lwe_dimension = LweDimension(100);
let polynomial_size = PolynomialSize(2048);
let glwe_size = GlweSize(2);
let decomp_base_log = DecompositionBaseLog(23);
let decomp_level_count = DecompositionLevelCount(1);
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct = LweBootstrapKey::new(
0u64,
glwe_size,
polynomial_size,
decomp_base_log,
decomp_level_count,
input_lwe_dimension,
ciphertext_modulus,
);
let _next_tfhe_struct: NextLweBootstrapKey<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,42 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::entities::lwe_ciphertext::LweCiphertext;
use next_tfhe::core_crypto::entities::lwe_ciphertext::LweCiphertext as NextLweCiphertext;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LweCiphertext<C>> for NextLweCiphertext<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LweCiphertext<C>) -> Self {
let ciphertext_modulus = value.ciphertext_modulus();
let data = value.into_container();
NextLweCiphertext::from_container(data, ciphertext_modulus.convert_into())
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_ciphertext() {
use crate::core_crypto::entities::lwe_ciphertext::LweCiphertext;
use next_tfhe::core_crypto::entities::lwe_ciphertext::LweCiphertext as NextLweCiphertext;
use crate::core_crypto::commons::parameters::*;
let lwe_size = LweSize(101);
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct = LweCiphertext::new(0u64, lwe_size, ciphertext_modulus);
let _next_tfhe_struct: NextLweCiphertext<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,50 @@
use crate::core_crypto::entities::lwe_ciphertext_list::LweCiphertextList;
use crate::forward_compatibility::ConvertInto;
use next_tfhe::core_crypto::entities::lwe_ciphertext_list::LweCiphertextList as NextLweCiphertextList;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LweCiphertextList<C>>
for NextLweCiphertextList<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LweCiphertextList<C>) -> Self {
let lwe_size = value.lwe_size();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
lwe_size.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_ciphertext_list() {
use crate::core_crypto::entities::lwe_ciphertext_list::LweCiphertextList;
use next_tfhe::core_crypto::entities::lwe_ciphertext_list::LweCiphertextList as NextLweCiphertextList;
use crate::core_crypto::commons::parameters::*;
let lwe_size = LweSize(101);
let lwe_ciphertext_count = LweCiphertextCount(10);
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct =
LweCiphertextList::new(0u64, lwe_size, lwe_ciphertext_count, ciphertext_modulus);
let _next_tfhe_struct: NextLweCiphertextList<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,53 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::entities::lwe_compact_ciphertext_list::LweCompactCiphertextList;
use next_tfhe::core_crypto::entities::lwe_compact_ciphertext_list::LweCompactCiphertextList as NextLweCompactCiphertextList;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LweCompactCiphertextList<C>>
for NextLweCompactCiphertextList<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LweCompactCiphertextList<C>) -> Self {
let lwe_size = value.lwe_size();
let lwe_ciphertext_count = value.lwe_ciphertext_count();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
lwe_size.convert_into(),
lwe_ciphertext_count.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_compact_ciphertext_list() {
use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::entities::lwe_compact_ciphertext_list::LweCompactCiphertextList;
use next_tfhe::core_crypto::entities::lwe_compact_ciphertext_list::LweCompactCiphertextList as NextLweCompactCiphertextList;
let tfhe_struct = LweCompactCiphertextList::new(
0u64,
LweSize(101),
LweCiphertextCount(10),
CiphertextModulus::new_native(),
);
let _next_tfhe_struct: NextLweCompactCiphertextList<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,42 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::entities::lwe_compact_public_key::LweCompactPublicKey;
use next_tfhe::core_crypto::entities::lwe_compact_public_key::LweCompactPublicKey as NextLweCompactPublicKey;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LweCompactPublicKey<C>>
for NextLweCompactPublicKey<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LweCompactPublicKey<C>) -> Self {
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(container, ciphertext_modulus.convert_into())
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_compact_public_key() {
use crate::core_crypto::entities::lwe_compact_public_key::LweCompactPublicKey;
use next_tfhe::core_crypto::entities::lwe_compact_public_key::LweCompactPublicKey as NextLweCompactPublicKey;
use crate::core_crypto::commons::parameters::*;
let tfhe_struct =
LweCompactPublicKey::new(0u64, LweDimension(1024), CiphertextModulus::new_native());
let _next_tfhe_struct: NextLweCompactPublicKey<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,57 @@
use crate::core_crypto::entities::lwe_keyswitch_key::LweKeyswitchKey;
use crate::forward_compatibility::ConvertInto;
use next_tfhe::core_crypto::entities::lwe_keyswitch_key::LweKeyswitchKey as NextLweKeyswitchKey;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LweKeyswitchKey<C>>
for NextLweKeyswitchKey<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LweKeyswitchKey<C>) -> Self {
let decomp_base_log = value.decomposition_base_log();
let decomp_level_count = value.decomposition_level_count();
let output_lwe_size = value.output_lwe_size();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
decomp_base_log.convert_into(),
decomp_level_count.convert_into(),
output_lwe_size.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_keyswitch_key() {
use crate::core_crypto::entities::lwe_keyswitch_key::LweKeyswitchKey;
use next_tfhe::core_crypto::entities::lwe_keyswitch_key::LweKeyswitchKey as NextLweKeyswitchKey;
use crate::core_crypto::commons::parameters::*;
let tfhe_struct = LweKeyswitchKey::new(
0u64,
DecompositionBaseLog(5),
DecompositionLevelCount(3),
LweDimension(200),
LweDimension(100),
CiphertextModulus::new_native(),
);
let _next_tfhe_struct: NextLweKeyswitchKey<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,157 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::entities::lwe_multi_bit_bootstrap_key::LweMultiBitBootstrapKey;
use crate::core_crypto::fft_impl::fft64::math::fft::FourierPolynomialList;
use next_tfhe::core_crypto::entities::lwe_multi_bit_bootstrap_key::LweMultiBitBootstrapKey as NextLweMultiBitBootstrapKey;
use next_tfhe::core_crypto::fft_impl::fft64::math::fft::FourierPolynomialList as NextFourierPolynomialList;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LweMultiBitBootstrapKey<C>>
for NextLweMultiBitBootstrapKey<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LweMultiBitBootstrapKey<C>) -> Self {
let glwe_size = value.glwe_size();
let polynomial_size = value.polynomial_size();
let decomp_base_log = value.decomposition_base_log();
let decomp_level_count = value.decomposition_level_count();
let grouping_factor = value.grouping_factor();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
glwe_size.convert_into(),
polynomial_size.convert_into(),
decomp_base_log.convert_into(),
decomp_level_count.convert_into(),
grouping_factor.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
use crate::core_crypto::entities::lwe_multi_bit_bootstrap_key::FourierLweMultiBitBootstrapKey;
use next_tfhe::core_crypto::entities::lwe_multi_bit_bootstrap_key::FourierLweMultiBitBootstrapKey as NextFourierLweMultiBitBootstrapKey;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
use next_tfhe::core_crypto::fft_impl::fft64::{c64 as NextC64, ABox as NextABox};
use crate::core_crypto::commons::traits::Container;
use crate::core_crypto::fft_impl::fft64::c64;
impl<C> crate::forward_compatibility::ConvertFrom<FourierLweMultiBitBootstrapKey<C>>
for NextFourierLweMultiBitBootstrapKey<NextABox<[NextC64]>>
where
C: Container<Element = c64> + NextContainer<Element = NextC64>,
{
#[inline]
fn convert_from(value: FourierLweMultiBitBootstrapKey<C>) -> Self {
let input_lwe_dimension = value.input_lwe_dimension();
let glwe_size = value.glwe_size();
let polynomial_size = value.polynomial_size();
let decomposition_base_log = value.decomposition_base_log();
let decomposition_level_count = value.decomposition_level_count();
let grouping_factor = value.grouping_factor();
let data = value.data();
let poly_list = FourierPolynomialList {
data,
polynomial_size,
};
let next_poly_list: NextFourierPolynomialList<_> = poly_list.convert_into();
let data = next_poly_list.data;
Self::from_container(
data,
input_lwe_dimension.convert_into(),
glwe_size.convert_into(),
polynomial_size.convert_into(),
decomposition_base_log.convert_into(),
decomposition_level_count.convert_into(),
grouping_factor.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_multi_bit_bootstrap_key() {
use crate::core_crypto::entities::lwe_multi_bit_bootstrap_key::LweMultiBitBootstrapKey;
use next_tfhe::core_crypto::entities::lwe_multi_bit_bootstrap_key::LweMultiBitBootstrapKey as NextLweMultiBitBootstrapKey;
use crate::core_crypto::commons::parameters::*;
let input_lwe_dimension = LweDimension(100);
let polynomial_size = PolynomialSize(2048);
let glwe_size = GlweSize(2);
let decomp_base_log = DecompositionBaseLog(23);
let decomp_level_count = DecompositionLevelCount(1);
let grouping_factor = LweBskGroupingFactor(2);
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct = LweMultiBitBootstrapKey::new(
0u64,
glwe_size,
polynomial_size,
decomp_base_log,
decomp_level_count,
input_lwe_dimension,
grouping_factor,
ciphertext_modulus,
);
let _next_tfhe_struct: NextLweMultiBitBootstrapKey<_> = tfhe_struct.convert_into();
}
#[test]
fn test_conversion_fourier_lwe_multi_bit_bootstrap_key() {
use crate::core_crypto::entities::lwe_multi_bit_bootstrap_key::{
FourierLweMultiBitBootstrapKey, LweMultiBitBootstrapKey,
};
use next_tfhe::core_crypto::entities::lwe_multi_bit_bootstrap_key::FourierLweMultiBitBootstrapKey as NextFourierLweMultiBitBootstrapKey;
use crate::core_crypto::algorithms::par_convert_standard_lwe_multi_bit_bootstrap_key_to_fourier;
use crate::core_crypto::commons::parameters::*;
let input_lwe_dimension = LweDimension(100);
let polynomial_size = PolynomialSize(2048);
let glwe_size = GlweSize(2);
let decomp_base_log = DecompositionBaseLog(23);
let decomp_level_count = DecompositionLevelCount(1);
let grouping_factor = LweBskGroupingFactor(2);
let ciphertext_modulus = CiphertextModulus::new_native();
let bsk = LweMultiBitBootstrapKey::new(
0u64,
glwe_size,
polynomial_size,
decomp_base_log,
decomp_level_count,
input_lwe_dimension,
grouping_factor,
ciphertext_modulus,
);
let mut tfhe_struct = FourierLweMultiBitBootstrapKey::new(
bsk.input_lwe_dimension(),
bsk.glwe_size(),
bsk.polynomial_size(),
bsk.decomposition_base_log(),
bsk.decomposition_level_count(),
bsk.grouping_factor(),
);
par_convert_standard_lwe_multi_bit_bootstrap_key_to_fourier(&bsk, &mut tfhe_struct);
let _next_tfhe_struct: NextFourierLweMultiBitBootstrapKey<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,67 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::entities::lwe_packing_keyswitch_key::LwePackingKeyswitchKey;
use next_tfhe::core_crypto::entities::lwe_packing_keyswitch_key::LwePackingKeyswitchKey as NextLwePackingKeyswitchKey;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LwePackingKeyswitchKey<C>>
for NextLwePackingKeyswitchKey<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LwePackingKeyswitchKey<C>) -> Self {
let decomp_base_log = value.decomposition_base_log();
let decomp_level_count = value.decomposition_level_count();
let output_glwe_size = value.output_glwe_size();
let output_polynomial_size = value.output_polynomial_size();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
decomp_base_log.convert_into(),
decomp_level_count.convert_into(),
output_glwe_size.convert_into(),
output_polynomial_size.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_packing_keyswitch_key() {
use crate::core_crypto::entities::lwe_packing_keyswitch_key::LwePackingKeyswitchKey;
use next_tfhe::core_crypto::entities::lwe_packing_keyswitch_key::LwePackingKeyswitchKey as NextLwePackingKeyswitchKey;
use crate::core_crypto::commons::parameters::*;
let decomp_base_log = DecompositionBaseLog(23);
let decomp_level_count = DecompositionLevelCount(1);
let input_key_lwe_dimension = LweDimension(100);
let output_key_glwe_dimension = GlweDimension(2);
let output_key_polynomial_size = PolynomialSize(2048);
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct = LwePackingKeyswitchKey::new(
0u64,
decomp_base_log,
decomp_level_count,
input_key_lwe_dimension,
output_key_glwe_dimension,
output_key_polynomial_size,
ciphertext_modulus,
);
let _next_tfhe_struct: NextLwePackingKeyswitchKey<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,69 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::entities::lwe_private_functional_packing_keyswitch_key::LwePrivateFunctionalPackingKeyswitchKey;
use next_tfhe::core_crypto::entities::lwe_private_functional_packing_keyswitch_key::LwePrivateFunctionalPackingKeyswitchKey as NextLwePrivateFunctionalPackingKeyswitchKey;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C>
crate::forward_compatibility::ConvertFrom<LwePrivateFunctionalPackingKeyswitchKey<C>>
for NextLwePrivateFunctionalPackingKeyswitchKey<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LwePrivateFunctionalPackingKeyswitchKey<C>) -> Self {
let decomp_base_log = value.decomposition_base_log();
let decomp_level_count = value.decomposition_level_count();
let output_glwe_size = value.output_glwe_size();
let output_polynomial_size = value.output_polynomial_size();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
decomp_base_log.convert_into(),
decomp_level_count.convert_into(),
output_glwe_size.convert_into(),
output_polynomial_size.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_private_functional_packing_keyswitch_key() {
use crate::core_crypto::entities::lwe_private_functional_packing_keyswitch_key::LwePrivateFunctionalPackingKeyswitchKey;
use next_tfhe::core_crypto::entities::lwe_private_functional_packing_keyswitch_key::LwePrivateFunctionalPackingKeyswitchKey as NextLwePrivateFunctionalPackingKeyswitchKey;
use crate::core_crypto::commons::parameters::*;
let decomp_base_log = DecompositionBaseLog(23);
let decomp_level_count = DecompositionLevelCount(1);
let input_key_lwe_dimension = LweDimension(100);
let output_key_glwe_size = GlweSize(2);
let output_key_polynomial_size = PolynomialSize(2048);
let ciphertext_modulus = CiphertextModulus::new_native();
let tfhe_struct = LwePrivateFunctionalPackingKeyswitchKey::new(
0u64,
decomp_base_log,
decomp_level_count,
input_key_lwe_dimension,
output_key_glwe_size,
output_key_polynomial_size,
ciphertext_modulus,
);
let _next_tfhe_struct: NextLwePrivateFunctionalPackingKeyswitchKey<_> =
tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,65 @@
use crate::core_crypto::entities::lwe_private_functional_packing_keyswitch_key_list::LwePrivateFunctionalPackingKeyswitchKeyList;
use crate::forward_compatibility::ConvertInto;
use next_tfhe::core_crypto::entities::lwe_private_functional_packing_keyswitch_key_list::LwePrivateFunctionalPackingKeyswitchKeyList as NextLwePrivateFunctionalPackingKeyswitchKeyList;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C>
crate::forward_compatibility::ConvertFrom<LwePrivateFunctionalPackingKeyswitchKeyList<C>>
for NextLwePrivateFunctionalPackingKeyswitchKeyList<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LwePrivateFunctionalPackingKeyswitchKeyList<C>) -> Self {
let decomp_base_log = value.decomposition_base_log();
let decomp_level_count = value.decomposition_level_count();
let input_lwe_size = value.input_lwe_size();
let output_glwe_size = value.output_glwe_size();
let output_polynomial_size = value.output_polynomial_size();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
decomp_base_log.convert_into(),
decomp_level_count.convert_into(),
input_lwe_size.convert_into(),
output_glwe_size.convert_into(),
output_polynomial_size.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_private_functional_packing_keyswitch_key_list() {
use crate::core_crypto::entities::lwe_private_functional_packing_keyswitch_key_list::LwePrivateFunctionalPackingKeyswitchKeyList;
use next_tfhe::core_crypto::entities::lwe_private_functional_packing_keyswitch_key_list::LwePrivateFunctionalPackingKeyswitchKeyList as NextLwePrivateFunctionalPackingKeyswitchKeyList;
use crate::core_crypto::commons::parameters::*;
let tfhe_struct = LwePrivateFunctionalPackingKeyswitchKeyList::new(
0u64,
DecompositionBaseLog(12),
DecompositionLevelCount(2),
LweDimension(100),
GlweSize(2),
PolynomialSize(1024),
FunctionalPackingKeyswitchKeyCount(2),
CiphertextModulus::new_native(),
);
let _next_tfhe_struct: NextLwePrivateFunctionalPackingKeyswitchKeyList<_> =
tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,50 @@
use crate::forward_compatibility::ConvertInto;
use crate::core_crypto::entities::lwe_public_key::LwePublicKey;
use next_tfhe::core_crypto::entities::lwe_public_key::LwePublicKey as NextLwePublicKey;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LwePublicKey<C>> for NextLwePublicKey<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LwePublicKey<C>) -> Self {
let lwe_size = value.lwe_size();
let ciphertext_modulus = value.ciphertext_modulus();
let container = value.into_container();
Self::from_container(
container,
lwe_size.convert_into(),
ciphertext_modulus.convert_into(),
)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_public_key() {
use crate::core_crypto::entities::lwe_public_key::LwePublicKey;
use next_tfhe::core_crypto::entities::lwe_public_key::LwePublicKey as NextLwePublicKey;
use crate::core_crypto::commons::parameters::*;
let tfhe_struct = LwePublicKey::new(
0u64,
LweSize(101),
LwePublicKeyZeroEncryptionCount(10),
CiphertextModulus::new_native(),
);
let _next_tfhe_struct: NextLwePublicKey<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,38 @@
use crate::core_crypto::entities::lwe_secret_key::LweSecretKey;
use next_tfhe::core_crypto::entities::lwe_secret_key::LweSecretKey as NextLweSecretKey;
use crate::core_crypto::commons::numeric::UnsignedInteger;
use crate::core_crypto::commons::traits::Container;
use next_tfhe::core_crypto::commons::numeric::UnsignedInteger as NextUnsignedInteger;
use next_tfhe::core_crypto::commons::traits::Container as NextContainer;
impl<Scalar, C> crate::forward_compatibility::ConvertFrom<LweSecretKey<C>> for NextLweSecretKey<C>
where
Scalar: UnsignedInteger + NextUnsignedInteger,
C: Container<Element = Scalar> + NextContainer<Element = Scalar>,
{
#[inline]
fn convert_from(value: LweSecretKey<C>) -> Self {
let container = value.into_container();
Self::from_container(container)
}
}
#[cfg(test)]
mod test {
use crate::forward_compatibility::ConvertInto;
#[test]
fn test_conversion_lwe_secret_key() {
use crate::core_crypto::entities::lwe_secret_key::LweSecretKey;
use next_tfhe::core_crypto::entities::lwe_secret_key::LweSecretKey as NextLweSecretKey;
use crate::core_crypto::commons::parameters::*;
let tfhe_struct = LweSecretKey::new_empty_key(0u64, LweDimension(100));
let _next_tfhe_struct: NextLweSecretKey<_> = tfhe_struct.convert_into();
}
}

View File

@@ -0,0 +1,34 @@
pub mod cleartext;
pub mod ggsw_ciphertext;
pub mod ggsw_ciphertext_list;
pub mod glwe_ciphertext;
pub mod glwe_ciphertext_list;
pub mod glwe_secret_key;
pub mod lwe_bootstrap_key;
pub mod lwe_ciphertext;
pub mod lwe_ciphertext_list;
pub mod lwe_compact_ciphertext_list;
pub mod lwe_compact_public_key;
pub mod lwe_keyswitch_key;
pub mod lwe_multi_bit_bootstrap_key;
pub mod lwe_packing_keyswitch_key;
pub mod lwe_private_functional_packing_keyswitch_key;
pub mod lwe_private_functional_packing_keyswitch_key_list;
pub mod lwe_public_key;
pub mod lwe_secret_key;
pub mod plaintext;
pub mod plaintext_list;
pub mod polynomial;
pub mod polynomial_list;
pub mod seeded_ggsw_ciphertext;
pub mod seeded_ggsw_ciphertext_list;
pub mod seeded_glwe_ciphertext;
pub mod seeded_glwe_ciphertext_list;
pub mod seeded_lwe_bootstrap_key;
pub mod seeded_lwe_ciphertext;
pub mod seeded_lwe_ciphertext_list;
pub mod seeded_lwe_compact_public_key;
pub mod seeded_lwe_keyswitch_key;
pub mod seeded_lwe_multi_bit_bootstrap_key;
pub mod seeded_lwe_packing_keyswitch_key;
pub mod seeded_lwe_public_key;

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