mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-11 07:38:08 -05:00
Compare commits
25 Commits
tfhe-rs-0.
...
tmp_ccs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03635afa8f | ||
|
|
4c659b5c70 | ||
|
|
b80e09f9d2 | ||
|
|
aae5b45047 | ||
|
|
c0240af4ca | ||
|
|
0578c2ab1d | ||
|
|
d1abdc081d | ||
|
|
44ff195704 | ||
|
|
1fb65f1f6e | ||
|
|
e1f54981bf | ||
|
|
621cbcb14a | ||
|
|
0898268733 | ||
|
|
6ec7f7e405 | ||
|
|
16ad67ace3 | ||
|
|
c949256323 | ||
|
|
7ae5f65909 | ||
|
|
4a2e9e5064 | ||
|
|
3ae27e79d0 | ||
|
|
2332f89aa0 | ||
|
|
3f9603a75c | ||
|
|
848cc37300 | ||
|
|
2f4d00b13a | ||
|
|
2f295ea467 | ||
|
|
fa54a02c01 | ||
|
|
646b644728 |
4
.github/workflows/aws_tfhe_fast_tests.yml
vendored
4
.github/workflows/aws_tfhe_fast_tests.yml
vendored
@@ -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
|
||||
|
||||
4
.github/workflows/aws_tfhe_tests.yml
vendored
4
.github/workflows/aws_tfhe_tests.yml
vendored
@@ -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
|
||||
|
||||
12
.github/workflows/pbs_benchmark.yml
vendored
12
.github/workflows/pbs_benchmark.yml
vendored
@@ -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
189
Makefile
@@ -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
84
README_CCS.md
Normal 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.
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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::
|
||||
|
||||
@@ -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::
|
||||
|
||||
90
scripts/symlink_c_libs_without_fingerprint.sh
Executable file
90
scripts/symlink_c_libs_without_fingerprint.sh
Executable 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
|
||||
@@ -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 {
|
||||
|
||||
110
tfhe/Cargo.toml
110
tfhe/Cargo.toml
@@ -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"
|
||||
|
||||
445
tfhe/benches/core_crypto/ccs_2024_cjp.rs
Normal file
445
tfhe/benches/core_crypto/ccs_2024_cjp.rs
Normal 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);
|
||||
// }
|
||||
// }
|
||||
581
tfhe/benches/core_crypto/ccs_2024_fft_shrinking_ks.rs
Normal file
581
tfhe/benches/core_crypto/ccs_2024_fft_shrinking_ks.rs
Normal 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);
|
||||
575
tfhe/benches/core_crypto/ccs_2024_stair_ks.rs
Normal file
575
tfhe/benches/core_crypto/ccs_2024_stair_ks.rs
Normal 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);
|
||||
@@ -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));
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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()
|
||||
|
||||
68
tfhe/c_api_tests/test_c_doc.c
Normal file
68
tfhe/c_api_tests/test_c_doc.c
Normal 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;
|
||||
}
|
||||
120
tfhe/c_api_tests/test_forward_compatibility.c
Normal file
120
tfhe/c_api_tests/test_forward_compatibility.c
Normal 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;
|
||||
}
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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" %}
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
```
|
||||
|
||||
142
tfhe/docs/how_to/migrate_data.md
Normal file
142
tfhe/docs/how_to/migrate_data.md
Normal 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.
|
||||
@@ -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"
|
||||
```
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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 {
|
||||
|
||||
43
tfhe/js_on_wasm_tests/test-hlapi-panic.js
Normal file
43
tfhe/js_on_wasm_tests/test-hlapi-panic.js
Normal 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);
|
||||
}
|
||||
});
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))));
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
///
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
234
tfhe/src/core_crypto/algorithms/lwe_fast_keyswitch.rs
Normal file
234
tfhe/src/core_crypto/algorithms/lwe_fast_keyswitch.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
// // // }
|
||||
@@ -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
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
150
tfhe/src/core_crypto/algorithms/lwe_shrinking_keyswitch.rs
Normal file
150
tfhe/src/core_crypto/algorithms/lwe_shrinking_keyswitch.rs
Normal 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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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::*;
|
||||
|
||||
74
tfhe/src/core_crypto/algorithms/pseudo_ggsw_conversion.rs
Normal file
74
tfhe/src/core_crypto/algorithms/pseudo_ggsw_conversion.rs
Normal 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)
|
||||
}
|
||||
191
tfhe/src/core_crypto/algorithms/pseudo_ggsw_encryption.rs
Normal file
191
tfhe/src/core_crypto/algorithms/pseudo_ggsw_encryption.rs
Normal 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);
|
||||
}
|
||||
617
tfhe/src/core_crypto/algorithms/test/lwe_fast_keyswitch.rs
Normal file
617
tfhe/src/core_crypto/algorithms/test/lwe_fast_keyswitch.rs
Normal 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
|
||||
});
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
|
||||
495
tfhe/src/core_crypto/algorithms/test/lwe_stair_keyswitch.rs
Normal file
495
tfhe/src/core_crypto/algorithms/test/lwe_stair_keyswitch.rs
Normal 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
|
||||
});
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
266
tfhe/src/core_crypto/entities/lwe_shrinking_keyswitch_key.rs
Normal file
266
tfhe/src/core_crypto/entities/lwe_shrinking_keyswitch_key.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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::*;
|
||||
|
||||
571
tfhe/src/core_crypto/entities/pseudo_ggsw_ciphertext.rs
Normal file
571
tfhe/src/core_crypto/entities/pseudo_ggsw_ciphertext.rs
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod bootstrap;
|
||||
pub mod ggsw;
|
||||
pub mod pseudo_ggsw;
|
||||
pub mod wop_pbs;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
501
tfhe/src/core_crypto/fft_impl/fft64/crypto/pseudo_ggsw.rs
Normal file
501
tfhe/src/core_crypto/fft_impl/fft64/crypto/pseudo_ggsw.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
64
tfhe/src/forward_compatibility/boolean/ciphertext/mod.rs
Normal file
64
tfhe/src/forward_compatibility/boolean/ciphertext/mod.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
33
tfhe/src/forward_compatibility/boolean/client_key/mod.rs
Normal file
33
tfhe/src/forward_compatibility/boolean/client_key/mod.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
1
tfhe/src/forward_compatibility/boolean/engine/mod.rs
Normal file
1
tfhe/src/forward_compatibility/boolean/engine/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod bootstrapping;
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
6
tfhe/src/forward_compatibility/boolean/mod.rs
Normal file
6
tfhe/src/forward_compatibility/boolean/mod.rs
Normal 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;
|
||||
104
tfhe/src/forward_compatibility/boolean/parameters/mod.rs
Normal file
104
tfhe/src/forward_compatibility/boolean/parameters/mod.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
65
tfhe/src/forward_compatibility/boolean/public_key/mod.rs
Normal file
65
tfhe/src/forward_compatibility/boolean/public_key/mod.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod random;
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod ciphertext_modulus;
|
||||
pub mod dispersion;
|
||||
pub mod math;
|
||||
pub mod parameters;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
34
tfhe/src/forward_compatibility/core_crypto/entities/mod.rs
Normal file
34
tfhe/src/forward_compatibility/core_crypto/entities/mod.rs
Normal 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
Reference in New Issue
Block a user