Compare commits

..

6 Commits

Author SHA1 Message Date
Thomas Montaigu
6e7ff77932 chore(pr): address some comments 2026-01-08 15:51:29 +01:00
Thomas Montaigu
40e96d4c84 chore(ci): add dedicatd param-prod run 2026-01-06 15:59:32 +01:00
Thomas Montaigu
aaec3fd109 chore(hlapi): set ks32 params as default
Notable changes:

- PublicKey::parameters, and CompressedPublicKey::parameters now returns
  ShortintParameterSet and not ClassicPBSParameters, to fix compatibility with KS32
- CompactCiphertextListExpansionKind::NoCasting changed to store an
  AtomicPatternKind, to allow correct expansion of compact list when
  using KS32 params
2026-01-06 14:38:27 +01:00
Thomas Montaigu
9bcc3507a7 chore(integer): add ks32 to test params 2026-01-06 14:38:27 +01:00
Arthur Meyre
d08a7eb097 chore(shortint): add prod params to tests in shortint
- special case the filter to manage prod parameters with a single flag
2026-01-06 14:38:26 +01:00
Arthur Meyre
ef044fca9c chore: remove integer test filter which is not relevant anymore 2026-01-06 14:38:26 +01:00
122 changed files with 1288 additions and 2134 deletions

View File

@@ -2,8 +2,6 @@
ignore = [
# Ignoring unmaintained 'paste' advisory as it is a widely used, low-risk build dependency.
"RUSTSEC-2024-0436",
# Ignoring unmaintained 'bincode' crate. Getting rid of it would be too complex on the short term.
"RUSTSEC-2025-0141",
]
[output]

View File

@@ -23,8 +23,6 @@ runs:
echo "${CMAKE_SCRIPT_SHA} cmake-${CMAKE_VERSION}-linux-x86_64.sh" > checksum
sha256sum -c checksum
sudo bash cmake-"${CMAKE_VERSION}"-linux-x86_64.sh --skip-license --prefix=/usr/ --exclude-subdir
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
sudo apt update
sudo apt remove -y unattended-upgrades
sudo apt install -y cmake-format libclang-dev

View File

@@ -80,7 +80,7 @@ jobs:
- name: Retrieve data from cache
id: retrieve-data-cache
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb #v5.0.1
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0
with:
path: |
utils/tfhe-backward-compat-data/**/*.cbor
@@ -109,7 +109,7 @@ jobs:
- name: Store data in cache
if: steps.retrieve-data-cache.outputs.cache-hit != 'true'
continue-on-error: true
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb #v5.0.1
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0
with:
path: |
utils/tfhe-backward-compat-data/**/*.cbor

View File

@@ -219,7 +219,7 @@ jobs:
- name: Node cache restoration
id: node-cache
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb #v5.0.1
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0
with:
path: |
~/.nvm
@@ -232,7 +232,7 @@ jobs:
make install_node
- name: Node cache save
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb #v5.0.1
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0
if: steps.node-cache.outputs.cache-hit != 'true'
with:
path: |

View File

@@ -0,0 +1,213 @@
# Run a small subset of tests to ensure quick feedback.
name: aws_tfhe_param_prod_tests
env:
CARGO_TERM_COLOR: always
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
RUSTFLAGS: "-C target-cpu=native"
RUST_BACKTRACE: "full"
RUST_MIN_STACK: "8388608"
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACKIFY_MARKDOWN: true
IS_PULL_REQUEST: ${{ github.event_name == 'pull_request' }}
PULL_REQUEST_MD_LINK: ""
CHECKOUT_TOKEN: ${{ secrets.REPO_CHECKOUT_TOKEN || secrets.GITHUB_TOKEN }}
# Secrets will be available only to zama-ai organization members
SECRETS_AVAILABLE: ${{ secrets.JOB_SECRET != '' }}
EXTERNAL_CONTRIBUTION_RUNNER: "large_ubuntu_64-22.04"
on:
# Allows you to run this workflow manually from the Actions tab as an alternative.
workflow_dispatch:
pull_request:
types: [ labeled ]
permissions:
contents: read
# zizmor: ignore[concurrency-limits] concurrency is managed after instance setup to ensure safe provisioning
jobs:
should-run:
name: aws_tfhe_param_prod_tests/should-run
if: (github.event_name == 'pull_request' && contains(github.event.label.name, 'approved')) || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
pull-requests: read # Needed to check for file change
outputs:
csprng_test: ${{ env.IS_PULL_REQUEST == 'false' || steps.changed-files.outputs.csprng_any_changed }}
zk_pok_test: ${{ env.IS_PULL_REQUEST == 'false' || steps.changed-files.outputs.zk_pok_any_changed }}
versionable_test: ${{ env.IS_PULL_REQUEST == 'false' || steps.changed-files.outputs.versionable_any_changed }}
shortint_test: ${{ env.IS_PULL_REQUEST == 'false' ||
steps.changed-files.outputs.shortint_any_changed ||
steps.changed-files.outputs.dependencies_any_changed }}
integer_test: ${{ env.IS_PULL_REQUEST == 'false' ||
steps.changed-files.outputs.integer_any_changed ||
steps.changed-files.outputs.dependencies_any_changed }}
high_level_api_test: ${{ env.IS_PULL_REQUEST == 'false' ||
steps.changed-files.outputs.high_level_api_any_changed ||
steps.changed-files.outputs.dependencies_any_changed }}
any_file_changed: ${{ env.IS_PULL_REQUEST == 'false' || steps.aggregated-changes.outputs.any_changed }}
steps:
- name: Checkout tfhe-rs
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
with:
fetch-depth: 0
persist-credentials: 'false'
token: ${{ env.CHECKOUT_TOKEN }}
- name: Check for file changes
id: changed-files
uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47.0.0
with:
files_yaml: |
dependencies:
- tfhe/Cargo.toml
- tfhe-csprng/**
- tfhe-fft/**
- tfhe-zk-pok/**
- utils/tfhe-versionable/**
- utils/tfhe-versionable-derive/**
versionable:
- utils/tfhe-versionable/**
- utils/tfhe-versionable-derive/**
shortint:
- tfhe/src/core_crypto/**
- tfhe/src/shortint/**
integer:
- tfhe/src/core_crypto/**
- tfhe/src/shortint/**
- tfhe/src/integer/**
high_level_api:
- tfhe/src/**
- '!tfhe/src/c_api/**'
- '!tfhe/src/boolean/**'
- '!tfhe/src/c_api/**'
- '!tfhe/src/js_on_wasm_api/**'
- name: Aggregate file changes
id: aggregated-changes
if: ( steps.changed-files.outputs.dependencies_any_changed == 'true' ||
steps.changed-files.outputs.csprng_any_changed == 'true' ||
steps.changed-files.outputs.zk_pok_any_changed == 'true' ||
steps.changed-files.outputs.versionable_any_changed == 'true' ||
steps.changed-files.outputs.core_crypto_any_changed == 'true' ||
steps.changed-files.outputs.boolean_any_changed == 'true' ||
steps.changed-files.outputs.shortint_any_changed == 'true' ||
steps.changed-files.outputs.integer_any_changed == 'true' ||
steps.changed-files.outputs.wasm_any_changed == 'true' ||
steps.changed-files.outputs.high_level_api_any_changed == 'true' ||
steps.changed-files.outputs.user_docs_any_changed == 'true')
run: |
echo "any_changed=true" >> "$GITHUB_OUTPUT"
setup-instance:
name: aws_tfhe_param_prod_tests/setup-instance
if: github.event_name == 'workflow_dispatch' ||
(github.event_name != 'workflow_dispatch' && needs.should-run.outputs.any_file_changed == 'true')
needs: should-run
runs-on: ubuntu-latest
outputs:
runner-name: ${{ steps.start-remote-instance.outputs.label || steps.start-github-instance.outputs.runner_group }}
steps:
- name: Start remote instance
id: start-remote-instance
if: env.SECRETS_AVAILABLE == 'true'
uses: zama-ai/slab-github-runner@973c1d22702de8d0acd2b34e83404c96ed92c264 # v1.4.2
with:
mode: start
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
backend: aws
profile: cpu-big
# This instance will be spawned especially for pull-request from forked repository
- name: Start GitHub instance
id: start-github-instance
if: env.SECRETS_AVAILABLE == 'false'
run: |
echo "runner_group=${EXTERNAL_CONTRIBUTION_RUNNER}" >> "$GITHUB_OUTPUT"
param-prod-tests:
name: aws_tfhe_param_prod_tests/param-prod-tests
needs: [ should-run, setup-instance ]
concurrency:
group: ${{ github.workflow_ref }}
cancel-in-progress: true
runs-on: ${{ needs.setup-instance.outputs.runner-name }}
steps:
- name: Checkout tfhe-rs
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
with:
persist-credentials: 'false'
token: ${{ env.CHECKOUT_TOKEN }}
- name: Install latest stable
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # zizmor: ignore[stale-action-refs] this action doesn't create releases
with:
toolchain: stable
- name: Gen Keys if required
if: needs.should-run.outputs.shortint_test == 'true' ||
needs.should-run.outputs.integer_test == 'true'
run: |
make gen_key_cache
- name: Run shortint tests
if: needs.should-run.outputs.shortint_test == 'true'
run: |
BIG_TESTS_INSTANCE=TRUE FAST_TESTS=FALSE make test_param_prod_shortint_ci
- name: Run integer tests
if: needs.should-run.outputs.integer_test == 'true'
run: |
BIG_TESTS_INSTANCE=TRUE FAST_TESTS=FALSE make test_param_prod_integer_ci
- name: Run high-level API tests
if: needs.should-run.outputs.high_level_api_test == 'true'
run: |
make test_high_level_api
- name: Set pull-request URL
if: ${{ failure() && github.event_name == 'pull_request' }}
run: |
echo "PULL_REQUEST_MD_LINK=[pull-request](${PR_BASE_URL}${PR_NUMBER}), " >> "${GITHUB_ENV}"
env:
PR_BASE_URL: ${{ vars.PR_BASE_URL }}
PR_NUMBER: ${{ github.event.pull_request.number }}
- name: Slack Notification
if: ${{ failure() && env.SECRETS_AVAILABLE == 'true' }}
continue-on-error: true
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661
env:
SLACK_COLOR: ${{ job.status }}
SLACK_MESSAGE: "Fast AWS tests finished with status: ${{ job.status }}. (${{ env.PULL_REQUEST_MD_LINK }}[action run](${{ env.ACTION_RUN_URL }}))"
teardown-instance:
name: aws_tfhe_param_prod_tests/teardown-instance
if: ${{ always() && needs.setup-instance.result == 'success' }}
needs: [ setup-instance, param-prod-tests ]
runs-on: ubuntu-latest
steps:
- name: Stop remote instance
id: stop-instance
if: env.SECRETS_AVAILABLE == 'true'
uses: zama-ai/slab-github-runner@973c1d22702de8d0acd2b34e83404c96ed92c264 # v1.4.2
with:
mode: stop
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
label: ${{ needs.setup-instance.outputs.runner-name }}
- name: Slack Notification
if: ${{ failure() || (cancelled() && github.event_name != 'pull_request') }}
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661
env:
SLACK_COLOR: ${{ job.status }}
SLACK_MESSAGE: "Instance teardown (param-prod-tests) finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"

View File

@@ -80,7 +80,7 @@ jobs:
- name: Node cache restoration
id: node-cache
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb #v5.0.1
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0
with:
path: |
~/.nvm
@@ -93,7 +93,7 @@ jobs:
make install_node
- name: Node cache save
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb #v5.0.1
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0
if: steps.node-cache.outputs.cache-hit != 'true'
with:
path: |

View File

@@ -195,7 +195,7 @@ jobs:
uses: foundry-rs/foundry-toolchain@8b0419c685ef46cb79ec93fbdc131174afceb730
- name: Cache cargo
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: |
~/.cargo/registry

View File

@@ -119,7 +119,7 @@ jobs:
- name: Node cache restoration
id: node-cache
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb #v5.0.1
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0
with:
path: |
~/.nvm
@@ -132,7 +132,7 @@ jobs:
make install_node
- name: Node cache save
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb #v5.0.1
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0
if: steps.node-cache.outputs.cache-hit != 'true'
with:
path: |
@@ -153,12 +153,6 @@ jobs:
env:
BROWSER: ${{ matrix.browser }}
- name: Run benchmarks (unsafe coop)
run: |
make bench_web_js_api_unsafe_coop_"${BROWSER}"_ci
env:
BROWSER: ${{ matrix.browser }}
- name: Parse results
run: |
make parse_wasm_benchmarks

1
.gitignore vendored
View File

@@ -10,7 +10,6 @@ target/
**/*.rmeta
**/Cargo.lock
**/*.bin
**/.DS_Store
# Some of our bench outputs
/tfhe/benchmarks_parameters

View File

@@ -11,7 +11,7 @@
/tfhe/src/core_crypto/gpu @agnesLeroy
/tfhe/src/core_crypto/hpu @zama-ai/hardware
/tfhe/src/shortint/ @mayeul-zama @nsarlin-zama
/tfhe/src/shortint/ @mayeul-zama
/tfhe/src/integer/ @tmontaigu
/tfhe/src/integer/gpu @agnesLeroy
@@ -19,12 +19,8 @@
/tfhe/src/high_level_api/ @tmontaigu
/tfhe-zk-pok/ @nsarlin-zama
/tfhe-benchmark/ @soonum
/utils/ @nsarlin-zama
/Makefile @IceTDrinker @soonum
/mockups/tfhe-hpu-mockup @zama-ai/hardware

View File

@@ -36,7 +36,6 @@ rayon = "1.11"
serde = { version = "1.0", default-features = false }
wasm-bindgen = "0.2.101"
getrandom = "0.2.8"
# The project maintainers consider that this is the last version of the 1.3 branch, any newer version should not be trusted
bincode = "=1.3.3"
[profile.bench]

View File

@@ -905,6 +905,14 @@ test_shortint_ci: install_cargo_nextest
./scripts/shortint-tests.sh \
--cargo-profile "$(CARGO_PROFILE)" --tfhe-package "tfhe"
.PHONY: test_param_prod_shortint_ci # Run the tests for shortint ci
test_param_prod_shortint_ci: install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
./scripts/shortint-tests.sh \
--cargo-profile "$(CARGO_PROFILE)" --run-prod-only --tfhe-package "tfhe"
.PHONY: test_shortint_multi_bit_ci # Run the tests for shortint ci running only multibit tests
test_shortint_multi_bit_ci: install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
@@ -934,6 +942,15 @@ test_integer_ci: install_cargo_nextest
--cargo-profile "$(CARGO_PROFILE)" --avx512-support "$(AVX512_SUPPORT)" \
--tfhe-package "tfhe"
.PHONY: test_param_prod_integer_ci # Run the tests for integer ci
test_param_prod_integer_ci: install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
FAST_TESTS="$(FAST_TESTS)" \
NIGHTLY_TESTS="$(NIGHTLY_TESTS)" \
./scripts/integer-tests.sh \
--cargo-profile "$(CARGO_PROFILE)" --avx512-support "$(AVX512_SUPPORT)" \
--run-prod-only --tfhe-package "tfhe"
.PHONY: test_unsigned_integer_ci # Run the tests for unsigned integer ci
test_unsigned_integer_ci: install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
@@ -1300,14 +1317,13 @@ run_web_js_api_parallel: build_web_js_api_parallel setup_venv
--browser-path $(browser_path) \
--driver-path $(driver_path) \
--browser-kind $(browser_kind) \
--server-cmd $(server_cmd) \
--server-cmd "npm run server" \
--server-workdir "$(WEB_SERVER_DIR)" \
--id-pattern $(filter)
test_web_js_api_parallel_chrome: browser_path = "$(WEB_RUNNER_DIR)/chrome/chrome-linux64/chrome"
test_web_js_api_parallel_chrome: driver_path = "$(WEB_RUNNER_DIR)/chrome/chromedriver-linux64/chromedriver"
test_web_js_api_parallel_chrome: browser_kind = chrome
test_web_js_api_parallel_chrome: server_cmd = "npm run server:multithreaded"
test_web_js_api_parallel_chrome: filter = Test
.PHONY: test_web_js_api_parallel_chrome # Run tests for the web wasm api on Chrome
@@ -1323,7 +1339,6 @@ test_web_js_api_parallel_chrome_ci: setup_venv
test_web_js_api_parallel_firefox: browser_path = "$(WEB_RUNNER_DIR)/firefox/firefox/firefox"
test_web_js_api_parallel_firefox: driver_path = "$(WEB_RUNNER_DIR)/firefox/geckodriver"
test_web_js_api_parallel_firefox: browser_kind = firefox
test_web_js_api_parallel_firefox: server_cmd = "npm run server:multithreaded"
test_web_js_api_parallel_firefox: filter = Test
.PHONY: test_web_js_api_parallel_firefox # Run tests for the web wasm api on Firefox
@@ -1573,7 +1588,6 @@ bench_pbs128_gpu: install_rs_check_toolchain
bench_web_js_api_parallel_chrome: browser_path = "$(WEB_RUNNER_DIR)/chrome/chrome-linux64/chrome"
bench_web_js_api_parallel_chrome: driver_path = "$(WEB_RUNNER_DIR)/chrome/chromedriver-linux64/chromedriver"
bench_web_js_api_parallel_chrome: browser_kind = chrome
bench_web_js_api_parallel_chrome: server_cmd = "npm run server:multithreaded"
bench_web_js_api_parallel_chrome: filter = Bench
.PHONY: bench_web_js_api_parallel_chrome # Run benchmarks for the web wasm api
@@ -1589,7 +1603,6 @@ bench_web_js_api_parallel_chrome_ci: setup_venv
bench_web_js_api_parallel_firefox: browser_path = "$(WEB_RUNNER_DIR)/firefox/firefox/firefox"
bench_web_js_api_parallel_firefox: driver_path = "$(WEB_RUNNER_DIR)/firefox/geckodriver"
bench_web_js_api_parallel_firefox: browser_kind = firefox
bench_web_js_api_parallel_firefox: server_cmd = "npm run server:multithreaded"
bench_web_js_api_parallel_firefox: filter = Bench
.PHONY: bench_web_js_api_parallel_firefox # Run benchmarks for the web wasm api
@@ -1602,38 +1615,6 @@ bench_web_js_api_parallel_firefox_ci: setup_venv
nvm use $(NODE_VERSION) && \
$(MAKE) bench_web_js_api_parallel_firefox
bench_web_js_api_unsafe_coop_chrome: browser_path = "$(WEB_RUNNER_DIR)/chrome/chrome-linux64/chrome"
bench_web_js_api_unsafe_coop_chrome: driver_path = "$(WEB_RUNNER_DIR)/chrome/chromedriver-linux64/chromedriver"
bench_web_js_api_unsafe_coop_chrome: browser_kind = chrome
bench_web_js_api_unsafe_coop_chrome: server_cmd = "npm run server:unsafe-coop"
bench_web_js_api_unsafe_coop_chrome: filter = ZeroKnowledgeBench # Only bench zk with unsafe coop
.PHONY: bench_web_js_api_unsafe_coop_chrome # Run benchmarks for the web wasm api without cross-origin isolation
bench_web_js_api_unsafe_coop_chrome: run_web_js_api_parallel
.PHONY: bench_web_js_api_unsafe_coop_chrome_ci # Run benchmarks for the web wasm api without cross-origin isolation
bench_web_js_api_unsafe_coop_chrome_ci: setup_venv
source ~/.nvm/nvm.sh && \
nvm install $(NODE_VERSION) && \
nvm use $(NODE_VERSION) && \
$(MAKE) bench_web_js_api_unsafe_coop_chrome
bench_web_js_api_unsafe_coop_firefox: browser_path = "$(WEB_RUNNER_DIR)/firefox/firefox/firefox"
bench_web_js_api_unsafe_coop_firefox: driver_path = "$(WEB_RUNNER_DIR)/firefox/geckodriver"
bench_web_js_api_unsafe_coop_firefox: browser_kind = firefox
bench_web_js_api_unsafe_coop_firefox: server_cmd = "npm run server:unsafe-coop"
bench_web_js_api_unsafe_coop_firefox: filter = ZeroKnowledgeBench # Only bench zk with unsafe coop
.PHONY: bench_web_js_api_unsafe_coop_firefox # Run benchmarks for the web wasm api without cross-origin isolation
bench_web_js_api_unsafe_coop_firefox: run_web_js_api_parallel
.PHONY: bench_web_js_api_unsafe_coop_firefox_ci # Run benchmarks for the web wasm api without cross-origin isolation
bench_web_js_api_unsafe_coop_firefox_ci: setup_venv
source ~/.nvm/nvm.sh && \
nvm install $(NODE_VERSION) && \
nvm use $(NODE_VERSION) && \
$(MAKE) bench_web_js_api_unsafe_coop_firefox
.PHONY: bench_hlapi # Run benchmarks for integer operations
bench_hlapi: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_BIT_SIZES_SET=$(BIT_SIZES_SET) \

View File

@@ -1,32 +1,24 @@
08f31a47c29cc4d72ad32c0b5411fa20b3deef5b84558dd2fb892d3cdf90528a data/toy_params/glwe_after_id_br_karatsuba.cbor
29b6e3e7d27700004b70dca24d225816500490e2d6ee49b9af05837fd421896b data/valid_params_128/lwe_after_spec_pbs.cbor
2c70d1d78cc3760733850a353ace2b9c4705e840141b75841739e90e51247e18 data/valid_params_128/small_lwe_secret_key.cbor
2fb4bb45c259b8383da10fc8f9459c40a6972c49b1696eb107f0a75640724be5 data/toy_params/lwe_after_id_pbs_karatsuba.cbor
36c9080b636475fcacca503ce041bbfeee800fd3e1890dee559ea18defff9fe8 data/toy_params/glwe_after_id_br.cbor
377761beeb4216cf5aa2624a8b64b8259f5a75c32d28e850be8bced3a0cdd6f5 data/toy_params/ksk.cbor
59dba26d457f96478eda130cab5301fce86f23c6a8807de42f2a1e78c4985ca7 data/valid_params_128/lwe_ks.cbor
5d80dd93fefae4f4f89484dfcd65bbe99cc32e7e3b0a90c33dd0d77516c0a023 data/valid_params_128/glwe_after_id_br_karatsuba.cbor
656f0009c7834c5bcb61621e222047516054b9bc5d0593d474ab8f1c086b67a6 data/valid_params_128/lwe_after_id_pbs.cbor
699580ca92b9c2f9e1f57fb1e312c9e8cb29714f7acdef9d2ba05f798546751f data/toy_params/lwe_sum.cbor
6e54ab41056984595b077baff70236d934308cf5c0c33b4482fbfb129b3756c6 data/valid_params_128/glwe_after_id_br.cbor
70f5e5728822de05b49071efb5ec28551b0f5cc87aa709a455d8e7f04b9c96ee data/toy_params/lwe_after_id_pbs.cbor
76a5c52cab7fec1dc167da676c6cd39479cda6b2bb9f4e0573cb7d99c2692faa data/valid_params_128/lwe_after_id_pbs_karatsuba.cbor
7cc6803f5fbc3d5a1bf597f2b979ce17eecd3d6baca12183dea21022a7b65c52 data/toy_params/bsk.cbor
7f3c40a134623b44779a556212477fea26eaed22450f3b6faeb8721d63699972 data/valid_params_128/lwe_sum.cbor
837b3bd3245d4d0534ed255fdef896fb4fa6998a258a14543dfdadd0bfc9b6dd data/toy_params/lwe_prod.cbor
9ece8ca9c1436258b94e8c5e629b8722f9b18fdd415dd5209b6167a9dde8491c data/toy_params/glwe_after_spec_br_karatsuba.cbor
aa44aea29efd6d9e4d35a21a625d9cba155672e3f7ed3eddee1e211e62ad146b data/valid_params_128/lwe_ms.cbor
b7a037b9eaa88d6385167579b93e26a0cb6976d9b8967416fd1173e113bda199 data/valid_params_128/large_lwe_secret_key.cbor
b7b8e3586128887bd682120f3e3a43156139bce5e3fe0b03284f8753a864d647 data/toy_params/lwe_after_spec_pbs_karatsuba.cbor
bd00a8ae7494e400de5753029552ee1647efe7e17409b863a26a13b081099b8c data/toy_params/lwe_after_spec_pbs.cbor
c6df98676de04fe54b5ffc2eb30a82ebb706c9d7d5a4e0ed509700fec88761f7 data/toy_params/lwe_ms.cbor
c7d5a864d5616a7d8ad50bbf40416e41e6c9b60c546dc14d4aa8fc40a418baa7 data/toy_params/large_lwe_secret_key.cbor
c806533b325b1009db38be2f9bef5f3b2fad6b77b4c71f2855ccc9d3b4162e98 data/valid_params_128/lwe_b.cbor
c9eb75bd2993639348a679cf48c06e3c38d1a513f48e5b0ce0047cea8cff6bbc data/toy_params/lwe_a.cbor
d3391969acf26dc69de0927ba279139d8d79999944069addc8ff469ad6c5ae2d data/valid_params_128/lwe_after_spec_pbs_karatsuba.cbor
d6da5baef0e787f6be56e218d8354e26904652602db964844156fdff08350ce6 data/toy_params/lwe_ks.cbor
e591ab9af1b6a0aede273f9a3abb65a4c387feb5fa06a6959e9314058ca0f7e5 data/valid_params_128/ksk.cbor
e59b002df3a9b01ad321ec51cf076fa35131ab9dbef141d1c54b717d61426c92 data/valid_params_128/glwe_after_spec_br_karatsuba.cbor
e628354c81508a2d888016e8282df363dd12f1e19190b6475d4eb9d7ab8ae007 data/valid_params_128/glwe_after_spec_br.cbor
e69d2d2c064fc8c0460b39191ca65338146990349954f5ec5ebd01d93610e7eb data/valid_params_128/lwe_a.cbor
e76c24b2a0c9a842ad13dda35473c2514f9e7d20983b5ea0759c4521a91626d9 data/valid_params_128/lwe_prod.cbor

View File

@@ -39,9 +39,6 @@ The following values are generated:
| `glwe_after_spec_br` | The glwe returned by the application of the spec blind rotation on the mod switched ciphertexts. | `GlweCiphertext<Vec<u64>>` | rot spec LUT |
| `lwe_after_spec_pbs` | The lwe returned by the application of the sample extract operation on the output of the spec blind rotation | `LweCiphertext<Vec<u64>>` | `spec(A)` |
Ciphertexts with the `_karatsuba` suffix are generated using the Karatsuba polynomial multiplication algorithm in the blind rotation, while default ciphertexts are generated using an FFT multiplication.
This makes it easier to reproduce bit exact results.
### Encodings
#### Non native encoding
Warning: TFHE-rs uses a specific encoding for non native (ie: u32, u64) power of two ciphertext modulus. This encoding puts the encoded value in the high bits of the native integer.

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:08f31a47c29cc4d72ad32c0b5411fa20b3deef5b84558dd2fb892d3cdf90528a
size 4679

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9ece8ca9c1436258b94e8c5e629b8722f9b18fdd415dd5209b6167a9dde8491c
size 4679

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2fb4bb45c259b8383da10fc8f9459c40a6972c49b1696eb107f0a75640724be5
size 2365

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b7b8e3586128887bd682120f3e3a43156139bce5e3fe0b03284f8753a864d647
size 2365

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5d80dd93fefae4f4f89484dfcd65bbe99cc32e7e3b0a90c33dd0d77516c0a023
size 36935

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e59b002df3a9b01ad321ec51cf076fa35131ab9dbef141d1c54b717d61426c92
size 36935

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:76a5c52cab7fec1dc167da676c6cd39479cda6b2bb9f4e0573cb7d99c2692faa
size 18493

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d3391969acf26dc69de0927ba279139d8d79999944069addc8ff469ad6c5ae2d
size 18493

View File

@@ -265,7 +265,6 @@ fn generate_test_vectors<P: AsRef<Path>>(
let mut id_lut = encoding.encode_lut(glwe_dimension, polynomial_size, ID_LUT);
assert_data_not_zero(&id_lut);
let mut id_lut_karatsuba = id_lut.clone();
blind_rotate_assign(&modswitched, &mut id_lut, &fourier_bsk);
assert_data_not_zero(&id_lut);
@@ -288,32 +287,8 @@ fn generate_test_vectors<P: AsRef<Path>>(
assert_data_not_zero(&lwe_pbs_id);
store_data(path, &lwe_pbs_id, "lwe_after_id_pbs");
blind_rotate_karatsuba_assign(&modswitched, &mut id_lut_karatsuba, &bsk);
store_data(path, &id_lut_karatsuba, "glwe_after_id_br_karatsuba");
let mut lwe_pbs_karatsuba_id = LweCiphertext::new(
0u64,
glwe_dimension
.to_equivalent_lwe_dimension(polynomial_size)
.to_lwe_size(),
encoding.ciphertext_modulus,
);
extract_lwe_sample_from_glwe_ciphertext(
&id_lut_karatsuba,
&mut lwe_pbs_karatsuba_id,
MonomialDegree(0),
);
let decrypted_pbs_id = decrypt_lwe_ciphertext(&large_lwe_secret_key, &lwe_pbs_karatsuba_id);
let res = encoding.decode(decrypted_pbs_id);
assert_eq!(res, MSG_A);
store_data(path, &lwe_pbs_karatsuba_id, "lwe_after_id_pbs_karatsuba");
let mut spec_lut = encoding.encode_lut(glwe_dimension, polynomial_size, SPEC_LUT);
assert_data_not_zero(&spec_lut);
let mut spec_lut_karatsuba = spec_lut.clone();
blind_rotate_assign(&modswitched, &mut spec_lut, &fourier_bsk);
assert_data_not_zero(&spec_lut);
@@ -335,33 +310,6 @@ fn generate_test_vectors<P: AsRef<Path>>(
assert_eq!(res, SPEC_LUT(MSG_A));
assert_data_not_zero(&lwe_pbs_spec);
store_data(path, &lwe_pbs_spec, "lwe_after_spec_pbs");
blind_rotate_karatsuba_assign(&modswitched, &mut spec_lut_karatsuba, &bsk);
store_data(path, &spec_lut_karatsuba, "glwe_after_spec_br_karatsuba");
let mut lwe_pbs_karatsuba_spec = LweCiphertext::new(
0u64,
glwe_dimension
.to_equivalent_lwe_dimension(polynomial_size)
.to_lwe_size(),
encoding.ciphertext_modulus,
);
extract_lwe_sample_from_glwe_ciphertext(
&spec_lut_karatsuba,
&mut lwe_pbs_karatsuba_spec,
MonomialDegree(0),
);
let decrypted_pbs_spec = decrypt_lwe_ciphertext(&large_lwe_secret_key, &lwe_pbs_karatsuba_spec);
let res = encoding.decode(decrypted_pbs_spec);
assert_eq!(res, SPEC_LUT(MSG_A));
store_data(
path,
&lwe_pbs_karatsuba_spec,
"lwe_after_spec_pbs_karatsuba",
);
}
fn rm_dir_except_readme<P: AsRef<Path>>(dir: P) {

View File

@@ -40,7 +40,7 @@ rand = "0.8.5"
regex = "1.10.4"
bitflags = { version = "2.5.0", features = ["serde"] }
itertools = "0.11.0"
lru = "0.16.3"
lru = "0.12.3"
bitfield-struct = "0.10.0"
crossbeam = { version = "0.8.4", features = ["crossbeam-queue"] }
rayon = { workspace = true }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:934c8131c12010dc837f6a2af5111b83f8f5d42f10485e9b3b971edb24c467f8
size 82201876
oid sha256:35cc06547a23b862ab9829351d74d944e60ea9dad3ecf593d15f0ce8445d145e
size 81710610

View File

@@ -113,7 +113,6 @@ pub fn iop_add_simd(prog: &mut Program) {
prog,
crate::asm::iop::SIMD_N,
fw_impl::llt::iop_add_ripple_rtl,
None,
);
}
@@ -228,23 +227,14 @@ pub fn iop_muls(prog: &mut Program) {
pub fn iop_erc_20(prog: &mut Program) {
// Add Comment header
prog.push_comment("ERC_20 (new_from, new_to) <- (from, to, amount)".to_string());
// TODO: Make sweep of kogge_blk_w
// All these little parameters would be very handy to write an
// exploration/compilation program which would try to minimize latency by
// playing with these.
iop_erc_20_rtl(prog, 0, Some(10)).add_to_prog(prog);
iop_erc_20_rtl(prog, 0).add_to_prog(prog);
}
#[instrument(level = "trace", skip(prog))]
pub fn iop_erc_20_simd(prog: &mut Program) {
// Add Comment header
prog.push_comment("ERC_20_SIMD (new_from, new_to) <- (from, to, amount)".to_string());
simd(
prog,
crate::asm::iop::SIMD_N,
fw_impl::llt::iop_erc_20_rtl,
None,
);
simd(prog, crate::asm::iop::SIMD_N, fw_impl::llt::iop_erc_20_rtl);
}
#[instrument(level = "trace", skip(prog))]
@@ -391,7 +381,7 @@ pub fn iop_rotate_scalar_left(prog: &mut Program) {
/// (dst_from[0], dst_to[0], ..., dst_from[N-1], dst_to[N-1])
/// Where N is the batch size
#[instrument(level = "trace", skip(prog))]
pub fn iop_erc_20_rtl(prog: &mut Program, batch_index: u8, kogge_blk_w: Option<usize>) -> Rtl {
pub fn iop_erc_20_rtl(prog: &mut Program, batch_index: u8) -> Rtl {
// Allocate metavariables:
// Dest -> Operand
let dst_from = prog.iop_template_var(OperandKind::Dst, 2 * batch_index);
@@ -402,6 +392,13 @@ pub fn iop_erc_20_rtl(prog: &mut Program, batch_index: u8, kogge_blk_w: Option<u
// Src Amount -> Operand
let src_amount = prog.iop_template_var(OperandKind::Src, 3 * batch_index + 2);
// TODO: Make this a parameter or sweep this
// All these little parameters would be very handy to write an
// exploration/compilation program which would try to minimize latency by
// playing with these.
let kogge_blk_w = 10;
let ripple = true;
{
let props = prog.params();
let tfhe_params: asm::DigitParameters = props.clone().into();
@@ -432,21 +429,19 @@ pub fn iop_erc_20_rtl(prog: &mut Program, batch_index: u8, kogge_blk_w: Option<u
})
.collect::<Vec<_>>();
if let Some(blk_w) = kogge_blk_w {
kogge::add(prog, dst_to, src_to, src_amount.clone(), None, blk_w)
+ kogge::sub(prog, dst_from, src_from, src_amount, blk_w)
} else {
// Default to ripple carry
if ripple {
kogge::ripple_add(dst_to, src_to, src_amount.clone(), None)
+ kogge::ripple_sub(prog, dst_from, src_from, src_amount)
} else {
kogge::add(prog, dst_to, src_to, src_amount.clone(), None, kogge_blk_w)
+ kogge::sub(prog, dst_from, src_from, src_amount, kogge_blk_w)
}
}
}
/// A SIMD implementation of add for maximum throughput
/// NB: No use of kogge_blk_w here, impl force to use ripple carry
#[instrument(level = "trace", skip(prog))]
pub fn iop_add_ripple_rtl(prog: &mut Program, i: u8, _kogge_blk_w: Option<usize>) -> Rtl {
pub fn iop_add_ripple_rtl(prog: &mut Program, i: u8) -> Rtl {
// Allocate metavariables:
let dst = prog.iop_template_var(OperandKind::Dst, i);
let src_a = prog.iop_template_var(OperandKind::Src, 2 * i);
@@ -904,13 +899,13 @@ fn bw_inv(prog: &mut Program, b: Vec<VarCell>) -> Vec<VarCell> {
/// Maybe this should go into a SIMD firmware implementation... At some point we
/// would need a mechanism to choose between implementations on the fly to make
/// real good use of all of this.
fn simd<F>(prog: &mut Program, batch_size: usize, rtl_closure: F, kogge_blk_w: Option<usize>)
fn simd<F>(prog: &mut Program, batch_size: usize, rtl_closure: F)
where
F: Fn(&mut Program, u8, Option<usize>) -> Rtl,
F: Fn(&mut Program, u8) -> Rtl,
{
(0..batch_size)
.map(|i| i as u8)
.map(|i| rtl_closure(prog, i, kogge_blk_w))
.map(|i| rtl_closure(prog, i))
.sum::<Rtl>()
.add_to_prog(prog);
}

View File

@@ -160,9 +160,9 @@ impl ProgramInner {
.filter(|(_, var)| var.is_none())
.map(|(rid, _)| *rid)
.collect::<Vec<_>>();
demote_order.into_iter().for_each(|rid| {
self.regs.demote(&rid);
});
demote_order
.into_iter()
.for_each(|rid| self.regs.demote(&rid));
}
/// Release register entry
@@ -179,7 +179,7 @@ impl ProgramInner {
/// Notify register access to update LRU state
pub(crate) fn reg_access(&mut self, rid: asm::RegId) {
self.regs.promote(&rid);
self.regs.promote(&rid)
}
/// Retrieved least-recent-used heap entry
@@ -220,9 +220,9 @@ impl ProgramInner {
.filter(|(_mid, var)| var.is_none())
.map(|(mid, _)| *mid)
.collect::<Vec<_>>();
demote_order.into_iter().for_each(|mid| {
self.heap.demote(&mid);
});
demote_order
.into_iter()
.for_each(|mid| self.heap.demote(&mid));
}
_ => { /*Only release Heap slot*/ }
}
@@ -231,9 +231,7 @@ impl ProgramInner {
/// Notify heap access to update LRU state
pub(crate) fn heap_access(&mut self, mid: asm::MemId) {
match mid {
asm::MemId::Heap { .. } => {
self.heap.promote(&mid);
}
asm::MemId::Heap { .. } => self.heap.promote(&mid),
_ => { /* Do Nothing slot do not below to heap*/ }
}
}

View File

@@ -367,8 +367,6 @@ def dump_benchmark_results(results, browser_kind):
"""
Dump as JSON benchmark results into a file.
If `results` is an empty dict then this function is a no-op.
If the file already exists, new results are merged with existing ones,
overwriting keys that already exist.
:param results: benchmark results as :class:`dict`
:param browser_kind: browser as :class:`BrowserKind`
@@ -378,15 +376,7 @@ def dump_benchmark_results(results, browser_kind):
key.replace("mean", "_".join((browser_kind.name, "mean"))): val
for key, val in results.items()
}
results_path = pathlib.Path("tfhe-benchmark/wasm_benchmark_results.json")
existing_results = {}
if results_path.exists():
try:
existing_results = json.loads(results_path.read_text())
except json.JSONDecodeError:
pass
existing_results.update(results)
results_path.write_text(json.dumps(existing_results))
pathlib.Path("tfhe-benchmark/wasm_benchmark_results.json").write_text(json.dumps(results))
def start_web_server(

View File

@@ -3,21 +3,23 @@
set -e
function usage() {
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 "--unsigned-only Run only unsigned integer tests, by default both signed and unsigned tests are run"
echo "--signed-only Run only signed integer tests, by default both signed and unsigned tests are run"
echo "--nightly-tests Run integer tests configured for nightly runs (3_3 params)"
echo "--fast-tests Run integer set but skip a subset of longer tests"
echo "--long-tests Run only long run integer tests"
echo "--cargo-profile The cargo profile used to build tests"
echo "--backend Backend to use with tfhe-rs"
echo "--avx512-support Set to ON to enable avx512"
echo "--tfhe-package The package spec like tfhe@0.4.2, default=tfhe"
echo
echo "$0: integer test runner"
echo
echo "--help Print this message"
echo "--no-run Does not run the tests, but prints which tests would be ran (except doctests)"
echo "--rust-toolchain The toolchain to run the tests with default: stable"
echo "--multi-bit Run multi-bit tests only: default off"
echo "--unsigned-only Run only unsigned integer tests, by default both signed and unsigned tests are run"
echo "--signed-only Run only signed integer tests, by default both signed and unsigned tests are run"
echo "--run-prod-only Run only the tests using the prod parameters"
echo "--nightly-tests Run integer tests configured for nightly runs (3_3 params)"
echo "--fast-tests Run integer set but skip a subset of longer tests"
echo "--long-tests Run only long run integer tests"
echo "--cargo-profile The cargo profile used to build tests"
echo "--backend Backend to use with tfhe-rs"
echo "--avx512-support Set to ON to enable avx512"
echo "--tfhe-package The package spec like tfhe@0.4.2, default=tfhe"
echo
}
RUST_TOOLCHAIN=""
@@ -33,87 +35,96 @@ backend="cpu"
gpu_feature=""
avx512_feature=""
tfhe_package="tfhe"
prod_param_argument=
no_run=false
while [ -n "$1" ]
do
case "$1" in
"--help" | "-h" )
usage
exit 0
;;
while [ -n "$1" ]; do
case "$1" in
"--help" | "-h")
usage
exit 0
;;
"--rust-toolchain" )
shift
RUST_TOOLCHAIN="$1"
;;
"--no-run")
no_run=true
;;
"--multi-bit" )
multi_bit_argument=--multi-bit
;;
"--run-prod-only")
prod_param_argument="--run-prod-only"
;;
"--unsigned-only" )
sign_argument=--unsigned-only
;;
"--rust-toolchain")
shift
RUST_TOOLCHAIN="$1"
;;
"--signed-only" )
sign_argument=--signed-only
;;
"--multi-bit")
multi_bit_argument=--multi-bit
;;
"--cargo-profile" )
shift
cargo_profile="$1"
;;
"--unsigned-only")
sign_argument=--unsigned-only
;;
"--backend" )
shift
backend="$1"
;;
"--avx512-support" )
shift
if [[ "$1" == "ON" ]]; then
avx512_feature=avx512
fi
;;
"--signed-only")
sign_argument=--signed-only
;;
"--tfhe-package" )
shift
tfhe_package="$1"
;;
"--cargo-profile")
shift
cargo_profile="$1"
;;
*)
echo "Unknown param : $1"
exit 1
;;
esac
shift
"--backend")
shift
backend="$1"
;;
"--avx512-support")
shift
if [[ "$1" == "ON" ]]; then
avx512_feature=avx512
fi
;;
"--tfhe-package")
shift
tfhe_package="$1"
;;
*)
echo "Unknown param : $1"
exit 1
;;
esac
shift
done
if [[ "${RUST_TOOLCHAIN::1}" != "+" ]]; then
RUST_TOOLCHAIN=${RUST_TOOLCHAIN:+"+${RUST_TOOLCHAIN}"}
RUST_TOOLCHAIN=${RUST_TOOLCHAIN:+"+${RUST_TOOLCHAIN}"}
fi
if [[ "${FAST_TESTS}" == TRUE ]]; then
fast_tests_argument=--fast-tests
fast_tests_argument=--fast-tests
fi
if [[ "${LONG_TESTS}" == TRUE ]]; then
long_tests_argument=--long-tests
long_tests_argument=--long-tests
fi
if [[ "${NIGHTLY_TESTS}" == TRUE ]]; then
nightly_tests_argument=--nightly-tests
nightly_tests_argument=--nightly-tests
fi
if [[ "${NO_BIG_PARAMS}" == TRUE ]]; then
no_big_params_argument=--no-big-params
no_big_params_argument=--no-big-params
fi
if [[ "${NO_BIG_PARAMS_GPU}" == TRUE ]]; then
no_big_params_argument_gpu=--no-big-params-gpu
no_big_params_argument_gpu=--no-big-params-gpu
fi
if [[ "${backend}" == "gpu" ]]; then
gpu_feature="gpu"
gpu_feature="gpu"
fi
CURR_DIR="$(dirname "$0")"
@@ -122,70 +133,80 @@ CURR_DIR="$(dirname "$0")"
num_cpu_threads="$("${CURR_DIR}"/cpu_count.sh)"
if uname -a | grep "arm64"; then
if [[ $(uname) == "Darwin" ]]; then
# Keys are 4.7 gigs at max, CI M1 macs only has 8 gigs of RAM
small_instance_n_threads=1
fi
if [[ $(uname) == "Darwin" ]]; then
# Keys are 4.7 gigs at max, CI M1 macs only has 8 gigs of RAM
small_instance_n_threads=1
fi
else
# Keys are 4.7 gigs at max, test machine has 32 gigs of RAM
small_instance_n_threads=6
# Keys are 4.7 gigs at max, test machine has 32 gigs of RAM
small_instance_n_threads=6
fi
if [[ "${BIG_TESTS_INSTANCE}" == TRUE ]]; then
test_threads="$((num_cpu_threads * 1 / 4))"
doctest_threads="${num_cpu_threads}"
test_threads="$((num_cpu_threads * 1 / 4))"
doctest_threads="${num_cpu_threads}"
else
test_threads="${small_instance_n_threads}"
doctest_threads="${num_cpu_threads}"
test_threads="${small_instance_n_threads}"
doctest_threads="${num_cpu_threads}"
fi
# Override test-threads number to avoid Out-of-memory issues on GPU instances
if [[ "${backend}" == "gpu" ]]; then
if [[ "${BIG_TESTS_INSTANCE}" == TRUE ]]; then
test_threads=8
doctest_threads=8
else
test_threads=4
doctest_threads=4
fi
if [[ "${BIG_TESTS_INSTANCE}" == TRUE ]]; then
test_threads=8
doctest_threads=8
else
test_threads=4
doctest_threads=4
fi
fi
filter_expression=$(/usr/bin/python3 scripts/test_filtering.py --layer integer --backend "${backend}" ${fast_tests_argument:+$fast_tests_argument} ${long_tests_argument:+$long_tests_argument} ${nightly_tests_argument:+$nightly_tests_argument} ${no_big_params_argument_gpu:+$no_big_params_argument_gpu} ${multi_bit_argument:+$multi_bit_argument} ${sign_argument:+$sign_argument} ${no_big_params_argument:+$no_big_params_argument})
filter_expression=$(/usr/bin/python3 scripts/test_filtering.py --layer integer --backend "${backend}" ${fast_tests_argument:+$fast_tests_argument} ${long_tests_argument:+$long_tests_argument} ${nightly_tests_argument:+$nightly_tests_argument} ${no_big_params_argument_gpu:+$no_big_params_argument_gpu} ${multi_bit_argument:+$multi_bit_argument} ${sign_argument:+$sign_argument} ${no_big_params_argument:+$no_big_params_argument} ${prod_param_argument:+$prod_param_argument})
if [[ "${FAST_TESTS}" == "TRUE" ]]; then
echo "Running 'fast' test set"
echo "Running 'fast' test set"
elif [[ "${LONG_TESTS}" == "FALSE" ]]; then
echo "Running 'slow' test set"
echo "Running 'slow' test set"
fi
if [[ "${LONG_TESTS}" == "TRUE" ]]; then
echo "Running 'long run' test set"
echo "Running 'long run' test set"
fi
if [[ "${NIGHTLY_TESTS}" == "TRUE" ]]; then
echo "Running 'nightly' test set"
echo "Running 'nightly' test set"
fi
echo "${filter_expression}"
cargo ${RUST_TOOLCHAIN:+"$RUST_TOOLCHAIN"} nextest run \
--tests \
--cargo-profile "${cargo_profile}" \
--package "${tfhe_package}" \
--profile ci \
--no-default-features \
--features=integer,internal-keycache,zk-pok,experimental,"${avx512_feature}","${gpu_feature}" \
--test-threads "${test_threads}" \
-E "$filter_expression"
if $no_run; then
nextest_command="list"
nextest_extra_flags=""
else
nextest_command="run"
nextest_extra_flags="--profile ci --test-threads ${test_threads}"
fi
if [[ -z ${multi_bit_argument} && -z ${long_tests_argument} ]]; then
cargo ${RUST_TOOLCHAIN:+"$RUST_TOOLCHAIN"} test \
--profile "${cargo_profile}" \
--package "${tfhe_package}" \
--no-default-features \
--features=integer,internal-keycache,experimental,"${avx512_feature}","${gpu_feature}" \
--doc \
-- --test-threads="${doctest_threads}" integer::"${gpu_feature}"
cargo ${RUST_TOOLCHAIN:+"$RUST_TOOLCHAIN"} nextest ${nextest_command} \
--tests \
--cargo-profile "${cargo_profile}" \
--package "${tfhe_package}" \
--no-default-features \
--features=integer,internal-keycache,zk-pok,experimental,"${avx512_feature}","${gpu_feature}" \
${nexttest_extra_flags} \
-E "$filter_expression"
if ! $no_run; then
# Unfortunately, we cannot skip running doctest with `--no-run`
if [[ -z ${multi_bit_argument} && -z ${long_tests_argument} ]]; then
cargo ${RUST_TOOLCHAIN:+"$RUST_TOOLCHAIN"} test \
--profile "${cargo_profile}" \
--package "${tfhe_package}" \
--no-default-features \
--features=integer,internal-keycache,experimental,"${avx512_feature}","${gpu_feature}" \
--doc \
-- --test-threads="${doctest_threads}" integer::"${gpu_feature}"
fi
fi
echo "Test ran in $SECONDS seconds"

View File

@@ -8,6 +8,7 @@ function usage() {
echo "--help Print this message"
echo "--rust-toolchain The toolchain to run the tests with default: stable"
echo "--multi-bit Run multi-bit tests only: default off"
echo "--run-prod-only Run only the tests using the prod parameters"
echo "--cargo-profile The cargo profile used to build tests"
echo "--tfhe-package The package spec like tfhe@0.4.2, default=tfhe"
echo
@@ -19,6 +20,7 @@ multi_bit_argument=
fast_tests_argument=
cargo_profile="release"
tfhe_package="tfhe"
prod_param_argument=
while [ -n "$1" ]
do
@@ -38,6 +40,9 @@ do
multi_bit_argument=--multi-bit
;;
"--run-prod-only")
prod_param_argument="--run-prod-only"
;;
"--cargo-profile" )
shift
cargo_profile="$1"
@@ -85,7 +90,7 @@ else
fi
if [[ "${BIG_TESTS_INSTANCE}" != TRUE ]]; then
filter_expression_small_params=$(/usr/bin/python3 scripts/test_filtering.py --layer shortint ${fast_tests_argument} ${multi_bit_argument})
filter_expression_small_params=$(/usr/bin/python3 scripts/test_filtering.py --layer shortint ${fast_tests_argument} ${multi_bit_argument} ${prod_param_argument})
# Run tests only no examples or benches with small params and more threads
cargo ${RUST_TOOLCHAIN:+"$RUST_TOOLCHAIN"} nextest run \
@@ -125,7 +130,7 @@ and not test(~smart_add_and_mul)"""
fi
fi
else
filter_expression=$(/usr/bin/python3 scripts/test_filtering.py --layer shortint --big-instance ${fast_tests_argument} ${multi_bit_argument})
filter_expression=$(/usr/bin/python3 scripts/test_filtering.py --layer shortint --big-instance ${fast_tests_argument} ${multi_bit_argument} ${prod_param_argument})
# Run tests only no examples or benches with small params and more threads
cargo ${RUST_TOOLCHAIN:+"$RUST_TOOLCHAIN"} nextest run \

View File

@@ -74,12 +74,17 @@ parser.add_argument(
action="store_true",
help="Do not run tests with big parameters set (e.g. 3bits message with 3 bits carry) for GPU",
)
parser.add_argument(
"--run-prod-only",
action="store_true",
help="Specify to run the CPU tests with the prod KS_PBS 2_2 parameters, \
only the 'layer' parameter will be taken into account if this flag is specified",
)
# block PBS are too slow for high params
# mul_crt_4_4 is extremely flaky (~80% failure)
# test_wopbs_bivariate_crt_wopbs_param_message generate tables that are too big at the moment
# test_integer_smart_mul_param_message_4_carry_4_ks_pbs_gaussian_2m64 is too slow
# so is test_integer_default_add_sequence_multi_thread_param_message_4_carry_4_ks_pbs_gaussian_2m64
# skip smart_div, smart_rem which are already covered by the smar_div_rem test
# skip default_div, default_rem which are covered by default_div_rem
EXCLUDED_INTEGER_TESTS = [
@@ -91,7 +96,6 @@ EXCLUDED_INTEGER_TESTS = [
"~mul_crt_param_message_4_carry_4_ks_pbs_gaussian_2m64",
"/.*test_wopbs_bivariate_crt_wopbs_param_message_[34]_carry_[34]_ks_pbs_gaussian_2m64$/",
"/.*test_integer_smart_mul_param_message_4_carry_4_ks_pbs_gaussian_2m64$/",
"/.*test_integer_default_add_sequence_multi_thread_param_message_4_carry_4_ks_pbs_gaussian_2m64$/",
"/.*::tests_long_run::.*/",
]
@@ -100,7 +104,6 @@ EXCLUDED_INTEGER_FAST_TESTS = [
"/.*integer_default_div_param/",
"/.*integer_default_rem_param/",
"/.*_param_message_[14]_carry_[14]_ks_pbs_gaussian_2m64$/",
"/.*default_add_sequence_multi_thread_param_message_3_carry_3_ks_pbs_gaussian_2m64$/",
]
EXCLUDED_BIG_PARAMETERS = [
@@ -125,7 +128,13 @@ def filter_integer_tests(input_args):
# For now, GPU only has specific parameters set for multi-bit
multi_bit_filter = "_gpu_multi_bit"
filter_expression = [f"test(/^integer::{backend_filter}.*/)"]
if input_args.run_prod_only:
filter_expression = [f"test(/^integer::{backend_filter}.*_param_prod.*/)"]
else:
filter_expression = [
f"test(/^integer::{backend_filter}.*/)",
"not test(/.*_param_prod.*/)",
]
if input_args.multi_bit:
filter_expression.append("test(~_multi_bit)")
@@ -161,29 +170,32 @@ def filter_integer_tests(input_args):
f"test(/.*_default_.*?_param{multi_bit_filter}{group_filter}_message_3_carry_3_.*/)"
)
excluded_tests = (
EXCLUDED_INTEGER_FAST_TESTS if input_args.fast_tests else EXCLUDED_INTEGER_TESTS
EXCLUDED_INTEGER_FAST_TESTS
if input_args.fast_tests
else EXCLUDED_INTEGER_TESTS
)
for pattern in excluded_tests:
filter_expression.append(f"not test({pattern})")
else:
if input_args.backend == "gpu":
filter_expression = ["test(/^integer::gpu::server_key::radix::tests_long_run.*/)"]
filter_expression = [
"test(/^integer::gpu::server_key::radix::tests_long_run.*/)"
]
elif input_args.backend == "cpu":
filter_expression = ["test(/^integer::server_key::radix_parallel::tests_long_run.*/)"]
filter_expression = [
"test(/^integer::server_key::radix_parallel::tests_long_run.*/)"
]
# Do not run noise check tests by default as they can be very slow
# they will be run e.g. nightly or on demand
filter = filter_expression.append(f"not test(/^integer::gpu::server_key::radix::tests_noise_distribution::.*::test_gpu_noise_check.*/)")
filter_expression.append(
"not test(/^integer::gpu::server_key::radix::tests_noise_distribution::.*::test_gpu_noise_check.*/)"
)
return " and ".join(filter_expression)
def filter_shortint_tests(input_args):
multi_bit_filter, group_filter = (
("_multi_bit", "_group_[0-9]") if input_args.multi_bit else ("", "")
)
def shortint_normal_filter(input_args):
multi_bit_filter = "_multi_bit_group_[0-9]" if input_args.multi_bit else ""
if input_args.fast_tests:
msg_carry_pairs = [(2, 1), (2, 2), (2, 3)]
@@ -206,13 +218,31 @@ def filter_shortint_tests(input_args):
msg_carry_pairs.append((4, 4))
filter_expression = [
f"test(/^shortint::.*_param{multi_bit_filter}{group_filter}_message_{msg}_carry_{carry}(_compact_pk)?_ks(32)?_pbs.*/)"
f"test(/^shortint::.*_param{multi_bit_filter}_message_{msg}_carry_{carry}\
(_compact_pk)?_ks(32)?_pbs.*/)"
for msg, carry in msg_carry_pairs
]
filter_expression.append("test(/^shortint::.*meta_param_cpu_2_2/)")
filter_expression.append("test(/^shortint::.*meta_param_cpu_2_2_ks32_pbs/)")
filter_expression.append("test(/^shortint::.*_ci_run_filter/)")
if input_args.run_prod_only:
filter_expression.append("test(/^shortint::.*_param_prod.*")
else:
filter_expression.append("not test(shortint::.*_param_prod.*/)")
return filter_expression
def filter_shortint_tests(input_args):
# We special case the CPU KS_PBS 2_2 parameters to be able to run them alone
if input_args.run_prod_only:
filter_expression = [
"test(/^shortint::.*_param_prod/)",
]
else:
filter_expression = shortint_normal_filter(input_args)
opt_in_tests = " or ".join(filter_expression)
# Do not run noise check tests by default as they can be very slow

View File

@@ -1 +0,0 @@
benchmarks_parameters/*

View File

@@ -2,9 +2,7 @@ use benchmark::utilities::{
hlapi_throughput_num_ops, write_to_json, BenchmarkType, BitSizesSet, EnvConfig, OperatorType,
};
use criterion::{black_box, Criterion, Throughput};
use oprf::oprf_any_range2;
use rand::prelude::*;
use rayon::prelude::*;
use std::marker::PhantomData;
use std::ops::*;
use tfhe::core_crypto::prelude::Numeric;
@@ -13,42 +11,34 @@ use tfhe::keycache::NamedParam;
use tfhe::named::Named;
use tfhe::prelude::*;
use tfhe::{
ClientKey, CompressedServerKey, FheIntegerType, FheUint, FheUint10, FheUint12, FheUint128,
FheUint14, FheUint16, FheUint2, FheUint32, FheUint4, FheUint6, FheUint64, FheUint8, FheUintId,
IntegerId, KVStore,
ClientKey, CompressedServerKey, FheIntegerType, FheUint10, FheUint12, FheUint128, FheUint14,
FheUint16, FheUint2, FheUint32, FheUint4, FheUint6, FheUint64, FheUint8, FheUintId, IntegerId,
KVStore,
};
mod oprf;
use rayon::prelude::*;
trait BenchWait {
fn wait_bench(&self);
}
impl<Id: FheUintId> BenchWait for FheUint<Id> {
fn wait_bench(&self) {
self.wait()
}
}
impl<T1: FheWait, T2> BenchWait for (T1, T2) {
fn wait_bench(&self) {
self.0.wait()
}
}
fn bench_fhe_type_op<FheType, F, R>(
fn bench_fhe_type<FheType>(
c: &mut Criterion,
client_key: &ClientKey,
type_name: &str,
bit_size: usize,
display_name: &str,
func_name: &str,
func: F,
) where
F: Fn(&FheType, &FheType) -> R,
R: BenchWait,
FheType: FheEncrypt<u128, ClientKey>,
FheType: FheWait,
for<'a> &'a FheType: Add<&'a FheType, Output = FheType>
+ Sub<&'a FheType, Output = FheType>
+ Mul<&'a FheType, Output = FheType>
+ BitAnd<&'a FheType, Output = FheType>
+ BitOr<&'a FheType, Output = FheType>
+ BitXor<&'a FheType, Output = FheType>
+ Shl<&'a FheType, Output = FheType>
+ Shr<&'a FheType, Output = FheType>
+ RotateLeft<&'a FheType, Output = FheType>
+ RotateRight<&'a FheType, Output = FheType>
+ OverflowingAdd<&'a FheType, Output = FheType>
+ OverflowingSub<&'a FheType, Output = FheType>,
for<'a> FheType: FheMin<&'a FheType, Output = FheType> + FheMax<&'a FheType, Output = FheType>,
{
let mut bench_group = c.benchmark_group(type_name);
let mut bench_prefix = "hlapi".to_string();
@@ -81,90 +71,170 @@ fn bench_fhe_type_op<FheType, F, R>(
let lhs = FheType::encrypt(rng.gen(), client_key);
let rhs = FheType::encrypt(rng.gen(), client_key);
let bench_id = format!("{bench_prefix}::{func_name}::{param_name}::{type_name}");
let mut bench_id;
bench_id = format!("{bench_prefix}::add::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = func(&lhs, &rhs);
res.wait_bench();
let res = &lhs + &rhs;
res.wait();
black_box(res)
})
});
write_record(bench_id, display_name);
write_record(bench_id, "add");
bench_id = format!("{bench_prefix}::overflowing_add::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let (res, flag) = lhs.overflowing_add(&rhs);
res.wait();
black_box((res, flag))
})
});
write_record(bench_id, "overflowing_add");
bench_id = format!("{bench_prefix}::overflowing_sub::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let (res, flag) = lhs.overflowing_sub(&rhs);
res.wait();
black_box((res, flag))
})
});
write_record(bench_id, "overflowing_sub");
bench_id = format!("{bench_prefix}::sub::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = &lhs - &rhs;
res.wait();
black_box(res)
})
});
write_record(bench_id, "sub");
bench_id = format!("{bench_prefix}::mul::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = &lhs * &rhs;
res.wait();
black_box(res)
})
});
write_record(bench_id, "mul");
bench_id = format!("{bench_prefix}::bitand::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = &lhs & &rhs;
res.wait();
black_box(res)
})
});
write_record(bench_id, "bitand");
bench_id = format!("{bench_prefix}::bitor::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = &lhs | &rhs;
res.wait();
black_box(res)
})
});
write_record(bench_id, "bitor");
bench_id = format!("{bench_prefix}::bitxor::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = &lhs ^ &rhs;
res.wait();
black_box(res)
})
});
write_record(bench_id, "bitxor");
bench_id = format!("{bench_prefix}::left_shift::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = &lhs << &rhs;
res.wait();
black_box(res)
})
});
write_record(bench_id, "left_shift");
bench_id = format!("{bench_prefix}::right_shift::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = &lhs >> &rhs;
res.wait();
black_box(res)
})
});
write_record(bench_id, "right_shift");
bench_id = format!("{bench_prefix}::left_rotate::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = (&lhs).rotate_left(&rhs);
res.wait();
black_box(res)
})
});
write_record(bench_id, "left_rotate");
bench_id = format!("{bench_prefix}::right_rotate::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = (&lhs).rotate_right(&rhs);
res.wait();
black_box(res)
})
});
write_record(bench_id, "right_rotate");
bench_id = format!("{bench_prefix}::min::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = lhs.min(&rhs);
res.wait();
black_box(res)
})
});
write_record(bench_id, "min");
bench_id = format!("{bench_prefix}::max::{param_name}::{type_name}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let res = lhs.max(&rhs);
res.wait();
black_box(res)
})
});
write_record(bench_id, "max");
}
macro_rules! bench_type_op (
(type_name: $fhe_type:ident, display_name: $display_name:literal, operation: $op:ident) => {
macro_rules! bench_type {
($fhe_type:ident) => {
::paste::paste! {
fn [<bench_ $fhe_type:snake _ $op>](c: &mut Criterion, cks: &ClientKey) {
bench_fhe_type_op::<$fhe_type, _, _>(
c,
cks,
stringify!($fhe_type),
$fhe_type::num_bits(),
$display_name,
stringify!($op),
|lhs, rhs| lhs.$op(rhs)
);
fn [<bench_ $fhe_type:snake>](c: &mut Criterion, cks: &ClientKey) {
bench_fhe_type::<$fhe_type>(c, cks, stringify!($fhe_type), $fhe_type::num_bits());
}
}
};
);
macro_rules! generate_typed_benches {
($fhe_type:ident) => {
bench_type_op!(type_name: $fhe_type, display_name: "add", operation: add);
bench_type_op!(type_name: $fhe_type, display_name: "overflowing_add", operation: overflowing_add);
bench_type_op!(type_name: $fhe_type, display_name: "sub", operation: sub);
bench_type_op!(type_name: $fhe_type, display_name: "overflowing_sub", operation: overflowing_sub);
bench_type_op!(type_name: $fhe_type, display_name: "mul", operation: mul);
bench_type_op!(type_name: $fhe_type, display_name: "bitand", operation: bitand);
bench_type_op!(type_name: $fhe_type, display_name: "bitor", operation: bitor);
bench_type_op!(type_name: $fhe_type, display_name: "bitxor", operation: bitxor);
bench_type_op!(type_name: $fhe_type, display_name: "left_shift", operation: shl);
bench_type_op!(type_name: $fhe_type, display_name: "right_shift", operation: shr);
bench_type_op!(type_name: $fhe_type, display_name: "left_rotate", operation: rotate_left);
bench_type_op!(type_name: $fhe_type, display_name: "right_rotate", operation: rotate_right);
bench_type_op!(type_name: $fhe_type, display_name: "min", operation: min);
bench_type_op!(type_name: $fhe_type, display_name: "max", operation: max);
};
}
// Generate benches for all FheUint types
generate_typed_benches!(FheUint2);
generate_typed_benches!(FheUint4);
generate_typed_benches!(FheUint6);
generate_typed_benches!(FheUint8);
generate_typed_benches!(FheUint10);
generate_typed_benches!(FheUint12);
generate_typed_benches!(FheUint14);
generate_typed_benches!(FheUint16);
generate_typed_benches!(FheUint32);
generate_typed_benches!(FheUint64);
generate_typed_benches!(FheUint128);
macro_rules! run_benches {
($c:expr, $cks:expr, $($fhe_type:ident),+ $(,)?) => {
$(
::paste::paste! {
[<bench_ $fhe_type:snake _add>]($c, $cks);
[<bench_ $fhe_type:snake _overflowing_add>]($c, $cks);
[<bench_ $fhe_type:snake _sub>]($c, $cks);
[<bench_ $fhe_type:snake _overflowing_sub>]($c, $cks);
[<bench_ $fhe_type:snake _mul>]($c, $cks);
[<bench_ $fhe_type:snake _bitand>]($c, $cks);
[<bench_ $fhe_type:snake _bitor>]($c, $cks);
[<bench_ $fhe_type:snake _bitxor>]($c, $cks);
[<bench_ $fhe_type:snake _shl>]($c, $cks);
[<bench_ $fhe_type:snake _shr>]($c, $cks);
[<bench_ $fhe_type:snake _rotate_left>]($c, $cks);
[<bench_ $fhe_type:snake _rotate_right>]($c, $cks);
[<bench_ $fhe_type:snake _min>]($c, $cks);
[<bench_ $fhe_type:snake _max>]($c, $cks);
}
)+
};
}
bench_type!(FheUint2);
bench_type!(FheUint4);
bench_type!(FheUint6);
bench_type!(FheUint8);
bench_type!(FheUint10);
bench_type!(FheUint12);
bench_type!(FheUint14);
bench_type!(FheUint16);
bench_type!(FheUint32);
bench_type!(FheUint64);
bench_type!(FheUint128);
trait TypeDisplay {
fn fmt(f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -374,7 +444,7 @@ fn main() {
match env_config.bit_sizes_set {
BitSizesSet::Fast => {
run_benches!(&mut c, &cks, FheUint64);
bench_fhe_uint64(&mut c, &cks);
// KVStore Benches
if benched_device == tfhe::Device::Cpu {
@@ -382,11 +452,17 @@ fn main() {
}
}
_ => {
// Call all benchmarks for all types
run_benches!(
&mut c, &cks, FheUint2, FheUint4, FheUint6, FheUint8, FheUint10, FheUint12,
FheUint14, FheUint16, FheUint32, FheUint64, FheUint128
);
bench_fhe_uint2(&mut c, &cks);
bench_fhe_uint4(&mut c, &cks);
bench_fhe_uint6(&mut c, &cks);
bench_fhe_uint8(&mut c, &cks);
bench_fhe_uint10(&mut c, &cks);
bench_fhe_uint12(&mut c, &cks);
bench_fhe_uint14(&mut c, &cks);
bench_fhe_uint16(&mut c, &cks);
bench_fhe_uint32(&mut c, &cks);
bench_fhe_uint64(&mut c, &cks);
bench_fhe_uint128(&mut c, &cks);
// KVStore Benches
if benched_device == tfhe::Device::Cpu {
@@ -405,7 +481,5 @@ fn main() {
}
}
oprf_any_range2();
c.final_summary();
}

View File

@@ -29,21 +29,12 @@ pub fn transfer_whitepaper<FheType>(
) -> (FheType, FheType)
where
FheType: Add<Output = FheType> + for<'a> FheOrd<&'a FheType> + FheTrivialEncrypt<u64>,
FheBool: IfThenZero<FheType> + IfThenElse<FheType>,
FheBool: IfThenElse<FheType>,
for<'a> &'a FheType: Add<Output = FheType> + Sub<Output = FheType>,
{
let has_enough_funds = (from_amount).ge(amount);
let amount_to_transfer = {
#[cfg(not(feature = "hpu"))]
{
let zero_amount = FheType::encrypt_trivial(0u64);
has_enough_funds.select(amount, &zero_amount)
}
#[cfg(feature = "hpu")]
{
has_enough_funds.if_then_zero(amount)
}
};
let zero_amount = FheType::encrypt_trivial(0u64);
let amount_to_transfer = has_enough_funds.select(amount, &zero_amount);
let new_to_amount = to_amount + &amount_to_transfer;
let new_from_amount = from_amount - &amount_to_transfer;
@@ -60,21 +51,12 @@ pub fn par_transfer_whitepaper<FheType>(
where
FheType:
Add<Output = FheType> + for<'a> FheOrd<&'a FheType> + Send + Sync + FheTrivialEncrypt<u64>,
FheBool: IfThenZero<FheType> + IfThenElse<FheType>,
FheBool: IfThenElse<FheType>,
for<'a> &'a FheType: Add<Output = FheType> + Sub<Output = FheType>,
{
let has_enough_funds = (from_amount).ge(amount);
let amount_to_transfer = {
#[cfg(feature = "gpu")]
{
let zero_amount = FheType::encrypt_trivial(0u64);
has_enough_funds.select(amount, &zero_amount)
}
#[cfg(not(feature = "gpu"))]
{
has_enough_funds.if_then_zero(amount)
}
};
let zero_amount = FheType::encrypt_trivial(0u64);
let amount_to_transfer = has_enough_funds.select(amount, &zero_amount);
let (new_to_amount, new_from_amount) = rayon::join(
|| to_amount + &amount_to_transfer,

View File

@@ -1,44 +0,0 @@
use benchmark::params_aliases::BENCH_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
use criterion::{black_box, criterion_group, Criterion};
use std::num::NonZeroU64;
use tfhe::{set_server_key, ClientKey, ConfigBuilder, FheUint64, RangeForRandom, Seed, ServerKey};
pub fn oprf_any_range(c: &mut Criterion) {
let bench_name = "hlapi::oprf_any_range";
let mut bench_group = c.benchmark_group(bench_name);
bench_group
.sample_size(15)
.measurement_time(std::time::Duration::from_secs(30));
let param = BENCH_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(param).build();
let cks = ClientKey::generate(config);
let sks = ServerKey::new(&cks);
rayon::broadcast(|_| set_server_key(sks.clone()));
set_server_key(sks);
for excluded_upper_bound in [3, 52] {
let range = RangeForRandom::new_from_excluded_upper_bound(
NonZeroU64::new(excluded_upper_bound).unwrap(),
);
let bench_id_oprf = format!("{bench_name}::bound_{excluded_upper_bound}");
bench_group.bench_function(&bench_id_oprf, |b| {
b.iter(|| {
_ = black_box(FheUint64::generate_oblivious_pseudo_random_custom_range(
Seed(0),
&range,
None,
));
})
});
}
bench_group.finish()
}
criterion_group!(oprf_any_range2, oprf_any_range);

View File

@@ -630,7 +630,7 @@ mod integer_params {
#[cfg(feature = "hpu")]
let params = vec![BENCH_HPU_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128.into()];
#[cfg(not(feature = "hpu"))]
let params = vec![BENCH_PARAM_MESSAGE_2_CARRY_2_KS32_PBS.into()];
let params = vec![BENCH_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.into()];
let params_and_bit_sizes = iproduct!(params, env_config.bit_sizes());
Self {

View File

@@ -1,10 +1,12 @@
#[cfg(any(feature = "shortint", feature = "integer"))]
pub mod shortint_params_aliases {
use tfhe::shortint::parameters::current_params::*;
#[cfg(feature = "hpu")]
use tfhe::shortint::parameters::KeySwitch32PBSParameters;
use tfhe::shortint::parameters::{
ClassicPBSParameters, CompactPublicKeyEncryptionParameters, CompressionParameters,
KeySwitch32PBSParameters, MultiBitPBSParameters, NoiseSquashingCompressionParameters,
NoiseSquashingParameters, ShortintKeySwitchingParameters,
MultiBitPBSParameters, NoiseSquashingCompressionParameters, NoiseSquashingParameters,
ShortintKeySwitchingParameters,
};
// KS PBS Gaussian
@@ -40,8 +42,6 @@ pub mod shortint_params_aliases {
V1_5_PARAM_MESSAGE_4_CARRY_4_KS_PBS_TUNIFORM_2M128;
pub const BENCH_PARAM_MESSAGE_2_CARRY_2_KS_PBS: ClassicPBSParameters =
V1_5_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
pub const BENCH_PARAM_MESSAGE_2_CARRY_2_KS32_PBS: KeySwitch32PBSParameters =
V1_5_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
pub const BENCH_ALL_CLASSIC_PBS_PARAMETERS: [(&ClassicPBSParameters, &str); 141] =
VEC_ALL_CLASSIC_PBS_PARAMETERS;

View File

@@ -27,7 +27,6 @@ rand_distr = "0.4.3"
criterion = "0.5.1"
doc-comment = "0.3.3"
serde_json = "1.0.94"
num-bigint = "0.4.6"
# clap has to be pinned as its minimum supported rust version
# changes often between minor releases, which breaks our CI
clap = { version = "=4.5.30", features = ["derive"] }

View File

@@ -2,30 +2,14 @@
This document explains the mechanism and steps to generate an oblivious encrypted random value using only server keys.
The goal is to give to the server the possibility to generate a random value, which will be obtained in an encrypted format and will remain unknown to the server.
The goal is to give to the server the possibility to generate a random value, which will be obtained in an encrypted format and will remain unknown to the server. The implementation is based on [this article](https://eprint.iacr.org/2024/665).
The main method for this is `FheUint::generate_oblivious_pseudo_random_custom_range` which returns an integer in the given range.
Currently the range can only be in the form `[0, excluded_upper_bound[` with any `excluded_upper_bound` in `[1, 2^64[`
It follows a distribution close to the uniform.
This function guarantees the norm-1 distance (defined as ∆(P,Q) := 1/2 Sum[ω∈Ω] |P(ω) Q(ω)|)
between the actual distribution and the target uniform distribution will be below the `max_distance` argument (which must be in ]0, 1[).
The higher the distance, the more dissimilar the actual distribution is from the target uniform distribution.
The default value for `max_distance` is `2^-128` if `None` is provided.
Higher values allow better performance but must be considered carefully in the context of their target application as it may have serious unintended consequences.
If the range is a power of 2, the distribution is uniform (for any `max_distance`) and the cost is smaller.
For powers of 2 specifically there are two methods on `FheUint` and `FheInt` (based on [this article](https://eprint.iacr.org/2024/665)):
This is possible through two methods on `FheUint` and `FheInt`:
- `generate_oblivious_pseudo_random` which return an integer taken uniformly in the full integer range (`[0; 2^N[` for a `FheUintN` and `[-2^(N-1); 2^(N-1)[` for a `FheIntN`).
- `generate_oblivious_pseudo_random_bounded` which return an integer taken uniformly in `[0; 2^random_bits_count[`. For a `FheUintN`, we must have `random_bits_count <= N`. For a `FheIntN`, we must have `random_bits_count <= N - 1`.
These method functions take a seed `Seed` as input, which could be any `u128` value.
They rely on the use of the usual server key.
Both methods functions take a seed `Seed` as input, which could be any `u128` value.
They both rely on the use of the usual server key.
The output is reproducible, i.e., the function is deterministic from the inputs: assuming the same hardware, seed and server key, this function outputs the same random encrypted value.
@@ -34,8 +18,7 @@ Here is an example of the usage:
```rust
use tfhe::prelude::FheDecrypt;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8, FheInt8, RangeForRandom, Seed};
use std::num::NonZeroU64;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8, FheInt8, Seed};
pub fn main() {
let config = ConfigBuilder::default().build();
@@ -43,30 +26,23 @@ pub fn main() {
set_server_key(server_key);
let excluded_upper_bound = NonZeroU64::new(3).unwrap();
let range = RangeForRandom::new_from_excluded_upper_bound(excluded_upper_bound);
// in [0, excluded_upper_bound[ = {0, 1, 2}
let ct_res = FheUint8::generate_oblivious_pseudo_random_custom_range(Seed(0), &range, None);
let dec_result: u8 = ct_res.decrypt(&client_key);
let random_bits_count = 3;
// in [0, 2^8[
let ct_res = FheUint8::generate_oblivious_pseudo_random(Seed(0));
let dec_result: u8 = ct_res.decrypt(&client_key);
// in [0, 2^random_bits_count[ = [0, 8[
let ct_res = FheUint8::generate_oblivious_pseudo_random_bounded(Seed(0), random_bits_count);
let dec_result: u8 = ct_res.decrypt(&client_key);
assert!(dec_result < (1 << random_bits_count));
// in [-2^7, 2^7[
let ct_res = FheInt8::generate_oblivious_pseudo_random(Seed(0));
let dec_result: i8 = ct_res.decrypt(&client_key);
// in [0, 2^random_bits_count[ = [0, 8[
let ct_res = FheInt8::generate_oblivious_pseudo_random_bounded(Seed(0), random_bits_count);
let dec_result: i8 = ct_res.decrypt(&client_key);
assert!(dec_result < (1 << random_bits_count));
}

View File

@@ -17,7 +17,8 @@ use tfhe::shortint::parameters::key_switching::ShortintKeySwitchingParameters;
use tfhe::shortint::parameters::current_params::*;
use tfhe::shortint::parameters::{
ClassicPBSParameters, PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
AtomicPatternParameters, ClassicPBSParameters, PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
};
#[cfg(feature = "experimental")]
use tfhe::shortint::parameters::{
@@ -129,6 +130,8 @@ fn client_server_keys() {
];
generate_pbs_keys(&PBS_KEYS);
generate_pbs_keys(&[PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128]);
#[cfg(feature = "experimental")]
{
const WOPBS_PARAMS: [(ClassicPBSParameters, WopbsParameters); 4] = [
@@ -155,10 +158,11 @@ fn client_server_keys() {
}
}
fn generate_pbs_keys(params: &[ClassicPBSParameters]) {
fn generate_pbs_keys<P: Into<AtomicPatternParameters> + Copy>(params: &[P]) {
println!("Generating shortint (ClientKey, ServerKey)");
for (i, param) in params.iter().copied().enumerate() {
let param: AtomicPatternParameters = param.into();
println!(
"Generating [{} / {}] : {}",
i + 1,

View File

@@ -1,415 +0,0 @@
use aligned_vec::CACHELINE_ALIGN;
use dyn_stack::{PodStack, StackReq};
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::commons::utils::izip_eq;
use crate::core_crypto::entities::*;
use crate::core_crypto::fft_impl::fft64::crypto::ggsw::collect_next_term;
use crate::core_crypto::fft_impl::fft64::math::decomposition::TensorSignedDecompositionLendingIter;
use crate::core_crypto::prelude::polynomial_algorithms::*;
use crate::core_crypto::prelude::{
extract_lwe_sample_from_glwe_ciphertext, lwe_ciphertext_modulus_switch, ComputationBuffers,
DecompositionBaseLog, DecompositionLevelCount, GlweSize, ModulusSwitchedLweCiphertext,
MonomialDegree, PolynomialSize, SignedDecomposer,
};
pub fn programmable_bootstrap_karatsuba_lwe_ciphertext_mem_optimized_requirement<Scalar>(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
) -> StackReq {
StackReq::all_of(&[
// local accumulator
StackReq::new_aligned::<Scalar>(glwe_size.0 * polynomial_size.0, CACHELINE_ALIGN),
// blind rotation
blind_rotate_karatsuba_assign_scratch::<Scalar>(glwe_size, polynomial_size),
])
}
/// Return the required memory for [`blind_rotate_karatsuba_assign`].
pub fn blind_rotate_karatsuba_assign_scratch<Scalar>(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
) -> StackReq {
StackReq::any_of(&[
// tmp_poly allocation
StackReq::new_aligned::<Scalar>(polynomial_size.0, CACHELINE_ALIGN),
StackReq::all_of(&[
// ct1 allocation
StackReq::new_aligned::<Scalar>(glwe_size.0 * polynomial_size.0, CACHELINE_ALIGN),
// external product
karatsuba_add_external_product_assign_scratch::<Scalar>(glwe_size, polynomial_size),
]),
])
}
/// Return the required memory for [`karatsuba_add_external_product_assign`].
pub fn karatsuba_add_external_product_assign_scratch<Scalar>(
glwe_size: GlweSize,
polynomial_size: PolynomialSize,
) -> StackReq {
StackReq::all_of(&[
// Output buffer
StackReq::new_aligned::<Scalar>(glwe_size.0 * polynomial_size.0, CACHELINE_ALIGN),
// decomposition
StackReq::new_aligned::<Scalar>(glwe_size.0 * polynomial_size.0, CACHELINE_ALIGN),
// decomposition term
StackReq::new_aligned::<Scalar>(glwe_size.0 * polynomial_size.0, CACHELINE_ALIGN),
])
}
/// Perform a programmable bootstrap given an input [`LWE ciphertext`](`LweCiphertext`), a
/// look-up table passed as a [`GLWE ciphertext`](`GlweCiphertext`) and an [`LWE bootstrap
/// key`](`LweBootstrapKey`) using the karatsuba polynomial multiplication. The result is written in
/// the provided output [`LWE ciphertext`](`LweCiphertext`).
///
/// If you want to manage the computation memory manually you can use
/// [`programmable_bootstrap_karatsuba_lwe_ciphertext_mem_optimized`].
///
/// # Warning
/// For a more efficient implementation of the programmable bootstrap, see
/// [`programmable_bootstrap_lwe_ciphertext`](super::programmable_bootstrap_lwe_ciphertext)
pub fn programmable_bootstrap_karatsuba_lwe_ciphertext<InputCont, OutputCont, AccCont, KeyCont>(
input: &LweCiphertext<InputCont>,
output: &mut LweCiphertext<OutputCont>,
accumulator: &GlweCiphertext<AccCont>,
bsk: &LweBootstrapKey<KeyCont>,
) where
InputCont: Container<Element = u64>,
OutputCont: ContainerMut<Element = u64>,
AccCont: Container<Element = u64>,
KeyCont: Container<Element = u64>,
{
assert!(
input.ciphertext_modulus().is_power_of_two(),
"This operation requires the input to have a power of two modulus."
);
assert_eq!(
output.ciphertext_modulus(),
accumulator.ciphertext_modulus()
);
let mut buffers = ComputationBuffers::new();
buffers.resize(
programmable_bootstrap_karatsuba_lwe_ciphertext_mem_optimized_requirement::<u64>(
bsk.glwe_size(),
bsk.polynomial_size(),
)
.unaligned_bytes_required(),
);
programmable_bootstrap_karatsuba_lwe_ciphertext_mem_optimized(
input,
output,
accumulator,
bsk,
buffers.stack(),
);
}
/// Perform a programmable bootstrap given an input [`LWE ciphertext`](`LweCiphertext`), a
/// look-up table passed as a [`GLWE ciphertext`](`GlweCiphertext`) and an [`LWE bootstrap
/// key`](`LweBootstrapKey`) using the karatsuba polynomial multiplication. The result is written in
/// the provided output [`LWE ciphertext`](`LweCiphertext`).
///
/// # Warning
/// For a more efficient implementation of the programmable bootstrap, see
/// [`programmable_bootstrap_lwe_ciphertext_mem_optimized`](super::programmable_bootstrap_lwe_ciphertext_mem_optimized)
pub fn programmable_bootstrap_karatsuba_lwe_ciphertext_mem_optimized<
InputCont,
OutputCont,
AccCont,
KeyCont,
>(
input: &LweCiphertext<InputCont>,
output: &mut LweCiphertext<OutputCont>,
accumulator: &GlweCiphertext<AccCont>,
bsk: &LweBootstrapKey<KeyCont>,
stack: &mut PodStack,
) where
InputCont: Container<Element = u64>,
OutputCont: ContainerMut<Element = u64>,
AccCont: Container<Element = u64>,
KeyCont: Container<Element = u64>,
{
assert_eq!(
output.ciphertext_modulus(),
accumulator.ciphertext_modulus()
);
assert_eq!(accumulator.ciphertext_modulus(), bsk.ciphertext_modulus());
let (local_accumulator_data, stack) =
stack.collect_aligned(CACHELINE_ALIGN, accumulator.as_ref().iter().copied());
let mut local_accumulator = GlweCiphertextMutView::from_container(
&mut *local_accumulator_data,
accumulator.polynomial_size(),
accumulator.ciphertext_modulus(),
);
let log_modulus = accumulator
.polynomial_size()
.to_blind_rotation_input_modulus_log();
let msed = lwe_ciphertext_modulus_switch(input.as_view(), log_modulus);
blind_rotate_karatsuba_assign_mem_optimized(&msed, &mut local_accumulator, bsk, stack);
extract_lwe_sample_from_glwe_ciphertext(&local_accumulator, output, MonomialDegree(0));
}
/// Perform a blind rotation given an input [`modulus switched LWE
/// ciphertext`](`ModulusSwitchedLweCiphertext`), modifying a look-up table passed as a [`GLWE
/// ciphertext`](`GlweCiphertext`) and an [`LWE bootstrap key`](`LweBootstrapKey`) using the
/// karatsuba polynomial multiplication.
///
/// If you want to manage the computation memory manually you can use
/// [`blind_rotate_karatsuba_assign_mem_optimized`].
///
/// # Warning
/// For a more efficient implementation of the blind rotation, see
/// [`blind_rotate_assign`](super::blind_rotate_assign)
pub fn blind_rotate_karatsuba_assign<OutputScalar, OutputCont, KeyCont>(
msed_input: &impl ModulusSwitchedLweCiphertext<usize>,
lut: &mut GlweCiphertext<OutputCont>,
bsk: &LweBootstrapKey<KeyCont>,
) where
OutputScalar: UnsignedTorus + CastInto<usize>,
OutputCont: ContainerMut<Element = OutputScalar>,
KeyCont: Container<Element = OutputScalar>,
GlweCiphertext<OutputCont>: PartialEq<GlweCiphertext<OutputCont>>,
{
let mut buffers = ComputationBuffers::new();
buffers.resize(
blind_rotate_karatsuba_assign_scratch::<u64>(bsk.glwe_size(), bsk.polynomial_size())
.unaligned_bytes_required(),
);
blind_rotate_karatsuba_assign_mem_optimized(msed_input, lut, bsk, buffers.stack())
}
/// Perform a blind rotation given an input [`modulus switched LWE
/// ciphertext`](`ModulusSwitchedLweCiphertext`), modifying a look-up table passed as a [`GLWE
/// ciphertext`](`GlweCiphertext`) and an [`LWE bootstrap key`](`LweBootstrapKey`) using the
/// karatsuba polynomial multiplication.
///
/// # Warning
/// For a more efficient implementation of the blind rotation, see
/// [`blind_rotate_assign`](super::blind_rotate_assign)
pub fn blind_rotate_karatsuba_assign_mem_optimized<OutputScalar, OutputCont, KeyCont>(
msed_input: &impl ModulusSwitchedLweCiphertext<usize>,
lut: &mut GlweCiphertext<OutputCont>,
bsk: &LweBootstrapKey<KeyCont>,
stack: &mut PodStack,
) where
OutputScalar: UnsignedTorus + CastInto<usize>,
OutputCont: ContainerMut<Element = OutputScalar>,
KeyCont: Container<Element = OutputScalar>,
GlweCiphertext<OutputCont>: PartialEq<GlweCiphertext<OutputCont>>,
{
assert!(lut.ciphertext_modulus().is_power_of_two());
assert_eq!(
bsk.input_lwe_dimension(),
msed_input.lwe_dimension(),
"Mismatched input LweDimension. \
LweBootstrapKey input LweDimension: {:?}, input LweCiphertext LweDimension {:?}.",
bsk.input_lwe_dimension(),
msed_input.lwe_dimension(),
);
assert_eq!(
bsk.glwe_size(),
lut.glwe_size(),
"Mismatched GlweSize. \
LweBootstrapKey GlweSize: {:?}, lut GlweSize {:?}.",
bsk.glwe_size(),
lut.glwe_size(),
);
assert_eq!(
lut.polynomial_size(),
bsk.polynomial_size(),
"Mismatched PolynomialSize. \
LweBootstrapKey PolynomialSize: {:?}, lut PolynomialSize {:?}.",
bsk.polynomial_size(),
lut.polynomial_size(),
);
let msed_lwe_mask = msed_input.mask();
let msed_lwe_body = msed_input.body();
let monomial_degree = MonomialDegree(msed_lwe_body.cast_into());
let lut_poly_size = lut.polynomial_size();
let ciphertext_modulus = lut.ciphertext_modulus();
assert!(ciphertext_modulus.is_compatible_with_native_modulus());
lut.as_mut_polynomial_list()
.iter_mut()
.for_each(|mut poly| {
let (tmp_poly, _) = stack.make_aligned_raw(poly.as_ref().len(), CACHELINE_ALIGN);
let mut tmp_poly = Polynomial::from_container(&mut *tmp_poly);
tmp_poly.as_mut().copy_from_slice(poly.as_ref());
polynomial_wrapping_monic_monomial_div(&mut poly, &tmp_poly, monomial_degree);
});
// We initialize the ct_0 used for the successive cmuxes
let ct0 = lut;
let (ct1, stack) = stack.make_aligned_raw(ct0.as_ref().len(), CACHELINE_ALIGN);
let mut ct1 =
GlweCiphertextMutView::from_container(&mut *ct1, lut_poly_size, ciphertext_modulus);
for (lwe_mask_element, bootstrap_key_ggsw) in izip_eq!(msed_lwe_mask, bsk.iter()) {
if lwe_mask_element != 0 {
let monomial_degree = MonomialDegree(lwe_mask_element);
// we effectively inline the body of cmux here, merging the initial subtraction
// operation with the monic polynomial multiplication, then performing the
// external product manually
// We rotate ct_1 and subtract ct_0 (first step of cmux) by performing
// ct_1 <- (ct_0 * X^a_i) - ct_0
for (mut ct1_poly, ct0_poly) in izip_eq!(
ct1.as_mut_polynomial_list().iter_mut(),
ct0.as_polynomial_list().iter(),
) {
polynomial_wrapping_monic_monomial_mul_and_subtract(
&mut ct1_poly,
&ct0_poly,
monomial_degree,
);
}
// second step of cmux:
// ct_0 <- ct_0 + ct1 * s_i
// with ct_0 + ct1s_i = ct_0 + ((ct_0 * X^a_i) - ct_0)s_i
// = ct_0 if s_i= 0
// ct_0 * X^a_i otherwise
// = ct_0 * X^(a_i * s_i)
//
// as_mut_view is required to keep borrow rules consistent
karatsuba_add_external_product_assign(
ct0.as_mut_view(),
bootstrap_key_ggsw,
ct1.as_view(),
stack,
);
}
}
if !ciphertext_modulus.is_native_modulus() {
let signed_decomposer = SignedDecomposer::new(
DecompositionBaseLog(ciphertext_modulus.get_custom_modulus().ilog2() as usize),
DecompositionLevelCount(1),
);
ct0.as_mut()
.iter_mut()
.for_each(|x| *x = signed_decomposer.closest_representable(*x));
}
}
/// Perform the external product of `ggsw` and `glwe`, and adds the result to `out`.
#[cfg_attr(feature = "__profiling", inline(never))]
pub fn karatsuba_add_external_product_assign<Scalar>(
mut out: GlweCiphertextMutView<'_, Scalar>,
ggsw: GgswCiphertextView<Scalar>,
glwe: GlweCiphertextView<Scalar>,
stack: &mut PodStack,
) where
Scalar: UnsignedTorus,
{
// 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(), glwe.glwe_size());
debug_assert_eq!(ggsw.glwe_size(), out.glwe_size());
let align = CACHELINE_ALIGN;
let poly_size = ggsw.polynomial_size().0;
// we round the input mask and body
let decomposer = SignedDecomposer::<Scalar>::new(
ggsw.decomposition_base_log(),
ggsw.decomposition_level_count(),
);
let (output_buffer, substack0) =
stack.make_aligned_raw::<Scalar>(poly_size * ggsw.glwe_size().0, align);
// 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_buffer = &mut *output_buffer;
let mut is_output_uninit = true;
let (mut decomposition, substack1) = TensorSignedDecompositionLendingIter::new(
glwe.as_ref()
.iter()
.map(|s| decomposer.init_decomposer_state(*s)),
DecompositionBaseLog(decomposer.base_log),
DecompositionLevelCount(decomposer.level_count),
substack0,
);
// We loop through the levels
for ggsw_decomp_matrix in ggsw.iter() {
// We retrieve the decomposition of this level.
let (_glwe_level, glwe_decomp_term, _substack2) =
collect_next_term(&mut decomposition, substack1, align);
let glwe_decomp_term = GlweCiphertextView::from_container(
&*glwe_decomp_term,
ggsw.polynomial_size(),
out.ciphertext_modulus(),
);
// 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 ...
for (ggsw_row, glwe_poly) in izip_eq!(
ggsw_decomp_matrix.as_glwe_list().iter(),
glwe_decomp_term.as_polynomial_list().iter()
) {
let row_as_poly_list = ggsw_row.as_polynomial_list();
if is_output_uninit {
for (mut output_poly, row_poly) in output_buffer
.chunks_exact_mut(poly_size)
.map(Polynomial::from_container)
.zip(row_as_poly_list.iter())
{
polynomial_wrapping_mul(&mut output_poly, &row_poly, &glwe_poly);
}
} else {
for (mut output_poly, row_poly) in output_buffer
.chunks_exact_mut(poly_size)
.map(Polynomial::from_container)
.zip(row_as_poly_list.iter())
{
polynomial_wrapping_add_mul_assign(&mut output_poly, &row_poly, &glwe_poly);
}
}
is_output_uninit = false;
}
}
// We iterate over the polynomials in the output.
if !is_output_uninit {
izip_eq!(
out.as_mut_polynomial_list().iter_mut(),
output_buffer
.into_chunks(poly_size)
.map(Polynomial::from_container),
)
.for_each(|(mut out, res)| polynomial_wrapping_add_assign(&mut out, &res));
}
}

View File

@@ -1,12 +1,10 @@
pub mod fft128_pbs;
pub mod fft64_pbs;
pub mod karatsuba_pbs;
pub mod ntt64_bnf_pbs;
pub mod ntt64_pbs;
pub use fft128_pbs::*;
pub use fft64_pbs::*;
pub use karatsuba_pbs::*;
pub use ntt64_bnf_pbs::*;
pub use ntt64_pbs::*;

View File

@@ -1161,91 +1161,3 @@ fn lwe_encrypt_pbs_ntt64_bnf_decrypt(params: ClassicTestParams<u64>) {
create_parameterized_test!(lwe_encrypt_pbs_ntt64_bnf_decrypt {
TEST_PARAMS_3_BITS_SOLINAS_U64
});
fn lwe_encrypt_pbs_karatsuba_decrypt_custom_mod(params: ClassicTestParams<u64>) {
let lwe_noise_distribution = params.lwe_noise_distribution;
let ciphertext_modulus = params.ciphertext_modulus;
let message_modulus_log = params.message_modulus_log;
let msg_modulus = 1 << (message_modulus_log.0);
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
let glwe_dimension = params.glwe_dimension;
let polynomial_size = params.polynomial_size;
let mut rsc = TestResources::new();
let f = |x: u64| x;
let delta: u64 = encoding_with_padding / msg_modulus;
let mut msg = msg_modulus;
let accumulator = generate_programmable_bootstrap_glwe_lut(
polynomial_size,
glwe_dimension.to_glwe_size(),
msg_modulus.cast_into(),
ciphertext_modulus,
delta,
f,
);
assert!(check_encrypted_content_respects_mod(
&accumulator,
ciphertext_modulus
));
while msg != 0 {
msg = msg.wrapping_sub(1);
let mut keys_gen = |params| generate_keys(params, &mut rsc);
let keys = gen_keys_or_get_from_cache_if_enabled(params, &mut keys_gen);
let (input_lwe_secret_key, output_lwe_secret_key, bsk) =
(keys.small_lwe_sk, keys.big_lwe_sk, keys.bsk);
for _ in 0..NB_TESTS {
let plaintext = Plaintext(msg * delta);
let lwe_ciphertext_in = allocate_and_encrypt_new_lwe_ciphertext(
&input_lwe_secret_key,
plaintext,
lwe_noise_distribution,
ciphertext_modulus,
&mut rsc.encryption_random_generator,
);
assert!(check_encrypted_content_respects_mod(
&lwe_ciphertext_in,
ciphertext_modulus
));
let mut out_pbs_ct = LweCiphertext::new(
0,
output_lwe_secret_key.lwe_dimension().to_lwe_size(),
ciphertext_modulus,
);
programmable_bootstrap_karatsuba_lwe_ciphertext(
&lwe_ciphertext_in,
&mut out_pbs_ct,
&accumulator,
&bsk,
);
assert!(check_encrypted_content_respects_mod(
&out_pbs_ct,
ciphertext_modulus
));
let decrypted = decrypt_lwe_ciphertext(&output_lwe_secret_key, &out_pbs_ct);
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
assert_eq!(decoded, f(msg));
}
// In coverage, we break after one while loop iteration, changing message values does not
// yield higher coverage
#[cfg(tarpaulin)]
break;
}
}
create_parameterized_test!(lwe_encrypt_pbs_karatsuba_decrypt_custom_mod);

View File

@@ -540,12 +540,10 @@ pub fn sup_diff(cumulative_bins: &[u64], theoretical_cdf: &[f64]) -> f64 {
.iter()
.copied()
.zip_eq(theoretical_cdf.iter().copied())
.enumerate()
.map(|(i, (x, theoretical_cdf))| {
.map(|(x, theoretical_cdf)| {
let empirical_cdf = x as f64 / number_of_samples as f64;
if i == cumulative_bins.len() - 1 {
assert_eq!(theoretical_cdf, 1.0);
if theoretical_cdf == 1.0 {
assert_eq!(empirical_cdf, 1.0);
}

View File

@@ -7,7 +7,7 @@ use crate::high_level_api::integers::{FheInt, FheIntId, FheUint, FheUintId};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::high_level_api::traits::{
FheEq, Flip, IfThenElse, IfThenZero, ReRandomize, ScalarIfThenElse, Tagged,
FheEq, Flip, IfThenElse, ReRandomize, ScalarIfThenElse, Tagged,
};
use crate::high_level_api::{global_state, CompactPublicKey};
use crate::integer::block_decomposition::DecomposableInto;
@@ -552,66 +552,6 @@ where
}
}
impl<Id> IfThenZero<FheUint<Id>> for FheBool
where
Id: FheUintId,
{
/// Conditional selection.
///
/// The output value returned depends on the value of `self`.
///
/// - if `self` is true, the output will have the value of `ct_then`
/// - if `self` is false, the output will be an encryption of 0
fn if_then_zero(&self, ct_then: &FheUint<Id>) -> FheUint<Id> {
global_state::with_internal_keys(|sks| match sks {
InternalServerKey::Cpu(cpu_sks) => {
let ct_condition = self;
let mut ct_out = ct_then.ciphertext.on_cpu().clone();
cpu_sks.pbs_key().zero_out_if_condition_is_false(
&mut ct_out,
&ct_condition.ciphertext.on_cpu().0,
);
FheUint::new(
ct_out,
cpu_sks.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => {
panic!("Cuda does not support if_then_zero")
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(device) => {
let hpu_then = ct_then.ciphertext.on_hpu(device);
let hpu_cond = self.ciphertext.on_hpu(device);
let (opcode, proto) = {
let asm_iop = &hpu_asm::iop::IOP_IF_THEN_ZERO;
(
asm_iop.opcode(),
&asm_iop.format().expect("Unspecified IOP format").proto,
)
};
// These clones are cheap are they are just Arc
let hpu_result = HpuRadixCiphertext::exec(
proto,
opcode,
&[hpu_then.clone(), hpu_cond.clone()],
&[],
)
.pop()
.unwrap();
FheUint::new(
hpu_result,
device.tag.clone(),
ReRandomizationMetadata::default(),
)
}
})
}
}
impl<Id: FheIntId> IfThenElse<FheInt<Id>> for FheBool {
/// Conditional selection.
///

View File

@@ -320,7 +320,7 @@ mod cpu {
use super::*;
use crate::high_level_api::booleans::compressed::CompressedFheBoolConformanceParams;
use crate::safe_serialization::{DeserializationConfig, SerializationConfig};
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
use crate::shortint::parameters::test_params::TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
use crate::FheBoolConformanceParams;
use rand::random;
@@ -675,7 +675,7 @@ mod cpu {
#[test]
fn test_safe_deserialize_conformant_fhe_bool() {
let block_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let block_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let (keys, server_key) = generate_keys(ConfigBuilder::with_custom_parameters(block_params));
set_server_key(server_key.clone());
@@ -698,7 +698,7 @@ mod cpu {
#[test]
fn test_safe_deserialize_conformant_compressed_fhe_bool() {
let block_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let block_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let (keys, server_key) = generate_keys(ConfigBuilder::with_custom_parameters(block_params));
set_server_key(server_key.clone());
let clear_a = random::<bool>();

View File

@@ -850,7 +850,7 @@ mod zk {
fn conformance_zk_compact_ciphertext_list() {
let mut rng = thread_rng();
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let params = PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let cpk_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;

View File

@@ -957,12 +957,13 @@ pub mod gpu {
mod tests {
use crate::prelude::*;
use crate::safe_serialization::{safe_deserialize, safe_serialize};
#[cfg(any(not(feature = "gpu"), feature = "strings"))]
use crate::shortint::parameters::test_params::TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
#[cfg(feature = "gpu")]
use crate::shortint::parameters::COMP_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
#[cfg(feature = "gpu")]
use crate::shortint::parameters::PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
#[cfg(not(feature = "gpu"))]
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
use crate::shortint::parameters::{
COMP_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
};
@@ -983,9 +984,10 @@ mod tests {
),
#[cfg(not(feature = "gpu"))]
(
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128.into(),
TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128.into(),
COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
),
#[cfg(feature = "gpu")]
(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.into(),
COMP_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
@@ -1147,7 +1149,7 @@ mod tests {
#[cfg(feature = "strings")]
#[test]
fn test_compressed_strings_cpu() {
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let config = crate::ConfigBuilder::with_custom_parameters(params)
.enable_compression(COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128)
.build();

View File

@@ -628,24 +628,25 @@ mod tests {
use super::*;
use crate::prelude::*;
use crate::safe_serialization::{safe_deserialize, safe_serialize};
use crate::shortint::parameters::current_params::*;
use crate::{generate_keys, set_server_key, ConfigBuilder, FheBool, FheInt32, FheUint32};
use crate::shortint::parameters::test_params::TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
#[cfg(feature = "gpu")]
use crate::shortint::parameters::v1_5::{
V1_5_NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
V1_5_NOISE_SQUASHING_PARAM_GPU_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
V1_5_NOISE_SQUASHING_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
V1_5_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
V1_5_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
};
#[cfg(feature = "gpu")]
use crate::ConfigBuilder;
use crate::{generate_keys, set_server_key, FheBool, FheInt32, FheUint32};
use rand::Rng;
#[test]
fn test_compressed_squashed_noise_ciphertext_list() {
let params = V1_5_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let noise_squashing_params =
V1_5_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let noise_squashing_compression_params =
V1_5_NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let meta_params = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(params)
.enable_noise_squashing(noise_squashing_params)
.enable_noise_squashing_compression(noise_squashing_compression_params)
.build();
let (cks, sks) = generate_keys(config);
let (cks, sks) = generate_keys(meta_params);
let mut rng = rand::thread_rng();

View File

@@ -4,9 +4,7 @@ use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::{CudaSignedRadixCiphertext, CudaUnsignedRadixCiphertext};
use crate::shortint::MessageModulus;
use crate::{FheInt, Seed};
use std::num::NonZeroU64;
impl<Id: FheUintId> FheUint<Id> {
/// Generates an encrypted unsigned integer
@@ -94,7 +92,7 @@ impl<Id: FheUintId> FheUint<Id> {
}
})
}
/// Generates an encrypted unsigned integer
/// Generates an encrypted `num_block` blocks unsigned integer
/// taken uniformly in `[0, 2^random_bits_count[` using the given seed.
/// The encrypted value is oblivious to the server.
/// It can be useful to make server random generation deterministic.
@@ -152,103 +150,6 @@ impl<Id: FheUintId> FheUint<Id> {
}
})
}
/// Generates an encrypted unsigned integer
/// taken almost uniformly in the given range using the given seed.
/// Currently the range can only be in the form `[0, excluded_upper_bound[`
/// with any `excluded_upper_bound` in `[1, 2^64[`.
///
/// The encrypted value is oblivious to the server.
/// It can be useful to make server random generation deterministic.
///
/// This function guarantees the the norm-1 distance
/// (defined as ∆(P,Q) := 1/2 Sum[ω∈Ω] |P(ω) Q(ω)|)
/// between the actual distribution and the target uniform distribution
/// will be below the `max_distance` argument (which must be in ]0, 1[).
/// The higher the distance, the more dissimilar the actual distribution is
/// from the target uniform distribution.
///
/// The default value for `max_distance` is `2^-128` if `None` is provided.
///
/// Higher values allow better performance but must be considered carefully in the context of
/// their target application as it may have serious unintended consequences.
///
/// If the range is a power of 2, the distribution is uniform (for any `max_distance`) and
/// the cost is smaller.
///
/// ```rust
/// use std::num::NonZeroU64;
/// use tfhe::prelude::FheDecrypt;
/// use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8, RangeForRandom, Seed};
///
/// let config = ConfigBuilder::default().build();
/// let (client_key, server_key) = generate_keys(config);
///
/// set_server_key(server_key);
///
/// let excluded_upper_bound = NonZeroU64::new(3).unwrap();
///
/// let range = RangeForRandom::new_from_excluded_upper_bound(excluded_upper_bound);
///
/// let ct_res = FheUint8::generate_oblivious_pseudo_random_custom_range(Seed(0), &range, None);
///
/// let dec_result: u16 = ct_res.decrypt(&client_key);
/// assert!(dec_result < excluded_upper_bound.get() as u16);
/// ```
pub fn generate_oblivious_pseudo_random_custom_range(
seed: Seed,
range: &RangeForRandom,
max_distance: Option<f64>,
) -> Self {
let excluded_upper_bound = range.excluded_upper_bound;
if excluded_upper_bound.is_power_of_two() {
let random_bits_count = excluded_upper_bound.ilog2() as u64;
Self::generate_oblivious_pseudo_random_bounded(seed, random_bits_count)
} else {
let max_distance = max_distance.unwrap_or_else(|| 2_f64.powi(-128));
assert!(
0_f64 < max_distance && max_distance < 1_f64,
"max_distance (={max_distance}) should be in ]0, 1["
);
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(key) => {
let message_modulus = key.message_modulus();
let num_input_random_bits = num_input_random_bits_for_max_distance(
excluded_upper_bound,
max_distance,
message_modulus,
);
let num_blocks_output = Id::num_blocks(key.message_modulus()) as u64;
let ct = key
.pbs_key()
.par_generate_oblivious_pseudo_random_unsigned_custom_range(
seed,
num_input_random_bits,
excluded_upper_bound,
num_blocks_output,
);
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_cuda_key) => {
panic!("Gpu does not support this operation yet.")
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_device) => {
panic!("Hpu does not support this operation yet.")
}
})
}
}
#[cfg(feature = "gpu")]
/// Returns the amount of memory required to execute generate_oblivious_pseudo_random_bounded
///
@@ -372,7 +273,7 @@ impl<Id: FheIntId> FheInt<Id> {
}
})
}
/// Generates an encrypted signed integer
/// Generates an encrypted `num_block` blocks signed integer
/// taken uniformly in `[0, 2^random_bits_count[` using the given seed.
/// The encrypted value is oblivious to the server.
/// It can be useful to make server random generation deterministic.
@@ -466,350 +367,10 @@ impl<Id: FheIntId> FheInt<Id> {
}
}
pub struct RangeForRandom {
excluded_upper_bound: NonZeroU64,
}
impl RangeForRandom {
pub fn new_from_excluded_upper_bound(excluded_upper_bound: NonZeroU64) -> Self {
Self {
excluded_upper_bound,
}
}
}
fn num_input_random_bits_for_max_distance(
excluded_upper_bound: NonZeroU64,
max_distance: f64,
message_modulus: MessageModulus,
) -> u64 {
assert!(message_modulus.0.is_power_of_two());
let log_message_modulus = message_modulus.0.ilog2() as u64;
let mut random_block_count = 1;
let random_block_count = loop {
let random_bit_count = random_block_count * log_message_modulus;
let distance = distance(excluded_upper_bound.get(), random_bit_count);
if distance < max_distance {
break random_block_count;
}
random_block_count += 1;
};
random_block_count * log_message_modulus
}
fn distance(excluded_upper_bound: u64, random_bit_count: u64) -> f64 {
let remainder = mod_pow_2(random_bit_count, excluded_upper_bound);
remainder as f64 * (excluded_upper_bound - remainder) as f64
/ (2_f64.powi(random_bit_count as i32) * excluded_upper_bound as f64)
}
// Computes 2^exponent % modulus
fn mod_pow_2(exponent: u64, modulus: u64) -> u64 {
assert_ne!(modulus, 0);
if modulus == 1 {
return 0;
}
let mut result: u128 = 1;
let mut base: u128 = 2; // We are calculating 2^i
// We cast exponent to u128 to match the loop, though u64 is fine
let mut exp = exponent;
let mod_val = modulus as u128;
while exp > 0 {
// If exponent is odd, multiply result with base
if exp % 2 == 1 {
result = (result * base) % mod_val;
}
// Square the base
base = (base * base) % mod_val;
// Divide exponent by 2
exp /= 2;
}
result as u64
}
#[cfg(test)]
mod test {
use super::*;
use crate::integer::server_key::radix_parallel::tests_unsigned::test_oprf::{
oprf_density_function, p_value_upper_bound_oprf_almost_uniformity_from_values,
probability_density_function_from_density,
};
use crate::prelude::FheDecrypt;
use crate::shortint::oprf::test::test_uniformity;
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
use crate::{generate_keys, set_server_key, ClientKey, ConfigBuilder, FheUint8, Seed};
use num_bigint::BigUint;
use rand::{thread_rng, Rng};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
// Helper: The "Oracle" implementation using BigInt
// This is slow but mathematically guaranteed to be correct.
fn oracle_mod_pow_2(exponent: u64, modulus: u64) -> u64 {
assert_ne!(modulus, 0);
if modulus == 1 {
return 0;
}
let base = BigUint::from(2u32);
let exp = BigUint::from(exponent);
let modu = BigUint::from(modulus);
let res = base.modpow(&exp, &modu);
res.iter_u64_digits().next().unwrap_or(0)
}
#[test]
fn test_edge_cases() {
// 2^0 % 10 = 1
assert_eq!(mod_pow_2(0, 10), 1, "Failed exponent 0");
// 2^10 % 1 = 0
assert_eq!(mod_pow_2(10, 1), 0, "Failed modulus 1");
// 2^1 % 10 = 2
assert_eq!(mod_pow_2(1, 10), 2, "Failed exponent 1");
// 2^3 % 5 = 8 % 5 = 3
assert_eq!(mod_pow_2(3, 5), 3, "Failed small calc");
}
#[test]
fn test_boundaries_and_overflow() {
assert_eq!(mod_pow_2(2, u64::MAX), 4);
assert_eq!(mod_pow_2(u64::MAX, 3), 2);
assert_eq!(mod_pow_2(5, 32), 0);
}
#[test]
fn test_against_oracle() {
let mut rng = thread_rng();
for _ in 0..1_000_000 {
let exp: u64 = rng.gen();
let mod_val: u64 = rng.gen();
let mod_val = if mod_val == 0 { 1 } else { mod_val };
let expected = oracle_mod_pow_2(exp, mod_val);
let actual = mod_pow_2(exp, mod_val);
assert_eq!(
actual, expected,
"Mismatch! 2^{exp} % {mod_val} => Ours: {actual}, Oracle: {expected}",
);
}
}
#[test]
fn test_distance_with_uniform() {
for excluded_upper_bound in 1..20 {
for num_input_random_bits in 0..20 {
let density = oprf_density_function(excluded_upper_bound, num_input_random_bits);
let theoretical_pdf = probability_density_function_from_density(&density);
let p_uniform = 1. / excluded_upper_bound as f64;
let actual_distance: f64 = 1. / 2.
* theoretical_pdf
.iter()
.map(|p| (*p - p_uniform).abs())
.sum::<f64>();
let theoretical_distance = distance(excluded_upper_bound, num_input_random_bits);
assert!(
(theoretical_distance - actual_distance).abs()
<= theoretical_distance / 1_000_000.,
"{theoretical_distance} != {actual_distance}"
);
}
}
}
#[test]
fn test_uniformity_scalar_mul_shift() {
let max_distance = 2_f64.powi(-20);
let message_modulus = MessageModulus(4);
let excluded_upper_bound = 3;
let num_input_random_bits = num_input_random_bits_for_max_distance(
NonZeroU64::new(excluded_upper_bound).unwrap(),
max_distance,
message_modulus,
);
let sample_count: usize = 10_000_000;
let p_value_limit: f64 = 0.001;
// The distribution is not exactly uniform
// This check ensures than with the given low max_distance,
// the distribution is indistinguishable from the uniform with at the given sample count
test_uniformity(sample_count, p_value_limit, excluded_upper_bound, |_seed| {
oprf_clear_equivalent(excluded_upper_bound, num_input_random_bits)
});
}
fn oprf_clear_equivalent(excluded_upper_bound: u64, num_input_random_bits: u64) -> u64 {
let random_input_upper_bound = 1 << num_input_random_bits;
let random_input = thread_rng().gen_range(0..random_input_upper_bound);
(random_input * excluded_upper_bound) >> num_input_random_bits
}
#[test]
fn test_uniformity_generate_oblivious_pseudo_random_custom_range() {
let base_sample_count: usize = 10_000;
let p_value_limit: f64 = 0.001;
let params = PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(params).build();
let (cks, sks) = generate_keys(config);
rayon::broadcast(|_| set_server_key(sks.clone()));
let message_modulus = params.message_modulus;
// [0.7, 0.1] for `max_distance` chosen to have `num_input_random_bits` be [2, 4]
// for any of the listed `excluded_upper_bound`
for (expected_num_input_random_bits, max_distance, excluded_upper_bounds) in
[(2, 0.7, [3, 5, 6, 7]), (4, 0.1, [3, 5, 6, 7])]
{
for excluded_upper_bound in excluded_upper_bounds {
let sample_count = base_sample_count * excluded_upper_bound as usize;
let excluded_upper_bound = NonZeroU64::new(excluded_upper_bound).unwrap();
let num_input_random_bits = num_input_random_bits_for_max_distance(
excluded_upper_bound,
max_distance,
message_modulus,
);
assert_eq!(num_input_random_bits, expected_num_input_random_bits);
test_uniformity_generate_oblivious_pseudo_random_custom_range2(
sample_count,
p_value_limit,
message_modulus,
&cks,
excluded_upper_bound,
max_distance,
);
}
}
}
fn test_uniformity_generate_oblivious_pseudo_random_custom_range2(
sample_count: usize,
p_value_limit: f64,
message_modulus: MessageModulus,
cks: &ClientKey,
excluded_upper_bound: NonZeroU64,
max_distance: f64,
) {
let num_input_random_bits = num_input_random_bits_for_max_distance(
excluded_upper_bound,
max_distance,
message_modulus,
);
let range = RangeForRandom::new_from_excluded_upper_bound(excluded_upper_bound);
let real_values: Vec<u64> = (0..sample_count)
.into_par_iter()
.map(|_| {
let img = FheUint8::generate_oblivious_pseudo_random_custom_range(
Seed(rand::thread_rng().gen::<u128>()),
&range,
Some(max_distance),
);
img.decrypt(cks)
})
.collect();
let excluded_upper_bound = excluded_upper_bound.get();
let uniform_values: Vec<u64> = (0..sample_count)
.into_par_iter()
.map(|_| thread_rng().gen_range(0..excluded_upper_bound))
.collect();
let clear_oprf_value_lower_num_input_random_bits = (0..sample_count)
.into_par_iter()
.map(|_| oprf_clear_equivalent(excluded_upper_bound, num_input_random_bits - 1))
.collect();
let clear_oprf_value_same_num_input_random_bits = (0..sample_count)
.into_par_iter()
.map(|_| oprf_clear_equivalent(excluded_upper_bound, num_input_random_bits))
.collect();
let clear_oprf_value_higher_num_input_random_bits = (0..sample_count)
.into_par_iter()
.map(|_| oprf_clear_equivalent(excluded_upper_bound, num_input_random_bits + 1))
.collect();
for (values, should_have_low_p_value) in [
(&real_values, false),
// to test that the same distribution passes
(&clear_oprf_value_same_num_input_random_bits, false),
// to test that other distribution don't pass
// (makes sure the test is statistically powerful)
(&uniform_values, true),
(&clear_oprf_value_lower_num_input_random_bits, true),
(&clear_oprf_value_higher_num_input_random_bits, true),
] {
let p_value_upper_bound = p_value_upper_bound_oprf_almost_uniformity_from_values(
values,
num_input_random_bits,
excluded_upper_bound,
);
println!("p_value_upper_bound: {p_value_upper_bound}");
if should_have_low_p_value {
assert!(
p_value_upper_bound < p_value_limit,
"p_value_upper_bound (={p_value_upper_bound}) expected to be smaller than {p_value_limit}"
);
} else {
assert!(
p_value_limit < p_value_upper_bound ,
"p_value_upper_bound (={p_value_upper_bound}) expected to be bigger than {p_value_limit}"
);
}
}
}
}
#[cfg(test)]
#[cfg(feature = "gpu")]
#[allow(unused_imports)]
mod test_gpu {
mod test {
use crate::prelude::*;
use crate::{
generate_keys, set_server_key, ConfigBuilder, FheInt128, FheUint32, FheUint64, GpuIndex,

View File

@@ -7,10 +7,10 @@ use crate::prelude::{
use crate::shortint::parameters::test_params::{
TEST_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS_GAUSSIAN_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_PBS_KS_GAUSSIAN_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_PBS_KS_GAUSSIAN_2M128,
TEST_PARAM_MULTI_BIT_GROUP_3_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128,
};
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
use crate::{
generate_keys, set_server_key, CompactCiphertextList, CompactPublicKey, CompressedFheInt16,
CompressedFheInt32, CompressedFheInt32ConformanceParams, ConfigBuilder, DeserializationConfig,
@@ -205,7 +205,7 @@ fn test_leading_trailing_zeros_ones() {
#[test]
fn test_safe_deserialize_conformant_fhe_int32() {
let block_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let block_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let (client_key, server_key) =
generate_keys(ConfigBuilder::with_custom_parameters(block_params));
set_server_key(server_key.clone());
@@ -230,7 +230,7 @@ fn test_safe_deserialize_conformant_fhe_int32() {
#[test]
fn test_safe_deserialize_conformant_compressed_fhe_int32() {
let block_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let block_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let (client_key, server_key) =
generate_keys(ConfigBuilder::with_custom_parameters(block_params));
set_server_key(server_key.clone());

View File

@@ -1850,7 +1850,10 @@ mod test {
use super::*;
use crate::core_crypto::prelude::UnsignedInteger;
use crate::prelude::*;
use crate::shortint::parameters::{AtomicPatternKind, PARAM_MESSAGE_2_CARRY_2_KS_PBS};
use crate::shortint::parameters::{
AtomicPatternKind, PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS,
};
use crate::shortint::{CiphertextModulus, PBSOrder};
use crate::{generate_keys, set_server_key, ConfigBuilder, FheUint8};
use rand::{thread_rng, Rng};
@@ -1880,7 +1883,7 @@ mod test {
let ct = FheUint8::try_encrypt(0_u64, &client_key).unwrap();
assert!(ct.is_conformant(&FheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
)));
let breaker_lists = [
@@ -1940,7 +1943,7 @@ mod test {
breaker(i, &mut ct_clone);
assert!(!ct_clone.is_conformant(&FheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
)));
}
}
@@ -1957,7 +1960,7 @@ mod test {
let ct = FheUint8::try_encrypt(0_u64, &client_key).unwrap();
assert!(ct.is_conformant(&FheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
)));
let mut rng = thread_rng();
@@ -1975,7 +1978,7 @@ mod test {
}
assert!(ct.is_conformant(&FheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
)));
ct_clone += &ct_clone.clone();

View File

@@ -263,7 +263,7 @@ where
mod test {
use super::*;
use crate::core_crypto::prelude::UnsignedInteger;
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
use crate::shortint::{CiphertextModulus, CompressedCiphertext};
use crate::{generate_keys, set_server_key, CompressedFheUint8, ConfigBuilder};
use rand::{thread_rng, Rng};
@@ -315,7 +315,7 @@ mod test {
let ct = CompressedFheUint8::try_encrypt(0_u64, &client_key).unwrap();
assert!(ct.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128
)));
let breaker_lists = [
@@ -340,7 +340,7 @@ mod test {
assert!(
!ct_clone.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128
))
);
}
@@ -373,7 +373,7 @@ mod test {
assert!(
!ct_clone.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128
))
);
}
@@ -391,7 +391,7 @@ mod test {
let ct = CompressedFheUint8::try_encrypt(0_u64, &client_key).unwrap();
assert!(ct.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128
)));
let mut rng = thread_rng();
@@ -410,9 +410,10 @@ mod test {
.seed
.0 = rng.gen::<u128>();
}
assert!(
ct_clone.is_conformant(&CompressedFheUintConformanceParams::from(
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128
))
);

View File

@@ -5,7 +5,6 @@ use crate::high_level_api::{generate_keys, set_server_key, ConfigBuilder, FheUin
use crate::integer::U256;
use crate::safe_serialization::{DeserializationConfig, SerializationConfig};
use crate::shortint::parameters::test_params::*;
use crate::shortint::parameters::*;
use crate::{
ClientKey, CompactCiphertextList, CompactCiphertextListConformanceParams, CompactPublicKey,
CompressedCompactPublicKey, CompressedFheUint16, CompressedFheUint256, CompressedFheUint32,
@@ -386,12 +385,6 @@ fn test_if_then_else() {
super::test_case_if_then_else(&client_key);
}
#[test]
fn test_if_then_zero() {
let client_key = setup_default_cpu();
super::test_case_if_then_zero(&client_key);
}
#[test]
fn test_flip() {
let client_key = setup_default_cpu();
@@ -476,7 +469,7 @@ fn test_match_value() {
#[test]
fn test_safe_deserialize_conformant_fhe_uint32() {
let block_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let block_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let (client_key, server_key) =
generate_keys(ConfigBuilder::with_custom_parameters(block_params));
set_server_key(server_key.clone());
@@ -500,7 +493,7 @@ fn test_safe_deserialize_conformant_fhe_uint32() {
#[test]
fn test_safe_deserialize_conformant_compressed_fhe_uint32() {
let block_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let block_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let (client_key, server_key) =
generate_keys(ConfigBuilder::with_custom_parameters(block_params));
set_server_key(server_key.clone());
@@ -525,7 +518,7 @@ fn test_safe_deserialize_conformant_compressed_fhe_uint32() {
#[test]
fn test_safe_deserialize_conformant_compact_fhe_uint32() {
let block_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let block_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let (client_key, server_key) =
generate_keys(ConfigBuilder::with_custom_parameters(block_params));
set_server_key(server_key);
@@ -561,9 +554,9 @@ fn test_safe_deserialize_conformant_compact_fhe_uint32() {
#[test]
fn test_cpk_encrypt_cast_compute_hl() {
let param_pke_only = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let param_fhe = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let param_ksk = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let param_fhe = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let param_pke_only = TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
let param_ksk = TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let num_block = 4usize;
@@ -610,10 +603,9 @@ fn test_cpk_encrypt_cast_compute_hl() {
#[test]
fn test_compressed_cpk_encrypt_cast_compute_hl() {
let param_pke_only = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let param_fhe = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let param_ksk = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let param_fhe = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let param_pke_only = TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
let param_ksk = TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let num_block = 4usize;
assert_eq!(param_pke_only.message_modulus, param_fhe.message_modulus);

View File

@@ -89,12 +89,6 @@ fn test_case_if_then_else_hpu() {
super::test_case_if_then_else(&client_key);
}
#[test]
fn test_case_if_then_zero_hpu() {
let client_key = setup_default_hpu();
super::test_case_if_then_zero(&client_key);
}
#[test]
fn test_case_flip_hpu() {
let client_key = setup_default_hpu();

View File

@@ -568,28 +568,6 @@ fn test_case_if_then_else(client_key: &ClientKey) {
);
}
fn test_case_if_then_zero(client_key: &ClientKey) {
let clear_a = 42u8;
let clear_b = 128u8;
let a = FheUint8::encrypt(clear_a, client_key);
let b = FheUint8::encrypt(clear_b, client_key);
let result = a.le(&b).if_then_zero(&a);
let decrypted_result: u8 = result.decrypt(client_key);
assert_eq!(
decrypted_result,
if clear_a <= clear_b { clear_a } else { 0 }
);
let result = a.ge(&b).if_then_zero(&a);
let decrypted_result: u8 = result.decrypt(client_key);
assert_eq!(
decrypted_result,
if clear_a >= clear_b { clear_a } else { 0 }
);
}
fn test_case_flip(client_key: &ClientKey) {
let clear_a = rand::random::<u32>();
let clear_b = rand::random::<u32>();

View File

@@ -117,7 +117,7 @@ impl Default for IntegerConfig {
fn default() -> Self {
#[cfg(not(feature = "gpu"))]
let params =
crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.into();
crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128.into();
#[cfg(feature = "gpu")]
let params =
crate::shortint::parameters::PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128

View File

@@ -57,7 +57,7 @@ impl PublicKey {
}
pub(crate) fn message_modulus(&self) -> MessageModulus {
self.key.parameters().message_modulus()
self.key.key.parameters.message_modulus()
}
}

View File

@@ -48,7 +48,6 @@ macro_rules! export_concrete_array_types {
}
pub use crate::core_crypto::commons::math::random::{Seed, XofSeed};
pub use crate::high_level_api::integers::oprf::RangeForRandom;
pub use crate::integer::server_key::MatchValues;
use crate::{error, Error, Versionize};
use backward_compatibility::compressed_ciphertext_list::SquashedNoiseCiphertextStateVersions;

View File

@@ -9,9 +9,8 @@
pub use crate::high_level_api::traits::{
BitSlice, CiphertextList, DivRem, FheDecrypt, FheEncrypt, FheEq, FheKeyswitch, FheMax, FheMin,
FheOrd, FheTrivialEncrypt, FheTryEncrypt, FheTryTrivialEncrypt, FheWait, Flip, IfThenElse,
IfThenZero, OverflowingAdd, OverflowingMul, OverflowingNeg, OverflowingSub, ReRandomize,
RotateLeft, RotateLeftAssign, RotateRight, RotateRightAssign, ScalarIfThenElse, SquashNoise,
Tagged,
OverflowingAdd, OverflowingMul, OverflowingNeg, OverflowingSub, ReRandomize, RotateLeft,
RotateLeftAssign, RotateRight, RotateRightAssign, ScalarIfThenElse, SquashNoise, Tagged,
};
#[cfg(feature = "hpu")]
pub use crate::high_level_api::traits::{FheHpu, HpuHandle};

View File

@@ -3,7 +3,7 @@ use crate::high_level_api::{
CompactPublicKey, CompressedCiphertextListBuilder, ConfigBuilder, FheBool, FheInt8, FheUint64,
ReRandomizationContext,
};
use crate::shortint::parameters::v1_5::meta::cpu::V1_5_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_BIG_ZKV2_TUNIFORM_2M128;
use crate::shortint::parameters::test_params::TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
#[cfg(feature = "gpu")]
use crate::shortint::parameters::v1_5::meta::gpu::V1_5_META_PARAM_GPU_2_2_MULTI_BIT_GROUP_4_KS_PBS_PKE_TO_BIG_ZKV2_TUNIFORM_2M128;
use crate::shortint::parameters::{MetaParameters, ShortintKeySwitchingParameters};
@@ -211,7 +211,7 @@ fn setup_re_rand_test(
#[test]
fn test_re_rand() {
let params = V1_5_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_BIG_ZKV2_TUNIFORM_2M128;
let params = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let (cks, sks, cpk) = setup_re_rand_test(params);
set_server_key(sks.decompress());

View File

@@ -10,6 +10,7 @@ use crate::high_level_api::{
generate_keys, ClientKey, ConfigBuilder, FheBool, FheUint256, FheUint8, PublicKey, ServerKey,
};
use crate::integer::U256;
use crate::shortint::parameters::test_params::TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
use crate::shortint::parameters::TestParameters;
use crate::shortint::ClassicPBSParameters;
use crate::{
@@ -186,7 +187,7 @@ fn test_serialize_deserialize_are_implemented() {
#[test]
fn test_try_from_single_lwe_encryption_key() {
let parameters = crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let parameters = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let lwe_sk = crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
crate::core_crypto::algorithms::allocate_and_generate_new_binary_lwe_secret_key(
parameters

View File

@@ -15,6 +15,7 @@ use crate::shortint::parameters::{
AtomicPatternParameters, ClassicPBSParameters, CompactPublicKeyEncryptionParameters,
ShortintKeySwitchingParameters,
};
use crate::shortint::AtomicPatternKind;
use crate::{ClientKey, CompactCiphertextList, CompactPublicKey, ConfigBuilder, FheUint2};
use rayon::prelude::*;
@@ -120,8 +121,9 @@ fn noise_check_compact_public_key_encryption_noise_tuniform(
block_params: ClassicPBSParameters,
) {
// Hack to avoid server key needs and get the ciphertext directly
cpke_params.expansion_kind =
CompactCiphertextListExpansionKind::NoCasting(block_params.encryption_key_choice.into());
cpke_params.expansion_kind = CompactCiphertextListExpansionKind::NoCasting(
AtomicPatternKind::Standard(block_params.encryption_key_choice.into_pbs_order()),
);
let modulus_as_f64 = cpke_params.ciphertext_modulus.raw_modulus_float();

View File

@@ -149,10 +149,6 @@ pub trait IfThenElse<Ciphertext> {
}
}
pub trait IfThenZero<Ciphertext> {
fn if_then_zero(&self, ct_then: &Ciphertext) -> Ciphertext;
}
pub trait ScalarIfThenElse<Lhs, Rhs> {
type Output;

View File

@@ -549,7 +549,7 @@ mod tests {
use crate::shortint::parameters::test_params::{
TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
};
use crate::upgrade::{DecompressionUpgradeKey, UpgradeKeyChain};
use crate::*;
@@ -621,7 +621,7 @@ mod tests {
#[test]
fn test_keychain_upgrade() {
let compute_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let compute_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let compression_parameters = TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(compute_params)

View File

@@ -1306,6 +1306,7 @@ mod zk_pok_tests {
};
use crate::shortint::ciphertext::Degree;
use crate::shortint::parameters::test_params::{
TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128,
TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV1,
TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV1,
};
@@ -1319,9 +1320,16 @@ mod zk_pok_tests {
use rand::random;
fn test_zk_list(is_packed: bool) {
let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let ksk_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let params = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let pke_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.pke_params;
let ksk_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.ksk_params;
let fhe_params = params.compute_parameters;
let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r'];
@@ -1411,9 +1419,16 @@ mod zk_pok_tests {
#[test]
fn test_zk_empty_list() {
let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let ksk_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let params = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let pke_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.pke_params;
let ksk_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.ksk_params;
let fhe_params = params.compute_parameters;
let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r'];
@@ -1563,9 +1578,16 @@ mod zk_pok_tests {
/// is modified
#[test]
fn test_attack_list_info() {
let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let ksk_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let params = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let pke_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.pke_params;
let ksk_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.ksk_params;
let fhe_params = params.compute_parameters;
let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r'];
@@ -1683,9 +1705,16 @@ mod zk_pok_tests {
#[test]
fn test_attack_proven_list_metadata() {
let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let ksk_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let params = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let pke_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.pke_params;
let ksk_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.ksk_params;
let fhe_params = params.compute_parameters;
let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r'];
@@ -1795,9 +1824,16 @@ mod zk_pok_tests {
#[test]
fn test_several_proven_lists() {
let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let ksk_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let params = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let pke_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.pke_params;
let ksk_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.ksk_params;
let fhe_params = params.compute_parameters;
let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r'];
@@ -1858,9 +1894,16 @@ mod zk_pok_tests {
fn test_malicious_boolean_proven_lists() {
use super::DataKind;
let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let ksk_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let params = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let pke_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.pke_params;
let ksk_params = params
.dedicated_compact_public_key_parameters
.unwrap()
.ksk_params;
let fhe_params = params.compute_parameters;
let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r'];

View File

@@ -224,6 +224,8 @@ mod tests {
use crate::shortint::parameters::test_params::{
TEST_COMP_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_META_PARAM_CPU_2_2_KS32_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128,
TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128,
TEST_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
@@ -278,6 +280,22 @@ mod tests {
TEST_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.into(),
TEST_COMP_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
),
(
TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128
.compute_parameters
.into(),
TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128
.compression_parameters
.unwrap(),
),
(
TEST_META_PARAM_CPU_2_2_KS32_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128
.compute_parameters
.into(),
TEST_META_PARAM_CPU_2_2_KS32_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128
.compression_parameters
.unwrap(),
),
] {
let (cks, sks) = gen_keys::<ShortintParameterSet>(params, IntegerKeyKind::Radix);

View File

@@ -420,18 +420,14 @@ impl CompressedSquashedNoiseCiphertextListBuilder {
mod test {
use super::*;
use crate::integer::noise_squashing::NoiseSquashingKey;
use crate::shortint::parameters::test_params::{
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
};
use crate::shortint::parameters::test_params::TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
use rand::Rng;
#[test]
fn test_compressed_noise_squashed_ciphertext_list() {
let param = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let noise_squashing_parameters =
TEST_PARAM_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let meta_param = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let param = meta_param.compute_parameters;
let noise_squashing_parameters = meta_param.noise_squashing_parameters.unwrap().parameters;
// The goal is to test that encrypting a value stored in a type
// for which the bit count does not match the target block count of the encrypted
@@ -442,7 +438,11 @@ mod test {
let noise_squashing_key = NoiseSquashingKey::new(&cks, &noise_squashing_private_key);
let noise_squashing_compression_private_key = NoiseSquashingCompressionPrivateKey::new(
TEST_PARAM_NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
meta_param
.noise_squashing_parameters
.unwrap()
.compression_parameters
.unwrap(),
);
let compression_key = noise_squashing_private_key
.new_noise_squashing_compression_key(&noise_squashing_compression_private_key);

View File

@@ -5,12 +5,7 @@ use crate::integer::{
gen_keys, BooleanBlock, CompactPrivateKey, CompactPublicKey, IntegerKeyKind, RadixCiphertext,
SignedRadixCiphertext,
};
use crate::shortint::parameters::test_params::{
TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2,
};
use crate::shortint::parameters::test_params::TEST_META_PARAM_CPU_2_2_KS32_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
use crate::shortint::ShortintParameterSet;
use itertools::Itertools;
use rand::Rng;
@@ -20,12 +15,20 @@ const NUM_BLOCKS: usize = 32;
#[test]
fn test_ciphertext_re_randomization_after_compression() {
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.into();
let comp_params = TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let cpk_params = TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
let ks_params = TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let meta_param = TEST_META_PARAM_CPU_2_2_KS32_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let params = meta_param.compute_parameters;
let comp_params = meta_param.compression_parameters.unwrap();
let cpk_params = meta_param
.dedicated_compact_public_key_parameters
.unwrap()
.pke_params;
let ks_params = meta_param
.dedicated_compact_public_key_parameters
.unwrap()
.re_randomization_parameters
.unwrap();
let (cks, sks) = gen_keys::<ShortintParameterSet>(params, IntegerKeyKind::Radix);
let (cks, sks) = gen_keys::<ShortintParameterSet>(params.into(), IntegerKeyKind::Radix);
let private_compression_key = cks.new_compression_private_key(comp_params);

View File

@@ -1,16 +1,14 @@
use crate::integer::keycache::KEY_CACHE;
use crate::integer::noise_squashing::{NoiseSquashingKey, NoiseSquashingPrivateKey};
use crate::integer::IntegerKeyKind;
use crate::shortint::parameters::{
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
};
use crate::shortint::parameters::test_params::TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
use rand::prelude::*;
#[test]
fn test_integer_noise_squashing_decrypt_auto_cast_and_bool() {
let param = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let noise_squashing_parameters = NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let meta_param = TEST_META_PARAM_PROD_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let param = meta_param.compute_parameters;
let noise_squashing_parameters = meta_param.noise_squashing_parameters.unwrap().parameters;
// The goal is to test that encrypting a value stored in a type
// for which the bit count does not match the target block count of the encrypted
@@ -21,7 +19,7 @@ fn test_integer_noise_squashing_decrypt_auto_cast_and_bool() {
let mut rng = rand::thread_rng();
let num_blocks = 32u32.div_ceil(param.message_modulus.0.ilog2()) as usize;
let num_blocks = 32u32.div_ceil(param.message_modulus().0.ilog2()) as usize;
// Positive signed value
let value = rng.gen_range(0..=i32::MAX);

View File

@@ -2,7 +2,6 @@ use super::{RadixCiphertext, ServerKey, SignedRadixCiphertext};
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::prelude::DefaultRandomGenerator;
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
use std::num::NonZeroU64;
pub use tfhe_csprng::seeders::{Seed, Seeder};
@@ -164,7 +163,6 @@ impl ServerKey {
/// as `num_input_random_bits`
///
/// ```rust
/// use std::num::NonZeroU64;
/// use tfhe::integer::gen_keys_radix;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128;
/// use tfhe::Seed;
@@ -175,7 +173,7 @@ impl ServerKey {
/// let (cks, sks) = gen_keys_radix(PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128, size);
///
/// let num_input_random_bits = 5;
/// let excluded_upper_bound = NonZeroU64::new(3).unwrap();
/// let excluded_upper_bound = 3;
/// let num_blocks_output = 8;
///
/// let ct_res = sks.par_generate_oblivious_pseudo_random_unsigned_custom_range(
@@ -188,17 +186,15 @@ impl ServerKey {
/// // Decrypt:
/// let dec_result: u64 = cks.decrypt(&ct_res);
///
/// assert!(dec_result < excluded_upper_bound.get());
/// assert!(dec_result < excluded_upper_bound);
/// ```
pub fn par_generate_oblivious_pseudo_random_unsigned_custom_range(
&self,
seed: Seed,
num_input_random_bits: u64,
excluded_upper_bound: NonZeroU64,
excluded_upper_bound: u64,
num_blocks_output: u64,
) -> RadixCiphertext {
let excluded_upper_bound = excluded_upper_bound.get();
assert!(self.message_modulus().0.is_power_of_two());
let message_bits_count = self.message_modulus().0.ilog2() as u64;

View File

@@ -70,8 +70,8 @@ impl CompressedPublicKey {
encrypt_many_crt(&self.key, message, base_vec, encrypt_block)
}
pub fn parameters(&self) -> crate::shortint::PBSParameters {
self.key.parameters.pbs_parameters().unwrap()
pub fn parameters(&self) -> crate::shortint::ShortintParameterSet {
self.key.parameters
}
pub fn encrypt_radix<T: DecomposableInto<u64>>(

View File

@@ -67,8 +67,8 @@ impl PublicKey {
encrypt_crt(&self.key, message, base_vec, encrypt_block)
}
pub fn parameters(&self) -> crate::shortint::PBSParameters {
self.key.parameters.pbs_parameters().unwrap()
pub fn parameters(&self) -> crate::shortint::ShortintParameterSet {
self.key.parameters
}
pub fn encrypt_radix<T>(&self, message: T, num_blocks: usize) -> RadixCiphertext
@@ -118,14 +118,16 @@ mod tests {
use crate::integer::keycache::KEY_CACHE;
use crate::integer::tests::create_parameterized_test;
use crate::integer::IntegerKeyKind;
use crate::shortint::parameters::test_params::TEST_PARAM_MESSAGE_2_CARRY_2_PBS_KS_GAUSSIAN_2M128;
use crate::shortint::parameters::ClassicPBSParameters;
use crate::shortint::parameters::test_params::{
TestParameters, TEST_PARAM_MESSAGE_2_CARRY_2_PBS_KS_GAUSSIAN_2M128,
};
create_parameterized_test!(integer_public_key_decompression_small {
TEST_PARAM_MESSAGE_2_CARRY_2_PBS_KS_GAUSSIAN_2M128,
});
fn integer_public_key_decompression_small(param: ClassicPBSParameters) {
fn integer_public_key_decompression_small<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let compressed_pk = crate::integer::CompressedPublicKey::new(&cks);

View File

@@ -15,7 +15,8 @@ create_parameterized_test!(big_radix_encrypt_decrypt_128_bits {
},
no_coverage => {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
/* PARAM_MESSAGE_3_CARRY_3_KS_PBS, Skipped as the key requires 32GB
* PARAM_MESSAGE_4_CARRY_4_KS_PBS, Skipped as the key requires 550GB */
}
@@ -29,7 +30,8 @@ create_parameterized_test!(
},
no_coverage => {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
/* PARAM_MESSAGE_3_CARRY_3_KS_PBS, Skipped as its slow
* PARAM_MESSAGE_4_CARRY_4_KS_PBS, Skipped as its slow */
}
@@ -37,35 +39,27 @@ create_parameterized_test!(
);
create_parameterized_test!(
big_radix_encrypt_decrypt_compact_128_bits_list {
radix_encrypt_decrypt_compact_128_bits_list {
coverage => {
COVERAGE_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS_GAUSSIAN_2M64,
},
no_coverage => {
TEST_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS_GAUSSIAN_2M128,
}
}
);
create_parameterized_test!(
small_radix_encrypt_decrypt_compact_128_bits_list {
coverage => {
COVERAGE_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_PBS_KS_GAUSSIAN_2M64,
},
no_coverage => {
TEST_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_PBS_KS_GAUSSIAN_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS_GAUSSIAN_2M128,
}
}
);
/// Test that the public key can encrypt a 128 bit number
/// in radix decomposition, and that the client key can decrypt it
fn big_radix_encrypt_decrypt_128_bits(param: ClassicPBSParameters) {
fn big_radix_encrypt_decrypt_128_bits<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let public_key = PublicKey::new(&cks);
let mut rng = rand::thread_rng();
let num_block = (128f64 / (param.message_modulus.0 as f64).log(2.0)).ceil() as usize;
let num_block = (128f64 / (param.message_modulus().0 as f64).log(2.0)).ceil() as usize;
let clear = rng.gen::<u128>();
@@ -76,12 +70,13 @@ fn big_radix_encrypt_decrypt_128_bits(param: ClassicPBSParameters) {
assert_eq!(clear, dec);
}
fn radix_encrypt_decrypt_compressed_128_bits(param: ClassicPBSParameters) {
fn radix_encrypt_decrypt_compressed_128_bits<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let public_key = CompressedPublicKey::new(&cks);
let mut rng = rand::thread_rng();
let num_block = (128f64 / (param.message_modulus.0 as f64).log(2.0)).ceil() as usize;
let num_block = (128f64 / (param.message_modulus().0 as f64).log(2.0)).ceil() as usize;
let clear = rng.gen::<u128>();
@@ -92,14 +87,6 @@ fn radix_encrypt_decrypt_compressed_128_bits(param: ClassicPBSParameters) {
assert_eq!(clear, dec);
}
fn big_radix_encrypt_decrypt_compact_128_bits_list(params: ClassicPBSParameters) {
radix_encrypt_decrypt_compact_128_bits_list(params);
}
fn small_radix_encrypt_decrypt_compact_128_bits_list(params: ClassicPBSParameters) {
radix_encrypt_decrypt_compact_128_bits_list(params);
}
fn radix_encrypt_decrypt_compact_128_bits_list(params: ClassicPBSParameters) {
let (cks, sks) = gen_keys(params, IntegerKeyKind::Radix);
let pk = crate::integer::public_key::CompactPublicKey::new(&cks);

View File

@@ -227,14 +227,15 @@ fn integer_unchecked_crt_scalar_sub_32_bits() {
}
}
fn integer_unchecked_crt_mul(param: ClassicPBSParameters) {
fn integer_unchecked_crt_mul<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// generate the server-client key set
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT);
let mut rng = rand::thread_rng();
// Define CRT basis, and global modulus
let basis = make_basis(param.message_modulus.0);
let basis = make_basis(param.message_modulus().0);
let modulus = basis.iter().product::<u64>();
for _ in 0..NB_TESTS {
@@ -253,9 +254,10 @@ fn integer_unchecked_crt_mul(param: ClassicPBSParameters) {
}
}
fn integer_smart_crt_add(param: ClassicPBSParameters) {
fn integer_smart_crt_add<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// Define CRT basis, and global modulus
let basis = make_basis(param.message_modulus.0);
let basis = make_basis(param.message_modulus().0);
let modulus = basis.iter().product::<u64>();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT);
@@ -279,12 +281,13 @@ fn integer_smart_crt_add(param: ClassicPBSParameters) {
}
}
fn integer_smart_crt_mul(param: ClassicPBSParameters) {
fn integer_smart_crt_mul<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// generate the server-client key set
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT);
// Define CRT basis, and global modulus
let basis = make_basis(param.message_modulus.0);
let basis = make_basis(param.message_modulus().0);
let modulus = basis.iter().product::<u64>();
println!("BASIS = {basis:?}");
@@ -308,9 +311,10 @@ fn integer_smart_crt_mul(param: ClassicPBSParameters) {
}
}
fn integer_smart_crt_neg(param: ClassicPBSParameters) {
fn integer_smart_crt_neg<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// Define CRT basis, and global modulus
let basis = make_basis(param.message_modulus.0);
let basis = make_basis(param.message_modulus().0);
let modulus = basis.iter().product::<u64>();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT);
@@ -334,9 +338,10 @@ fn integer_smart_crt_neg(param: ClassicPBSParameters) {
}
}
fn integer_smart_crt_scalar_add(param: ClassicPBSParameters) {
fn integer_smart_crt_scalar_add<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// Define CRT basis, and global modulus
let basis = make_basis(param.message_modulus.0);
let basis = make_basis(param.message_modulus().0);
let modulus = basis.iter().product::<u64>();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT);
@@ -358,9 +363,10 @@ fn integer_smart_crt_scalar_add(param: ClassicPBSParameters) {
}
}
fn integer_smart_crt_scalar_mul(param: ClassicPBSParameters) {
fn integer_smart_crt_scalar_mul<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// Define CRT basis, and global modulus
let basis = make_basis(param.message_modulus.0);
let basis = make_basis(param.message_modulus().0);
let modulus = basis.iter().product::<u64>();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT);
@@ -382,9 +388,10 @@ fn integer_smart_crt_scalar_mul(param: ClassicPBSParameters) {
}
}
fn integer_smart_crt_scalar_sub(param: ClassicPBSParameters) {
fn integer_smart_crt_scalar_sub<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// Define CRT basis, and global modulus
let basis = make_basis(param.message_modulus.0);
let basis = make_basis(param.message_modulus().0);
let modulus = basis.iter().product::<u64>();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT);
@@ -409,9 +416,10 @@ fn integer_smart_crt_scalar_sub(param: ClassicPBSParameters) {
}
}
fn integer_smart_crt_sub(param: ClassicPBSParameters) {
fn integer_smart_crt_sub<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// Define CRT basis, and global modulus
let basis = make_basis(param.message_modulus.0);
let basis = make_basis(param.message_modulus().0);
let modulus = basis.iter().product::<u64>();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::CRT);

View File

@@ -129,19 +129,21 @@ create_parameterized_test!(integer_unchecked_min {
COVERAGE_PARAM_MESSAGE_2_CARRY_2_KS_PBS
},
no_coverage => {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
}
});
fn integer_encrypt_decrypt(param: ClassicPBSParameters) {
fn integer_encrypt_decrypt<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
let modulus = param.message_modulus.0.pow(NB_CTXT as u32);
let modulus = param.message_modulus().0.pow(NB_CTXT as u32);
for _ in 0..NB_TESTS {
let clear = rng.gen::<u64>() % modulus;
@@ -154,11 +156,12 @@ fn integer_encrypt_decrypt(param: ClassicPBSParameters) {
}
}
fn integer_encrypt_decrypt_128_bits(param: ClassicPBSParameters) {
fn integer_encrypt_decrypt_128_bits<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
let num_block = 128u32.div_ceil(param.message_modulus.0.ilog2()) as usize;
let num_block = 128u32.div_ceil(param.message_modulus().0.ilog2()) as usize;
for _ in 0..10 {
let clear = rng.gen::<u128>();
@@ -170,10 +173,11 @@ fn integer_encrypt_decrypt_128_bits(param: ClassicPBSParameters) {
}
}
fn integer_encrypt_decrypt_128_bits_specific_values(param: ClassicPBSParameters) {
fn integer_encrypt_decrypt_128_bits_specific_values<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let num_block = 128u32.div_ceil(param.message_modulus.0.ilog2()) as usize;
let num_block = 128u32.div_ceil(param.message_modulus().0.ilog2()) as usize;
{
let a = u64::MAX as u128;
let ct = cks.encrypt_radix(a, num_block);
@@ -218,10 +222,11 @@ fn integer_encrypt_decrypt_128_bits_specific_values(param: ClassicPBSParameters)
}
}
fn integer_encrypt_decrypt_256_bits_specific_values(param: ClassicPBSParameters) {
fn integer_encrypt_decrypt_256_bits_specific_values<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let num_block = 256u32.div_ceil(param.message_modulus.0.ilog2()) as usize;
let num_block = 256u32.div_ceil(param.message_modulus().0.ilog2()) as usize;
{
let a = (u64::MAX as u128) << 64;
let b = 0;
@@ -242,11 +247,12 @@ fn integer_encrypt_decrypt_256_bits_specific_values(param: ClassicPBSParameters)
}
}
fn integer_encrypt_decrypt_256_bits(param: ClassicPBSParameters) {
fn integer_encrypt_decrypt_256_bits<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
let num_block = 256u32.div_ceil(param.message_modulus.0.ilog2()) as usize;
let num_block = 256u32.div_ceil(param.message_modulus().0.ilog2()) as usize;
for _ in 0..10 {
let clear0 = rng.gen::<u128>();
@@ -262,7 +268,8 @@ fn integer_encrypt_decrypt_256_bits(param: ClassicPBSParameters) {
}
}
fn integer_encrypt_auto_cast(param: ClassicPBSParameters) {
fn integer_encrypt_auto_cast<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// The goal is to test that encrypting a value stored in a type
// for which the bit count does not match the target block count of the encrypted
// radix properly applies upcasting/downcasting
@@ -270,7 +277,7 @@ fn integer_encrypt_auto_cast(param: ClassicPBSParameters) {
let (cks, _) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
let num_blocks = 32u32.div_ceil(param.message_modulus.0.ilog2()) as usize;
let num_blocks = 32u32.div_ceil(param.message_modulus().0.ilog2()) as usize;
// Positive signed value
let value = rng.gen_range(0..=i32::MAX);
@@ -311,11 +318,12 @@ fn integer_encrypt_auto_cast(param: ClassicPBSParameters) {
assert_eq!(value as u16, d);
}
fn integer_smart_add_128_bits(param: ClassicPBSParameters) {
fn integer_smart_add_128_bits<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
let num_block = 128u32.div_ceil(param.message_modulus.0.ilog2()) as usize;
let num_block = 128u32.div_ceil(param.message_modulus().0.ilog2()) as usize;
for _ in 0..100 {
let clear_0 = rng.gen::<u128>();
@@ -346,12 +354,14 @@ fn integer_smart_add_128_bits(param: ClassicPBSParameters) {
}
}
fn integer_unchecked_add(param: ClassicPBSParameters) {
fn integer_unchecked_add<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_add);
unchecked_add_test(param, executor);
}
fn integer_smart_add(param: ClassicPBSParameters) {
fn integer_smart_add<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::smart_add);
smart_add_test(param, executor);
}
@@ -404,15 +414,16 @@ where
smart_bitxor_test(param, executor);
}
fn integer_unchecked_small_scalar_mul(param: ClassicPBSParameters) {
fn integer_unchecked_small_scalar_mul<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
// message_modulus^vec_length
let modulus = param.message_modulus.0.pow(NB_CTXT as u32);
let modulus = param.message_modulus().0.pow(NB_CTXT as u32);
let scalar_modulus = param.message_modulus.0;
let scalar_modulus = param.message_modulus().0;
for _ in 0..NB_TESTS {
let clear = rng.gen::<u64>() % modulus;
@@ -430,15 +441,16 @@ fn integer_unchecked_small_scalar_mul(param: ClassicPBSParameters) {
}
}
fn integer_smart_small_scalar_mul(param: ClassicPBSParameters) {
fn integer_smart_small_scalar_mul<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
// message_modulus^vec_length
let modulus = param.message_modulus.0.pow(NB_CTXT as u32);
let modulus = param.message_modulus().0.pow(NB_CTXT as u32);
let scalar_modulus = param.message_modulus.0;
let scalar_modulus = param.message_modulus().0;
let mut clear_res;
for _ in 0..NB_TESTS_SMALLER {
@@ -463,13 +475,14 @@ fn integer_smart_small_scalar_mul(param: ClassicPBSParameters) {
}
}
fn integer_blockshift(param: ClassicPBSParameters) {
fn integer_blockshift<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
// message_modulus^vec_length
let modulus = param.message_modulus.0.pow(NB_CTXT as u32);
let modulus = param.message_modulus().0.pow(NB_CTXT as u32);
for _ in 0..NB_TESTS {
let clear = rng.gen::<u64>() % modulus;
@@ -484,19 +497,20 @@ fn integer_blockshift(param: ClassicPBSParameters) {
let dec_res: u64 = cks.decrypt_radix(&ct_res);
assert_eq!(
(clear * param.message_modulus.0.pow(power as u32) as u64) % modulus,
(clear * param.message_modulus().0.pow(power as u32) as u64) % modulus,
dec_res
);
}
}
fn integer_blockshift_right(param: ClassicPBSParameters) {
fn integer_blockshift_right<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
// message_modulus^vec_length
let modulus = param.message_modulus.0.pow(NB_CTXT as u32);
let modulus = param.message_modulus().0.pow(NB_CTXT as u32);
for _ in 0..NB_TESTS {
let clear = rng.gen::<u64>() % modulus;
@@ -511,19 +525,20 @@ fn integer_blockshift_right(param: ClassicPBSParameters) {
let dec_res: u64 = cks.decrypt_radix(&ct_res);
assert_eq!(
(clear / param.message_modulus.0.pow(power as u32) as u64) % modulus,
(clear / param.message_modulus().0.pow(power as u32) as u64) % modulus,
dec_res
);
}
}
fn integer_smart_scalar_mul(param: ClassicPBSParameters) {
fn integer_smart_scalar_mul<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
// message_modulus^vec_length
let modulus = param.message_modulus.0.pow(NB_CTXT as u32);
let modulus = param.message_modulus().0.pow(NB_CTXT as u32);
for _ in 0..NB_TESTS {
let clear = rng.gen::<u64>() % modulus;
@@ -565,7 +580,8 @@ where
unchecked_neg_test(param, executor);
}
fn integer_smart_neg(param: ClassicPBSParameters) {
fn integer_smart_neg<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::smart_neg);
smart_neg_test(param, executor);
}
@@ -578,7 +594,8 @@ where
unchecked_sub_test(param, executor);
}
fn integer_smart_sub(param: ClassicPBSParameters) {
fn integer_smart_sub<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::smart_sub);
smart_sub_test(param, executor);
}
@@ -591,15 +608,16 @@ where
unchecked_block_mul_test(param, executor);
}
fn integer_smart_block_mul(param: ClassicPBSParameters) {
fn integer_smart_block_mul<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let mut rng = rand::thread_rng();
// message_modulus^vec_length
let modulus = param.message_modulus.0.pow(NB_CTXT as u32);
let modulus = param.message_modulus().0.pow(NB_CTXT as u32);
let block_modulus = param.message_modulus.0;
let block_modulus = param.message_modulus().0;
for _ in 0..5 {
// Define the cleartexts
@@ -675,7 +693,8 @@ where
smart_scalar_sub_test(param, executor);
}
fn integer_unchecked_scalar_decomposition_overflow(param: ClassicPBSParameters) {
fn integer_unchecked_scalar_decomposition_overflow<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
// This is a regression test.
//
// The purpose here is to check the behaviour when the scalar value has less bits
@@ -683,7 +702,7 @@ fn integer_unchecked_scalar_decomposition_overflow(param: ClassicPBSParameters)
let mut rng = rand::thread_rng();
let num_block = (128_f64 / (param.message_modulus.0 as f64).log(2.0)).ceil() as usize;
let num_block = (128_f64 / (param.message_modulus().0 as f64).log(2.0)).ceil() as usize;
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
@@ -828,47 +847,56 @@ fn integer_signed_decryption_correctly_sign_extend(param: impl Into<TestParamete
assert_eq!(trivial.decrypt_trivial::<i128>().unwrap(), value as i128);
}
fn integer_scalar_blockslice(param: ClassicPBSParameters) {
fn integer_scalar_blockslice<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_blockslice);
scalar_blockslice_test(param, executor);
}
fn integer_scalar_blockslice_assign(param: ClassicPBSParameters) {
fn integer_scalar_blockslice_assign<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_blockslice_assign);
scalar_blockslice_assign_test(param, executor);
}
fn integer_unchecked_scalar_slice(param: ClassicPBSParameters) {
fn integer_unchecked_scalar_slice<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_scalar_bitslice);
unchecked_scalar_bitslice_test(param, executor);
}
fn integer_unchecked_scalar_slice_assign(param: ClassicPBSParameters) {
fn integer_unchecked_scalar_slice_assign<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_scalar_bitslice_assign);
unchecked_scalar_bitslice_assign_test(param, executor);
}
fn integer_default_scalar_slice(param: ClassicPBSParameters) {
fn integer_default_scalar_slice<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_bitslice);
default_scalar_bitslice_test(param, executor);
}
fn integer_default_scalar_slice_assign(param: ClassicPBSParameters) {
fn integer_default_scalar_slice_assign<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_bitslice_assign);
default_scalar_bitslice_assign_test(param, executor);
}
fn integer_smart_scalar_slice(param: ClassicPBSParameters) {
fn integer_smart_scalar_slice<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::smart_scalar_bitslice);
smart_scalar_bitslice_test(param, executor);
}
fn integer_smart_scalar_slice_assign(param: ClassicPBSParameters) {
fn integer_smart_scalar_slice_assign<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::smart_scalar_bitslice_assign);
smart_scalar_bitslice_assign_test(param, executor);
}
fn integer_unchecked_min(param: ClassicPBSParameters) {
fn integer_unchecked_min<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_min);
test_unchecked_minmax(param, 2, executor, std::cmp::min::<u64>);
}

View File

@@ -439,10 +439,7 @@ mod tests {
use crate::integer::{
gen_keys, ClientKey, IntegerKeyKind, RadixCiphertext, SignedRadixCiphertext,
};
use crate::shortint::parameters::test_params::{
TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
};
use crate::shortint::parameters::test_params::TEST_META_PARAM_CPU_2_2_KS32_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
use crate::shortint::ShortintParameterSet;
fn assert_store_unsigned_matches(
@@ -471,12 +468,13 @@ mod tests {
#[test]
fn test_compression_serialization_unsigned() {
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.into();
let meta_params = TEST_META_PARAM_CPU_2_2_KS32_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let params = meta_params.compute_parameters.into();
let (cks, _) = gen_keys::<ShortintParameterSet>(params, IntegerKeyKind::Radix);
let private_compression_key = cks
.new_compression_private_key(TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
let private_compression_key =
cks.new_compression_private_key(meta_params.compression_parameters.unwrap());
let (compression_key, decompression_key) =
cks.new_compression_decompression_keys(&private_compression_key);
@@ -538,12 +536,13 @@ mod tests {
#[test]
fn test_compression_serialization_signed() {
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.into();
let meta_params = TEST_META_PARAM_CPU_2_2_KS32_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let params = meta_params.compute_parameters.into();
let (cks, _) = gen_keys::<ShortintParameterSet>(params, IntegerKeyKind::Radix);
let private_compression_key = cks
.new_compression_private_key(TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
let private_compression_key =
cks.new_compression_private_key(meta_params.compression_parameters.unwrap());
let (compression_key, decompression_key) =
cks.new_compression_decompression_keys(&private_compression_key);

View File

@@ -8,21 +8,26 @@ use crate::integer::tests::create_parameterized_test;
use crate::integer::{
BooleanBlock, IntegerCiphertext, IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey,
};
use crate::shortint::parameters::test_params::*;
use crate::shortint::parameters::*;
use rand::Rng;
use std::sync::Arc;
create_parameterized_test!(safe_erc20 {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
create_parameterized_test!(whitepaper_erc20 {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
create_parameterized_test!(no_cmux_erc20 {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
create_parameterized_test!(overflow_erc20 {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
fn safe_erc20<P>(param: P)

View File

@@ -7,18 +7,20 @@ use crate::integer::server_key::radix_parallel::tests_long_run::{
use crate::integer::server_key::radix_parallel::tests_unsigned::OpSequenceCpuFunctionExecutor;
use crate::integer::tests::create_parameterized_test;
use crate::integer::{BooleanBlock, IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey};
use crate::shortint::parameters::test_params::*;
use crate::shortint::parameters::*;
use crate::{ClientKey, CompressedServerKey, MatchValues, Seed, Tag};
use std::cmp::{max, min};
use std::num::NonZeroU64;
use std::sync::Arc;
create_parameterized_test!(random_op_sequence {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
create_parameterized_test!(random_op_sequence_data_generator {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
pub(crate) type BinaryOpExecutor = Box<
@@ -499,18 +501,7 @@ where
&ServerKey::par_generate_oblivious_pseudo_random_unsigned_integer_bounded,
);
let oprf_custom_range_executor = OpSequenceCpuFunctionExecutor::new(
&|sk: &ServerKey,
seed: Seed,
num_input_random_bits: u64,
excluded_upper_bound: u64,
num_blocks_output: u64| {
sk.par_generate_oblivious_pseudo_random_unsigned_custom_range(
seed,
num_input_random_bits,
NonZeroU64::new(excluded_upper_bound).unwrap_or(NonZeroU64::new(1).unwrap()),
num_blocks_output,
)
},
&ServerKey::par_generate_oblivious_pseudo_random_unsigned_custom_range,
);
let mut oprf_ops: Vec<(OprfExecutor, String)> = vec![(

View File

@@ -9,15 +9,18 @@ use crate::integer::{
BooleanBlock, IntegerCiphertext, IntegerKeyKind, RadixClientKey, ServerKey,
SignedRadixCiphertext,
};
use crate::shortint::parameters::test_params::*;
use crate::shortint::parameters::*;
use rand::Rng;
use std::sync::Arc;
create_parameterized_test!(whitepaper_erc20 {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
create_parameterized_test!(no_cmux_erc20 {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
fn whitepaper_erc20<P>(param: P)

View File

@@ -9,13 +9,15 @@ use crate::integer::tests::create_parameterized_test;
use crate::integer::{
BooleanBlock, IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey, SignedRadixCiphertext,
};
use crate::shortint::parameters::test_params::*;
use crate::shortint::parameters::*;
use crate::{ClientKey, CompressedServerKey, Seed, Tag};
use std::cmp::{max, min};
use std::sync::Arc;
create_parameterized_test!(random_op_sequence {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
pub(crate) type SignedBinaryOpExecutor = Box<

View File

@@ -31,7 +31,8 @@ create_parameterized_test!(
no_coverage => {
// Requires 4 bits, so 1_1 parameters are not supported
// until they get their own version of the algorithm
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -59,7 +60,8 @@ create_parameterized_test!(
no_coverage => {
// Requires 4 bits, so 1_1 parameters are not supported
// until they get their own version of the algorithm
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -350,7 +350,8 @@ macro_rules! define_signed_comparison_test_functions {
{
// Non parallelized does not support 1_1
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
@@ -364,7 +365,8 @@ macro_rules! define_signed_comparison_test_functions {
{
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
@@ -378,7 +380,8 @@ macro_rules! define_signed_comparison_test_functions {
{
// Non parallelized does not support PARAM_MESSAGE_1_CARRY_1_KS_PBS,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as smart test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -394,7 +397,8 @@ macro_rules! define_signed_comparison_test_functions {
{
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as smart test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -410,7 +414,8 @@ macro_rules! define_signed_comparison_test_functions {
{
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -720,7 +725,8 @@ mod no_coverage {
create_parameterized_test!(integer_signed_unchecked_min_parallelized_128_bits);
create_parameterized_test!(integer_signed_smart_max_parallelized_128_bits {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -730,7 +736,8 @@ mod no_coverage {
});
create_parameterized_test!(integer_signed_smart_min_parallelized_128_bits {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -740,7 +747,8 @@ mod no_coverage {
});
create_parameterized_test!(integer_signed_max_parallelized_128_bits {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -750,7 +758,8 @@ mod no_coverage {
});
create_parameterized_test!(integer_signed_min_parallelized_128_bits {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits

View File

@@ -23,7 +23,8 @@ create_parameterized_test!(
},
no_coverage => {
// Does not support 1_1
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -42,7 +43,8 @@ create_parameterized_test!(
},
no_coverage => {
// Does not support 1_1
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -26,7 +26,8 @@ create_parameterized_test!(integer_signed_default_leading_ones);
create_parameterized_test!(integer_signed_default_ilog2);
create_parameterized_test!(integer_signed_default_checked_ilog2 {
// uses comparison so 1_1 parameters are not supported
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -26,7 +26,8 @@ create_parameterized_test!(
},
no_coverage => {
// Uses comparisons internally, so no 1_1
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -3,6 +3,7 @@ use crate::integer::server_key::radix_parallel::tests_cases_unsigned::FunctionEx
use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor;
use crate::integer::tests::create_parameterized_test;
use crate::integer::{IntegerKeyKind, RadixClientKey, ServerKey, SignedRadixCiphertext};
use crate::shortint::parameters::test_params::*;
use crate::shortint::parameters::*;
use statrs::distribution::ContinuousCDF;
use std::collections::HashMap;
@@ -10,11 +11,13 @@ use std::sync::Arc;
use tfhe_csprng::seeders::Seed;
create_parameterized_test!(oprf_signed_uniformity_bounded {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
create_parameterized_test!(oprf_signed_uniformity_unbounded {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
});
fn oprf_signed_uniformity_bounded<P>(param: P)

View File

@@ -269,7 +269,8 @@ macro_rules! define_signed_scalar_comparison_test_functions {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
@@ -284,7 +285,8 @@ macro_rules! define_signed_scalar_comparison_test_functions {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as smart test might overflow values
// and when using 3_3 to represent 128 we actually have more than 128 bits
@@ -301,7 +303,8 @@ macro_rules! define_signed_scalar_comparison_test_functions {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 128 we actually have more than 128 bits
@@ -316,9 +319,10 @@ macro_rules! define_signed_scalar_comparison_test_functions {
};
}
fn integer_signed_is_scalar_out_of_bounds(param: ClassicPBSParameters) {
fn integer_signed_is_scalar_out_of_bounds<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let num_block = (128f64 / (param.message_modulus.0 as f64).log(2.0)).ceil() as usize;
let num_block = (128f64 / (param.message_modulus().0 as f64).log(2.0)).ceil() as usize;
let mut rng = rand::thread_rng();
@@ -574,61 +578,56 @@ pub(crate) fn test_signed_default_scalar_minmax<P, T, ClearF, Scalar>(
mod no_coverage {
use super::*;
fn integer_signed_unchecked_scalar_min_parallelized_i128(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_signed_unchecked_scalar_min_parallelized_i128(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_scalar_min_parallelized);
test_signed_unchecked_scalar_minmax(params, 2, executor, std::cmp::min::<i128>);
}
fn integer_signed_unchecked_scalar_max_parallelized_i128(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_signed_unchecked_scalar_max_parallelized_i128(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_scalar_max_parallelized);
test_signed_unchecked_scalar_minmax(params, 2, executor, std::cmp::max::<i128>);
}
fn integer_signed_smart_scalar_min_parallelized_i128(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_signed_smart_scalar_min_parallelized_i128(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::smart_scalar_min_parallelized);
test_signed_smart_scalar_minmax(params, 2, executor, std::cmp::min::<i128>);
}
fn integer_signed_smart_scalar_max_parallelized_i128(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_signed_smart_scalar_max_parallelized_i128(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::smart_scalar_max_parallelized);
test_signed_smart_scalar_minmax(params, 2, executor, std::cmp::max::<i128>);
}
fn integer_signed_scalar_min_parallelized_i128(params: crate::shortint::ClassicPBSParameters) {
fn integer_signed_scalar_min_parallelized_i128(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_min_parallelized);
test_signed_default_scalar_minmax(params, 2, executor, std::cmp::min::<i128>);
}
fn integer_signed_scalar_max_parallelized_i128(params: crate::shortint::ClassicPBSParameters) {
fn integer_signed_scalar_max_parallelized_i128(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_max_parallelized);
test_signed_default_scalar_minmax(params, 2, executor, std::cmp::max::<i128>);
}
create_parameterized_test!(integer_signed_unchecked_scalar_max_parallelized_i128 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_signed_unchecked_scalar_min_parallelized_i128 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_signed_smart_scalar_max_parallelized_i128 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -638,7 +637,8 @@ mod no_coverage {
});
create_parameterized_test!(integer_signed_smart_scalar_min_parallelized_i128 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -648,7 +648,8 @@ mod no_coverage {
});
create_parameterized_test!(integer_signed_scalar_max_parallelized_i128 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -658,7 +659,8 @@ mod no_coverage {
});
create_parameterized_test!(integer_signed_scalar_min_parallelized_i128 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -676,7 +678,8 @@ mod no_coverage {
create_parameterized_test!(integer_signed_is_scalar_out_of_bounds {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as the test relies on the ciphertext to encrypt 128bits
// but with param 3_3 we actually encrypt more that 128bits
@@ -691,39 +694,31 @@ mod coverage {
use super::*;
use crate::integer::tests::create_parameterized_test_classical_params;
fn integer_signed_unchecked_scalar_min_parallelized_i8(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_signed_unchecked_scalar_min_parallelized_i8(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_scalar_min_parallelized);
test_signed_unchecked_scalar_minmax(params, 1, executor, std::cmp::min::<i8>);
}
fn integer_signed_unchecked_scalar_max_parallelized_i8(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_signed_unchecked_scalar_max_parallelized_i8(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_scalar_max_parallelized);
test_signed_unchecked_scalar_minmax(params, 1, executor, std::cmp::max::<i8>);
}
fn integer_signed_smart_scalar_min_parallelized_i8(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_signed_smart_scalar_min_parallelized_i8(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::smart_scalar_min_parallelized);
test_signed_smart_scalar_minmax(params, 1, executor, std::cmp::min::<i8>);
}
fn integer_signed_smart_scalar_max_parallelized_i8(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_signed_smart_scalar_max_parallelized_i8(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::smart_scalar_max_parallelized);
test_signed_smart_scalar_minmax(params, 1, executor, std::cmp::max::<i8>);
}
fn integer_signed_scalar_min_parallelized_i8(params: crate::shortint::ClassicPBSParameters) {
fn integer_signed_scalar_min_parallelized_i8(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_min_parallelized);
test_signed_default_scalar_minmax(params, 1, executor, std::cmp::min::<i8>);
}
fn integer_signed_scalar_max_parallelized_i8(params: crate::shortint::ClassicPBSParameters) {
fn integer_signed_scalar_max_parallelized_i8(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_max_parallelized);
test_signed_default_scalar_minmax(params, 1, executor, std::cmp::max::<i8>);
}

View File

@@ -32,7 +32,8 @@ create_parameterized_test!(integer_signed_default_overflowing_sub_parallel {
COVERAGE_PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS
},
no_coverage => {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -520,7 +520,8 @@ create_parameterized_test!(
},
no_coverage => {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_2_CARRY_3_KS_PBS_GAUSSIAN_2M128, // Test case where carry_modulus > message_modulus
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower

View File

@@ -30,7 +30,8 @@ create_parameterized_test!(integer_advanced_overflowing_add_assign_with_carry_at
COVERAGE_PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS
},
no_coverage => {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -47,7 +48,8 @@ create_parameterized_test!(integer_extensive_trivial_overflowing_advanced_add_as
COVERAGE_PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS
},
no_coverage => {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -321,7 +321,8 @@ macro_rules! define_comparison_test_functions {
{
// Non parallelized does not support 1_1
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
@@ -334,7 +335,8 @@ macro_rules! define_comparison_test_functions {
{
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
@@ -348,7 +350,8 @@ macro_rules! define_comparison_test_functions {
{
// Non parallelized does not support 1_1
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as smart test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -364,7 +367,8 @@ macro_rules! define_comparison_test_functions {
{
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as smart test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -380,7 +384,8 @@ macro_rules! define_comparison_test_functions {
{
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -670,28 +675,32 @@ mod no_coverage {
create_parameterized_test!(integer_unchecked_max_parallelized_u256);
create_parameterized_test!(integer_smart_min_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// No test for 3_3, see define_comparison_test_functions macro
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_smart_max_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// No test for 3_3, see define_comparison_test_functions macro
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_min_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// No test for 3_3, see define_comparison_test_functions macro
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_max_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// No test for 3_3, see define_comparison_test_functions macro
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64

View File

@@ -21,7 +21,8 @@ create_parameterized_test!(
no_coverage => {
// Due to the use of comparison,
// this algorithm requires 3 bits
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -41,7 +42,8 @@ create_parameterized_test!(
no_coverage => {
// Due to the use of comparison,
// this algorithm requires 3 bits
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -61,7 +63,8 @@ create_parameterized_test!(
no_coverage => {
// Due to the use of comparison,
// this algorithm requires 3 bits
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -81,7 +84,8 @@ create_parameterized_test!(
no_coverage => {
// Due to the use of comparison,
// this algorithm requires 3 bits
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -101,7 +105,8 @@ create_parameterized_test!(
no_coverage => {
// Due to the use of comparison,
// this algorithm requires 3 bits
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -121,7 +126,8 @@ create_parameterized_test!(
no_coverage => {
// Due to the use of comparison,
// this algorithm requires 3 bits
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -142,7 +148,8 @@ create_parameterized_test!(
// Due to the use of comparison,
// this algorithm requires 3 bits
// The algorithm is agnostic to multibit so we don't test those params
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
}

View File

@@ -20,7 +20,8 @@ create_parameterized_test!(integer_default_leading_ones);
create_parameterized_test!(integer_default_ilog2);
create_parameterized_test!(integer_default_checked_ilog2 {
// This uses comparisons, so require more than 1 bit
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -18,7 +18,8 @@ create_parameterized_test!(
},
no_coverage => {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -37,7 +38,8 @@ create_parameterized_test!(
},
no_coverage => {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -9,7 +9,6 @@ use crate::integer::{IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey}
use crate::shortint::parameters::*;
use statrs::distribution::ContinuousCDF;
use std::collections::HashMap;
use std::num::NonZeroU64;
use std::sync::Arc;
use tfhe_csprng::seeders::Seed;
@@ -37,19 +36,9 @@ fn oprf_any_range_unsigned<P>(param: P)
where
P: Into<TestParameters>,
{
let executor =
CpuFunctionExecutor::new(&|sk: &ServerKey,
seed: Seed,
num_input_random_bits: u64,
excluded_upper_bound: u64,
num_blocks_output: u64| {
sk.par_generate_oblivious_pseudo_random_unsigned_custom_range(
seed,
num_input_random_bits,
NonZeroU64::new(excluded_upper_bound).unwrap(),
num_blocks_output,
)
});
let executor = CpuFunctionExecutor::new(
&ServerKey::par_generate_oblivious_pseudo_random_unsigned_custom_range,
);
oprf_any_range_test(param, executor);
}
@@ -57,19 +46,9 @@ fn oprf_almost_uniformity_unsigned<P>(param: P)
where
P: Into<TestParameters>,
{
let executor =
CpuFunctionExecutor::new(&|sk: &ServerKey,
seed: Seed,
num_input_random_bits: u64,
excluded_upper_bound: u64,
num_blocks_output: u64| {
sk.par_generate_oblivious_pseudo_random_unsigned_custom_range(
seed,
num_input_random_bits,
NonZeroU64::new(excluded_upper_bound).unwrap(),
num_blocks_output,
)
});
let executor = CpuFunctionExecutor::new(
&ServerKey::par_generate_oblivious_pseudo_random_unsigned_custom_range,
);
oprf_almost_uniformity_test(param, executor);
}
@@ -110,7 +89,7 @@ where
);
}
pub(crate) fn oprf_uniformity_test<P, E>(param: P, mut executor: E)
pub fn oprf_uniformity_test<P, E>(param: P, mut executor: E)
where
P: Into<TestParameters>,
E: for<'a> FunctionExecutor<(Seed, u64, u64), RadixCiphertext>,
@@ -134,7 +113,7 @@ where
});
}
pub(crate) fn oprf_any_range_test<P, E>(param: P, mut executor: E)
pub fn oprf_any_range_test<P, E>(param: P, mut executor: E)
where
P: Into<TestParameters>,
E: for<'a> FunctionExecutor<(Seed, u64, u64, u64), RadixCiphertext>,
@@ -170,7 +149,7 @@ where
}
}
pub(crate) fn oprf_almost_uniformity_test<P, E>(param: P, mut executor: E)
pub fn oprf_almost_uniformity_test<P, E>(param: P, mut executor: E)
where
P: Into<TestParameters>,
E: for<'a> FunctionExecutor<(Seed, u64, u64, u64), RadixCiphertext>,
@@ -186,70 +165,40 @@ where
let num_input_random_bits: u64 = 4;
let num_blocks_output = 64;
let excluded_upper_bound = 10;
let random_input_upper_bound = 1 << num_input_random_bits;
let mut density = vec![0_usize; excluded_upper_bound as usize];
for i in 0..random_input_upper_bound {
let index = ((i * excluded_upper_bound) as f64 / random_input_upper_bound as f64) as usize;
density[index] += 1;
}
let theoretical_pdf: Vec<f64> = density
.iter()
.map(|count| *count as f64 / random_input_upper_bound as f64)
.collect();
let values: Vec<u64> = (0..sample_count)
.map(|seed| {
let img = executor.execute((
Seed(seed as u128),
num_input_random_bits,
excluded_upper_bound,
excluded_upper_bound as u64,
num_blocks_output,
));
cks.decrypt(&img)
})
.collect();
let p_value_upper_bound = p_value_upper_bound_oprf_almost_uniformity_from_values(
&values,
num_input_random_bits,
excluded_upper_bound,
);
assert!(p_value_limit < p_value_upper_bound);
}
pub(crate) fn p_value_upper_bound_oprf_almost_uniformity_from_values(
values: &[u64],
num_input_random_bits: u64,
excluded_upper_bound: u64,
) -> f64 {
let density = oprf_density_function(excluded_upper_bound, num_input_random_bits);
let theoretical_pdf = probability_density_function_from_density(&density);
let mut bins = vec![0_u64; excluded_upper_bound as usize];
for value in values.iter().copied() {
for value in values {
bins[value as usize] += 1;
}
let cumulative_bins = cumulate(&bins);
let theoretical_cdf = cumulate(&theoretical_pdf);
let sup_diff = sup_diff(&cumulative_bins, &theoretical_cdf);
let p_value_upper_bound = dkw_alpha_from_epsilon(sample_count as f64, sup_diff);
dkw_alpha_from_epsilon(values.len() as f64, sup_diff)
}
pub(crate) fn oprf_density_function(
excluded_upper_bound: u64,
num_input_random_bits: u64,
) -> Vec<usize> {
let random_input_upper_bound = 1 << num_input_random_bits;
let mut density = vec![0_usize; excluded_upper_bound as usize];
for i in 0..random_input_upper_bound {
let output = ((i * excluded_upper_bound) >> num_input_random_bits) as usize;
density[output] += 1;
}
density
}
pub(crate) fn probability_density_function_from_density(density: &[usize]) -> Vec<f64> {
let total_count: usize = density.iter().copied().sum();
density
.iter()
.map(|count| *count as f64 / total_count as f64)
.collect()
assert!(p_value_limit < p_value_upper_bound);
}

View File

@@ -248,7 +248,8 @@ macro_rules! define_scalar_comparison_test_functions {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
@@ -262,7 +263,8 @@ macro_rules! define_scalar_comparison_test_functions {
{
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as smart test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -278,7 +280,8 @@ macro_rules! define_scalar_comparison_test_functions {
{
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as default test might overflow values
// and when using 3_3 to represent 256 we actually have more than 256 bits
@@ -296,10 +299,11 @@ macro_rules! define_scalar_comparison_test_functions {
/// The goal of this function is to ensure that scalar comparisons
/// work when the scalar type used is either bigger or smaller (in bit size)
/// compared to the ciphertext
fn integer_unchecked_scalar_comparisons_edge(param: ClassicPBSParameters) {
fn integer_unchecked_scalar_comparisons_edge<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let mut rng = rand::thread_rng();
let num_block = (128f64 / (param.message_modulus.0 as f64).log(2.0)).ceil() as usize;
let num_block = (128f64 / (param.message_modulus().0 as f64).log(2.0)).ceil() as usize;
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
@@ -402,7 +406,8 @@ fn integer_unchecked_scalar_comparisons_edge(param: ClassicPBSParameters) {
}
}
fn integer_unchecked_scalar_comparisons_edge_one_block(param: ClassicPBSParameters) {
fn integer_unchecked_scalar_comparisons_edge_one_block<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let mut rng = rand::thread_rng();
let num_block = 1;
@@ -486,7 +491,8 @@ fn integer_unchecked_scalar_comparisons_edge_one_block(param: ClassicPBSParamete
// Given a ciphertext that consists of empty blocks,
// the function tests whether comparisons still hold.
fn integer_comparisons_for_empty_blocks(param: ClassicPBSParameters) {
fn integer_comparisons_for_empty_blocks<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let mut rng = rand::thread_rng();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
@@ -519,9 +525,10 @@ fn integer_comparisons_for_empty_blocks(param: ClassicPBSParameters) {
}
}
fn integer_is_scalar_out_of_bounds(param: ClassicPBSParameters) {
fn integer_is_scalar_out_of_bounds<P: Into<TestParameters>>(param: P) {
let param: TestParameters = param.into();
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let num_block = 128usize.div_ceil(param.message_modulus.0.ilog2() as usize);
let num_block = 128usize.div_ceil(param.message_modulus().0.ilog2() as usize);
let mut rng = thread_rng();
@@ -764,64 +771,64 @@ pub(crate) fn test_default_scalar_minmax<P, T, ClearF, Scalar>(
mod no_coverage {
use super::*;
fn integer_unchecked_scalar_min_parallelized_u256(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_unchecked_scalar_min_parallelized_u256(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_scalar_min_parallelized);
test_unchecked_scalar_minmax(params, 2, executor, std::cmp::min::<U256>);
}
fn integer_unchecked_scalar_max_parallelized_u256(
params: crate::shortint::ClassicPBSParameters,
) {
fn integer_unchecked_scalar_max_parallelized_u256(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::unchecked_scalar_max_parallelized);
test_unchecked_scalar_minmax(params, 2, executor, std::cmp::max::<U256>);
}
fn integer_smart_scalar_min_parallelized_u256(params: crate::shortint::ClassicPBSParameters) {
fn integer_smart_scalar_min_parallelized_u256(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::smart_scalar_min_parallelized);
test_smart_scalar_minmax(params, 2, executor, std::cmp::min::<U256>);
}
fn integer_smart_scalar_max_parallelized_u256(params: crate::shortint::ClassicPBSParameters) {
fn integer_smart_scalar_max_parallelized_u256(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::smart_scalar_max_parallelized);
test_smart_scalar_minmax(params, 2, executor, std::cmp::max::<U256>);
}
fn integer_scalar_min_parallelized_u256(params: crate::shortint::ClassicPBSParameters) {
fn integer_scalar_min_parallelized_u256(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_min_parallelized);
test_default_scalar_minmax(params, 2, executor, std::cmp::min::<U256>);
}
fn integer_scalar_max_parallelized_u256(params: crate::shortint::ClassicPBSParameters) {
fn integer_scalar_max_parallelized_u256(params: impl Into<TestParameters>) {
let executor = CpuFunctionExecutor::new(&ServerKey::scalar_max_parallelized);
test_default_scalar_minmax(params, 2, executor, std::cmp::max::<U256>);
}
create_parameterized_test!(integer_unchecked_scalar_min_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_unchecked_scalar_max_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_smart_scalar_min_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// No test for 3_3, see define_scalar_comparison_test_functions macro
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_smart_scalar_max_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// No test for 3_3, see define_scalar_comparison_test_functions macro
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
@@ -829,14 +836,16 @@ mod no_coverage {
create_parameterized_test!(integer_scalar_min_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// No test for 3_3, see define_scalar_comparison_test_functions macro
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_scalar_max_parallelized_u256 {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// No test for 3_3, see define_scalar_comparison_test_functions macro
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
@@ -851,7 +860,8 @@ mod no_coverage {
create_parameterized_test!(integer_unchecked_scalar_comparisons_edge {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
@@ -859,14 +869,16 @@ mod no_coverage {
create_parameterized_test!(integer_unchecked_scalar_comparisons_edge_one_block {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
});
create_parameterized_test!(integer_is_scalar_out_of_bounds {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
// We don't use PARAM_MESSAGE_3_CARRY_3_KS_PBS,
// as the test relies on the ciphertext to encrypt 128bits
// but with param 3_3 we actually encrypt more that 128bits
@@ -876,7 +888,8 @@ mod no_coverage {
create_parameterized_test!(integer_comparisons_for_empty_blocks {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -17,7 +17,8 @@ create_parameterized_test!(
},
no_coverage => {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
}
}
);
@@ -28,7 +29,8 @@ create_parameterized_test!(
COVERAGE_PARAM_MESSAGE_2_CARRY_2_KS_PBS,
},
no_coverage => {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
}
}
);

View File

@@ -30,7 +30,8 @@ create_parameterized_test!(integer_advanced_sub_assign_with_borrow_at_least_4_bi
COVERAGE_PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS
},
no_coverage => {
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,

View File

@@ -24,7 +24,7 @@ macro_rules! create_parameterized_test {
},
no_coverage => {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
@@ -33,7 +33,9 @@ macro_rules! create_parameterized_test {
TEST_PARAM_MULTI_BIT_GROUP_2_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M64,
TEST_PARAM_MULTI_BIT_GROUP_3_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M64,
TEST_PARAM_MULTI_BIT_GROUP_3_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M64,
TEST_PARAM_MULTI_BIT_GROUP_3_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M64
TEST_PARAM_MULTI_BIT_GROUP_3_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M64,
// Test prod params
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
}
});
};
@@ -67,10 +69,12 @@ macro_rules! create_parameterized_test_classical_params {
},
no_coverage => {
TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128,
// 2M128 is too slow for 4_4, it is estimated to be 2x slower
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64
TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64,
// Test prod params
TEST_PARAM_PROD_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
}
});
};

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