Compare commits

...

26 Commits

Author SHA1 Message Date
Thomas Montaigu
88241fee21 feat: add bitonic_shuffle
Bitonic shuffles allows to shuffle a vec of homomorphic integers
by using a bitonic sort using random generated keys
2026-04-22 15:50:02 +02:00
Arthur Meyre
7b174b1865 chore: make the plaintext PRF available as a test util
- KMS is testing things around the PRF and they need a way to verify the
PRF application, so making a cleartext PRF function available as a test
utils
2026-04-22 10:18:32 +02:00
Arthur Meyre
79cb6b6066 chore: dirty fix for zk-cuda-backend rust build 2026-04-22 10:18:21 +02:00
Nicolas Sarlin
6ff87e94bb chore(gpu): remove os detection script (done in rust) 2026-04-22 10:04:52 +02:00
Thomas Montaigu
4c27f48968 chore(oprf): add missing into/from raw parts 2026-04-22 00:25:44 +02:00
Arthur Meyre
8bf2a12e9b chore: dirty fix for zk-cuda-backend build problem
- when compiling for real it cannot find the file which is not available
2026-04-21 17:23:30 +02:00
Arthur Meyre
64b5a0fdcd chore: fix cuda release workflow 2026-04-21 16:30:30 +02:00
Thomas Montaigu
49c390edef refactor(oprf): change hashed data 2026-04-21 14:43:17 +02:00
Thomas Montaigu
82860a0b01 refactor(oprf)!: use a dedicated key for oprf
The OPRF is a simple bootstrap, however as it
uses a custom modulus switch I decided to define a
new type and not re-use the ShortintBoostrapKey,
except for GPU where it was easier to reuse it.

This means that shortint/integer APIs must now create
an OprkPrivateKey + OprfServerKey to do oprf (or use .as_oprf_key_view)
In the HLAPI no breaking change as we can use either dedicated
key or fallback on the compute bsk

This refactor makes the shortint oprf able to generate
multiple blocks at once starting from the same seed.
This is to follow some guidelines.

This means that shortint's oprf now has a function doing most
of the all to generate Ciphertext that encrypts random bits
split evenly amongst multiple blocks
2026-04-21 14:43:17 +02:00
Theo Souchon
39ca504ce4 chore(lint): change report backward to have the right behavior for message generation 2026-04-21 14:34:13 +02:00
dependabot[bot]
61c7ffea2e chore(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](bbbca2ddaa...043fb46d1a)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-21 12:08:45 +02:00
Nicolas Sarlin
48bb3833e7 fix(shortint): proven ct list expand with a ksk but no fn fails 2026-04-20 14:15:54 +02:00
Theo Souchon
2ad2f522db chore(lint): remove upgrade false positive warning if new variant added in an enum versioned 2026-04-20 08:24:29 +02:00
Nicolas Sarlin
2333a5591e chore(ci): check that Cargo.lock of generate_ crates is up to date 2026-04-17 17:33:59 +02:00
David Testé
9e3e283741 doc(bench): update benchmark results tables 2026-04-17 12:52:37 +02:00
Arthur Meyre
e3b9fd56df feat: add mul div entry points
- this operation has optimization opportunities (at least for the scalar
mul and scalar div case) but those won't be implemented here, this is a
first commit to make the API available
2026-04-17 11:04:32 +02:00
Thomas Montaigu
05b1c9a651 feat(hlapi): bind CudaServerKey::contains 2026-04-16 16:20:11 +02:00
Thomas Montaigu
8d2caa108a chore(hlapi): add gpu stuff to FheInteger trait 2026-04-16 16:20:11 +02:00
Thomas Montaigu
dea1b81b06 feat(hlapi): add contains for cpu 2026-04-16 16:20:11 +02:00
Arthur Meyre
a1dc91af4f chore: update rand version in tfhe-hpu-backend
- to silence a soundness warning (which does not concern us since we don't
use the faulty mechanism)
2026-04-16 16:11:34 +02:00
Arthur Meyre
b34b7d39f1 chore: remove unused deps from mockup
- those are not referenced at all in the code
- clap-num is less clear since clap is used, so left it in for now
2026-04-16 16:11:34 +02:00
Arthur Meyre
dc14834559 chore: bump tfhe-hpu-backend after erc7984 update 2026-04-16 11:51:58 +02:00
Nicolas Sarlin
10ab4f4409 feat: add re_randomization for ProvenCompactCiphertList 2026-04-16 11:37:21 +02:00
Nicolas Sarlin
d5439a9f48 fix(core): check that ct modulus is power of two in glwe algebra 2026-04-16 11:37:21 +02:00
Mayeul@Zama
e299dc2af7 feat(integer): add improved leading_zeroes 2026-04-15 17:29:05 +02:00
Enzo Di Maria
bdb75ec806 fix(gpu): AES noise fix 2026-04-15 17:08:04 +02:00
154 changed files with 7386 additions and 1461 deletions

View File

@@ -79,19 +79,11 @@ jobs:
exit 1
fi
- name: Find existing comment
- name: Post/refresh backward-compat report
if: steps.report.outputs.has_report == 'true'
id: find-comment
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
uses: marocchino/sticky-pull-request-comment@0ea0beb66eb9baf113663a64ec522f60e49231c0
with:
issue-number: ${{ github.event.pull_request.number }}
body-includes: '**Backward-compat snapshot:'
- name: Comment on PR
if: steps.report.outputs.has_report == 'true'
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: report.md
edit-mode: replace
header: backward-compat-snapshot
hide_and_recreate: true
hide_classify: OUTDATED
path: report.md

View File

@@ -223,7 +223,7 @@ jobs:
results_type: ${{ inputs.additional_results_type }}
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_${{ matrix.command }}_${{ matrix.op_flavor }}_${{ matrix.bench_type }}_${{ matrix.params_type }}
path: ${{ env.RESULTS_FILENAME }}

View File

@@ -99,7 +99,7 @@ jobs:
--append-results
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_ct_key_sizes
path: ${{ env.RESULTS_FILENAME }}

View File

@@ -89,7 +89,7 @@ jobs:
REF_NAME: ${{ github.ref_name }}
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_integer_multi_bit_gpu_default
path: ${{ env.RESULTS_FILENAME }}
@@ -173,7 +173,7 @@ jobs:
REF_NAME: ${{ github.ref_name }}
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_core_crypto
path: ${{ env.RESULTS_FILENAME }}

View File

@@ -270,7 +270,7 @@ jobs:
filenames: ${{ inputs.additional_file_to_parse }}
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_${{ matrix.command }}_${{ matrix.op_flavor }}_${{ inputs.profile }}_${{ matrix.bench_type }}_${{ matrix.params_type }}
path: ${{ env.RESULTS_FILENAME }}

View File

@@ -271,7 +271,7 @@ jobs:
- name: Upload profile artifact
env:
REPORT_NAME: ${{ steps.nsys_profile_name.outputs.profile }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.REPORT_NAME }}
path: fhevm/coprocessor/fhevm-engine/tfhe-worker/${{ env.REPORT_NAME }}
@@ -302,7 +302,7 @@ jobs:
working-directory: fhevm/
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${COMMIT_SHA}_${BENCHMARKS}_${{ needs.parse-inputs.outputs.profile }}
path: fhevm/$${{ env.RESULTS_FILENAME }}

View File

@@ -185,7 +185,7 @@ jobs:
BENCH_TYPE: ${{ matrix.bench_type }}
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_${{ matrix.bench_type }}_${{ matrix.command }}_benchmarks
path: ${{ env.RESULTS_FILENAME }}

View File

@@ -280,7 +280,7 @@ jobs:
BENCH_TYPE: ${{ env.__TFHE_RS_BENCH_TYPE }}
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_regression_${{ env.RESULTS_FILE_SHA }} # RESULT_FILE_SHA is needed to avoid collision between matrix.command runs
path: ${{ env.RESULTS_FILENAME }}

View File

@@ -99,7 +99,7 @@ jobs:
REF_NAME: ${{ github.ref_name }}
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_fft
path: ${{ env.RESULTS_FILENAME }}

View File

@@ -99,7 +99,7 @@ jobs:
REF_NAME: ${{ github.ref_name }}
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_ntt
path: ${{ env.RESULTS_FILENAME }}

View File

@@ -180,7 +180,7 @@ jobs:
REF_NAME: ${{ github.ref_name }}
- name: Upload parsed results artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_wasm_${{ matrix.browser }}
path: ${{ env.RESULTS_FILENAME }}

View File

@@ -87,7 +87,7 @@ jobs:
- name: Upload tables
if: inputs.backend_comparison == false
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_${{ inputs.backend }}_${{ inputs.layer }}_subset_${{inputs.bench_subset}}_${{ inputs.pbs_kind }}_${{ inputs.bench_type }}_tables
# This will upload all the file generated
@@ -111,7 +111,7 @@ jobs:
- name: Upload comparison tables
if: inputs.backend_comparison == true
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ github.sha }}_backends_comparison_tables
# This will upload all the file generated

View File

@@ -62,7 +62,7 @@ jobs:
PACKAGE: ${{ inputs.package-name }}
run: |
cargo package -p "${PACKAGE}"
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: crate-${{ inputs.package-name }}
path: target/package/*.crate

View File

@@ -128,7 +128,7 @@ jobs:
run: |
cargo package -p "${PACKAGE}"
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: crate-${{ inputs.package-name }}
path: target/package/*.crate
@@ -196,6 +196,13 @@ jobs:
env:
GCC_VERSION: ${{ matrix.gcc }}
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: "false"
token: ${{ secrets.REPO_CHECKOUT_TOKEN }}
- name: Download artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
@@ -210,12 +217,12 @@ jobs:
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
PACKAGE: ${{ inputs.package-name }}
DRY-RUN: ${{ inputs.dry-run && '--dry-run' || '' }}
DRY_RUN: ${{ inputs.dry-run && '--dry-run' || '' }}
run: |
# dry-run expansion cannot be double quoted when variable contains empty string otherwise cargo publish
# would fail. This is safe since dry-run is handled in the env section above.
# DRY_RUN expansion cannot be double quoted when variable contains empty string otherwise cargo publish
# would fail. This is safe since DRY_RUN is handled in the env section above.
# shellcheck disable=SC2086
cargo publish -p "${PACKAGE}" ${DRY-RUN}
cargo publish -p "${PACKAGE}" ${DRY_RUN}
- name: Generate hash
id: published_hash
@@ -255,7 +262,7 @@ jobs:
- name: Slack Notification
if: ${{ failure() }}
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_COLOR: ${{ job.status }}
SLACK_MESSAGE: "Instance teardown (${{ inputs.package-name }} release) finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"

View File

@@ -587,6 +587,17 @@ clippy_backward_compat_data: install_rs_check_toolchain # the toolchain is selec
echo "Cannot run clippy for backward compat crate on non x86 platform for now."; \
fi
.PHONY: check_backward_compat_locks_did_not_change # Check backward compat Cargo.lock files are up to date
check_backward_compat_locks_did_not_change: install_rs_check_toolchain
@for crate in `ls -1 $(BACKWARD_COMPAT_DATA_DIR)/crates/ | grep generate_`; do \
echo "checking Cargo.lock for $$crate"; \
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" -Z unstable-options \
-C $(BACKWARD_COMPAT_DATA_DIR)/crates/$$crate metadata --locked --format-version 1 > /dev/null || \
( echo "Cargo.lock for $$crate is out of date. Update it with:" && \
echo " cd $(BACKWARD_COMPAT_DATA_DIR)/crates/$$crate && cargo metadata --format-version 1 > /dev/null" && \
echo "then commit the updated Cargo.lock." && exit 1 ); \
done
.PHONY: clippy_test_vectors # Run clippy lints on the test vectors app
clippy_test_vectors: install_rs_check_toolchain
cd apps/test-vectors; RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
@@ -2265,6 +2276,7 @@ pcc_batch_5:
$(call run_recipe_with_details,clippy_tfhe_lints)
$(call run_recipe_with_details,check_compile_tests)
$(call run_recipe_with_details,clippy_backward_compat_data)
$(call run_recipe_with_details,check_backward_compat_locks_did_not_change)
.PHONY: pcc_batch_6 # duration: 6'32''
pcc_batch_6:

View File

@@ -1,5 +1,14 @@
use std::path::PathBuf;
use std::process::Command;
fn get_linux_distribution_name() -> Option<String> {
let content = std::fs::read_to_string("/etc/os-release").ok()?;
for line in content.lines() {
if let Some(value) = line.strip_prefix("NAME=") {
return Some(value.trim_matches('"').to_string());
}
}
None
}
fn main() {
if let Ok(val) = std::env::var("DOCS_RS") {
@@ -28,9 +37,7 @@ fn main() {
println!("cargo::rerun-if-changed=src");
if std::env::consts::OS == "linux" {
let output = Command::new("./get_os_name.sh").output().unwrap();
let distribution = String::from_utf8(output.stdout).unwrap();
if distribution != "Ubuntu\n" {
if get_linux_distribution_name().as_deref() != Some("Ubuntu") {
println!(
"cargo:warning=This Linux distribution is not officially supported. \
Only Ubuntu is supported by tfhe-cuda-backend at this time. Build may fail\n"

View File

@@ -721,7 +721,7 @@ void cuda_integer_grouped_oprf_custom_range_64_async(
uint32_t num_blocks_intermediate, const void *seeded_lwe_input,
const uint64_t *decomposed_scalar, const uint64_t *has_at_least_one_set,
uint32_t num_scalars, uint32_t shift, int8_t *mem, void *const *bsks,
void *const *ksks);
void *const *compute_bsks, void *const *ksks);
void cleanup_cuda_integer_grouped_oprf_custom_range_64(CudaStreamsFFI streams,
int8_t **mem_ptr_void);

View File

@@ -390,7 +390,7 @@ __host__ void vectorized_sbox_n_bytes(CudaStreams streams,
XOR(&wires_a[6], &wires_a[15], &input_bits[7]);
XOR(&wires_a[10], &wires_a[15], &wires_b[0]);
XOR(&wires_a[11], &wires_a[20], &wires_a[9]);
FLUSH(&wires_a[6], &wires_a[10]);
FLUSH(&wires_a[6], &wires_a[10], &wires_a[11]);
XOR(&wires_a[7], &input_bits[7], &wires_a[11]);
FLUSH(&wires_a[7]);
XOR(&wires_a[17], &wires_a[10], &wires_a[11]);
@@ -426,7 +426,7 @@ __host__ void vectorized_sbox_n_bytes(CudaStreams streams,
XOR(&wires_b[22], &wires_b[18], &wires_a[19]);
XOR(&wires_b[23], &wires_b[19], &wires_a[21]);
XOR(&wires_b[24], &wires_b[20], &wires_a[18]);
FLUSH(&wires_b[21], &wires_b[23], &wires_b[24]);
FLUSH(&wires_b[21], &wires_b[22], &wires_b[23], &wires_b[24]);
XOR(&wires_b[25], &wires_b[21], &wires_b[22]);
FLUSH(&wires_b[25]);
@@ -468,7 +468,7 @@ __host__ void vectorized_sbox_n_bytes(CudaStreams streams,
XOR(&wires_b[37], &wires_b[36], &wires_b[34]);
XOR(&wires_b[38], &wires_b[27], &wires_b[36]);
FLUSH(&wires_b[38]);
FLUSH(&wires_b[38], &wires_b[37]);
XOR(&wires_b[44], &wires_b[33], &wires_b[37]);
CudaRadixCiphertextFFI *and_outs_6[] = {&wires_b[39]};
@@ -479,7 +479,7 @@ __host__ void vectorized_sbox_n_bytes(CudaStreams streams,
XOR(&wires_b[40], &wires_b[25], &wires_b[39]);
XOR(&wires_b[41], &wires_b[40], &wires_b[37]);
XOR(&wires_b[43], &wires_b[29], &wires_b[40]);
FLUSH(&wires_b[41]);
FLUSH(&wires_b[41], &wires_b[40], &wires_b[43], &wires_b[44]);
XOR(&wires_b[45], &wires_b[42], &wires_b[41]);
FLUSH(&wires_b[45]);
@@ -514,6 +514,7 @@ __host__ void vectorized_sbox_n_bytes(CudaStreams streams,
XOR(&wires_b[57], &wires_b[50], &wires_b[53]);
XOR(&wires_b[58], &wires_c[4], &wires_b[46]);
XOR(&wires_b[59], &wires_c[3], &wires_b[54]);
FLUSH(&wires_b[57], &wires_b[58]);
XOR(&wires_b[60], &wires_b[46], &wires_b[57]);
XOR(&wires_b[61], &wires_c[14], &wires_b[57]);
XOR(&wires_b[62], &wires_b[52], &wires_b[58]);
@@ -589,6 +590,7 @@ __host__ void vectorized_sbox_n_bytes(CudaStreams streams,
#undef FLUSH
#undef AND
#undef ADD_ONE_FLUSH
#undef ADD_ONE
}
/**

View File

@@ -72,13 +72,13 @@ void cuda_integer_grouped_oprf_custom_range_64_async(
uint32_t num_blocks_intermediate, const void *seeded_lwe_input,
const uint64_t *decomposed_scalar, const uint64_t *has_at_least_one_set,
uint32_t num_scalars, uint32_t shift, int8_t *mem, void *const *bsks,
void *const *ksks) {
void *const *compute_bsks, void *const *ksks) {
host_integer_grouped_oprf_custom_range<uint64_t>(
CudaStreams(streams), radix_lwe_out, num_blocks_intermediate,
(const uint64_t *)seeded_lwe_input, decomposed_scalar,
has_at_least_one_set, num_scalars, shift,
(int_grouped_oprf_custom_range_memory<uint64_t> *)mem, bsks,
(int_grouped_oprf_custom_range_memory<uint64_t> *)mem, bsks, compute_bsks,
(uint64_t *const *)ksks);
}

View File

@@ -114,7 +114,7 @@ void host_integer_grouped_oprf_custom_range(
const Torus *decomposed_scalar, const Torus *has_at_least_one_set,
uint32_t num_scalars, uint32_t shift,
int_grouped_oprf_custom_range_memory<Torus> *mem_ptr, void *const *bsks,
Torus *const *ksks) {
void *const *compute_bsks, Torus *const *ksks) {
CudaRadixCiphertextFFI *computation_buffer = mem_ptr->tmp_oprf_output;
set_zero_radix_ciphertext_slice_async<Torus>(
@@ -127,12 +127,12 @@ void host_integer_grouped_oprf_custom_range(
host_integer_scalar_mul_radix<Torus>(
streams, computation_buffer, decomposed_scalar, has_at_least_one_set,
mem_ptr->scalar_mul_buffer, bsks, ksks, mem_ptr->params.message_modulus,
num_scalars);
mem_ptr->scalar_mul_buffer, compute_bsks, ksks,
mem_ptr->params.message_modulus, num_scalars);
host_logical_scalar_shift_inplace<Torus>(streams, computation_buffer, shift,
mem_ptr->logical_scalar_shift_buffer,
bsks, ksks, num_blocks_intermediate);
host_logical_scalar_shift_inplace<Torus>(
streams, computation_buffer, shift, mem_ptr->logical_scalar_shift_buffer,
compute_bsks, ksks, num_blocks_intermediate);
uint32_t num_blocks_output = radix_lwe_out->num_radix_blocks;
uint32_t blocks_to_copy =

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env bash
cat /etc/os-release | grep "\<NAME\>" | sed "s/NAME=\"//g" | sed "s/\"//g"

View File

@@ -1647,6 +1647,7 @@ unsafe extern "C" {
shift: u32,
mem: *mut i8,
bsks: *const *mut ffi::c_void,
compute_bsks: *const *mut ffi::c_void,
ksks: *const *mut ffi::c_void,
);
}

View File

@@ -1,6 +1,6 @@
[package]
name = "tfhe-hpu-backend"
version = "0.4.0"
version = "0.5.0"
edition = "2021"
license = "BSD-3-Clause-Clear"
description = "HPU implementation on FPGA of TFHE-rs primitives."
@@ -36,7 +36,7 @@ thiserror = "1.0.61"
bytemuck = { workspace = true }
anyhow = "1.0.82"
lazy_static = "1.4.0"
rand = "0.8.5"
rand = "0.10.1"
regex = "1.10.4"
bitflags = { version = "2.5.0", features = ["serde"] }
itertools = "0.11.0"

View File

@@ -24,7 +24,7 @@ use mem_alloc::{MemAlloc, MemChunk};
mod qdma;
use qdma::QdmaDriver;
use rand::Rng;
use rand::RngExt;
const DMA_XFER_ALIGN: usize = 4096_usize;
@@ -148,8 +148,8 @@ impl HpuHw {
tracing::debug!("Load stage1 through JTAG");
let pdi_stg1_tmp = format!(
"hpu_stg1_{}.pdi",
rand::thread_rng()
.sample_iter(rand::distributions::Alphanumeric)
rand::rng()
.sample_iter(rand::distr::Alphanumeric)
.take(5)
.map(char::from)
.collect::<String>()

View File

@@ -1,5 +1,14 @@
use std::path::PathBuf;
use std::process::Command;
fn get_linux_distribution_name() -> Option<String> {
let content = std::fs::read_to_string("/etc/os-release").ok()?;
for line in content.lines() {
if let Some(value) = line.strip_prefix("NAME=") {
return Some(value.trim_matches('"').to_string());
}
}
None
}
fn main() {
// Handle docs.rs builds (no CUDA available)
@@ -29,16 +38,10 @@ fn main() {
println!("cargo:rustc-link-arg=-Wl,--allow-multiple-definition");
println!("cargo:rustc-link-arg=-Wl,--no-as-needed");
// Check Linux distribution (reuse script from tfhe-cuda-backend)
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
.expect("CARGO_MANIFEST_DIR must be set by cargo during build");
let script_path = PathBuf::from(&manifest_dir).join("../tfhe-cuda-backend/get_os_name.sh");
let output = Command::new(&script_path)
.output()
.expect("Failed to run get_os_name.sh — is tfhe-cuda-backend present?");
let distribution =
String::from_utf8(output.stdout).expect("get_os_name.sh output must be valid UTF-8");
if distribution != "Ubuntu\n" {
if get_linux_distribution_name().as_deref() != Some("Ubuntu") {
println!(
"cargo:warning=This Linux distribution is not officially supported. \
Only Ubuntu is supported by zk-cuda-backend at this time. Build may fail\n"

View File

@@ -71,11 +71,6 @@ set(CMAKE_CUDA_FLAGS_DEBUG "-g -O0 -G")
# Additional CUDA flags (aligned with tfhe-cuda-backend)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler -Wall -Xcompiler -Wextra --use_fast_math --expt-relaxed-constexpr")
# =============================================================================
# Path to tfhe-cuda-backend for device utilities
# =============================================================================
set(TFHE_CUDA_BACKEND_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../tfhe-cuda-backend/cuda)
# Core source files (without device utilities) Device utilities come from tfhe-cuda-backend.
set(FP_CORE_SOURCES src/primitives/fp.cu src/primitives/fp2.cu src/curve.cu src/msm/pippenger/msm_pippenger.cu
src/msm/msm.cu)
@@ -112,7 +107,7 @@ endif()
target_link_libraries(zk_cuda_backend PUBLIC cudart)
# Include both local headers and tfhe-cuda-backend headers (for device.h)
target_include_directories(zk_cuda_backend PUBLIC include ../src/include ${TFHE_CUDA_BACKEND_DIR}/include)
target_include_directories(zk_cuda_backend PUBLIC include ../src/include)
# =============================================================================
# Tests and Benchmarks (optional, controlled by ZK_CUDA_BACKEND_BUILD_TESTS/BENCHMARKS)
@@ -135,4 +130,3 @@ message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "CUDA architectures: ${CMAKE_CUDA_ARCHITECTURES}")
message(STATUS "C++ standard: ${CMAKE_CXX_STANDARD}")
message(STATUS "CUDA standard: ${CMAKE_CUDA_STANDARD}")
message(STATUS "tfhe-cuda-backend path: ${TFHE_CUDA_BACKEND_DIR}")

View File

@@ -0,0 +1,35 @@
#pragma once
#include <cstddef>
#include <cstdio>
#include "device.h"
// Variadic checked multiplication of size_t values.
// Folds left-to-right using __builtin_mul_overflow, returning true on overflow.
// On overflow the value written to *out is unspecified.
template <typename... Args>
inline bool checked_mul(size_t *out, size_t first, Args... rest) {
size_t result = first;
for (size_t value : {static_cast<size_t>(rest)...}) {
if (__builtin_mul_overflow(result, value, &result))
return true;
}
*out = result;
return false;
}
// Variadic safe multiplication: computes the product and panics on overflow.
template <typename... Args> inline size_t safe_mul(size_t first, Args... rest) {
size_t result;
bool overflow = checked_mul(&result, first, rest...);
PANIC_IF_FALSE(!overflow, "multiplication overflow wraps size_t");
return result;
}
// Variadic safe multiplication with an appended sizeof(T) factor.
// Computes (args... * sizeof(T)) with overflow checking.
template <typename T, typename... Args>
inline size_t safe_mul_sizeof(Args... args) {
return safe_mul(args..., sizeof(T));
}

View File

@@ -0,0 +1,145 @@
#ifndef DEVICE_H
#define DEVICE_H
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cuda_runtime.h>
extern "C" {
#define check_cuda_error(ans) \
{ cuda_error((ans), __FILE__, __LINE__); }
inline void cuda_error(cudaError_t code, const char *file, int line) {
if (code != cudaSuccess) {
std::fprintf(stderr, "Cuda error: %s %s %d\n", cudaGetErrorString(code),
file, line);
std::abort();
}
}
// The PANIC macro should be used to validate user-inputs to GPU functions
// it will execute in all targets, including production settings
// e.g., cudaMemCopy to the device should check that the destination pointer is
// a device pointer
#define PANIC(format, ...) \
{ \
std::fprintf(stderr, "%s::%d::%s: panic.\n" format "\n", __FILE__, \
__LINE__, __func__, ##__VA_ARGS__); \
std::abort(); \
}
// This is a generic assertion checking macro with user defined printf-style
// message
#define PANIC_IF_FALSE(cond, format, ...) \
do { \
if (!(cond)) { \
PANIC(format "\n\n %s\n", ##__VA_ARGS__, #cond); \
} \
} while (0)
#ifndef GPU_ASSERTS_DISABLE
// The GPU assert should be used to validate assumptions in algorithms,
// for example, checking that two user-provided quantities have a certain
// relationship or that the size of the buffer provided to a function is
// sufficient when it is filled with some algorithm that depends on
// user-provided inputs e.g., OPRF corrections buffer should not have a size
// higher than the number of blocks in the datatype that is generated
#define GPU_ASSERT(cond, format, ...) \
PANIC_IF_FALSE(cond, format, ##__VA_ARGS__)
#else
#define GPU_ASSERT(cond) \
do { \
} while (0)
#endif
uint32_t cuda_get_device();
void cuda_set_device(uint32_t gpu_index);
cudaEvent_t cuda_create_event(uint32_t gpu_index);
void cuda_event_record(cudaEvent_t event, cudaStream_t stream,
uint32_t gpu_index);
void cuda_stream_wait_event(cudaStream_t stream, cudaEvent_t event,
uint32_t gpu_index);
void cuda_event_destroy(cudaEvent_t event, uint32_t gpu_index);
cudaStream_t cuda_create_stream(uint32_t gpu_index);
void cuda_destroy_stream(cudaStream_t stream, uint32_t gpu_index);
void cuda_synchronize_stream(cudaStream_t stream, uint32_t gpu_index);
uint32_t cuda_is_available();
void *cuda_malloc(uint64_t size, uint32_t gpu_index);
void *cuda_malloc_with_size_tracking_async(uint64_t size, cudaStream_t stream,
uint32_t gpu_index,
uint64_t &size_tracker,
bool allocate_gpu_memory);
void *cuda_malloc_async(uint64_t size, cudaStream_t stream, uint32_t gpu_index);
bool cuda_check_valid_malloc(uint64_t size, uint32_t gpu_index);
uint64_t cuda_device_total_memory(uint32_t gpu_index);
void cuda_memcpy_with_size_tracking_async_to_gpu(void *dest, const void *src,
uint64_t size,
cudaStream_t stream,
uint32_t gpu_index,
bool gpu_memory_allocated);
void cuda_memcpy_async_to_gpu(void *dest, const void *src, uint64_t size,
cudaStream_t stream, uint32_t gpu_index);
void cuda_memcpy_with_size_tracking_async_gpu_to_gpu(
void *dest, void const *src, uint64_t size, cudaStream_t stream,
uint32_t gpu_index, bool gpu_memory_allocated);
void cuda_memcpy_async_gpu_to_gpu(void *dest, void const *src, uint64_t size,
cudaStream_t stream, uint32_t gpu_index);
void cuda_memcpy_gpu_to_gpu(void *dest, void const *src, uint64_t size,
uint32_t gpu_index);
void cuda_memcpy_async_to_cpu(void *dest, const void *src, uint64_t size,
cudaStream_t stream, uint32_t gpu_index);
void cuda_memset_with_size_tracking_async(void *dest, uint64_t val,
uint64_t size, cudaStream_t stream,
uint32_t gpu_index,
bool gpu_memory_allocated);
void cuda_memset_async(void *dest, uint64_t val, uint64_t size,
cudaStream_t stream, uint32_t gpu_index);
int cuda_get_number_of_gpus();
int cuda_get_number_of_sms();
void cuda_synchronize_device(uint32_t gpu_index);
void cuda_drop(void *ptr, uint32_t gpu_index);
void cuda_drop_with_size_tracking_async(void *ptr, cudaStream_t stream,
uint32_t gpu_index,
bool gpu_memory_allocated);
void cuda_drop_async(void *ptr, cudaStream_t stream, uint32_t gpu_index);
}
uint32_t cuda_get_max_shared_memory(uint32_t gpu_index);
uint32_t cuda_get_max_shared_memory_per_block(uint32_t gpu_index);
bool cuda_check_support_cooperative_groups();
bool cuda_check_support_thread_block_clusters();
template <typename Torus>
void cuda_set_value_async(cudaStream_t stream, uint32_t gpu_index,
Torus *d_array, Torus value, Torus n);
#endif

View File

@@ -0,0 +1,16 @@
#ifndef HELPER_PROFILE
#define HELPER_PROFILE
#ifdef USE_NVTOOLS
#include <nvtx3/nvToolsExt.h>
#endif
void cuda_nvtx_label_with_color(const char *name);
void cuda_nvtx_pop();
#define PUSH_RANGE(name) \
{ cuda_nvtx_label_with_color(name); }
#define POP_RANGE() \
{ cuda_nvtx_pop(); }
#endif

View File

@@ -0,0 +1,43 @@
#include "helper_profile.cuh"
#include <stdint.h>
uint32_t adler32(const unsigned char *data) {
const uint32_t MOD_ADLER = 65521;
uint32_t a = 1, b = 0;
size_t index;
for (index = 0; data[index] != 0; ++index) {
a = (a + data[index] * 2) % MOD_ADLER;
b = (b + a) % MOD_ADLER;
}
return (b << 16) | a;
}
void cuda_nvtx_label_with_color(const char *name) {
#ifdef USE_NVTOOLS
int color_id = adler32((const unsigned char *)name);
int r, g, b;
r = color_id & 0x000000ff;
g = (color_id & 0x000ff000) >> 12;
b = (color_id & 0x0ff00000) >> 20;
if (r < 64 & g < 64 & b < 64) {
r = r * 3;
g = g * 3 + 64;
b = b * 4;
}
color_id = 0xff000000 | (r << 16) | (g << 8) | (b);
nvtxEventAttributes_t eventAttrib = {0};
eventAttrib.version = NVTX_VERSION;
eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE;
eventAttrib.colorType = NVTX_COLOR_ARGB;
eventAttrib.color = color_id;
eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII;
eventAttrib.message.ascii = name;
nvtxRangePushEx(&eventAttrib);
#endif
}
void cuda_nvtx_pop() {
#ifdef USE_NVTOOLS
nvtxRangePop();
#endif
}

View File

@@ -11,7 +11,7 @@
#include <stddef.h>
#include <cstring>
#include "../../tfhe-cuda-backend/cuda/src/utils/helper_profile.cuh"
#include "helper_profile.cuh"
// C++ helper functions (not exported, used internally)
// These can call template functions since they have C++ linkage

View File

@@ -16,19 +16,14 @@ tfhe = { path = "../../tfhe", features = ["hpu", "hpu-debug"] }
ipc-channel = "0.18.3"
strum = { version = "0.26.2", features = ["derive"] }
strum_macros = "0.26.2"
bytemuck = { workspace = true }
clap = { version = "4.4.4", features = ["derive"] }
clap-num = "*"
anyhow = "1.0.82"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] }
serde_json = "1.0"
rand = "0.8.5"
serde = { version = "1", features = ["derive"] }
bitflags = "2.6.0"
[[bin]]
name = "hpu_mockup"

View File

@@ -25,7 +25,7 @@ use tfhe::{
CompressedKVStore, CompressedPublicKey, CompressedServerKey,
CompressedSquashedNoiseCiphertextList, CompressedSquashedNoiseCiphertextListBuilder, FheBool,
FheInt8, FheUint32, FheUint64, FheUint8, ReRandomizationContext, ReRandomizationMode,
ReRandomizationSupport, ServerKey, SquashedNoiseFheBool, SquashedNoiseFheInt,
ReRandomizationSupport, Seed, ServerKey, SquashedNoiseFheBool, SquashedNoiseFheInt,
SquashedNoiseFheUint,
};
use tfhe_backward_compat_data::load::{
@@ -748,6 +748,22 @@ fn test_hl_key_features(
}
}
// OPRF: check that oblivious pseudo-random generation works with the dedicated key.
// The decrypted values only need to be within range; the seed is deterministic but we
// don't compare to specific bit values (those are validated in the unit tests).
if server_key.supports_oprf() {
let seed = Seed(42u128);
let rand_bool = FheBool::generate_oblivious_pseudo_random(seed);
let _: bool = rand_bool.decrypt(client_key);
let rand_uint = FheUint8::generate_oblivious_pseudo_random(seed);
let _: u8 = rand_uint.decrypt(client_key);
let rand_int = FheInt8::generate_oblivious_pseudo_random(seed);
let _: i8 = rand_int.decrypt(client_key);
}
Ok(())
}

View File

@@ -97,6 +97,12 @@ path = "benches/high_level_api/erc7984.rs"
harness = false
required-features = ["integer", "internal-keycache"]
[[bench]]
name = "hlapi-bitonic-shuffle"
path = "benches/high_level_api/bitonic_shuffle.rs"
harness = false
required-features = ["integer", "internal-keycache"]
[[bench]]
name = "hlapi-dex"
path = "benches/high_level_api/dex.rs"

View File

@@ -0,0 +1,53 @@
use benchmark::params_aliases::BENCH_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
use criterion::{black_box, criterion_group, Criterion};
use rand::Rng;
use tfhe::core_crypto::seeders::UnixSeeder;
use tfhe::prelude::*;
use tfhe::{bitonic_shuffle, set_server_key, ClientKey, ConfigBuilder, FheUint64, ServerKey};
fn bitonic_shuffle_bench(c: &mut Criterion, bench_name: &str, cks: &ClientKey) {
let mut bench_group = c.benchmark_group(bench_name);
bench_group.sample_size(10);
let mut rng = rand::thread_rng();
for num_elements in [16, 32] {
let clear_values: Vec<u64> = (0..num_elements).map(|_| rng.gen()).collect();
let encrypted: Vec<FheUint64> = clear_values
.iter()
.map(|&v| FheUint64::encrypt(v, cks))
.collect();
let bench_id = format!("{bench_name}::n_{num_elements}");
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
let mut seeder = UnixSeeder::new(0);
let result = bitonic_shuffle(
encrypted.clone(),
tfhe::integer::server_key::BitonicShuffleKeySize::NumBlocks(16),
&mut seeder,
)
.expect("shuffle failed");
black_box(result);
})
});
}
bench_group.finish();
}
pub fn bitonic_shuffle_cpu(c: &mut Criterion) {
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);
bitonic_shuffle_bench(c, "hlapi::bitonic_shuffle_cpu", &cks);
}
criterion_group!(bitonic_shuffle_group, bitonic_shuffle_cpu);
criterion::criterion_main!(bitonic_shuffle_group);

View File

@@ -8,6 +8,7 @@ use rayon::prelude::*;
#[cfg(any(feature = "gpu", feature = "hpu"))]
use std::cmp::max;
use tfhe::integer::keycache::KEY_CACHE;
use tfhe::integer::oprf::{OprfPrivateKey, OprfServerKey};
use tfhe::integer::IntegerKeyKind;
use tfhe::keycache::NamedParam;
#[cfg(any(feature = "gpu", feature = "hpu"))]
@@ -35,32 +36,42 @@ pub fn unsigned_oprf(c: &mut Criterion) {
format!("{bench_name}_bounded::{param_name}::{bit_size}_bits");
bench_group.bench_function(&bench_id_oprf, |b| {
let (_, sk) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let oprf_pk = OprfPrivateKey::new(&cks);
let oprf_sk = OprfServerKey::new(&oprf_pk, &cks).unwrap();
b.iter(|| {
_ = black_box(sk.par_generate_oblivious_pseudo_random_unsigned_integer(
Seed(0),
num_block as u64,
));
_ = black_box(
oprf_sk.par_generate_oblivious_pseudo_random_unsigned_integer(
Seed(0),
num_block as u64,
&sks,
),
);
})
});
bench_group.bench_function(&bench_id_oprf_bounded, |b| {
let (_, sk) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let oprf_pk = OprfPrivateKey::new(&cks);
let oprf_sk = OprfServerKey::new(&oprf_pk, &cks).unwrap();
b.iter(|| {
_ = black_box(
sk.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
oprf_sk.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
Seed(0),
bit_size as u64,
num_block as u64,
&sks,
),
);
})
});
}
BenchmarkType::Throughput => {
let (_, sk) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let oprf_pk = OprfPrivateKey::new(&cks);
let oprf_sk = OprfServerKey::new(&oprf_pk, &cks).unwrap();
bench_id_oprf = format!("{bench_name}::throughput::{param_name}::{bit_size}_bits");
bench_id_oprf_bounded =
@@ -71,10 +82,11 @@ pub fn unsigned_oprf(c: &mut Criterion) {
{
// Execute the operation once to know its cost.
reset_pbs_count();
sk.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
oprf_sk.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
Seed(0),
bit_size as u64,
num_block as u64,
&sks,
);
let pbs_count = max(get_pbs_count(), 1);
throughput_num_threads(num_block, pbs_count)
@@ -85,11 +97,13 @@ pub fn unsigned_oprf(c: &mut Criterion) {
let setup = |_batch_size: usize| ();
let run = |_: &mut (), batch_size: usize| {
(0..batch_size).into_par_iter().for_each(|_| {
sk.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
Seed(0),
bit_size as u64,
num_block as u64,
);
oprf_sk
.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
Seed(0),
bit_size as u64,
num_block as u64,
&sks,
);
});
};
find_optimal_batch(run, setup) as u64
@@ -100,9 +114,10 @@ pub fn unsigned_oprf(c: &mut Criterion) {
bench_group.bench_function(&bench_id_oprf, |b| {
b.iter(|| {
(0..elements).into_par_iter().for_each(|_| {
sk.par_generate_oblivious_pseudo_random_unsigned_integer(
oprf_sk.par_generate_oblivious_pseudo_random_unsigned_integer(
Seed(0),
num_block as u64,
&sks,
);
})
})
@@ -111,10 +126,11 @@ pub fn unsigned_oprf(c: &mut Criterion) {
bench_group.bench_function(&bench_id_oprf_bounded, |b| {
b.iter(|| {
(0..elements).into_par_iter().for_each(|_| {
sk.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
oprf_sk.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
Seed(0),
bit_size as u64,
num_block as u64,
&sks,
);
})
})
@@ -148,6 +164,8 @@ pub mod cuda {
use criterion::black_box;
use tfhe::core_crypto::gpu::{get_number_of_gpus, CudaStreams};
use tfhe::integer::gpu::server_key::CudaServerKey;
use tfhe::integer::gpu::CudaOprfServerKey;
use tfhe::integer::oprf::{CompressedOprfServerKey, OprfPrivateKey};
use tfhe::GpuIndex;
use tfhe_csprng::seeders::Seed;
@@ -177,12 +195,18 @@ pub mod cuda {
let (cks, _cpu_sks) =
KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let gpu_sks = CudaServerKey::new(&cks, &streams);
let oprf_pk = OprfPrivateKey::new(&cks);
let compressed_oprf_sk =
CompressedOprfServerKey::new(&oprf_pk, &cks).unwrap();
let cuda_oprf_sk =
CudaOprfServerKey::decompress_from_cpu(&compressed_oprf_sk, &streams);
b.iter(|| {
_ = black_box(
gpu_sks.par_generate_oblivious_pseudo_random_unsigned_integer(
cuda_oprf_sk.par_generate_oblivious_pseudo_random_unsigned_integer(
Seed(0),
num_block as u64,
&gpu_sks,
&streams,
),
);
@@ -193,14 +217,20 @@ pub mod cuda {
let (cks, _cpu_sks) =
KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let gpu_sks = CudaServerKey::new(&cks, &streams);
let oprf_pk = OprfPrivateKey::new(&cks);
let compressed_oprf_sk =
CompressedOprfServerKey::new(&oprf_pk, &cks).unwrap();
let cuda_oprf_sk =
CudaOprfServerKey::decompress_from_cpu(&compressed_oprf_sk, &streams);
b.iter(|| {
_ = black_box(
gpu_sks
cuda_oprf_sk
.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
Seed(0),
bit_size as u64,
num_block as u64,
&gpu_sks,
&streams,
),
);
@@ -210,13 +240,25 @@ pub mod cuda {
BenchmarkType::Throughput => {
let (cks, cpu_sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
let gpu_sks_vec = cuda_local_keys(&cks);
let cpu_oprf_pk = OprfPrivateKey::new(&cks);
let cpu_oprf_sk = OprfServerKey::new(&cpu_oprf_pk, &cks).unwrap();
let compressed_oprf_sk =
CompressedOprfServerKey::new(&cpu_oprf_pk, &cks).unwrap();
// One CudaOprfServerKey per GPU, matching `gpu_sks_vec`.
let cuda_oprf_sks_vec: Vec<CudaOprfServerKey> = (0..get_number_of_gpus())
.map(|gpu_index| {
let stream = CudaStreams::new_single_gpu(GpuIndex::new(gpu_index));
CudaOprfServerKey::decompress_from_cpu(&compressed_oprf_sk, &stream)
})
.collect();
// Execute the operation once to know its cost.
reset_pbs_count();
cpu_sks.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
cpu_oprf_sk.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
Seed(0),
bit_size as u64,
num_block as u64,
&cpu_sks,
);
let pbs_count = max(get_pbs_count(), 1); // Operation might not perform any PBS, so we take 1 as default
@@ -232,10 +274,11 @@ pub mod cuda {
(0..elements).into_par_iter().for_each(|i| {
let gpu_index: u32 = i as u32 % get_number_of_gpus();
let stream = CudaStreams::new_single_gpu(GpuIndex::new(gpu_index));
gpu_sks_vec[gpu_index as usize]
cuda_oprf_sks_vec[gpu_index as usize]
.par_generate_oblivious_pseudo_random_unsigned_integer(
Seed(0),
num_block as u64,
&gpu_sks_vec[gpu_index as usize],
&stream,
);
})
@@ -247,11 +290,12 @@ pub mod cuda {
(0..elements).into_par_iter().for_each(|i| {
let gpu_index: u32 = i as u32 % get_number_of_gpus();
let stream = CudaStreams::new_single_gpu(GpuIndex::new(gpu_index));
gpu_sks_vec[gpu_index as usize]
cuda_oprf_sks_vec[gpu_index as usize]
.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
Seed(0),
bit_size as u64,
num_block as u64,
&gpu_sks_vec[gpu_index as usize],
&stream,
);
})

View File

@@ -2,6 +2,7 @@ use benchmark::params_aliases::*;
use criterion::{black_box, criterion_group, Criterion};
use tfhe::keycache::NamedParam;
use tfhe::shortint::keycache::KEY_CACHE;
use tfhe::shortint::oprf::{OprfPrivateKey, OprfServerKey};
use tfhe_csprng::seeders::Seed;
fn oprf(c: &mut Criterion) {
@@ -12,11 +13,15 @@ fn oprf(c: &mut Criterion) {
let param = BENCH_PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let keys = KEY_CACHE.get_from_param(param);
let cks = keys.client_key();
let sks = keys.server_key();
let oprf_pk = OprfPrivateKey::new(cks);
let oprf_sk = OprfServerKey::new(&oprf_pk, cks).unwrap();
bench_group.bench_function(format!("2-bits-oprf::{}", param.name()), |b| {
b.iter(|| {
_ = black_box(sks.generate_oblivious_pseudo_random(Seed(0), 2));
_ = black_box(oprf_sk.generate_oblivious_pseudo_random(Seed(0), 2, sks));
})
});
}

View File

@@ -342,6 +342,28 @@ impl<G: Curve> Proof<G> {
None => ComputeLoad::Verify,
}
}
pub fn to_le_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
let Self {
c_hat,
c_y,
pi,
compute_load_proof_fields,
} = self;
bytes.extend_from_slice(c_hat.to_le_bytes().as_ref());
bytes.extend_from_slice(c_y.to_le_bytes().as_ref());
bytes.extend_from_slice(pi.to_le_bytes().as_ref());
let (c_hat_t_bytes, c_h_bytes, pi_kzg_bytes) =
ComputeLoadProofFields::to_le_bytes(compute_load_proof_fields);
bytes.extend_from_slice(&c_hat_t_bytes);
bytes.extend_from_slice(&c_h_bytes);
bytes.extend_from_slice(&pi_kzg_bytes);
bytes
}
}
impl<G: Curve> ParameterSetConformant for Proof<G> {
@@ -404,6 +426,26 @@ pub(crate) struct ComputeLoadProofFields<G: Curve> {
pub(crate) pi_kzg: G::G1,
}
impl<G: Curve> ComputeLoadProofFields<G> {
#[allow(clippy::type_complexity)]
fn to_le_bytes(fields: &Option<Self>) -> (Box<[u8]>, Box<[u8]>, Box<[u8]>) {
if let Some(ComputeLoadProofFields {
c_hat_t,
c_h,
pi_kzg,
}) = fields.as_ref()
{
(
Box::from(G::G2::to_le_bytes(*c_hat_t).as_ref()),
Box::from(G::G1::to_le_bytes(*c_h).as_ref()),
Box::from(G::G1::to_le_bytes(*pi_kzg).as_ref()),
)
} else {
(Box::from([]), Box::from([]), Box::from([]))
}
}
}
type CompressedG2<G> = <<G as Curve>::G2 as Compressible>::Compressed;
type CompressedG1<G> = <<G as Curve>::G1 as Compressible>::Compressed;

View File

@@ -440,6 +440,44 @@ impl<G: Curve> Proof<G> {
pub fn hash_config(&self) -> PkeV2SupportedHashConfig {
self.hash_config
}
pub fn to_le_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
let Self {
C_hat_e,
C_e,
C_r_tilde,
C_R,
C_hat_bin,
C_y,
C_h1,
C_h2,
C_hat_t,
pi,
pi_kzg,
compute_load_proof_fields,
hash_config: _,
} = self;
bytes.extend_from_slice(C_hat_e.to_le_bytes().as_ref());
bytes.extend_from_slice(C_e.to_le_bytes().as_ref());
bytes.extend_from_slice(C_r_tilde.to_le_bytes().as_ref());
bytes.extend_from_slice(C_R.to_le_bytes().as_ref());
bytes.extend_from_slice(C_hat_bin.to_le_bytes().as_ref());
bytes.extend_from_slice(C_y.to_le_bytes().as_ref());
bytes.extend_from_slice(C_h1.to_le_bytes().as_ref());
bytes.extend_from_slice(C_h2.to_le_bytes().as_ref());
bytes.extend_from_slice(C_hat_t.to_le_bytes().as_ref());
bytes.extend_from_slice(pi.to_le_bytes().as_ref());
bytes.extend_from_slice(pi_kzg.to_le_bytes().as_ref());
let (C_hat_h3_bytes, C_hat_w_bytes) =
ComputeLoadProofFields::to_le_bytes(compute_load_proof_fields);
bytes.extend_from_slice(&C_hat_h3_bytes);
bytes.extend_from_slice(&C_hat_w_bytes);
bytes
}
}
/// These fields can be pre-computed on the prover side in the faster Verifier scheme. If that's the

View File

@@ -99,7 +99,7 @@ serde-wasm-bindgen = { workspace = true, optional = true }
getrandom = { workspace = true, optional = true }
bytemuck = { workspace = true }
tfhe-hpu-backend = { version = "0.4", path = "../backends/tfhe-hpu-backend", optional = true }
tfhe-hpu-backend = { version = "0.5", path = "../backends/tfhe-hpu-backend", optional = true }
[features]
default = ["avx512"]

View File

@@ -8,23 +8,23 @@
<rect x="0" y="40" width="300" height="520" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="520" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">Negation (-)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">71.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">77.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">9.08 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="60.0">8.4 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">Add / Sub (+,-)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">93.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">91.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">9.07 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="100.0">8.35 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">Mul (x)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">352 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">357 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">32.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="140.0">122 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="180.0">Equal / Not Equal (eq, ne)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="180.0">70.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="180.0">72.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="180.0">7.03 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="180.0">6.77 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="220.0">Comparisons (ge, gt, le, lt)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="220.0">87.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="220.0">89.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="220.0">10.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="220.0">6.81 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="260.0">Max / Min (max, min)</text>
@@ -32,31 +32,31 @@
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="260.0">15.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="260.0">11.7 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="300.0">Bitwise operations (&amp;, |, ^)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="300.0">19.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="300.0">19.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="300.0">1.99 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="300.0">2.95 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="340.0">Div / Rem (/, %)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="340.0">5.04 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="340.0">4.88 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="340.0">514 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="340.0">912 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="380.0">Left / Right Shifts (&lt;&lt;, &gt;&gt;)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="380.0">119 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="380.0">121 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="380.0">18.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="380.0">25.8 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="420.0">Left / Right Rotations (left_rotate, right_rotate)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="420.0">119 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="420.0">121 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="420.0">18.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="420.0">27.9 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="460.0">Leading / Trailing zeros/ones</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="460.0">223 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="460.0">222 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="460.0">20.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="460.0">14.7 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="500.0">Log2</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="500.0">244 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="500.0">246 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="500.0">21.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="500.0">14.8 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="540.0">Select</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="540.0">39.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="540.0">40.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="540.0">4.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="540.0">5.53 ms</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -7,13 +7,13 @@
<rect x="0" y="40" width="300" height="120" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="120" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">whitepaper</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="405.0" y="60.0">276 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="615.0" y="60.0">23.0 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="405.0" y="60.0">253 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="615.0" y="60.0">25.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">no_cmux</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="405.0" y="100.0">238 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="615.0" y="100.0">24.0 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="405.0" y="100.0">256 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="615.0" y="100.0">25.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">overflow</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="405.0" y="140.0">225 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="405.0" y="140.0">238 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="615.0" y="140.0">21.3 ops/s</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -15,83 +15,83 @@
<rect x="0" y="40" width="300" height="520" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="520" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">Negation (-)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="60.0">52.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="60.0">55.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">54.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="60.0">76.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="60.0">96.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="60.0">50.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="60.0">55.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">57.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="60.0">77.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="60.0">96.4 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">Add / Sub (+,-)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="100.0">50.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="100.0">55.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">75.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="100.0">96.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="100.0">145 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="100.0">50.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="100.0">55.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">74.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="100.0">91.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="100.0">150 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">Mul (x)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="140.0">89.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="140.0">89.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="140.0">131 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">195 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="140.0">363 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="140.0">1.01 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="140.0">357 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="140.0">1.02 s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="180.0">Equal / Not Equal (eq, ne)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="180.0">33.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="180.0">50.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="180.0">51.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="180.0">71.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="180.0">72.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="180.0">33.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="180.0">52.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="180.0">52.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="180.0">72.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="180.0">72.7 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="220.0">Comparisons (ge, gt, le, lt)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="220.0">34.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="220.0">50.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="220.0">70.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="220.0">88.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="220.0">32.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="220.0">52.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="220.0">70.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="220.0">89.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="220.0">128 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="260.0">Max / Min (max, min)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="260.0">70.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="260.0">88.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="260.0">69.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="260.0">88.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="260.0">109 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="260.0">131 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="260.0">168 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="260.0">128 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="260.0">173 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="300.0">Bitwise operations (&amp;, |, ^)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="300.0">17.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="300.0">18.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="300.0">18.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="300.0">18.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="300.0">20.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="300.0">17.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="300.0">18.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="300.0">19.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="300.0">19.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="300.0">19.9 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="340.0">Div / Rem (/, %)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="340.0">457 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="340.0">1.0 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="340.0">2.2 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="340.0">4.99 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="340.0">12.5 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="340.0">460 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="340.0">1.01 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="340.0">2.22 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="340.0">4.88 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="340.0">12.6 s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="380.0">Left / Right Shifts (&lt;&lt;, &gt;&gt;)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="380.0">54.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="380.0">75.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="380.0">97.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="380.0">122 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="380.0">150 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="380.0">53.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="380.0">74.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="380.0">97.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="380.0">121 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="380.0">158 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="420.0">Left / Right Rotations (left_rotate, right_rotate)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="420.0">53.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="420.0">75.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="420.0">96.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="420.0">116 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="420.0">164 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="420.0">54.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="420.0">75.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="420.0">94.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="420.0">121 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="420.0">165 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="460.0">Leading / Trailing zeros/ones</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="460.0">86.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="460.0">140 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="460.0">164 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="460.0">220 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="460.0">264 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="460.0">88.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="460.0">148 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="460.0">169 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="460.0">222 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="460.0">275 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="500.0">Log2</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="500.0">103 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="500.0">159 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="500.0">183 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="500.0">236 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="500.0">279 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="500.0">110 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="500.0">163 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="500.0">186 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="500.0">246 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="500.0">290 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="540.0">Select</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="540.0">35.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="540.0">37.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="540.0">36.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="540.0">39.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="540.0">42.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="540.0">36.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="540.0">36.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="540.0">38.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="540.0">40.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="540.0">43.1 ms</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -15,65 +15,65 @@
<rect x="0" y="40" width="300" height="400" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="400" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">Add / Sub (+,-)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="60.0">50.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="60.0">54.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">54.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="60.0">76.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="60.0">95.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="60.0">53.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="60.0">55.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">57.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="60.0">78.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="60.0">99.7 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">Mul (x)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="100.0">70.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="100.0">71.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="100.0">115 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">156 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="100.0">208 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="100.0">412 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">155 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="100.0">207 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="100.0">422 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">Equal / Not Equal (eq, ne)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="140.0">33.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="140.0">33.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">52.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="140.0">53.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="140.0">71.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="140.0">34.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="140.0">33.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">52.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="140.0">52.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="140.0">72.4 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="180.0">Comparisons (ge, gt, le, lt)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="180.0">31.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="180.0">34.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="180.0">51.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="180.0">38.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="180.0">34.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="180.0">54.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="180.0">70.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="180.0">90.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="180.0">90.7 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="220.0">Max / Min (max, min)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="220.0">52.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="220.0">52.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="220.0">71.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="220.0">91.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="220.0">108 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="220.0">54.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="220.0">53.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="220.0">71.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="220.0">91.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="220.0">110 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="260.0">Bitwise operations (&amp;, |, ^)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="260.0">17.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="260.0">17.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="260.0">18.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="260.0">19.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="260.0">19.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="260.0">20.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="260.0">19.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="260.0">19.9 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="300.0">Div (/)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="300.0">126 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="300.0">182 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="300.0">234 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="300.0">427 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="300.0">799 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="300.0">136 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="300.0">172 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="300.0">245 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="300.0">437 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="300.0">792 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="340.0">Rem (%)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="340.0">244 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="340.0">334 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="340.0">462 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="340.0">657 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="340.0">1.19 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="340.0">235 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="340.0">337 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="340.0">468 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="340.0">690 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="340.0">1.27 s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="380.0">Left / Right Shifts (&lt;&lt;, &gt;&gt;)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="380.0">17.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="380.0">18.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="380.0">19.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="380.0">19.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="380.0">19.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="380.0">17.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="380.0">18.5 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="380.0">19.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="380.0">19.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="380.0">21.0 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="420.0">Left / Right Rotations (left_rotate, right_rotate)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="420.0">17.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="420.0">18.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="420.0">18.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="420.0">20.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="420.0">21.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="420.0">18.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="420.0">18.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="420.0">19.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="420.0">19.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="420.0">20.8 ms</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -15,83 +15,83 @@
<rect x="0" y="40" width="300" height="520" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="520" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">Negation (-)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="60.0">824 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="60.0">388 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">184 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="60.0">88.7 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="60.0">42.8 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="60.0">804 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="60.0">372 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">181 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="60.0">86.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="60.0">42.1 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">Add / Sub (+,-)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="100.0">752 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="100.0">368 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">172 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="100.0">82.1 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="100.0">39.5 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="100.0">733 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="100.0">356 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">167 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="100.0">82.6 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="100.0">40.0 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">Mul (x)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="140.0">283 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="140.0">65.7 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">17.7 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="140.0">4.68 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="140.0">1.17 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="140.0">293 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="140.0">71.9 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">18.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="140.0">4.58 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="140.0">1.19 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="180.0">Equal / Not Equal (eq, ne)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="180.0">1.65 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="180.0">748 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="180.0">391 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="180.0">195 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="180.0">102 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="180.0">1.6 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="180.0">740 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="180.0">392 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="180.0">200 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="180.0">101 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="220.0">Comparisons (ge, gt, le, lt)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="220.0">1.62 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="220.0">745 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="220.0">355 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="220.0">170 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="220.0">65.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="220.0">1.58 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="220.0">733 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="220.0">354 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="220.0">171 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="220.0">64.7 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="260.0">Max / Min (max, min)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="260.0">488 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="260.0">239 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="260.0">117 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="260.0">57.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="260.0">25.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="260.0">493 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="260.0">236 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="260.0">116 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="260.0">58.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="260.0">25.7 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="300.0">Bitwise operations (&amp;, |, ^)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="300.0">2.14 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="300.0">1.06 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="300.0">537 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="300.0">270 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="300.0">136 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="300.0">2.1 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="300.0">981 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="300.0">490 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="300.0">262 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="300.0">130 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="340.0">Div / Rem (/, %)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="340.0">42.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="340.0">12.7 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="340.0">3.51 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="340.0">0.914 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="340.0">0.143 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="340.0">45.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="340.0">12.9 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="340.0">3.56 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="340.0">0.893 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="340.0">0.223 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="380.0">Left / Right Shifts (&lt;&lt;, &gt;&gt;)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="380.0">469 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="380.0">182 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="380.0">74.5 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="380.0">32.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="380.0">14.1 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="380.0">464 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="380.0">183 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="380.0">76.1 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="380.0">32.4 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="380.0">14.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="420.0">Left / Right Rotations (left_rotate, right_rotate)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="420.0">397 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="420.0">391 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="420.0">170 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="420.0">72.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="420.0">32.1 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="420.0">74.0 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="420.0">32.5 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="420.0">14.0 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="460.0">Leading / Trailing zeros/ones</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="460.0">621 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="460.0">235 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="460.0">104 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="460.0">41.8 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="460.0">17.8 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="460.0">625 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="460.0">247 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="460.0">108 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="460.0">44.1 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="460.0">19.0 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="500.0">Log2</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="500.0">536 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="500.0">207 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="500.0">96.4 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="500.0">40.4 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="500.0">17.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="500.0">542 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="500.0">220 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="500.0">102 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="500.0">42.0 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="500.0">18.6 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="540.0">Select</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="540.0">699 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="540.0">351 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="540.0">175 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="540.0">87.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="540.0">43.4 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="540.0">676 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="540.0">350 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="540.0">176 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="540.0">84.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="540.0">42.6 ops/s</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -15,65 +15,65 @@
<rect x="0" y="40" width="300" height="400" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="400" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">Add / Sub (+,-)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="60.0">836 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="60.0">383 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">184 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="60.0">87.9 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="60.0">42.5 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="60.0">810 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="60.0">379 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">178 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="60.0">86.0 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="60.0">41.7 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">Mul (x)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="100.0">659 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="100.0">182 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">52.8 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="100.0">16.5 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="100.0">4.79 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="100.0">658 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="100.0">185 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">57.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="100.0">17.6 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="100.0">4.83 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">Equal / Not Equal (eq, ne)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="140.0">2.73 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="140.0">1.68 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">757 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="140.0">399 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="140.0">198 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="140.0">2.69 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="140.0">1.57 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">723 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="140.0">378 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="140.0">192 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="180.0">Comparisons (ge, gt, le, lt)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="180.0">2.82 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="180.0">1.64 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="180.0">747 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="180.0">356 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="180.0">173 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="180.0">2.61 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="180.0">1.63 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="180.0">717 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="180.0">348 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="180.0">172 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="220.0">Max / Min (max, min)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="220.0">1.18 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="220.0">645 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="220.0">305 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="220.0">150 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="220.0">73.2 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="220.0">1.15 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="220.0">621 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="220.0">302 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="220.0">148 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="220.0">73.6 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="260.0">Bitwise operations (&amp;, |, ^)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="260.0">2.31 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="260.0">1.12 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="260.0">555 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="260.0">276 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="260.0">139 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="260.0">2.11 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="260.0">1.04 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="260.0">516 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="260.0">260 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="260.0">128 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="300.0">Div (/)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="300.0">196 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="300.0">69.6 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="300.0">23.7 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="300.0">7.63 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="300.0">2.13 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="300.0">203 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="300.0">73.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="300.0">24.8 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="300.0">7.38 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="300.0">2.16 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="340.0">Rem (%)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="340.0">114 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="340.0">44.5 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="340.0">16.6 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="340.0">5.78 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="340.0">1.66 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="340.0">130 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="340.0">49.1 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="340.0">17.1 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="340.0">5.65 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="340.0">1.75 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="380.0">Left / Right Shifts (&lt;&lt;, &gt;&gt;)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="380.0">2.13 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="380.0">1.07 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="380.0">546 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="380.0">270 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="380.0">138 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="380.0">2.01 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="380.0">1.02 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="380.0">510 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="380.0">247 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="380.0">124 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="420.0">Left / Right Rotations (left_rotate, right_rotate)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="420.0">2.14 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="420.0">1.07 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="420.0">541 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="420.0">270 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="420.0">137 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="342.0" y="420.0">2.01 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="426.0" y="420.0">992 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="420.0">517 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="594.0" y="420.0">254 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="678.0" y="420.0">124 ops/s</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -9,25 +9,25 @@
<rect x="0" y="40" width="300" height="160" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="160" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">PBS</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="60.0">9.54 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="60.0">12.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="60.0">111 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="60.0">1.39 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="60.0">9.57 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="60.0">12.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="60.0">112 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="60.0">1.58 s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">MB-PBS</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="100.0">4.02 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="100.0">4.55 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="100.0">30.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="100.0">244 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="100.0">4.42 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="100.0">4.71 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="100.0">30.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="100.0">257 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">KS - PBS</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="140.0">10.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="140.0">15.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="140.0">125 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="140.0">1.51 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="140.0">11.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="140.0">15.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="140.0">126 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="140.0">1.58 s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="180.0">KS - MB-PBS</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="180.0">5.56 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="180.0">7.29 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="180.0">61.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="180.0">418 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="180.0">6.67 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="180.0">8.49 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="180.0">46.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="180.0">388 ms</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -9,25 +9,25 @@
<rect x="0" y="40" width="300" height="160" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="160" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">PBS</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="60.0">8.94 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="60.0">8.93 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="60.0">11.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="60.0">104 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="60.0">670 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="60.0">102 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="60.0">654 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">MB-PBS</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="100.0">4.87 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="100.0">4.53 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="100.0">30.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="100.0">185 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="100.0">4.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="100.0">4.58 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="100.0">28.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="100.0">214 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">KS - PBS</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="140.0">10.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="140.0">15.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="140.0">120 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="140.0">871 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="140.0">10.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="140.0">14.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="140.0">119 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="140.0">865 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="180.0">KS - MB-PBS</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="180.0">6.83 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="180.0">7.13 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="180.0">44.7 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="180.0">228 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="352.5" y="180.0">6.96 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="457.5" y="180.0">7.59 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="562.5" y="180.0">47.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="667.5" y="180.0">247 ms</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -6,11 +6,11 @@
<rect x="0" y="40" width="300" height="120" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="120" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">1xFheUint64 (64 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">1.66 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">1.53 s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">4xFheUint64 (256 bits) </text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">1.66 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">1.55 s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">32xFheUint64 (2048 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">1.8 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">1.76 s</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -8,17 +8,17 @@
<rect x="0" y="40" width="300" height="120" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="120" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">1xFheUint64 (64 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">276 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">44.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="60.0">66.0 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">209 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">43.9 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="60.0">67.1 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">4xFheUint64 (256 bits) </text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">277 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">211 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">44.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="100.0">70.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="100.0">72.9 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">32xFheUint64 (2048 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">293 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">219 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">49.1 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="140.0">184 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="140.0">185 ms</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -8,17 +8,17 @@
<rect x="0" y="40" width="300" height="120" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="120" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">1xFheUint64 (64 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">7.9 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">274 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="60.0">131 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">8.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">265 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="60.0">129 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">4xFheUint64 (256 bits) </text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">7.9 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">277 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="100.0">51.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">8.36 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">259 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="100.0">50.8 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">32xFheUint64 (2048 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">7.73 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">242 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="140.0">8.62 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">8.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">236 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="140.0">8.38 ops/s</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -6,11 +6,11 @@
<rect x="0" y="40" width="300" height="120" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="120" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">1xFheUint64 (64 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">1.94 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">1.71 s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">4xFheUint64 (256 bits) </text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">1.96 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">1.72 s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">32xFheUint64 (2048 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">2.13 s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">1.93 s</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -8,17 +8,17 @@
<rect x="0" y="40" width="300" height="120" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="120" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">1xFheUint64 (64 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">292 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">31.4 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="60.0">51.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">214 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">31.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="60.0">52.5 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">4xFheUint64 (256 bits) </text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">294 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">31.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="100.0">56.2 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">217 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">31.3 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="100.0">57.3 ms</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">32xFheUint64 (2048 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">317 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">33.8 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="140.0">167 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">225 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">33.6 ms</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="140.0">170 ms</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -8,17 +8,17 @@
<rect x="0" y="40" width="300" height="120" fill="#fbbc04"/>
<rect x="300" y="40" width="420" height="120" fill="#f3f3f3"/>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="60.0">1xFheUint64 (64 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">7.3 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">988 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="60.0">201 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="60.0">7.78 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="60.0">877 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="60.0">200 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="100.0">4xFheUint64 (256 bits) </text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">7.23 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">987 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="100.0">59.5 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="100.0">7.79 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="100.0">931 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="100.0">58.9 ops/s</text>
<text dominant-baseline="middle" text-anchor="start" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="6" y="140.0">32xFheUint64 (2048 bits)</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">7.1 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">1.11 k.ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="140.0">8.85 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="370.0" y="140.0">7.77 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="510.0" y="140.0">993 ops/s</text>
<text dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="14" font-weight="normal" fill="black" x="650.0" y="140.0">8.59 ops/s</text>
<line stroke="white" stroke-width="2" x1="0" y1="0" x2="720" y2="0"/>
<line stroke="white" stroke-width="2" x1="0" y1="40" x2="720" y2="40"/>
<line stroke="white" stroke-width="2" x1="0" y1="80" x2="720" y2="80"/>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -97,6 +97,76 @@ pub fn main() {
}
```
## Example: Re-randomization of a `ProvenCompactCiphertextList`
Untrusted user inputs received in a `ProvenCompactCiphertextList` should also be re-randomized.
Here is how to do it:
```rust
use tfhe::prelude::*;
use tfhe::shortint::parameters::v1_6::meta::cpu::V1_6_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
use tfhe::zk::{CompactPkeCrs, ZkComputeLoad};
use tfhe::{
CompactPublicKey, Config, FheBool, FheInt8, FheUint64, ProvenCompactCiphertextList,
ReRandomizationContext, generate_keys, set_server_key,
};
pub fn main() {
let config = Config::from(V1_6_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128);
let (cks, sks) = generate_keys(config);
let cpk = CompactPublicKey::new(&cks);
let compact_public_encryption_domain_separator = *b"TFHE_Enc";
let rerand_domain_separator = *b"TFHE_Rrd";
let crs = CompactPkeCrs::from_config(config, 2048).unwrap();
let metadata = [b'r', b'e', b'r', b'a', b'n', b'd'];
set_server_key(sks);
// Generate a list of ciphertexts
let clear_a = rand::random::<u64>();
let clear_b = rand::random::<i8>();
let compact_list = ProvenCompactCiphertextList::builder(&cpk)
.push(clear_a)
.push(clear_b)
.push(false)
.build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)
.unwrap();
// Simulate a 256 bits nonce
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let mut re_rand_context = ReRandomizationContext::new(
rerand_domain_separator,
[b"expand".as_slice(), nonce.as_slice()],
compact_public_encryption_domain_separator,
);
// Add the compact list to the context
re_rand_context.add_ciphertext(&compact_list);
let mut seed_gen = re_rand_context.finalize();
// Verify, re_randomize and expand
let expander = compact_list
.verify_re_randomize_and_expand(&crs, &cpk, &metadata, seed_gen.next_seed().unwrap())
.unwrap();
let a: FheUint64 = expander.get(0).unwrap().unwrap();
let b: FheInt8 = expander.get(1).unwrap().unwrap();
let c: FheBool = expander.get(2).unwrap().unwrap();
let dec_a: u64 = a.decrypt(&cks);
assert_eq!(dec_a, clear_a);
let dec_b: i8 = b.decrypt(&cks);
assert_eq!(dec_b, clear_b);
let dec_c: bool = c.decrypt(&cks);
assert!(!dec_c);
}
```
## Managing legacy Re-Randomization API
Because of an API change in version 1.6 you may find yourself needing to manage older keys using the old API, the following example shows how it can be done:

View File

@@ -92,6 +92,7 @@ pub fn glwe_ciphertext_add_assign<Scalar, LhsCont, RhsCont>(
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
assert!(lhs.ciphertext_modulus().is_power_of_two());
slice_wrapping_add_assign(lhs.as_mut(), rhs.as_ref());
}
@@ -196,6 +197,7 @@ pub fn glwe_ciphertext_add<Scalar, OutputCont, LhsCont, RhsCont>(
output.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
assert!(lhs.ciphertext_modulus().is_power_of_two());
slice_wrapping_add(output.as_mut(), lhs.as_ref(), rhs.as_ref());
}
@@ -640,6 +642,7 @@ where
Scalar: UnsignedInteger,
InCont: ContainerMut<Element = Scalar>,
{
assert!(ct.ciphertext_modulus().is_power_of_two());
slice_wrapping_opposite_assign(ct.as_mut());
}
@@ -723,6 +726,8 @@ pub fn glwe_ciphertext_cleartext_mul_assign<Scalar, InCont>(
Scalar: UnsignedInteger,
InCont: ContainerMut<Element = Scalar>,
{
assert!(lhs.ciphertext_modulus().is_power_of_two());
slice_wrapping_scalar_mul_assign(lhs.as_mut(), rhs.0);
}
@@ -908,6 +913,7 @@ pub fn glwe_ciphertext_sub_assign<Scalar, LhsCont, RhsCont>(
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
assert!(lhs.ciphertext_modulus().is_power_of_two());
slice_wrapping_sub_assign(lhs.as_mut(), rhs.as_ref());
}

View File

@@ -816,6 +816,111 @@ pub fn lwe_ciphertext_sub<Scalar, OutputCont, LhsCont, RhsCont>(
lwe_ciphertext_sub_assign(output, rhs);
}
/// Add the right-hand side [`LWE compact ciphertext list`](`LweCompactCiphertextList`) to the
/// left-hand side [`LWE compact ciphertext list`](`LweCompactCiphertextList`) updating it in-place.
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for LweCompactCiphertextList creation
/// let lwe_dimension = LweDimension(2048);
/// let lwe_ciphertext_count = LweCiphertextCount(3);
/// let noise_distribution =
/// Gaussian::from_dispersion_parameter(StandardDev(0.00000000000000029403601535432533), 0.0);
/// let ciphertext_modulus = CiphertextModulus::new_native();
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut secret_generator = SecretRandomGenerator::<DefaultRandomGenerator>::new(seeder.seed());
/// let mut encryption_generator =
/// EncryptionRandomGenerator::<DefaultRandomGenerator>::new(seeder.seed(), seeder);
///
/// // Create the LweSecretKey
/// let lwe_secret_key =
/// allocate_and_generate_new_binary_lwe_secret_key(lwe_dimension, &mut secret_generator);
///
/// let lwe_compact_public_key = allocate_and_generate_new_lwe_compact_public_key(
/// &lwe_secret_key,
/// noise_distribution,
/// ciphertext_modulus,
/// &mut encryption_generator,
/// );
///
/// // Create the plaintext
/// let msg = 3u64;
/// let encoded_msg = msg << 60;
/// let input_plaintext_list =
/// PlaintextList::new(encoded_msg, PlaintextCount(lwe_ciphertext_count.0));
///
/// // Create and encrypt a new LweCompactCiphertextList
/// let mut lwe_compact_ct_list = LweCompactCiphertextList::new(
/// 0u64,
/// lwe_dimension.to_lwe_size(),
/// lwe_ciphertext_count,
/// ciphertext_modulus,
/// );
/// encrypt_lwe_compact_ciphertext_list_with_compact_public_key(
/// &lwe_compact_public_key,
/// &mut lwe_compact_ct_list,
/// &input_plaintext_list,
/// noise_distribution,
/// noise_distribution,
/// encryption_generator.noise_generator_mut(),
/// );
///
/// let rhs = lwe_compact_ct_list.clone();
///
/// lwe_compact_ciphertext_list_add_assign(&mut lwe_compact_ct_list, &rhs);
///
/// // Expand and decrypt
/// let lwe_ciphertext_list = lwe_compact_ct_list.expand_into_lwe_ciphertext_list();
///
/// let mut output_plaintext_list =
/// PlaintextList::new(0u64, PlaintextCount(lwe_ciphertext_count.0));
///
/// decrypt_lwe_ciphertext_list(
/// &lwe_secret_key,
/// &lwe_ciphertext_list,
/// &mut output_plaintext_list,
/// );
///
/// // Round and remove encoding
/// // First create a decomposer working on the high 4 bits corresponding to our encoding.
/// let decomposer = SignedDecomposer::new(DecompositionBaseLog(4), DecompositionLevelCount(1));
///
/// // Round and remove encoding in the output plaintext list
/// output_plaintext_list
/// .iter_mut()
/// .for_each(|x| *x.0 = decomposer.closest_representable(*x.0) >> 60);
///
/// // Check we recovered the expected result
/// assert!(output_plaintext_list.iter().all(|x| *x.0 == msg + msg));
/// ```
pub fn lwe_compact_ciphertext_list_add_assign<Scalar, LhsCont, RhsCont>(
lhs: &mut LweCompactCiphertextList<LhsCont>,
rhs: &LweCompactCiphertextList<RhsCont>,
) where
Scalar: UnsignedInteger,
LhsCont: ContainerMut<Element = Scalar>,
RhsCont: Container<Element = Scalar>,
{
assert_eq!(
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus(),
"Mismatched moduli between lhs ({:?}) and rhs ({:?}) LweCompactCiphertextList",
lhs.ciphertext_modulus(),
rhs.ciphertext_modulus()
);
assert!(lhs.ciphertext_modulus().is_power_of_two());
slice_wrapping_add_assign(lhs.as_mut(), rhs.as_ref());
}
// ============== Noise measurement trait implementations ============== //
use crate::core_crypto::commons::noise_formulas::noise_simulation::traits::{
LweUncorrelatedAdd, LweUncorrelatedSub, ScalarMul, ScalarMulAssign,

View File

@@ -13,7 +13,7 @@ pub(in crate::high_level_api) mod traits;
use crate::array::traits::TensorSlice;
use crate::high_level_api::array::traits::HasClear;
use crate::high_level_api::global_state;
use crate::high_level_api::integers::{FheIntId, FheUintId};
use crate::high_level_api::integers::{FheIntId, FheIntegerType, FheUintId};
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::{FheBool, FheId, FheInt, FheUint, Tag};
@@ -24,6 +24,8 @@ pub use traits::{IOwnedArray, Slicing, SlicingMut};
use crate::array::stride::DynDimensions;
use crate::core_crypto::prelude::{Numeric, OverflowingAdd, SignedNumeric, UnsignedNumeric};
use crate::integer::block_decomposition::DecomposableInto;
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::CudaIntegerRadixCiphertext;
use crate::integer::RadixCiphertext;
use crate::prelude::{CastFrom, CastInto};
pub use cpu::{
@@ -450,6 +452,55 @@ pub fn fhe_uint_array_contains_sub_slice<Id: FheUintId>(
})
}
pub fn fhe_array_contains<T>(data: &[T], value: &T) -> FheBool
where
T: FheIntegerType,
{
global_state::with_internal_keys(|sks| match sks {
InternalServerKey::Cpu(cpu_key) => {
let tmp_data = data
.iter()
.map(|element| element.on_cpu().into_owned())
.collect::<Vec<_>>();
let tmp_value = value.on_cpu();
let result = cpu_key
.pbs_key()
.contains_parallelized(&tmp_data, &*tmp_value);
FheBool::new(
result,
cpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(gpu_key) => {
use crate::high_level_api::details::MaybeCloned;
let streams = &gpu_key.streams;
let tmp_data = data
.iter()
.map(|element| match element.on_gpu(streams) {
MaybeCloned::Borrowed(ct) => ct.duplicate(streams),
MaybeCloned::Cloned(ct) => ct,
})
.collect::<Vec<_>>();
let tmp_value = value.on_gpu(streams);
let result = gpu_key.pbs_key().contains(&tmp_data, &*tmp_value, streams);
FheBool::new(
result,
gpu_key.tag.clone(),
ReRandomizationMetadata::default(),
)
}
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_) => {
panic!("HPU does not support contains() on FheIntegerType yet")
}
})
}
/// Small helper to reduce code
///
/// * num_bits: num bits of the FheType

View File

@@ -2,6 +2,8 @@ mod booleans;
mod signed;
mod unsigned;
use crate::high_level_api::array::fhe_array_contains;
use crate::high_level_api::integers::FheIntegerType;
use crate::{generate_keys, set_server_key, ClientKey, ConfigBuilder, FheId};
use rand::distributions::{Distribution, Standard};
use rand::random;
@@ -10,7 +12,7 @@ use std::fmt::Debug;
use crate::array::traits::IOwnedArray;
use crate::array::ClearArray;
use crate::high_level_api::array::{FheBackendArray, FheBackendArraySlice};
use crate::prelude::{FheDecrypt, FheTryEncrypt};
use crate::prelude::{FheDecrypt, FheEncrypt, FheTryEncrypt};
use std::ops::{BitAnd, BitOr, BitXor};
fn draw_random_values<T>(num_values: usize) -> Vec<T>
@@ -274,3 +276,42 @@ where
assert_eq!(result, expected_result);
}
}
fn test_case_contains<T, Clear>(ck: &ClientKey)
where
T: FheIntegerType + FheEncrypt<Clear, ClientKey>,
Standard: Distribution<Clear>,
Clear: Copy + Eq,
{
let values = draw_random_values::<Clear>(5);
// Pick one element that is guaranteed to be in the slice
let present_value = values[random::<usize>() % values.len()];
// Generate an absent value that is not in the slice
let absent_value = loop {
let candidate: Clear = random();
if !values.contains(&candidate) {
break candidate;
}
};
let data: Vec<T> = values.iter().map(|&v| T::encrypt(v, ck)).collect();
let present = T::encrypt(present_value, ck);
let result: bool = fhe_array_contains(&data, &present).decrypt(ck);
assert!(result);
let absent = T::encrypt(absent_value, ck);
let result: bool = fhe_array_contains(&data, &absent).decrypt(ck);
assert!(!result);
// Test with a duplicated value in the slice
let mut values_with_dup = values.clone();
values_with_dup.push(values[0]);
let data_with_dup: Vec<T> = values_with_dup.iter().map(|&v| T::encrypt(v, ck)).collect();
let present_dup = T::encrypt(values[0], ck);
let result: bool = fhe_array_contains(&data_with_dup, &present_dup).decrypt(ck);
assert!(result);
}

View File

@@ -101,6 +101,21 @@ fn test_cpu_dyn_bitand_scalar_slice() {
super::bitand_scalar_slice_test_case::<crate::FheUint32Array, u32>(&ck);
}
#[test]
fn test_contains() {
let ck = super::setup_default_cpu();
super::test_case_contains::<crate::FheUint8, u8>(&ck);
}
#[test]
#[cfg(feature = "gpu")]
fn test_contains_gpu() {
for setup_fn in crate::high_level_api::integers::unsigned::tests::gpu::GPU_SETUP_FN {
let ck = setup_fn();
super::test_case_contains::<crate::FheUint8, u8>(&ck);
}
}
#[test]
fn test_single_dimension() {
let config = ConfigBuilder::default().build();

View File

@@ -10,8 +10,10 @@ use crate::integer::compression_keys::{
use crate::integer::noise_squashing::{
CompressedNoiseSquashingKey, NoiseSquashingKey, NoiseSquashingPrivateKey,
};
use crate::shortint::parameters::list_compression::CompressionParameters;
use crate::shortint::parameters::{
EncryptionKeyChoice, ReRandomizationParameters, ShortintKeySwitchingParameters,
CompactPublicKeyEncryptionParameters, EncryptionKeyChoice, NoiseSquashingCompressionParameters,
NoiseSquashingParameters, ReRandomizationParameters, ShortintKeySwitchingParameters,
};
use crate::Tag;
use std::convert::Infallible;
@@ -75,8 +77,9 @@ impl Upgrade<PublicKey> for PublicKeyV0 {
type Error = Infallible;
fn upgrade(self) -> Result<PublicKey, Self::Error> {
let Self { key } = self;
Ok(PublicKey {
key: self.key,
key,
tag: Tag::default(),
})
}
@@ -97,8 +100,9 @@ impl Upgrade<CompactPublicKey> for CompactPublicKeyV0 {
type Error = Infallible;
fn upgrade(self) -> Result<CompactPublicKey, Self::Error> {
let Self { key } = self;
Ok(CompactPublicKey {
key: self.key,
key,
tag: Tag::default(),
})
}
@@ -119,8 +123,9 @@ impl Upgrade<CompressedPublicKey> for CompressedPublicKeyV0 {
type Error = Infallible;
fn upgrade(self) -> Result<CompressedPublicKey, Self::Error> {
let Self { key } = self;
Ok(CompressedPublicKey {
key: self.key,
key,
tag: Tag::default(),
})
}
@@ -141,8 +146,9 @@ impl Upgrade<CompressedCompactPublicKey> for CompressedCompactPublicKeyV0 {
type Error = Infallible;
fn upgrade(self) -> Result<CompressedCompactPublicKey, Self::Error> {
let Self { key } = self;
Ok(CompressedCompactPublicKey {
key: self.key,
key,
tag: Tag::default(),
})
}
@@ -154,10 +160,48 @@ pub enum CompressedCompactPublicKeyVersions {
V1(CompressedCompactPublicKey),
}
#[derive(Version)]
pub(crate) struct IntegerConfigV0 {
pub(crate) block_parameters: crate::shortint::atomic_pattern::AtomicPatternParameters,
pub(crate) dedicated_compact_public_key_parameters: Option<(
CompactPublicKeyEncryptionParameters,
ShortintKeySwitchingParameters,
)>,
pub(crate) compression_parameters: Option<CompressionParameters>,
pub(crate) noise_squashing_parameters: Option<NoiseSquashingParameters>,
pub(crate) noise_squashing_compression_parameters: Option<NoiseSquashingCompressionParameters>,
pub(crate) cpk_re_randomization_params: Option<ReRandomizationParameters>,
}
impl Upgrade<IntegerConfig> for IntegerConfigV0 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerConfig, Self::Error> {
let Self {
block_parameters,
dedicated_compact_public_key_parameters,
compression_parameters,
noise_squashing_parameters,
noise_squashing_compression_parameters,
cpk_re_randomization_params,
} = self;
Ok(IntegerConfig {
block_parameters,
dedicated_compact_public_key_parameters,
compression_parameters,
noise_squashing_parameters,
noise_squashing_compression_parameters,
cpk_re_randomization_params,
dedicated_oprf_key: false,
})
}
}
#[derive(VersionsDispatch)]
#[allow(unused)]
pub(crate) enum IntegerConfigVersions {
V0(IntegerConfig),
V0(IntegerConfigV0),
V1(IntegerConfig),
}
impl Deprecable for IntegerClientKey {
@@ -176,11 +220,15 @@ impl Upgrade<IntegerClientKeyV3> for IntegerClientKeyV2 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerClientKeyV3, Self::Error> {
let Self {
key,
dedicated_compact_private_key,
compression_key,
} = self;
Ok(IntegerClientKeyV3 {
key: self.key,
dedicated_compact_private_key: self.dedicated_compact_private_key,
compression_key: self
.compression_key
key,
dedicated_compact_private_key,
compression_key: compression_key
.map(|key| crate::integer::compression_keys::CompressionPrivateKeys { key }),
})
}
@@ -286,10 +334,10 @@ pub(crate) struct IntegerClientKeyV6 {
pub(crate) cpk_re_randomization_ksk_params: Option<ShortintKeySwitchingParameters>,
}
impl Upgrade<IntegerClientKey> for IntegerClientKeyV6 {
impl Upgrade<IntegerClientKeyV7> for IntegerClientKeyV6 {
type Error = crate::Error;
fn upgrade(self) -> Result<IntegerClientKey, Self::Error> {
fn upgrade(self) -> Result<IntegerClientKeyV7, Self::Error> {
let Self {
key,
dedicated_compact_private_key,
@@ -328,6 +376,39 @@ impl Upgrade<IntegerClientKey> for IntegerClientKeyV6 {
}
};
Ok(IntegerClientKeyV7 {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_params,
})
}
}
#[derive(Version)]
pub(crate) struct IntegerClientKeyV7 {
pub(crate) key: crate::integer::ClientKey,
pub(crate) dedicated_compact_private_key: Option<CompactPrivateKey>,
pub(crate) compression_key: Option<CompressionPrivateKeys>,
pub(crate) noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
pub(crate) noise_squashing_compression_private_key: Option<NoiseSquashingCompressionPrivateKey>,
pub(crate) cpk_re_randomization_params: Option<ReRandomizationParameters>,
}
impl Upgrade<IntegerClientKey> for IntegerClientKeyV7 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerClientKey, Self::Error> {
let Self {
key,
dedicated_compact_private_key,
compression_key,
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_params,
} = self;
Ok(IntegerClientKey {
key,
dedicated_compact_private_key,
@@ -335,6 +416,7 @@ impl Upgrade<IntegerClientKey> for IntegerClientKeyV6 {
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_params,
dedicated_oprf_private_key: None,
})
}
}
@@ -349,7 +431,8 @@ pub(crate) enum IntegerClientKeyVersions {
V4(IntegerClientKeyV4),
V5(IntegerClientKeyV5),
V6(IntegerClientKeyV6),
V7(IntegerClientKey),
V7(IntegerClientKeyV7),
V8(IntegerClientKey),
}
impl Deprecable for IntegerServerKey {
@@ -473,10 +556,10 @@ pub struct IntegerServerKeyV7 {
Option<ReRandomizationKeySwitchingKey>,
}
impl Upgrade<IntegerServerKey> for IntegerServerKeyV7 {
impl Upgrade<IntegerServerKeyV8> for IntegerServerKeyV7 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerServerKey, Self::Error> {
fn upgrade(self) -> Result<IntegerServerKeyV8, Self::Error> {
let Self {
key,
cpk_key_switching_key_material,
@@ -487,7 +570,7 @@ impl Upgrade<IntegerServerKey> for IntegerServerKeyV7 {
cpk_re_randomization_key_switching_key_material,
} = self;
Ok(IntegerServerKey {
Ok(IntegerServerKeyV8 {
key,
cpk_key_switching_key_material,
compression_key,
@@ -503,6 +586,44 @@ impl Upgrade<IntegerServerKey> for IntegerServerKeyV7 {
}
}
#[derive(Version)]
pub struct IntegerServerKeyV8 {
pub(crate) key: crate::integer::ServerKey,
pub(crate) cpk_key_switching_key_material:
Option<crate::integer::key_switching_key::KeySwitchingKeyMaterial>,
pub(crate) compression_key: Option<CompressionKey>,
pub(crate) decompression_key: Option<DecompressionKey>,
pub(crate) noise_squashing_key: Option<NoiseSquashingKey>,
pub(crate) noise_squashing_compression_key: Option<NoiseSquashingCompressionKey>,
pub(crate) cpk_re_randomization_key: Option<ReRandomizationKey>,
}
impl Upgrade<IntegerServerKey> for IntegerServerKeyV8 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerServerKey, Self::Error> {
let Self {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
} = self;
Ok(IntegerServerKey {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key: None,
})
}
}
#[derive(VersionsDispatch)]
pub enum IntegerServerKeyVersions {
V0(Deprecated<IntegerServerKey>),
@@ -513,7 +634,8 @@ pub enum IntegerServerKeyVersions {
V5(IntegerServerKeyV5),
V6(IntegerServerKeyV6),
V7(IntegerServerKeyV7),
V8(IntegerServerKey),
V8(IntegerServerKeyV8),
V9(IntegerServerKey),
}
impl Deprecable for IntegerCompressedServerKey {
@@ -633,10 +755,10 @@ pub struct IntegerCompressedServerKeyV5 {
Option<CompressedReRandomizationKeySwitchingKey>,
}
impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV5 {
impl Upgrade<IntegerCompressedServerKeyV6> for IntegerCompressedServerKeyV5 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerCompressedServerKey, Self::Error> {
fn upgrade(self) -> Result<IntegerCompressedServerKeyV6, Self::Error> {
let Self {
key,
cpk_key_switching_key_material,
@@ -647,7 +769,7 @@ impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV5 {
cpk_re_randomization_key_switching_key_material,
} = self;
Ok(IntegerCompressedServerKey {
Ok(IntegerCompressedServerKeyV6 {
key,
cpk_key_switching_key_material,
compression_key,
@@ -663,6 +785,45 @@ impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV5 {
}
}
#[derive(Version)]
pub struct IntegerCompressedServerKeyV6 {
pub(crate) key: crate::integer::CompressedServerKey,
pub(crate) cpk_key_switching_key_material:
Option<crate::integer::key_switching_key::CompressedKeySwitchingKeyMaterial>,
pub(crate) compression_key: Option<CompressedCompressionKey>,
pub(crate) decompression_key: Option<CompressedDecompressionKey>,
pub(crate) noise_squashing_key: Option<CompressedNoiseSquashingKey>,
pub(crate) noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
pub(crate) cpk_re_randomization_key: Option<CompressedReRandomizationKey>,
}
impl Upgrade<IntegerCompressedServerKey> for IntegerCompressedServerKeyV6 {
type Error = Infallible;
fn upgrade(self) -> Result<IntegerCompressedServerKey, Self::Error> {
let Self {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
} = self;
Ok(IntegerCompressedServerKey {
key,
cpk_key_switching_key_material,
compression_key,
decompression_key,
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key: None,
})
}
}
#[derive(VersionsDispatch)]
pub enum IntegerCompressedServerKeyVersions {
V0(Deprecated<IntegerCompressedServerKey>),
@@ -671,7 +832,8 @@ pub enum IntegerCompressedServerKeyVersions {
V3(IntegerCompressedServerKeyV3),
V4(IntegerCompressedServerKeyV4),
V5(IntegerCompressedServerKeyV5),
V6(IntegerCompressedServerKey),
V6(IntegerCompressedServerKeyV6),
V7(IntegerCompressedServerKey),
}
#[derive(VersionsDispatch)]

View File

@@ -7,7 +7,7 @@ use crate::integer::gpu::ciphertext::boolean_value::CudaBooleanBlock;
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::CudaUnsignedRadixCiphertext;
use crate::integer::BooleanBlock;
use tfhe_csprng::seeders::Seed;
use crate::shortint::OprfSeed;
impl FheBool {
/// Generates an encrypted boolean
@@ -28,12 +28,15 @@ impl FheBool {
///
/// let dec_result: bool = ct_res.decrypt(&client_key);
/// ```
pub fn generate_oblivious_pseudo_random(seed: Seed) -> Self {
pub fn generate_oblivious_pseudo_random(seed: impl OprfSeed) -> Self {
let (ciphertext, tag) = global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(key) => {
let sk = &key.pbs_key().key;
let ct = sk.generate_oblivious_pseudo_random(seed, 1);
let ct = key
.oprf_key()
.key
.generate_oblivious_pseudo_random(seed, 1, sk);
(
InnerBoolean::Cpu(BooleanBlock::new_unchecked(ct)),
key.tag.clone(),
@@ -43,9 +46,8 @@ impl FheBool {
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let d_ct: CudaUnsignedRadixCiphertext = cuda_key
.key
.key
.generate_oblivious_pseudo_random(seed, 1, streams);
.oprf_key()
.generate_oblivious_pseudo_random(seed, 1, cuda_key.pbs_key(), streams);
(
InnerBoolean::Cuda(CudaBooleanBlock::from_cuda_radix_ciphertext(
d_ct.ciphertext,
@@ -66,17 +68,18 @@ impl FheBool {
#[cfg(feature = "gpu")]
mod test {
use crate::prelude::FheDecrypt;
use tfhe_csprng::seeders::Seed;
#[test]
fn test_oprf_boolean() {
let config = crate::ConfigBuilder::default().build();
let config = crate::ConfigBuilder::default()
.use_dedicated_oprf_key(true)
.build();
let client_key = crate::ClientKey::generate(config);
let compressed_server_key = crate::CompressedServerKey::new(&client_key);
let gpu_key = compressed_server_key.decompress_to_gpu();
crate::set_server_key(gpu_key);
let rnd = crate::FheBool::generate_oblivious_pseudo_random(Seed(123u128));
let rnd = crate::FheBool::generate_oblivious_pseudo_random(crate::Seed(123));
let decrypted_result: bool = rnd.decrypt(&client_key);
println!("Random bool: {decrypted_result}");
}

View File

@@ -462,7 +462,10 @@ mod zk {
use crate::conformance::ParameterSetConformant;
use crate::high_level_api::global_state::device_of_internal_keys;
use crate::high_level_api::keys::InternalServerKey;
use crate::integer::ciphertext::IntegerProvenCompactCiphertextListConformanceParams;
use crate::high_level_api::re_randomization::ReRandContextAdd;
use crate::integer::ciphertext::{
IntegerProvenCompactCiphertextListConformanceParams, ReRandomizationSeed,
};
#[cfg(feature = "gpu")]
use crate::integer::gpu::zk::CudaProvenCompactCiphertextList;
use serde::Serializer;
@@ -620,6 +623,13 @@ mod zk {
const NAME: &'static str = "high_level_api::ProvenCompactCiphertextList";
}
impl ReRandContextAdd for ProvenCompactCiphertextList {
fn add_to_re_randomization_context(&self, context: &mut crate::ReRandomizationContext) {
let on_cpu = self.inner.on_cpu();
context.inner.add_proven_ciphertext_list(on_cpu)
}
}
impl ProvenCompactCiphertextList {
pub fn builder(pk: &CompactPublicKey) -> CompactCiphertextListBuilder {
CompactCiphertextListBuilder::new(pk)
@@ -655,7 +665,7 @@ mod zk {
pk: &CompactPublicKey,
metadata: &[u8],
) -> crate::Result<CompactCiphertextListExpander> {
self.maybe_verify_and_expand(Some((crs, pk, metadata)))
self.maybe_verify_maybe_re_randomize_and_expand(Some((crs, pk, metadata)), None)
}
#[doc(hidden)]
@@ -663,27 +673,68 @@ mod zk {
///
/// If you are here you were probably looking for it: use at your own risks.
pub fn expand_without_verification(&self) -> crate::Result<CompactCiphertextListExpander> {
self.maybe_verify_and_expand(None)
self.maybe_verify_maybe_re_randomize_and_expand(None, None)
}
/// Internal helper that does expansion, and verification only if crs, public key and
/// metadata are provided
fn maybe_verify_and_expand(
pub fn verify_re_randomize_and_expand(
&self,
crs: &CompactPkeCrs,
pk: &CompactPublicKey,
metadata: &[u8],
seed: ReRandomizationSeed,
) -> crate::Result<CompactCiphertextListExpander> {
self.maybe_verify_maybe_re_randomize_and_expand(
Some((crs, pk, metadata)),
Some((pk, seed)),
)
}
#[doc(hidden)]
/// This function allows to re_randomize and expand a ciphertext without verifying the
/// associated proof.
///
/// If you are here you were probably looking for it: use at your own risks.
pub fn re_randomize_and_expand_without_verification(
&self,
pk: &CompactPublicKey,
seed: ReRandomizationSeed,
) -> crate::Result<CompactCiphertextListExpander> {
self.maybe_verify_maybe_re_randomize_and_expand(None, Some((pk, seed)))
}
/// Internal helper that does expansion, and optionally verification and re_randomization if
/// the required materials are provided
fn maybe_verify_maybe_re_randomize_and_expand(
&self,
verification_materials: Option<(&CompactPkeCrs, &CompactPublicKey, &[u8])>,
re_randomization_materials: Option<(&CompactPublicKey, ReRandomizationSeed)>,
) -> crate::Result<CompactCiphertextListExpander> {
#[allow(irrefutable_let_patterns)]
if let InnerProvenCompactCiphertextList::Cpu(inner) = &self.inner {
// For WASM
if !inner.is_packed() && !inner.needs_casting() {
let expander = match verification_materials {
Some((crs, pk, metadata)) => inner.verify_and_expand(
let expander = match (verification_materials, re_randomization_materials) {
(Some((crs, pk, metadata)), Some((_, seed))) => inner
.verify_re_randomize_and_expand(
crs,
&pk.key.key,
metadata,
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking,
seed,
),
(None, Some((pk, seed))) => inner
.re_randomize_and_expand_without_verification(
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking,
&pk.key.key,
seed,
),
(Some((crs, pk, metadata)), None) => inner.verify_and_expand(
crs,
&pk.key.key,
metadata,
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking,
),
None => inner.expand_without_verification(
(None, None) => inner.expand_without_verification(
IntegerCompactCiphertextListExpansionMode::NoCastingAndNoUnpacking,
),
}?;
@@ -705,14 +756,28 @@ mod zk {
InnerProvenCompactCiphertextList::Cuda(inner) => &inner.h_proved_lists,
};
let expander = match verification_materials {
Some((crs, pk, metadata)) => proven_ct.verify_and_expand(
let expander = match (verification_materials, re_randomization_materials) {
(Some((crs, pk, metadata)), Some((_, seed))) => proven_ct
.verify_re_randomize_and_expand(
crs,
&pk.key.key,
metadata,
cpu_key.integer_compact_ciphertext_list_expansion_mode(),
seed,
),
(Some((crs, pk, metadata)), None) => proven_ct.verify_and_expand(
crs,
&pk.key.key,
metadata,
cpu_key.integer_compact_ciphertext_list_expansion_mode(),
),
None => proven_ct.expand_without_verification(
(None, Some((pk, seed))) => proven_ct
.re_randomize_and_expand_without_verification(
cpu_key.integer_compact_ciphertext_list_expansion_mode(),
&pk.key.key,
seed,
),
(None, None) => proven_ct.expand_without_verification(
cpu_key.integer_compact_ciphertext_list_expansion_mode(),
),
}?;
@@ -734,11 +799,28 @@ mod zk {
};
let ksk = gpu_key.cpk_key_switching_key();
let expander = match verification_materials {
Some((crs, pk, metadata)) => {
let expander = match (verification_materials, re_randomization_materials) {
(Some((crs, pk, metadata)), Some((_, seed))) => proven_ct
.verify_re_randomize_and_expand(
crs,
&pk.key.key,
metadata,
&ksk,
seed,
streams,
),
(Some((crs, pk, metadata)), None) => {
proven_ct.verify_and_expand(crs, &pk.key.key, metadata, &ksk, streams)
}
None => proven_ct.expand_without_verification(&ksk, streams),
(None, Some((pk, seed))) => proven_ct
.re_randomize_and_expand_without_verification(
&ksk,
&pk.key.key,
seed,
streams,
),
(None, None) => proven_ct.expand_without_verification(&ksk, streams),
}?;
Ok(CompactCiphertextListExpander {

View File

@@ -132,6 +132,11 @@ impl ConfigBuilder {
self
}
pub fn use_dedicated_oprf_key(mut self, enabled: bool) -> Self {
self.config.inner.use_dedicated_oprf_key(enabled);
self
}
pub fn use_custom_parameters<P>(mut self, block_parameters: P) -> Self
where
P: Into<crate::shortint::atomic_pattern::AtomicPatternParameters>,
@@ -167,6 +172,7 @@ impl From<MetaParameters> for Config {
.noise_squashing_parameters
.and_then(|ns_p| ns_p.compression_parameters),
cpk_re_randomization_params: meta_params.rerandomization_parameters(),
dedicated_oprf_key: true,
},
}
}

View File

@@ -49,6 +49,7 @@ pub use signed::{CompressedFheInt, FheInt, FheIntId, SquashedNoiseFheInt};
pub use unsigned::{CompressedFheUint, FheUint, FheUintId, SquashedNoiseFheUint};
pub mod oprf;
pub mod shuffle;
pub(super) mod signed;
pub(super) mod unsigned;
@@ -58,6 +59,9 @@ pub(super) mod unsigned;
pub trait IntegerId: FheId + 'static {
type InnerCpu: crate::integer::IntegerRadixCiphertext;
#[cfg(feature = "gpu")]
type InnerGpu: crate::integer::gpu::ciphertext::CudaIntegerRadixCiphertext;
#[cfg(not(feature = "gpu"))]
type InnerGpu;
type InnerHpu;
@@ -89,4 +93,23 @@ pub trait FheIntegerType: Tagged + private::Sealed {
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self;
#[cfg(feature = "gpu")]
fn on_gpu(
&self,
streams: &crate::core_crypto::gpu::CudaStreams,
) -> MaybeCloned<'_, <Self::Id as IntegerId>::InnerGpu>;
#[cfg(feature = "gpu")]
fn into_gpu(
self,
streams: &crate::core_crypto::gpu::CudaStreams,
) -> <Self::Id as IntegerId>::InnerGpu;
#[cfg(feature = "gpu")]
fn from_gpu(
inner: <Self::Id as IntegerId>::InnerGpu,
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self;
}

View File

@@ -4,8 +4,8 @@ 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 crate::shortint::{MessageModulus, OprfSeed};
use crate::FheInt;
use std::num::NonZeroU64;
impl<Id: FheUintId> FheUint<Id> {
@@ -27,14 +27,16 @@ impl<Id: FheUintId> FheUint<Id> {
///
/// let dec_result: u16 = ct_res.decrypt(&client_key);
/// ```
pub fn generate_oblivious_pseudo_random(seed: Seed) -> Self {
pub fn generate_oblivious_pseudo_random(seed: impl OprfSeed) -> Self {
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(key) => {
let sk = key.pbs_key();
let ct = key
.pbs_key()
.oprf_key()
.par_generate_oblivious_pseudo_random_unsigned_integer(
seed,
Id::num_blocks(key.message_modulus()) as u64,
sk,
);
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
@@ -43,11 +45,11 @@ impl<Id: FheUintId> FheUint<Id> {
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let d_ct: CudaUnsignedRadixCiphertext = cuda_key
.key
.key
.oprf_key()
.par_generate_oblivious_pseudo_random_unsigned_integer(
seed,
Id::num_blocks(cuda_key.message_modulus()) as u64,
cuda_key.pbs_key(),
streams,
);
@@ -86,9 +88,11 @@ impl<Id: FheUintId> FheUint<Id> {
if let InternalServerKey::Cuda(cuda_key) = key {
let streams = &cuda_key.streams;
cuda_key
.key
.key
.get_par_generate_oblivious_pseudo_random_unsigned_integer_size_on_gpu(streams)
.oprf_key()
.get_par_generate_oblivious_pseudo_random_unsigned_integer_size_on_gpu(
cuda_key.pbs_key(),
streams,
)
} else {
0
}
@@ -115,15 +119,20 @@ impl<Id: FheUintId> FheUint<Id> {
/// let dec_result: u16 = ct_res.decrypt(&client_key);
/// assert!(dec_result < (1 << random_bits_count));
/// ```
pub fn generate_oblivious_pseudo_random_bounded(seed: Seed, random_bits_count: u64) -> Self {
pub fn generate_oblivious_pseudo_random_bounded(
seed: impl OprfSeed,
random_bits_count: u64,
) -> Self {
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(key) => {
let sk = key.pbs_key();
let ct = key
.pbs_key()
.oprf_key()
.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
seed,
random_bits_count,
Id::num_blocks(key.message_modulus()) as u64,
sk,
);
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
@@ -132,12 +141,12 @@ impl<Id: FheUintId> FheUint<Id> {
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let d_ct: CudaUnsignedRadixCiphertext = cuda_key
.key
.key
.oprf_key()
.par_generate_oblivious_pseudo_random_unsigned_integer_bounded(
seed,
random_bits_count,
Id::num_blocks(cuda_key.message_modulus()) as u64,
cuda_key.pbs_key(),
streams,
);
Self::new(
@@ -196,7 +205,7 @@ impl<Id: FheUintId> FheUint<Id> {
/// assert!(dec_result < excluded_upper_bound.get() as u16);
/// ```
pub fn generate_oblivious_pseudo_random_custom_range(
seed: Seed,
seed: impl OprfSeed,
range: &RangeForRandom,
max_distance: Option<f64>,
) -> Self {
@@ -226,13 +235,15 @@ impl<Id: FheUintId> FheUint<Id> {
let num_blocks_output = Id::num_blocks(key.message_modulus()) as u64;
let sk = key.pbs_key();
let ct = key
.pbs_key()
.oprf_key()
.par_generate_oblivious_pseudo_random_unsigned_custom_range(
seed,
num_input_random_bits,
excluded_upper_bound,
num_blocks_output,
sk,
);
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
@@ -250,12 +261,13 @@ impl<Id: FheUintId> FheUint<Id> {
let num_blocks_output = Id::num_blocks(cuda_key.message_modulus()) as u64;
let ct = cuda_key
.pbs_key()
.oprf_key()
.par_generate_oblivious_pseudo_random_unsigned_custom_range(
seed,
num_input_random_bits,
excluded_upper_bound.get(),
num_blocks_output,
cuda_key.pbs_key(),
&cuda_key.streams,
);
@@ -292,9 +304,9 @@ impl<Id: FheUintId> FheUint<Id> {
if let InternalServerKey::Cuda(cuda_key) = key {
let streams = &cuda_key.streams;
cuda_key
.key
.key
.oprf_key()
.get_par_generate_oblivious_pseudo_random_unsigned_integer_bounded_size_on_gpu(
cuda_key.pbs_key(),
streams,
)
} else {
@@ -325,14 +337,16 @@ impl<Id: FheIntId> FheInt<Id> {
/// assert!(dec_result < 1 << 7);
/// assert!(dec_result >= -(1 << 7));
/// ```
pub fn generate_oblivious_pseudo_random(seed: Seed) -> Self {
pub fn generate_oblivious_pseudo_random(seed: impl OprfSeed) -> Self {
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(key) => {
let sk = key.pbs_key();
let ct = key
.pbs_key()
.oprf_key()
.par_generate_oblivious_pseudo_random_signed_integer(
seed,
Id::num_blocks(key.message_modulus()) as u64,
sk,
);
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
}
@@ -340,11 +354,11 @@ impl<Id: FheIntId> FheInt<Id> {
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let d_ct: CudaSignedRadixCiphertext = cuda_key
.key
.key
.oprf_key()
.par_generate_oblivious_pseudo_random_signed_integer(
seed,
Id::num_blocks(cuda_key.message_modulus()) as u64,
cuda_key.pbs_key(),
streams,
);
@@ -384,9 +398,11 @@ impl<Id: FheIntId> FheInt<Id> {
if let InternalServerKey::Cuda(cuda_key) = key {
let streams = &cuda_key.streams;
cuda_key
.key
.key
.get_par_generate_oblivious_pseudo_random_signed_integer_size_on_gpu(streams)
.oprf_key()
.get_par_generate_oblivious_pseudo_random_signed_integer_size_on_gpu(
cuda_key.pbs_key(),
streams,
)
} else {
0
}
@@ -414,15 +430,20 @@ impl<Id: FheIntId> FheInt<Id> {
/// assert!(dec_result >= 0);
/// assert!(dec_result < 1 << random_bits_count);
/// ```
pub fn generate_oblivious_pseudo_random_bounded(seed: Seed, random_bits_count: u64) -> Self {
pub fn generate_oblivious_pseudo_random_bounded(
seed: impl OprfSeed,
random_bits_count: u64,
) -> Self {
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(key) => {
let sk = key.pbs_key();
let ct = key
.pbs_key()
.oprf_key()
.par_generate_oblivious_pseudo_random_signed_integer_bounded(
seed,
random_bits_count,
Id::num_blocks(key.message_modulus()) as u64,
sk,
);
Self::new(ct, key.tag.clone(), ReRandomizationMetadata::default())
@@ -431,12 +452,12 @@ impl<Id: FheIntId> FheInt<Id> {
InternalServerKey::Cuda(cuda_key) => {
let streams = &cuda_key.streams;
let d_ct: CudaSignedRadixCiphertext = cuda_key
.key
.key
.oprf_key()
.par_generate_oblivious_pseudo_random_signed_integer_bounded(
seed,
random_bits_count,
Id::num_blocks(cuda_key.message_modulus()) as u64,
cuda_key.pbs_key(),
streams,
);
Self::new(
@@ -474,9 +495,9 @@ impl<Id: FheIntId> FheInt<Id> {
if let InternalServerKey::Cuda(cuda_key) = key {
let streams = &cuda_key.streams;
cuda_key
.key
.key
.oprf_key()
.get_par_generate_oblivious_pseudo_random_unsigned_integer_bounded_size_on_gpu(
cuda_key.pbs_key(),
streams,
)
} else {
@@ -570,6 +591,7 @@ mod test {
};
use crate::prelude::FheDecrypt;
use crate::shortint::oprf::test::test_uniformity;
use crate::shortint::parameters::test_params::TEST_PARAM_MESSAGE_2_CARRY_2_PBS_KS_GAUSSIAN_2M128;
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
use crate::{generate_keys, set_server_key, ConfigBuilder, FheUint8, Seed};
use num_bigint::BigUint;
@@ -707,7 +729,9 @@ mod test {
#[test]
fn test_uniformity_generate_oblivious_pseudo_random_custom_range_cpu() {
let params = PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(params).build();
let config = ConfigBuilder::with_custom_parameters(params)
.use_dedicated_oprf_key(true)
.build();
let (cks, sks) = generate_keys(config);
rayon::broadcast(|_| set_server_key(sks.clone()));
let message_modulus = cks.message_modulus();
@@ -738,8 +762,10 @@ mod test {
let real_values: Vec<u64> = (0..sample_count)
.into_par_iter()
.map(|_| {
let seed = Seed(rand::thread_rng().gen::<u128>());
let img = FheUint8::generate_oblivious_pseudo_random_custom_range(
Seed(rand::thread_rng().gen::<u128>()),
seed,
&range,
Some(max_distance),
);
@@ -820,6 +846,50 @@ mod test {
}
}
/// Test that OPRF generation works without a dedicated OPRF key by falling
/// back to the compute server key's bootstrapping key.
#[test]
fn test_oprf_fallback_without_dedicated_key() {
// Explicitly disable OPRF so no dedicated OPRF key is generated.
let config = ConfigBuilder::default()
.use_dedicated_oprf_key(false)
.build();
let (client_key, server_key) = generate_keys(config);
set_server_key(server_key);
let ct = FheUint8::generate_oblivious_pseudo_random(Seed(42));
let result: u16 = ct.decrypt(&client_key);
// 8-bit value must fit in [0, 256)
assert!(result < 256);
let ct_bounded = FheUint8::generate_oblivious_pseudo_random_bounded(Seed(42), 3);
let result_bounded: u16 = ct_bounded.decrypt(&client_key);
assert!(result_bounded < (1 << 3));
}
/// Test OPRF with BootstrapKeyswitch (PBS_KS) parameter order.
///
/// This exercises the keyswitch-after-bootstrap code path in
/// `OprfBootstrappingKey::generate_pseudo_random_bits`.
#[test]
fn test_oprf_with_pbs_ks_params() {
let config = ConfigBuilder::with_custom_parameters(
TEST_PARAM_MESSAGE_2_CARRY_2_PBS_KS_GAUSSIAN_2M128,
)
.use_dedicated_oprf_key(true)
.build();
let (client_key, server_key) = generate_keys(config);
set_server_key(server_key);
let ct = FheUint8::generate_oblivious_pseudo_random(Seed(123));
let result: u16 = ct.decrypt(&client_key);
assert!(result < 256);
let ct_bounded = FheUint8::generate_oblivious_pseudo_random_bounded(Seed(456), 3);
let result_bounded: u16 = ct_bounded.decrypt(&client_key);
assert!(result_bounded < (1 << 3));
}
#[cfg(feature = "gpu")]
mod gpu {
use super::*;
@@ -838,13 +908,11 @@ mod test {
fn test_oprf_gpu() {
for setup_fn in crate::high_level_api::integers::unsigned::tests::gpu::GPU_SETUP_FN {
let _ck = setup_fn();
let seed = Seed(0);
let img = FheUint64::generate_oblivious_pseudo_random_bounded(seed, 1);
let img = FheUint64::generate_oblivious_pseudo_random_bounded(Seed(0), 1);
assert_eq!(img.ciphertext.into_cpu().blocks.len(), 32);
let img = FheInt128::generate_oblivious_pseudo_random_bounded(seed, 1);
let img = FheInt128::generate_oblivious_pseudo_random_bounded(Seed(0), 1);
assert_eq!(img.ciphertext.into_cpu().blocks.len(), 64);
}
@@ -864,7 +932,9 @@ mod test {
#[test]
fn test_uniformity_generate_oblivious_pseudo_random_custom_range_gpu() {
let params = PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(params).build();
let config = ConfigBuilder::with_custom_parameters(params)
.use_dedicated_oprf_key(true)
.build();
let cks = ClientKey::generate(config);
let message_modulus = cks.message_modulus();
@@ -921,8 +991,9 @@ mod test {
rand::thread_rng()
},
|rng, _| {
let seed = Seed(rng.gen::<u128>());
let img = FheUint8::generate_oblivious_pseudo_random_custom_range(
Seed(rng.gen::<u128>()),
seed,
&range,
Some(max_distance),
);

View File

@@ -0,0 +1,121 @@
use crate::high_level_api::global_state;
use crate::high_level_api::integers::FheIntegerType;
use crate::high_level_api::keys::InternalServerKey;
use crate::high_level_api::re_randomization::ReRandomizationMetadata;
use crate::integer::server_key::radix_parallel::bitonic_shuffle::BitonicShuffleKeySize;
use tfhe_csprng::seeders::Seeder;
/// Shuffles `data` into a uniformly random permutation using a bitonic
/// sorting network with OPRF-generated random keys.
///
/// `key_size` controls the bit-width of the random sort keys used internally,
/// either by specifying a target collision probability or by passing a raw
/// block count. Larger keys reduce collision probability (improving shuffle
/// uniformity) at the cost of more computation per comparison.
///
/// The re-randomization metadata of the input elements is not preserved
/// through the shuffle.
///
/// # Errors
///
/// Returns an error if the resolved key block count is 0, or if the Cuda/Hpu
/// backend is active (not yet supported).
pub fn bitonic_shuffle<T, S>(
data: Vec<T>,
key_size: BitonicShuffleKeySize,
seeder: &mut S,
) -> Result<Vec<T>, crate::Error>
where
T: FheIntegerType,
S: Seeder,
{
global_state::with_internal_keys(|key| match key {
InternalServerKey::Cpu(cpu_key) => {
let inner = data.into_iter().map(|v| v.into_cpu()).collect();
let result =
cpu_key
.pbs_key()
.bitonic_shuffle(&cpu_key.oprf_key(), inner, key_size, seeder)?;
Ok(result
.into_iter()
.map(|ct| T::from_cpu(ct, cpu_key.tag.clone(), ReRandomizationMetadata::default()))
.collect())
}
#[cfg(feature = "gpu")]
InternalServerKey::Cuda(_) => Err(crate::Error::new(
"bitonic_shuffle is not supported on Cuda".to_string(),
)),
#[cfg(feature = "hpu")]
InternalServerKey::Hpu(_) => Err(crate::Error::new(
"bitonic_shuffle is not supported on Hpu".to_string(),
)),
})
}
#[cfg(test)]
mod test {
use super::{bitonic_shuffle, BitonicShuffleKeySize};
use crate::core_crypto::commons::generators::DeterministicSeeder;
use crate::core_crypto::prelude::new_seeder;
use crate::high_level_api::prelude::*;
use crate::high_level_api::tests::setup_default_cpu;
use crate::{FheInt8, FheUint8};
use rand::Rng;
use tfhe_csprng::generators::DefaultRandomGenerator;
#[test]
fn test_bitonic_shuffle_fheuint() {
let cks = setup_default_cpu();
let mut rng = rand::thread_rng();
let mut clear_values: Vec<u8> = (0..15).map(|_| rng.gen()).collect();
let encrypted: Vec<FheUint8> = clear_values
.iter()
.map(|&v| FheUint8::try_encrypt(v, &cks).unwrap())
.collect();
let seed = new_seeder().seed();
println!("seed: {seed:?}");
let mut seeder = DeterministicSeeder::<DefaultRandomGenerator>::new(seed);
let shuffled = bitonic_shuffle(
encrypted,
BitonicShuffleKeySize::num_blocks(16),
&mut seeder,
)
.unwrap();
let mut decrypted: Vec<u8> = shuffled.iter().map(|ct| ct.decrypt(&cks)).collect();
clear_values.sort_unstable();
decrypted.sort_unstable();
assert_eq!(decrypted, clear_values);
}
#[test]
fn test_bitonic_shuffle_fheint() {
let cks = setup_default_cpu();
let mut rng = rand::thread_rng();
let mut clear_values: Vec<i8> = (0..15).map(|_| rng.gen()).collect();
let encrypted: Vec<FheInt8> = clear_values
.iter()
.map(|&v| FheInt8::try_encrypt(v, &cks).unwrap())
.collect();
let seed = new_seeder().seed();
println!("seed: {seed:?}");
let mut seeder = DeterministicSeeder::<DefaultRandomGenerator>::new(seed);
let shuffled = bitonic_shuffle(
encrypted,
BitonicShuffleKeySize::num_blocks(16),
&mut seeder,
)
.unwrap();
let mut decrypted: Vec<i8> = shuffled.iter().map(|ct| ct.decrypt(&cks)).collect();
clear_values.sort_unstable();
decrypted.sort_unstable();
assert_eq!(decrypted, clear_values);
}
}

View File

@@ -137,6 +137,31 @@ where
) -> Self {
Self::new(inner, tag, re_randomization_metadata)
}
#[cfg(feature = "gpu")]
fn on_gpu(
&self,
streams: &crate::core_crypto::gpu::CudaStreams,
) -> MaybeCloned<'_, <Self::Id as IntegerId>::InnerGpu> {
self.ciphertext.on_gpu(streams)
}
#[cfg(feature = "gpu")]
fn into_gpu(
self,
streams: &crate::core_crypto::gpu::CudaStreams,
) -> <Self::Id as IntegerId>::InnerGpu {
self.ciphertext.into_gpu(streams)
}
#[cfg(feature = "gpu")]
fn from_gpu(
inner: <Self::Id as IntegerId>::InnerGpu,
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self {
Self::new(inner, tag, re_randomization_metadata)
}
}
impl<Id> FheInt<Id>
@@ -210,6 +235,30 @@ where
self.ciphertext.current_device()
}
/// Returns an encrypted `true` if `value` is found in `cts`.
///
/// # Example
///
/// ```rust
/// use tfhe::prelude::*;
/// use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheInt16};
///
/// let (client_key, server_key) = generate_keys(ConfigBuilder::default());
/// set_server_key(server_key);
///
/// let a = FheInt16::encrypt(1i16, &client_key);
/// let b = FheInt16::encrypt(-2i16, &client_key);
/// let c = FheInt16::encrypt(3i16, &client_key);
/// let value = FheInt16::encrypt(-2i16, &client_key);
///
/// let result = FheInt16::contains(&[a, b, c], &value);
/// let decrypted = result.decrypt(&client_key);
/// assert!(decrypted);
/// ```
pub fn contains(cts: &[Self], value: &Self) -> FheBool {
crate::high_level_api::array::fhe_array_contains(cts, value)
}
/// Returns the absolute value
///
/// # Example

View File

@@ -0,0 +1,54 @@
use crate::high_level_api::integers::unsigned::fused_ops::impl_fused_mul_divs;
use crate::integer::bigint::{I1024, I2048, I256, I512};
// Standard types (always available)
//
// (NarrowFhe, WideFhe, NarrowScalar, WideScalar)
//
// Types without at least double-width FheInt (FheInt2048) are not supported.
impl_fused_mul_divs!(
(super::FheInt2, super::FheInt4, i8, i8),
(super::FheInt4, super::FheInt8, i8, i8),
(super::FheInt6, super::FheInt12, i8, i16),
(super::FheInt8, super::FheInt16, i8, i16),
(super::FheInt10, super::FheInt32, i16, i32),
(super::FheInt12, super::FheInt32, i16, i32),
(super::FheInt14, super::FheInt32, i16, i32),
(super::FheInt16, super::FheInt32, i16, i32),
(super::FheInt32, super::FheInt64, i32, i64),
(super::FheInt64, super::FheInt128, i64, i128),
(super::FheInt128, super::FheInt256, i128, I256),
(super::FheInt160, super::FheInt512, I256, I512),
(super::FheInt256, super::FheInt512, I256, I512),
(super::FheInt512, super::FheInt1024, I512, I1024),
(super::FheInt1024, super::FheInt2048, I1024, I2048),
);
#[cfg(feature = "extended-types")]
impl_fused_mul_divs!(
(super::FheInt24, super::FheInt48, i32, i64),
(super::FheInt40, super::FheInt80, i64, i128),
(super::FheInt48, super::FheInt96, i64, i128),
(super::FheInt56, super::FheInt112, i64, i128),
(super::FheInt72, super::FheInt144, i128, I256),
(super::FheInt80, super::FheInt160, i128, I256),
(super::FheInt88, super::FheInt176, i128, I256),
(super::FheInt96, super::FheInt192, i128, I256),
(super::FheInt104, super::FheInt208, i128, I256),
(super::FheInt112, super::FheInt224, i128, I256),
(super::FheInt120, super::FheInt240, i128, I256),
(super::FheInt136, super::FheInt512, I256, I512),
(super::FheInt144, super::FheInt512, I256, I512),
(super::FheInt152, super::FheInt512, I256, I512),
(super::FheInt168, super::FheInt512, I256, I512),
(super::FheInt176, super::FheInt512, I256, I512),
(super::FheInt184, super::FheInt512, I256, I512),
(super::FheInt192, super::FheInt512, I256, I512),
(super::FheInt200, super::FheInt512, I256, I512),
(super::FheInt208, super::FheInt512, I256, I512),
(super::FheInt216, super::FheInt512, I256, I512),
(super::FheInt224, super::FheInt512, I256, I512),
(super::FheInt232, super::FheInt512, I256, I512),
(super::FheInt240, super::FheInt512, I256, I512),
(super::FheInt248, super::FheInt512, I256, I512),
);

View File

@@ -3,6 +3,7 @@ mod compressed;
mod squashed_noise;
mod encrypt;
mod fused_ops;
mod inner;
mod ops;
mod overflowing_ops;

View File

@@ -253,3 +253,9 @@ fn test_safe_deserialize_conformant_compressed_fhe_int32() {
let decrypted: i32 = deserialized_a.decompress().decrypt(&client_key);
assert_eq!(decrypted, clear_a);
}
#[test]
fn test_int16_fused_mul_div() {
let client_key = setup_default_cpu();
super::test_case_int16_fused_mul_div(&client_key);
}

View File

@@ -373,3 +373,11 @@ fn test_gpu_get_div_size_on_gpu() {
check_valid_cuda_malloc_assert_oom(scalar_div_rem_tmp_buffer_size, GpuIndex::new(0));
}
}
#[test]
fn test_int16_fused_mul_div_gpu() {
for setup_fn in crate::high_level_api::integers::unsigned::tests::gpu::GPU_SETUP_FN {
let client_key = setup_fn();
super::test_case_int16_fused_mul_div(&client_key);
}
}

View File

@@ -519,3 +519,71 @@ fn test_case_min_max(cks: &ClientKey) {
assert_eq!(decrypted_min, a_val.min(b_val));
assert_eq!(decrypted_max, a_val.max(b_val));
}
fn test_case_int16_fused_mul_div(cks: &ClientKey) {
let mut rng = rand::thread_rng();
// Widening prevents incorrect result with signed values:
// (-200) * 200 = -40_000 which overflows i16 (min -32_768),
// but with widening: -40_000 / 100 = -400, correct.
{
let input = -200i16;
let mul = 200i16;
let div = 100i16;
let expected = -400i16;
let a = FheInt16::try_encrypt(input, cks).unwrap();
let b = FheInt16::try_encrypt(mul, cks).unwrap();
let result = (&a).fused_mul_scalar_div(&b, div);
let decrypted: i16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
let result = (&a).fused_scalar_mul_scalar_div(mul, div);
let decrypted: i16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
}
for _ in 0..5 {
let clear_a: i16 = rng.gen();
let clear_b: i16 = rng.gen();
let clear_c: i16 = loop {
let v: i16 = rng.gen();
if v != 0 {
break v;
}
};
let a = FheInt16::try_encrypt(clear_a, cks).unwrap();
let b = FheInt16::try_encrypt(clear_b, cks).unwrap();
let expected = (i32::from(clear_a) * i32::from(clear_b) / i32::from(clear_c)) as i16;
// encrypted * encrypted / scalar
{
let result = (&a).fused_mul_scalar_div(&b, clear_c);
let decrypted: i16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
}
// encrypted * scalar / scalar
{
let result = (&a).fused_scalar_mul_scalar_div(clear_b, clear_c);
let decrypted: i16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
}
// Owned variants
{
let result = a.fused_mul_scalar_div(b, clear_c);
let decrypted: i16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
// Need to encrypt again since "a" was consumed above
let a = FheInt16::try_encrypt(clear_a, cks).unwrap();
let result = a.fused_scalar_mul_scalar_div(clear_b, clear_c);
let decrypted: i16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
}
}
}

View File

@@ -174,6 +174,31 @@ where
) -> Self {
Self::new(inner, tag, re_randomization_metadata)
}
#[cfg(feature = "gpu")]
fn on_gpu(
&self,
streams: &crate::core_crypto::gpu::CudaStreams,
) -> MaybeCloned<'_, <Self::Id as IntegerId>::InnerGpu> {
self.ciphertext.on_gpu(streams)
}
#[cfg(feature = "gpu")]
fn into_gpu(
self,
streams: &crate::core_crypto::gpu::CudaStreams,
) -> <Self::Id as IntegerId>::InnerGpu {
self.ciphertext.into_gpu(streams)
}
#[cfg(feature = "gpu")]
fn from_gpu(
inner: <Self::Id as IntegerId>::InnerGpu,
tag: Tag,
re_randomization_metadata: ReRandomizationMetadata,
) -> Self {
Self::new(inner, tag, re_randomization_metadata)
}
}
impl<Id> Tagged for FheUint<Id>
@@ -537,6 +562,30 @@ where
collection.as_ref().iter().copied().sum()
}
/// Returns an encrypted `true` if `value` is found in `cts`.
///
/// # Example
///
/// ```rust
/// use tfhe::prelude::*;
/// use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint16};
///
/// let (client_key, server_key) = generate_keys(ConfigBuilder::default());
/// set_server_key(server_key);
///
/// let a = FheUint16::encrypt(1u16, &client_key);
/// let b = FheUint16::encrypt(2u16, &client_key);
/// let c = FheUint16::encrypt(3u16, &client_key);
/// let value = FheUint16::encrypt(2u16, &client_key);
///
/// let result = FheUint16::contains(&[a, b, c], &value);
/// let decrypted = result.decrypt(&client_key);
/// assert!(decrypted);
/// ```
pub fn contains(cts: &[Self], value: &Self) -> FheBool {
crate::high_level_api::array::fhe_array_contains(cts, value)
}
/// Returns the number of leading zeros in the binary representation of self.
///
/// # Example

View File

@@ -0,0 +1,186 @@
use crate::integer::bigint::{U1024, U2048, U256, U512};
/// Generates `FusedMulScalarDiv` impls for (encrypted * encrypted) / scalar.
///
/// Input tuple is of the form (NarrowFhe, WideFhe, NarrowScalar, WideScalar)`
/// Inputs are `NarrowFhe` and `NarrowScalar`, and get widened to `WideFhe` and `WideScalar`, mul
/// and div are computed on the widened values and result is truncated back down to `NarrowFhe`
macro_rules! impl_fused_mul_scalar_div {
($(
($fhe_narrow:ty, $fhe_wide:ty, $scalar_narrow:ty, $scalar_wide:ty)
),* $(,)?) => {
$(
// (&enc * &enc) / scalar (ref, ref, main impl)
impl crate::high_level_api::traits::FusedMulScalarDiv<&$fhe_narrow, $scalar_narrow> for &$fhe_narrow {
type Output = $fhe_narrow;
fn fused_mul_scalar_div(
self,
mul: &$fhe_narrow,
div_scalar: $scalar_narrow,
) -> Self::Output {
use crate::core_crypto::prelude::CastFrom;
let wide_self = <$fhe_wide>::cast_from(self.clone());
let wide_mul = <$fhe_wide>::cast_from(mul.clone());
let wide_product = &wide_self * &wide_mul;
let wide_result = wide_product / <$scalar_wide>::cast_from(div_scalar);
<$fhe_narrow>::cast_from(wide_result)
}
}
// (enc * enc) / scalar (owned, owned)
impl crate::high_level_api::traits::FusedMulScalarDiv<$fhe_narrow, $scalar_narrow> for $fhe_narrow {
type Output = $fhe_narrow;
fn fused_mul_scalar_div(
self,
mul: $fhe_narrow,
div_scalar: $scalar_narrow,
) -> Self::Output {
use crate::high_level_api::traits::FusedMulScalarDiv;
<&Self as FusedMulScalarDiv<&$fhe_narrow, $scalar_narrow>>::fused_mul_scalar_div(&self, &mul, div_scalar)
}
}
// (&enc * enc) / scalar (ref, owned)
impl crate::high_level_api::traits::FusedMulScalarDiv<$fhe_narrow, $scalar_narrow> for &$fhe_narrow {
type Output = $fhe_narrow;
fn fused_mul_scalar_div(
self,
mul: $fhe_narrow,
div_scalar: $scalar_narrow,
) -> Self::Output {
use crate::high_level_api::traits::FusedMulScalarDiv;
<Self as FusedMulScalarDiv<&$fhe_narrow, $scalar_narrow>>::fused_mul_scalar_div(self, &mul, div_scalar)
}
}
// (enc * &enc) / scalar (owned, ref)
impl crate::high_level_api::traits::FusedMulScalarDiv<&$fhe_narrow, $scalar_narrow> for $fhe_narrow {
type Output = $fhe_narrow;
fn fused_mul_scalar_div(
self,
mul: &$fhe_narrow,
div_scalar: $scalar_narrow,
) -> Self::Output {
use crate::high_level_api::traits::FusedMulScalarDiv;
<&Self as FusedMulScalarDiv<&$fhe_narrow, $scalar_narrow>>::fused_mul_scalar_div(&self, mul, div_scalar)
}
}
)*
};
}
pub(crate) use impl_fused_mul_scalar_div;
/// Generates `FusedScalarMulScalarDiv` impls for (encrypted * scalar) / scalar.
///
/// Input tuple is of the form (NarrowFhe, WideFhe, NarrowScalar, WideScalar)`
/// Inputs are `NarrowFhe` and `NarrowScalar`, and get widened to `WideFhe` and `WideScalar`, mul
/// and div are computed on the widened values and result is truncated back down to `NarrowFhe`
macro_rules! impl_fused_scalar_mul_scalar_div {
($(
($fhe_narrow:ty, $fhe_wide:ty, $scalar_narrow:ty, $scalar_wide:ty)
),* $(,)?) => {
$(
// (&enc * scalar) / scalar (ref, main impl)
impl crate::high_level_api::traits::FusedScalarMulScalarDiv<$scalar_narrow> for &$fhe_narrow {
type Output = $fhe_narrow;
fn fused_scalar_mul_scalar_div(
self,
mul_scalar: $scalar_narrow,
div_scalar: $scalar_narrow,
) -> Self::Output {
use crate::core_crypto::prelude::CastFrom;
let wide_self = <$fhe_wide>::cast_from(self.clone());
let wide_product = wide_self * <$scalar_wide>::cast_from(mul_scalar);
let wide_result = wide_product / <$scalar_wide>::cast_from(div_scalar);
<$fhe_narrow>::cast_from(wide_result)
}
}
// (enc * scalar) / scalar (owned)
impl crate::high_level_api::traits::FusedScalarMulScalarDiv<$scalar_narrow> for $fhe_narrow {
type Output = $fhe_narrow;
fn fused_scalar_mul_scalar_div(
self,
mul_scalar: $scalar_narrow,
div_scalar: $scalar_narrow,
) -> Self::Output {
use crate::high_level_api::traits::FusedScalarMulScalarDiv;
<&Self as FusedScalarMulScalarDiv<$scalar_narrow>>::fused_scalar_mul_scalar_div(&self, mul_scalar, div_scalar)
}
}
)*
};
}
pub(crate) use impl_fused_scalar_mul_scalar_div;
macro_rules! impl_fused_mul_divs {
($(
($fhe_narrow:ty, $fhe_wide:ty, $scalar_narrow:ty, $scalar_wide:ty)
),* $(,)?) => {
crate::high_level_api::integers::unsigned::fused_ops::impl_fused_mul_scalar_div!($(
($fhe_narrow, $fhe_wide, $scalar_narrow, $scalar_wide),
)*);
crate::high_level_api::integers::unsigned::fused_ops::impl_fused_scalar_mul_scalar_div!($(
($fhe_narrow, $fhe_wide, $scalar_narrow, $scalar_wide),
)*);
}
}
pub(crate) use impl_fused_mul_divs;
// Standard types (always available)
//
// (NarrowFhe, WideFhe, NarrowScalar, WideScalar)
//
// Types without at least double-width FheUint (FheUint2048) are not supported.
impl_fused_mul_divs!(
(super::FheUint2, super::FheUint4, u8, u8),
(super::FheUint4, super::FheUint8, u8, u8),
(super::FheUint6, super::FheUint12, u8, u16),
(super::FheUint8, super::FheUint16, u8, u16),
(super::FheUint10, super::FheUint32, u16, u32),
(super::FheUint12, super::FheUint32, u16, u32),
(super::FheUint14, super::FheUint32, u16, u32),
(super::FheUint16, super::FheUint32, u16, u32),
(super::FheUint32, super::FheUint64, u32, u64),
(super::FheUint64, super::FheUint128, u64, u128),
(super::FheUint128, super::FheUint256, u128, U256),
(super::FheUint160, super::FheUint512, U256, U512),
(super::FheUint256, super::FheUint512, U256, U512),
(super::FheUint512, super::FheUint1024, U512, U1024),
(super::FheUint1024, super::FheUint2048, U1024, U2048),
);
#[cfg(feature = "extended-types")]
impl_fused_mul_divs!(
(super::FheUint24, super::FheUint48, u32, u64),
(super::FheUint40, super::FheUint80, u64, u128),
(super::FheUint48, super::FheUint96, u64, u128),
(super::FheUint56, super::FheUint112, u64, u128),
(super::FheUint72, super::FheUint144, u128, U256),
(super::FheUint80, super::FheUint160, u128, U256),
(super::FheUint88, super::FheUint176, u128, U256),
(super::FheUint96, super::FheUint192, u128, U256),
(super::FheUint104, super::FheUint208, u128, U256),
(super::FheUint112, super::FheUint224, u128, U256),
(super::FheUint120, super::FheUint240, u128, U256),
(super::FheUint136, super::FheUint512, U256, U512),
(super::FheUint144, super::FheUint512, U256, U512),
(super::FheUint152, super::FheUint512, U256, U512),
(super::FheUint168, super::FheUint512, U256, U512),
(super::FheUint176, super::FheUint512, U256, U512),
(super::FheUint184, super::FheUint512, U256, U512),
(super::FheUint192, super::FheUint512, U256, U512),
(super::FheUint200, super::FheUint512, U256, U512),
(super::FheUint208, super::FheUint512, U256, U512),
(super::FheUint216, super::FheUint512, U256, U512),
(super::FheUint224, super::FheUint512, U256, U512),
(super::FheUint232, super::FheUint512, U256, U512),
(super::FheUint240, super::FheUint512, U256, U512),
(super::FheUint248, super::FheUint512, U256, U512),
);

View File

@@ -32,6 +32,7 @@ mod squashed_noise;
mod static_;
mod encrypt;
pub(in crate::high_level_api) mod fused_ops;
mod inner;
mod ops;
mod overflowing_ops;

View File

@@ -703,3 +703,9 @@ fn test_match_value_or() {
let client_key = setup_default_cpu();
super::test_case_match_value_or(&client_key);
}
#[test]
fn test_uint16_fused_mul_div() {
let client_key = setup_default_cpu();
super::test_case_uint16_fused_mul_div(&client_key);
}

View File

@@ -33,6 +33,7 @@ pub(crate) fn setup_gpu(params: Option<impl Into<TestParameters>>) -> ClientKey
.map_or_else(ConfigBuilder::default, |p| {
ConfigBuilder::with_custom_parameters(p.into())
})
.use_dedicated_oprf_key(true)
.build();
let client_key = ClientKey::generate(config);
@@ -1004,3 +1005,11 @@ fn test_gpu_get_match_value_or_size_on_gpu() {
assert!(memory_size > 0);
}
}
#[test]
fn test_uint16_fused_mul_div_gpu() {
for setup_fn in GPU_SETUP_FN {
let client_key = setup_fn();
super::test_case_uint16_fused_mul_div(&client_key);
}
}

View File

@@ -1,7 +1,9 @@
use crate::high_level_api::traits::BitSlice;
use crate::integer::U256;
use crate::prelude::*;
use crate::{ClientKey, FheBool, FheUint256, FheUint32, FheUint64, FheUint8, MatchValues};
use crate::{
ClientKey, FheBool, FheUint16, FheUint256, FheUint32, FheUint64, FheUint8, MatchValues,
};
use rand::{thread_rng, Rng};
use std::collections::HashMap;
@@ -910,3 +912,66 @@ fn test_case_match_value_or(cks: &ClientKey) {
);
}
}
fn test_case_uint16_fused_mul_div(cks: &ClientKey) {
let mut rng = rand::thread_rng();
// Widening prevents incorrect result:
// 300 * 300 = 90_000 which overflows u16 (max 65_535),
// but with widening: 90_000 / 100 = 900, correct.
{
let input = 300u16;
let mul = 300u16;
let div = 100u16;
let expected = 900u16;
let a = FheUint16::try_encrypt(input, cks).unwrap();
let b = FheUint16::try_encrypt(mul, cks).unwrap();
let result = (&a).fused_mul_scalar_div(&b, div);
let decrypted: u16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
let result = (&a).fused_scalar_mul_scalar_div(mul, div);
let decrypted: u16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
}
for _ in 0..5 {
let clear_a: u16 = rng.gen();
let clear_b: u16 = rng.gen();
let clear_c: u16 = rng.gen_range(1..=u16::MAX);
let a = FheUint16::try_encrypt(clear_a, cks).unwrap();
let b = FheUint16::try_encrypt(clear_b, cks).unwrap();
let expected = (u32::from(clear_a) * u32::from(clear_b) / u32::from(clear_c)) as u16;
// encrypted * encrypted / scalar
{
let result = (&a).fused_mul_scalar_div(&b, clear_c);
let decrypted: u16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
}
// encrypted * scalar / scalar
{
let result = (&a).fused_scalar_mul_scalar_div(clear_b, clear_c);
let decrypted: u16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
}
// Owned variants
{
let result = a.fused_mul_scalar_div(b, clear_c);
let decrypted: u16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
// Need to encrypt again since "a" was consumed above
let a = FheUint16::try_encrypt(clear_a, cks).unwrap();
let result = a.fused_scalar_mul_scalar_div(clear_b, clear_c);
let decrypted: u16 = result.decrypt(cks);
assert_eq!(decrypted, expected);
}
}
}

View File

@@ -10,6 +10,7 @@ use crate::high_level_api::SquashedNoiseCiphertextState;
use crate::integer::ciphertext::NoiseSquashingCompressionPrivateKey;
use crate::integer::compression_keys::CompressionPrivateKeys;
use crate::integer::noise_squashing::{NoiseSquashingPrivateKey, NoiseSquashingPrivateKeyView};
use crate::integer::oprf::OprfPrivateKey;
use crate::named::Named;
use crate::prelude::Tagged;
use crate::shortint::parameters::ReRandomizationParameters;
@@ -88,12 +89,14 @@ impl ClientKey {
Option<NoiseSquashingPrivateKey>,
Option<NoiseSquashingCompressionPrivateKey>,
Option<ReRandomizationParameters>,
Option<OprfPrivateKey>,
Tag,
) {
let (cks, cpk, cppk, nsk, nscpk, cpkrndp) = self.key.into_raw_parts();
(cks, cpk, cppk, nsk, nscpk, cpkrndp, self.tag)
let (cks, cpk, cppk, nsk, nscpk, cpkrndp, oprf) = self.key.into_raw_parts();
(cks, cpk, cppk, nsk, nscpk, cpkrndp, oprf, self.tag)
}
#[allow(clippy::too_many_arguments)]
pub fn from_raw_parts(
key: crate::integer::ClientKey,
dedicated_compact_private_key: Option<(
@@ -104,6 +107,7 @@ impl ClientKey {
noise_squashing_key: Option<NoiseSquashingPrivateKey>,
noise_squashing_compression_key: Option<NoiseSquashingCompressionPrivateKey>,
cpk_re_randomization_params: Option<ReRandomizationParameters>,
oprf_private_key: Option<OprfPrivateKey>,
tag: Tag,
) -> Self {
Self {
@@ -114,6 +118,7 @@ impl ClientKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_params,
oprf_private_key,
),
tag,
}

View File

@@ -17,6 +17,7 @@ use crate::high_level_api::keys::inner::CudaReRandomizationKey;
use crate::integer::compression_keys::CompressedDecompressionKey;
use crate::integer::noise_squashing::CompressedNoiseSquashingKey;
use crate::integer::oprf::ExpandedOprfServerKey;
use crate::shortint::atomic_pattern::expanded::{
ExpandedAtomicPatternServerKey, ExpandedKS32AtomicPatternServerKey,
ExpandedStandardAtomicPatternServerKey,
@@ -43,6 +44,7 @@ pub struct IntegerExpandedServerKey {
pub noise_squashing_key: Option<ExpandedNoiseSquashingKey>,
pub noise_squashing_compression_key: Option<NoiseSquashingCompressionKey>,
pub cpk_re_randomization_key: Option<ReRandomizationKey>,
pub oprf_key: Option<ExpandedOprfServerKey>,
}
impl IntegerExpandedServerKey {
@@ -63,6 +65,7 @@ impl IntegerExpandedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
} = self;
let atomic_pattern_key = match compute_key.atomic_pattern {
@@ -138,6 +141,8 @@ impl IntegerExpandedServerKey {
)
});
let oprf_key = oprf_key.map(|oprf_key| oprf_key.to_fourier());
IntegerServerKey {
key,
cpk_key_switching_key_material,
@@ -146,6 +151,7 @@ impl IntegerExpandedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
}
}
}
@@ -175,6 +181,7 @@ impl IntegerExpandedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
} = self;
let key = CudaServerKey::from_expanded_server_key(compute_key, streams)?;
@@ -239,6 +246,10 @@ impl IntegerExpandedServerKey {
}
});
let oprf_key = oprf_key.as_ref().map(|expanded_oprf_key| {
crate::integer::gpu::CudaOprfServerKey::from_expanded_cpu(expanded_oprf_key, streams)
});
Ok(crate::high_level_api::keys::inner::IntegerCudaServerKey {
key,
cpk_key_switching_key_material,
@@ -247,6 +258,7 @@ impl IntegerExpandedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
})
}
}

View File

@@ -21,6 +21,7 @@ use crate::integer::compression_keys::{
use crate::integer::noise_squashing::{
CompressedNoiseSquashingKey, NoiseSquashingKey, NoiseSquashingPrivateKey,
};
use crate::integer::oprf::{CompressedOprfServerKey, OprfPrivateKey, OprfServerKey};
use crate::integer::public_key::CompactPublicKey;
use crate::integer::CompressedCompactPublicKey;
use crate::shortint::atomic_pattern::AtomicPatternParameters;
@@ -48,6 +49,8 @@ pub(crate) struct IntegerConfig {
pub(crate) noise_squashing_parameters: Option<NoiseSquashingParameters>,
pub(crate) noise_squashing_compression_parameters: Option<NoiseSquashingCompressionParameters>,
pub(crate) cpk_re_randomization_params: Option<ReRandomizationParameters>,
// Oprf uses the same parameters as the bootstrap key from the block_parameters
pub(crate) dedicated_oprf_key: bool,
}
impl IntegerConfig {
@@ -61,6 +64,7 @@ impl IntegerConfig {
noise_squashing_parameters: None,
noise_squashing_compression_parameters: None,
cpk_re_randomization_params: None,
dedicated_oprf_key: true,
}
}
@@ -121,6 +125,11 @@ impl IntegerConfig {
self.cpk_re_randomization_params = Some(cpk_re_randomization_params);
}
/// Whether to use a dedicated key for the OPRF (default) or not
pub(crate) fn use_dedicated_oprf_key(&mut self, enabled: bool) {
self.dedicated_oprf_key = enabled;
}
pub(crate) fn public_key_encryption_parameters(
&self,
) -> Result<crate::shortint::parameters::CompactPublicKeyEncryptionParameters, crate::Error>
@@ -149,6 +158,7 @@ impl Default for IntegerConfig {
noise_squashing_parameters: None,
noise_squashing_compression_parameters: None,
cpk_re_randomization_params: None,
dedicated_oprf_key: true,
}
}
}
@@ -171,6 +181,7 @@ pub(crate) struct IntegerClientKey {
// compact private key and the post PBS secret key, it needs additional information on how
// to create the required key switching key.
pub(crate) cpk_re_randomization_params: Option<ReRandomizationParameters>,
pub(crate) dedicated_oprf_private_key: Option<OprfPrivateKey>,
}
impl IntegerClientKey {
@@ -185,8 +196,13 @@ impl IntegerClientKey {
first_index: tfhe_csprng::generators::aes_ctr::TableIndex::SECOND,
};
let mut seeder = DeterministicSeeder::<DefaultRandomGenerator>::new(aes_ctr_params);
let cks = crate::shortint::engine::ShortintEngine::new_from_seeder(&mut seeder)
.new_client_key(config.block_parameters);
let mut engine = crate::shortint::engine::ShortintEngine::new_from_seeder(&mut seeder);
let cks = engine.new_client_key(config.block_parameters);
let previous_engine =
crate::shortint::engine::ShortintEngine::with_thread_local_mut(|local_engine| {
std::mem::replace(local_engine, engine)
});
let key = crate::integer::ClientKey::from(cks);
@@ -208,6 +224,13 @@ impl IntegerClientKey {
let cpk_re_randomization_params = config.cpk_re_randomization_params;
let dedicated_oprf_private_key =
config.dedicated_oprf_key.then(|| OprfPrivateKey::new(&key));
crate::shortint::engine::ShortintEngine::with_thread_local_mut(|local_engine| {
*local_engine = previous_engine;
});
Self {
key,
dedicated_compact_private_key,
@@ -215,6 +238,7 @@ impl IntegerClientKey {
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_params,
dedicated_oprf_private_key,
}
}
@@ -229,6 +253,7 @@ impl IntegerClientKey {
Option<NoiseSquashingPrivateKey>,
Option<NoiseSquashingCompressionPrivateKey>,
Option<ReRandomizationParameters>,
Option<OprfPrivateKey>,
) {
let Self {
key,
@@ -237,6 +262,7 @@ impl IntegerClientKey {
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_params,
dedicated_oprf_private_key,
} = self;
(
key,
@@ -245,6 +271,7 @@ impl IntegerClientKey {
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_params,
dedicated_oprf_private_key,
)
}
@@ -260,6 +287,7 @@ impl IntegerClientKey {
noise_squashing_private_key: Option<NoiseSquashingPrivateKey>,
noise_squashing_compression_private_key: Option<NoiseSquashingCompressionPrivateKey>,
cpk_re_randomization_params: Option<ReRandomizationParameters>,
dedicated_oprf_private_key: Option<OprfPrivateKey>,
) -> Self {
let shortint_cks: &crate::shortint::ClientKey = key.as_ref();
@@ -289,6 +317,7 @@ impl IntegerClientKey {
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_params,
dedicated_oprf_private_key,
}
}
@@ -366,6 +395,9 @@ impl From<IntegerConfig> for IntegerClientKey {
let cpk_re_randomization_params = config.cpk_re_randomization_params;
let dedicated_oprf_private_key =
config.dedicated_oprf_key.then(|| OprfPrivateKey::new(&key));
Self {
key,
dedicated_compact_private_key,
@@ -373,6 +405,7 @@ impl From<IntegerConfig> for IntegerClientKey {
noise_squashing_private_key,
noise_squashing_compression_private_key,
cpk_re_randomization_params,
dedicated_oprf_private_key,
}
}
}
@@ -392,6 +425,7 @@ pub struct IntegerServerKey {
pub(crate) noise_squashing_key: Option<NoiseSquashingKey>,
pub(crate) noise_squashing_compression_key: Option<NoiseSquashingCompressionKey>,
pub(crate) cpk_re_randomization_key: Option<ReRandomizationKey>,
pub(crate) oprf_key: Option<OprfServerKey>,
}
impl IntegerServerKey {
@@ -474,6 +508,13 @@ impl IntegerServerKey {
}
});
let oprf_key = client_key
.dedicated_oprf_private_key
.as_ref()
.map(|oprf_pk| OprfServerKey::new(oprf_pk, &client_key.key))
.transpose()
.expect("Failed to create the server key for the oprf");
Self {
key: base_integer_key,
cpk_key_switching_key_material,
@@ -482,6 +523,7 @@ impl IntegerServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
}
}
@@ -566,6 +608,7 @@ pub struct IntegerCudaServerKey {
crate::integer::gpu::list_compression::server_keys::CudaNoiseSquashingCompressionKey,
>,
pub(crate) cpk_re_randomization_key: Option<CudaReRandomizationKey>,
pub(crate) oprf_key: Option<crate::integer::gpu::CudaOprfServerKey>,
}
#[cfg(feature = "gpu")]
@@ -626,6 +669,7 @@ pub struct IntegerCompressedServerKey {
pub(crate) noise_squashing_key: Option<CompressedNoiseSquashingKey>,
pub(crate) noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
pub(crate) cpk_re_randomization_key: Option<CompressedReRandomizationKey>,
pub(crate) oprf_key: Option<CompressedOprfServerKey>,
}
impl IntegerCompressedServerKey {
@@ -713,6 +757,14 @@ impl IntegerCompressedServerKey {
}
});
let oprf_key = client_key
.dedicated_oprf_private_key
.as_ref()
.map(|oprf_private_key| {
CompressedOprfServerKey::new(oprf_private_key, &client_key.key)
.expect("Failed to create the OPRF key")
});
Self {
key,
cpk_key_switching_key_material,
@@ -721,6 +773,7 @@ impl IntegerCompressedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
}
}
@@ -735,6 +788,7 @@ impl IntegerCompressedServerKey {
Option<CompressedNoiseSquashingKey>,
Option<CompressedNoiseSquashingCompressionKey>,
Option<CompressedReRandomizationKey>,
Option<CompressedOprfServerKey>,
) {
let Self {
key,
@@ -744,6 +798,7 @@ impl IntegerCompressedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
} = self;
(
@@ -754,9 +809,11 @@ impl IntegerCompressedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
)
}
#[allow(clippy::too_many_arguments)]
pub fn from_raw_parts(
key: crate::integer::CompressedServerKey,
cpk_key_switching_key_material: Option<
@@ -767,6 +824,7 @@ impl IntegerCompressedServerKey {
noise_squashing_key: Option<CompressedNoiseSquashingKey>,
noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
cpk_re_randomization_key: Option<CompressedReRandomizationKey>,
oprf_key: Option<CompressedOprfServerKey>,
) -> Self {
Self {
key,
@@ -776,6 +834,7 @@ impl IntegerCompressedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
}
}
@@ -803,6 +862,7 @@ impl IntegerCompressedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
} = self;
// Expand the main server key (compute key)
@@ -833,6 +893,8 @@ impl IntegerCompressedServerKey {
let cpk_re_randomization_key = cpk_re_randomization_key.as_ref().map(|k| k.decompress());
let oprf_key = oprf_key.as_ref().map(|k| k.expand());
IntegerExpandedServerKey {
compute_key,
cpk_key_switching_key_material,
@@ -841,6 +903,7 @@ impl IntegerCompressedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
}
}
}
@@ -931,6 +994,7 @@ pub struct IntegerServerKeyConformanceParams {
pub noise_squashing_param: Option<NoiseSquashingParameters>,
pub noise_squashing_compression_param: Option<NoiseSquashingCompressionParameters>,
pub cpk_re_randomization_params: Option<ReRandomizationParameters>,
pub dedicated_oprf_key: bool,
}
impl<C: Into<Config>> From<C> for IntegerServerKeyConformanceParams {
@@ -943,6 +1007,7 @@ impl<C: Into<Config>> From<C> for IntegerServerKeyConformanceParams {
noise_squashing_param: config.inner.noise_squashing_parameters,
noise_squashing_compression_param: config.inner.noise_squashing_compression_parameters,
cpk_re_randomization_params: config.inner.cpk_re_randomization_params,
dedicated_oprf_key: config.inner.dedicated_oprf_key,
}
}
}
@@ -1008,6 +1073,7 @@ impl ParameterSetConformant for IntegerServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
} = self;
let cpk_key_switching_key_material_is_ok = match (
@@ -1128,12 +1194,24 @@ impl ParameterSetConformant for IntegerServerKey {
}
};
let oprf_is_ok = match (parameter_set.dedicated_oprf_key, oprf_key.as_ref()) {
// We have to have a dedicated oprf key
// Make sure it's there and that it's conformant
(true, Some(key)) => key.is_conformant(&parameter_set.sk_param),
(true, None) => false,
// The config says to not use a dedicated oprf key but we have one
// while it works, it is not strictly conformant
(false, Some(_)) => false,
(false, None) => true,
};
key.is_conformant(&parameter_set.sk_param)
&& cpk_key_switching_key_material_is_ok
&& compression_is_ok
&& noise_squashing_key_is_ok
&& noise_squashing_compression_key_is_ok
&& re_randomization_keys_are_ok
&& oprf_is_ok
}
}
@@ -1149,6 +1227,7 @@ impl ParameterSetConformant for IntegerCompressedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
} = self;
let cpk_key_switching_key_material_is_ok = match (
@@ -1271,12 +1350,24 @@ impl ParameterSetConformant for IntegerCompressedServerKey {
}
};
let oprf_is_ok = match (parameter_set.dedicated_oprf_key, oprf_key.as_ref()) {
// We have to have a dedicated oprf key
// Make sure it's there and that it's conformant
(true, Some(key)) => key.is_conformant(&parameter_set.sk_param),
(true, None) => false,
// The config says to not use a dedicated oprf key but we have one
// while it works, it is not strictly conformant
(false, Some(_)) => false,
(false, None) => true,
};
key.is_conformant(&parameter_set.sk_param)
&& cpk_key_switching_key_material_is_ok
&& compression_is_ok
&& noise_squashing_key_is_ok
&& noise_squashing_compression_key_is_ok
&& re_randomization_keys_are_ok
&& oprf_is_ok
}
}

View File

@@ -21,6 +21,7 @@ use crate::integer::compression_keys::{
#[cfg(feature = "gpu")]
use crate::integer::gpu::ciphertext::re_randomization::CudaReRandomizationKey as IntegerCudaReRandomizationKey;
use crate::integer::noise_squashing::{CompressedNoiseSquashingKey, NoiseSquashingKey};
use crate::integer::oprf::{CompressedOprfServerKey, OprfServerKey, OprfServerKeyView};
use crate::integer::parameters::IntegerCompactCiphertextListExpansionMode;
use crate::integer::public_key::compact::CompactPublicKey;
use crate::named::Named;
@@ -85,6 +86,7 @@ impl ServerKey {
Option<NoiseSquashingKey>,
Option<NoiseSquashingCompressionKey>,
Option<ReRandomizationKey>,
Option<OprfServerKey>,
Tag,
) {
let IntegerServerKey {
@@ -95,6 +97,7 @@ impl ServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
} = (*self.key).clone();
(
@@ -105,6 +108,7 @@ impl ServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
self.tag,
)
}
@@ -120,6 +124,7 @@ impl ServerKey {
noise_squashing_key: Option<NoiseSquashingKey>,
noise_squashing_compression_key: Option<NoiseSquashingCompressionKey>,
cpk_re_randomization_key: Option<ReRandomizationKey>,
oprf_key: Option<OprfServerKey>,
tag: Tag,
) -> Self {
Self {
@@ -131,6 +136,7 @@ impl ServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
}),
tag,
}
@@ -140,6 +146,17 @@ impl ServerKey {
self.key.pbs_key()
}
/// Returns an OPRF key reference for pseudo-random generation.
///
/// If a dedicated OPRF key was generated, it is used.
/// Otherwise, falls back to the compute server key's bootstrapping key.
pub(in crate::high_level_api) fn oprf_key(&self) -> OprfServerKeyView<'_> {
self.key.oprf_key.as_ref().map_or_else(
|| self.pbs_key().as_oprf_key_view(),
|dedicated| dedicated.as_view(),
)
}
#[cfg(feature = "strings")]
pub(in crate::high_level_api) fn string_key(&self) -> crate::strings::ServerKeyRef<'_> {
crate::strings::ServerKeyRef::new(self.key.pbs_key())
@@ -269,6 +286,10 @@ impl ServerKey {
self.key.compression_key.is_some()
}
pub fn supports_oprf(&self) -> bool {
true
}
pub(in crate::high_level_api) fn message_modulus(&self) -> MessageModulus {
self.key.message_modulus()
}
@@ -393,10 +414,11 @@ impl CompressedServerKey {
Option<CompressedNoiseSquashingKey>,
Option<CompressedNoiseSquashingCompressionKey>,
Option<CompressedReRandomizationKey>,
Option<CompressedOprfServerKey>,
Tag,
) {
let (a, b, c, d, e, f, g) = self.integer_key.into_raw_parts();
(a, b, c, d, e, f, g, self.tag)
let (a, b, c, d, e, f, g, h) = self.integer_key.into_raw_parts();
(a, b, c, d, e, f, g, h, self.tag)
}
#[allow(clippy::too_many_arguments)]
@@ -410,6 +432,7 @@ impl CompressedServerKey {
noise_squashing_key: Option<CompressedNoiseSquashingKey>,
noise_squashing_compression_key: Option<CompressedNoiseSquashingCompressionKey>,
cpk_re_randomization_key: Option<CompressedReRandomizationKey>,
oprf_key: Option<CompressedOprfServerKey>,
tag: Tag,
) -> Self {
Self {
@@ -421,6 +444,7 @@ impl CompressedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
),
tag,
}
@@ -497,6 +521,17 @@ impl CudaServerKey {
}
}
pub(crate) fn oprf_key(&self) -> crate::integer::gpu::CudaOprfServerKeyView<'_> {
self.key.oprf_key.as_ref().map_or_else(
|| {
crate::integer::gpu::GenericCudaOprfServerKey::from_borrowed_bsk(
&self.key.key.bootstrapping_key,
)
},
|dedicated| dedicated.as_view(),
)
}
pub fn gpu_indexes(&self) -> &[GpuIndex] {
match &self.key.key.key_switching_key {
CudaDynamicKeyswitchingKey::KeySwitch32(ksk_32) => ksk_32.d_vec.gpu_indexes.as_slice(),
@@ -857,6 +892,7 @@ mod test {
noise_squashing_param: None,
noise_squashing_compression_param: None,
cpk_re_randomization_params: None,
dedicated_oprf_key: true,
};
assert!(!sk.is_conformant(&conformance_params));
@@ -887,6 +923,7 @@ mod test {
noise_squashing_param: None,
noise_squashing_compression_param: None,
cpk_re_randomization_params: None,
dedicated_oprf_key: true,
};
assert!(!sk.is_conformant(&conformance_params));
@@ -1024,6 +1061,7 @@ mod test {
noise_squashing_param: None,
noise_squashing_compression_param: None,
cpk_re_randomization_params: None,
dedicated_oprf_key: true,
};
assert!(!sk.is_conformant(&conformance_params));
@@ -1054,9 +1092,34 @@ mod test {
noise_squashing_param: None,
noise_squashing_compression_param: None,
cpk_re_randomization_params: None,
dedicated_oprf_key: true,
};
assert!(!sk.is_conformant(&conformance_params));
}
{
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(params)
.use_dedicated_oprf_key(false)
.build();
let ck = ClientKey::generate(config);
let sk = CompressedServerKey::new(&ck);
let sk_param = params.into();
let mut conformance_params = IntegerServerKeyConformanceParams {
sk_param,
cpk_param: None,
compression_param: None,
noise_squashing_param: None,
noise_squashing_compression_param: None,
cpk_re_randomization_params: None,
dedicated_oprf_key: true,
};
assert!(!sk.is_conformant(&conformance_params));
conformance_params.dedicated_oprf_key = false;
assert!(sk.is_conformant(&conformance_params));
}
}
}

View File

@@ -47,9 +47,11 @@ macro_rules! export_concrete_array_types {
};
}
pub use crate::core_crypto::commons::math::random::{Seed, XofSeed};
pub use crate::core_crypto::commons::math::random::{Seed, Seeder, XofSeed};
pub use crate::high_level_api::integers::oprf::RangeForRandom;
pub use crate::high_level_api::integers::shuffle::bitonic_shuffle;
pub use crate::integer::server_key::MatchValues;
pub use crate::shortint::OprfSeed;
use crate::{error, Error, Versionize};
use backward_compatibility::compressed_ciphertext_list::SquashedNoiseCiphertextStateVersions;
pub use config::{Config, ConfigBuilder};
@@ -107,9 +109,9 @@ expand_pub_use_fhe_type!(
};
);
pub use array::{
ClearArray, CpuFheIntArray, CpuFheIntSlice, CpuFheIntSliceMut, CpuFheUintArray,
CpuFheUintSlice, CpuFheUintSliceMut, FheBoolId, FheIntArray, FheIntSlice, FheIntSliceMut,
FheUintArray, FheUintSlice, FheUintSliceMut,
fhe_array_contains, ClearArray, CpuFheIntArray, CpuFheIntSlice, CpuFheIntSliceMut,
CpuFheUintArray, CpuFheUintSlice, CpuFheUintSliceMut, FheBoolId, FheIntArray, FheIntSlice,
FheIntSliceMut, FheUintArray, FheUintSlice, FheUintSliceMut,
};
export_concrete_array_types!(
pub use array{

View File

@@ -8,10 +8,10 @@
//! ```
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,
FheOrd, FheTrivialEncrypt, FheTryEncrypt, FheTryTrivialEncrypt, FheWait, Flip,
FusedMulScalarDiv, FusedScalarMulScalarDiv, IfThenElse, IfThenZero, 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

@@ -325,6 +325,121 @@ fn execute_re_rand_test(cks: &ClientKey, cpk: &CompactPublicKey) {
}
}
#[cfg(feature = "zk-pok")]
mod zk {
use super::*;
use crate::high_level_api::{FheInt64, FheUint32};
use crate::zk::{CompactPkeCrs, ZkComputeLoad};
use crate::{Config, ProvenCompactCiphertextList};
#[test]
fn test_compact_list_re_rand() {
use crate::shortint::parameters::test_params::TEST_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
let params = TEST_META_PARAM_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());
let config = Config::from(params);
let compact_public_encryption_domain_separator = *b"TFHE_Enc";
let rerand_domain_separator = *b"TFHE_Rrd";
// Intentionally low so that we test when multiple lists and proofs are needed
let crs = CompactPkeCrs::from_config(config, 32).unwrap();
let metadata = [b'r', b'e', b'r', b'a', b'n', b'd'];
// Case where we want to re-randomize a CompactCiphertextList containing
// FheUint64, FheInt8, and FheBool
{
let clear_a = rand::random::<u64>();
let clear_b = rand::random::<i8>();
let compact_list = ProvenCompactCiphertextList::builder(&cpk)
.push(clear_a)
.push(clear_b)
.push(false)
.build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)
.unwrap();
// Simulate a 256 bits nonce
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let mut re_rand_context = ReRandomizationContext::new(
rerand_domain_separator,
[b"expand".as_slice(), nonce.as_slice()],
compact_public_encryption_domain_separator,
);
// Add the compact list to the context
re_rand_context.add_ciphertext(&compact_list);
let mut seed_gen = re_rand_context.finalize();
// Verify, re_randomize and expand
let expander = compact_list
.verify_re_randomize_and_expand(
&crs,
&cpk,
&metadata,
seed_gen.next_seed().unwrap(),
)
.unwrap();
let a: FheUint64 = expander.get(0).unwrap().unwrap();
let b: FheInt8 = expander.get(1).unwrap().unwrap();
let c: FheBool = expander.get(2).unwrap().unwrap();
let dec_a: u64 = a.decrypt(&cks);
assert_eq!(dec_a, clear_a);
let dec_b: i8 = b.decrypt(&cks);
assert_eq!(dec_b, clear_b);
let dec_c: bool = c.decrypt(&cks);
assert!(!dec_c);
}
// Also test expand_and_re_randomize_without_verification
{
let clear_a = rand::random::<u32>();
let clear_b = rand::random::<i64>();
let compact_list = ProvenCompactCiphertextList::builder(&cpk)
.push(clear_a)
.push(clear_b)
.push(false)
.build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)
.unwrap();
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
let mut re_rand_context = ReRandomizationContext::new(
rerand_domain_separator,
[b"expand".as_slice(), nonce.as_slice()],
compact_public_encryption_domain_separator,
);
re_rand_context.add_ciphertext(&compact_list);
let mut seed_gen = re_rand_context.finalize();
let expander = compact_list
.re_randomize_and_expand_without_verification(&cpk, seed_gen.next_seed().unwrap())
.unwrap();
let a: FheUint32 = expander.get(0).unwrap().unwrap();
let b: FheInt64 = expander.get(1).unwrap().unwrap();
let c: FheBool = expander.get(2).unwrap().unwrap();
let dec_a: u32 = a.decrypt(&cks);
assert_eq!(dec_a, clear_a);
let dec_b: i64 = b.decrypt(&cks);
assert_eq!(dec_b, clear_b);
let dec_c: bool = c.decrypt(&cks);
assert!(!dec_c);
}
}
}
fn setup_re_rand_test(
mut params: MetaParameters,
) -> (crate::ClientKey, CompressedServerKey, CompactPublicKey) {

View File

@@ -126,9 +126,13 @@ fn test_server_key_decompression() -> Result<(), Box<dyn std::error::Error>> {
#[test]
fn test_with_seed() {
use crate::shortint::parameters::test_params::TEST_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
use crate::Seed;
let builder = ConfigBuilder::default();
let config = builder.build();
// Use the most complete meta-params available so that the seed-determinism check
// covers every optional key in the config
let config =
crate::Config::from(TEST_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128);
let cks1 = ClientKey::generate_with_seed(config, Seed(125));
let cks2 = ClientKey::generate(config);
@@ -205,6 +209,7 @@ fn test_try_from_single_lwe_encryption_key() {
None,
None,
None,
None,
Tag::default(),
);
let sks = ServerKey::new(&client_key);

View File

@@ -139,6 +139,30 @@ pub trait DivRem<Rhs = Self> {
fn div_rem(self, amount: Rhs) -> Self::Output;
}
/// Computes `(self * mul) / div_scalar` where `self` and `mul` are encrypted and `div_scaalr` is a
/// plaintext divisor.
///
/// The intermediate multiplication is performed to have the exact result without overflowing.
/// The final result is truncated back to the original width, which may wrap if the full precision
/// division result does not fit in the original type.
pub trait FusedMulScalarDiv<Mul, DivScalar> {
type Output;
fn fused_mul_scalar_div(self, mul: Mul, div_scalar: DivScalar) -> Self::Output;
}
/// Computes `(self * mul_scalar) / div_scalar` where `self` is encrypted and both scalars are
/// plaintext.
///
/// The intermediate multiplication is performed to have the exact result without overflowing.
/// The final result is truncated back to the original width, which may wrap if the full precision
/// division result does not fit in the original type.
pub trait FusedScalarMulScalarDiv<Scalar> {
type Output;
fn fused_scalar_mul_scalar_div(self, mul_scalar: Scalar, div_scalar: Scalar) -> Self::Output;
}
pub trait IfThenElse<Ciphertext> {
fn if_then_else(&self, ct_then: &Ciphertext, ct_else: &Ciphertext) -> Ciphertext;
fn select(&self, ct_when_true: &Ciphertext, ct_when_false: &Ciphertext) -> Ciphertext {

View File

@@ -828,8 +828,10 @@ mod tests {
// We need the private compression key to be common between GPU and CPU
// for the rest of the test to work. This is the only way to do it
// until a more convenient API is added
let (cks, pk, _, nsk, cnsk, cpkrndp, tag) = ck.into_raw_parts();
let ck = ClientKey::from_raw_parts(cks, pk, common_cck, nsk, cnsk, cpkrndp, tag);
let (cks, pk, _, nsk, cnsk, cpkrndp, oprf_key, tag) = ck.into_raw_parts();
let ck = ClientKey::from_raw_parts(
cks, pk, common_cck, nsk, cnsk, cpkrndp, oprf_key, tag,
);
let sk = CompressedServerKey::new(&ck);
assert_eq!(sk.tag().as_u64(), 0);

View File

@@ -11,6 +11,7 @@ use crate::integer::key_switching_key::{
};
use crate::integer::noise_squashing::{CompressedNoiseSquashingKey, NoiseSquashingPrivateKey};
use crate::integer::oprf::{CompressedOprfServerKey, ExpandedOprfServerKey, OprfPrivateKey};
use crate::shortint::atomic_pattern::compressed::{
CompressedAtomicPatternServerKey, CompressedKS32AtomicPatternServerKey,
CompressedStandardAtomicPatternServerKey,
@@ -154,6 +155,44 @@ impl crate::integer::ClientKey {
}
}
impl OprfPrivateKey {
fn generate_with_pre_seeded_generator<G>(
params: AtomicPatternParameters,
max_norm_hwt: NormalizedHammingWeightBound,
secret_generator: &mut SecretRandomGenerator<G>,
) -> Self
where
G: ByteRandomGenerator,
{
let sk = match params {
shortint::AtomicPatternParameters::Standard(std_params) => {
let mut lwe_secret_key =
LweSecretKey::new_empty_key(0u64, std_params.lwe_dimension());
generate_binary_lwe_secret_key_with_bounded_hamming_weight(
&mut lwe_secret_key,
secret_generator,
max_norm_hwt,
);
crate::shortint::oprf::AtomicPatternOprfPrivateKey::Standard(lwe_secret_key)
}
shortint::AtomicPatternParameters::KeySwitch32(ks32_params) => {
let mut lwe_secret_key =
LweSecretKey::new_empty_key(0u32, ks32_params.lwe_dimension());
generate_binary_lwe_secret_key_with_bounded_hamming_weight(
&mut lwe_secret_key,
secret_generator,
max_norm_hwt,
);
crate::shortint::oprf::AtomicPatternOprfPrivateKey::KeySwitch32(lwe_secret_key)
}
};
Self::from_raw_parts(crate::shortint::oprf::OprfPrivateKey::from_raw_parts(sk))
}
}
impl crate::integer::compression_keys::CompressionPrivateKeys {
pub(super) fn generate_with_pre_seeded_generator<G>(
params: CompressionParameters,
@@ -276,6 +315,14 @@ impl ClientKey {
crate::integer::ciphertext::NoiseSquashingCompressionPrivateKey::generate_with_pre_seeded_generator(params, max_norm_hwt, secret_generator)
});
let dedicated_oprf_private_key = config.inner.dedicated_oprf_key.then(|| {
OprfPrivateKey::generate_with_pre_seeded_generator(
config.inner.block_parameters,
max_norm_hwt,
secret_generator,
)
});
Ok(Self {
key: crate::high_level_api::keys::IntegerClientKey {
key: integer_ck,
@@ -288,6 +335,7 @@ impl ClientKey {
noise_squashing_compression_private_key:
integer_private_noise_squashing_compression_key,
cpk_re_randomization_params: config.inner.cpk_re_randomization_params,
dedicated_oprf_private_key,
},
tag,
})
@@ -462,6 +510,12 @@ impl crate::CompressedServerKey {
.as_ref()
.map(|ns_comp_key| ns_comp_key.decompress_with_pre_seeded_generator(generator));
let oprf_key = self
.integer_key
.oprf_key
.as_ref()
.map(|key| key.decompress_with_pre_seeded_generator(generator));
IntegerExpandedServerKey {
compute_key,
cpk_key_switching_key_material,
@@ -470,6 +524,7 @@ impl crate::CompressedServerKey {
noise_squashing_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
}
}
}
@@ -626,6 +681,126 @@ impl integer::compression_keys::CompressedDecompressionKey {
}
}
impl CompressedOprfServerKey {
pub(super) fn generate_with_pre_seeded_generator<Gen>(
private_oprf_key: &OprfPrivateKey,
client_key: &crate::integer::ClientKey,
generator: &mut EncryptionRandomGenerator<Gen>,
) -> Self
where
Gen: ByteRandomGenerator + ParallelByteRandomGenerator,
{
use crate::shortint::oprf::CompressedOprfBootstrappingKey;
let inner = match (&private_oprf_key.0 .0, &client_key.key.atomic_pattern) {
(
crate::shortint::oprf::AtomicPatternOprfPrivateKey::Standard(oprf_lwe_sk),
AtomicPatternClientKey::Standard(ck),
) => match ck.parameters {
PBSParameters::PBS(pbs_params) => {
let seeded_bsk =
allocate_and_generate_lwe_bootstrapping_key_with_pre_seeded_generator(
oprf_lwe_sk,
&ck.glwe_secret_key,
pbs_params.pbs_base_log,
pbs_params.pbs_level,
pbs_params.glwe_noise_distribution,
pbs_params.ciphertext_modulus,
generator,
);
CompressedOprfBootstrappingKey::Classic { seeded_bsk }
}
PBSParameters::MultiBitPBS(mb_params) => {
let mut seeded_bsk = SeededLweMultiBitBootstrapKeyOwned::new(
0u64,
ck.glwe_secret_key.glwe_dimension().to_glwe_size(),
ck.glwe_secret_key.polynomial_size(),
mb_params.pbs_base_log,
mb_params.pbs_level,
oprf_lwe_sk.lwe_dimension(),
mb_params.grouping_factor,
generator.mask_generator().current_compression_seed(),
mb_params.ciphertext_modulus,
);
par_generate_seeded_lwe_multi_bit_bootstrap_key_with_pre_seeded_generator(
oprf_lwe_sk,
&ck.glwe_secret_key,
&mut seeded_bsk,
mb_params.glwe_noise_distribution,
generator,
);
CompressedOprfBootstrappingKey::MultiBit {
seeded_bsk,
deterministic_execution: true,
}
}
},
(
crate::shortint::oprf::AtomicPatternOprfPrivateKey::KeySwitch32(oprf_lwe_sk),
AtomicPatternClientKey::KeySwitch32(ck),
) => {
let seeded_bsk =
allocate_and_generate_lwe_bootstrapping_key_with_pre_seeded_generator(
oprf_lwe_sk,
&ck.glwe_secret_key,
ck.parameters.pbs_base_log,
ck.parameters.pbs_level,
ck.parameters.glwe_noise_distribution,
ck.parameters.ciphertext_modulus,
generator,
);
CompressedOprfBootstrappingKey::Classic { seeded_bsk }
}
_ => panic!("Mismatched atomic patterns for oprf key and client key"),
};
Self(crate::shortint::oprf::CompressedOprfServerKey { inner })
}
pub(super) fn decompress_with_pre_seeded_generator<Gen>(
&self,
generator: &mut MaskRandomGenerator<Gen>,
) -> ExpandedOprfServerKey
where
Gen: ByteRandomGenerator + ParallelByteRandomGenerator,
{
use crate::shortint::oprf::{CompressedOprfBootstrappingKey, ExpandedOprfBootstrappingKey};
let inner = match &self.0.inner {
CompressedOprfBootstrappingKey::Classic { seeded_bsk } => {
let bsk = decompress_bootstrap_key_with_pre_seeded_generator(seeded_bsk, generator);
ExpandedOprfBootstrappingKey::Classic { bsk }
}
CompressedOprfBootstrappingKey::MultiBit {
seeded_bsk,
deterministic_execution: _,
} => {
let bsk =
par_decompress_seeded_lwe_multi_bit_bootstrap_key_to_new_with_pre_seeded_generator(
seeded_bsk, generator,
);
let thread_count =
crate::shortint::engine::ShortintEngine::get_thread_count_for_multi_bit_pbs(
seeded_bsk.input_lwe_dimension(),
seeded_bsk.glwe_size().to_glwe_dimension(),
seeded_bsk.polynomial_size(),
seeded_bsk.decomposition_base_log(),
seeded_bsk.decomposition_level_count(),
seeded_bsk.grouping_factor(),
);
ExpandedOprfBootstrappingKey::MultiBit {
bsk,
thread_count,
deterministic_execution: true,
}
}
};
ExpandedOprfServerKey::from_raw_parts(crate::shortint::oprf::ExpandedOprfServerKey(inner))
}
}
impl CompressedNoiseSquashingKey {
pub(super) fn generate_with_pre_seeded_generator<Gen>(
private_noise_squashing_key: &integer::noise_squashing::NoiseSquashingPrivateKey,
@@ -832,7 +1007,7 @@ where
Self::MultiBit {
bsk,
thread_count,
deterministic_execution: params.deterministic_execution,
deterministic_execution: true,
}
}
}
@@ -875,7 +1050,7 @@ impl ShortintMultibitCompressedBootstrappingKeyParts {
Self {
core_bsk,
deterministic_execution: multibit_params.deterministic_execution,
deterministic_execution: true,
}
}
}
@@ -1085,7 +1260,7 @@ where
}
Self::MultiBit {
seeded_bsk,
deterministic_execution,
deterministic_execution: _,
} => {
let core_bsk = par_decompress_seeded_lwe_multi_bit_bootstrap_key_to_new_with_pre_seeded_generator(
seeded_bsk,
@@ -1105,7 +1280,7 @@ where
ShortintExpandedBootstrappingKey::MultiBit {
bsk: core_bsk,
thread_count,
deterministic_execution: *deterministic_execution,
deterministic_execution: true,
}
}
}
@@ -1142,7 +1317,7 @@ where
Self::MultiBit {
bsk,
thread_count,
deterministic_execution,
deterministic_execution: _,
} => {
let core_bsk = par_decompress_seeded_lwe_multi_bit_bootstrap_key_to_new_with_pre_seeded_generator(
bsk,
@@ -1152,7 +1327,7 @@ where
ShortintExpandedBootstrappingKey::MultiBit {
bsk: core_bsk,
thread_count: *thread_count,
deterministic_execution: *deterministic_execution,
deterministic_execution: true,
}
}
}

View File

@@ -6,6 +6,7 @@ use crate::backward_compatibility::xof_key_set::{
CompressedXofKeySetVersions, XofSeedStartVersions,
};
use crate::core_crypto::commons::generators::MaskRandomGenerator;
use crate::integer::oprf::CompressedOprfServerKey;
use crate::keys::{
CompressedReRandomizationKey, IntegerServerKeyConformanceParams, ReRandomizationKeyGenInfo,
};
@@ -57,6 +58,7 @@ use crate::high_level_api::keys::expanded::IntegerExpandedServerKey;
// else:
// - Re-Rand Public Key (stored in ServerKey) derived from compute params
// 11) SNS Compression Key
// 12) OPRF Key
/// Holds a [XofSeed] and the byte at which the random generator should start.
/// This maintains backward compatibility with tfhe-rs=1.5.4 (csprng=0.8.1)
@@ -359,6 +361,14 @@ impl CompressedXofKeySet {
},
);
let oprf_key = ck.key.dedicated_oprf_private_key.as_ref().map(|sk| {
CompressedOprfServerKey::generate_with_pre_seeded_generator(
sk,
&ck.key.key,
&mut encryption_rand_gen,
)
});
let compressed_server_key = CompressedServerKey::from_raw_parts(
integer_compressed_server_key,
Some(integer_ksk_material),
@@ -367,6 +377,7 @@ impl CompressedXofKeySet {
noise_squashing_bs_key,
noise_squashing_compression_key,
cpk_re_randomization_key,
oprf_key,
ck.tag.clone(),
);

View File

@@ -5,5 +5,6 @@ pub mod client_key;
pub mod key_switching_key;
pub mod list_compression;
pub mod noise_squashing;
pub mod oprf;
pub mod public_key;
pub mod server_key;

View File

@@ -0,0 +1,20 @@
use tfhe_fft::c64;
use tfhe_versionable::VersionsDispatch;
use crate::core_crypto::prelude::Container;
use crate::integer::oprf::{CompressedOprfServerKey, GenericOprfServerKey, OprfPrivateKey};
#[derive(VersionsDispatch)]
pub enum OprfPrivateKeyVersions {
V0(OprfPrivateKey),
}
#[derive(VersionsDispatch)]
pub enum GenericOprfServerKeyVersions<C: Container<Element = c64>> {
V0(GenericOprfServerKey<C>),
}
#[derive(VersionsDispatch)]
pub enum CompressedOprfServerKeyVersions {
V0(CompressedOprfServerKey),
}

View File

@@ -421,10 +421,28 @@ impl<const N: usize> From<(u64, u64, u64, u64)> for StaticSignedBigInt<N> {
}
}
impl<const N: usize> CastFrom<Self> for StaticSignedBigInt<N> {
#[inline(always)]
fn cast_from(input: Self) -> Self {
input
impl<const N_IN: usize, const N_OUT: usize> CastFrom<StaticSignedBigInt<N_IN>>
for StaticSignedBigInt<N_OUT>
{
fn cast_from(input: StaticSignedBigInt<N_IN>) -> Self {
// Get rid of special case, will be removed at compile time, no runtime impact
if N_IN == 0 {
return Self::ZERO;
}
// Safe to unwrap, N_IN > 0
let sign = input.0.last().unwrap() >> 63;
// If sign == 1, i.e. top bit was set, then the BigInt was negative, taking the wrapping_neg
// yields u64::MAX == -1 == 0xffffffffffffffff, if sign == 0, wrapping_neg does nothing and
// we get 0, this is a branchless way of getting the fill u64 for sign extension
let fill = sign.wrapping_neg();
let smallest = N_IN.min(N_OUT);
// init data with fill will naturally sign extend as required, since the low bits will be
// copied and the high bits will be 1s or 0s depending on sign
let mut data = [fill; N_OUT];
data[..smallest].copy_from_slice(&input.0[..smallest]);
Self(data)
}
}
@@ -477,6 +495,36 @@ impl<const N: usize> CastFrom<u128> for StaticSignedBigInt<N> {
}
}
impl<const N: usize> CastFrom<i8> for StaticSignedBigInt<N> {
fn cast_from(input: i8) -> Self {
Self::from(input as i128)
}
}
impl<const N: usize> CastFrom<i16> for StaticSignedBigInt<N> {
fn cast_from(input: i16) -> Self {
Self::from(input as i128)
}
}
impl<const N: usize> CastFrom<i32> for StaticSignedBigInt<N> {
fn cast_from(input: i32) -> Self {
Self::from(input as i128)
}
}
impl<const N: usize> CastFrom<i64> for StaticSignedBigInt<N> {
fn cast_from(input: i64) -> Self {
Self::from(input as i128)
}
}
impl<const N: usize> CastFrom<i128> for StaticSignedBigInt<N> {
fn cast_from(input: i128) -> Self {
Self::from(input)
}
}
impl<const N: usize> CastFrom<StaticSignedBigInt<N>> for u8 {
fn cast_from(input: StaticSignedBigInt<N>) -> Self {
input.0[0] as Self
@@ -540,12 +588,31 @@ mod test {
#[test]
fn test_i128_cast() {
let a = 1_i128 << 64;
{
let a = 1_i128 << 64;
let b: StaticSignedBigInt<4> = a.into();
let b: StaticSignedBigInt<4> = a.into();
let c = i128::cast_from(b);
let c = i128::cast_from(b);
assert_eq!(a, c);
assert_eq!(a, c);
}
{
let a = -1_i128 << 64;
let b: StaticSignedBigInt<4> = a.into();
let c = i128::cast_from(b);
assert_eq!(a, c);
assert_eq!(b, StaticSignedBigInt::<4>::ONE.wrapping_neg() << 64u32);
let d = StaticSignedBigInt::<5>::cast_from(b);
let e = i128::cast_from(d);
assert_eq!(a, e);
assert_eq!(d, StaticSignedBigInt::<5>::ONE.wrapping_neg() << 64u32);
}
}
}

View File

@@ -1,3 +1,5 @@
#[cfg(feature = "zk-pok")]
use super::ReRandomizationSeed;
use super::{DataKind, Expandable};
use crate::conformance::{ListSizeConstraint, ParameterSetConformant};
use crate::core_crypto::prelude::{LweCiphertextListConformanceParams, Numeric};
@@ -1109,6 +1111,32 @@ impl ProvenCompactCiphertextList {
self.expand_without_verification(expansion_mode)
}
pub fn verify_re_randomize_and_expand(
&self,
crs: &CompactPkeCrs,
public_key: &CompactPublicKey,
metadata: &[u8],
expansion_mode: IntegerCompactCiphertextListExpansionMode<'_>,
seed: ReRandomizationSeed,
) -> crate::Result<CompactCiphertextListExpander> {
if self.verify(crs, public_key, metadata) == ZkVerificationOutcome::Invalid {
return Err(crate::ErrorKind::InvalidZkProof.into());
}
self.re_randomize_and_expand_without_verification(expansion_mode, public_key, seed)
}
pub fn re_randomize(
&mut self,
public_key: &CompactPublicKey,
seed: ReRandomizationSeed,
) -> crate::Result<()> {
public_key.key.re_randomize_compact_ciphertext_lists(
self.ct_list.proved_lists.iter_mut().map(|(list, _)| list),
seed,
)
}
#[doc(hidden)]
/// This function allows to expand a ciphertext without verifying the associated proof.
///
@@ -1142,6 +1170,23 @@ is not"
))
}
#[doc(hidden)]
/// This function allows to re_randomize and expand a ciphertext without verifying the
/// associated proof.
///
/// If you are here you were probably looking for it: use at your own risks.
pub fn re_randomize_and_expand_without_verification(
&self,
expansion_mode: IntegerCompactCiphertextListExpansionMode<'_>,
public_key: &CompactPublicKey,
seed: ReRandomizationSeed,
) -> crate::Result<CompactCiphertextListExpander> {
let mut rerandomized = self.clone();
rerandomized.re_randomize(public_key, seed)?;
rerandomized.expand_without_verification(expansion_mode)
}
pub fn is_packed(&self) -> bool {
if self.is_empty() {
return false;

View File

@@ -8,6 +8,9 @@ pub use crate::shortint::ciphertext::{ReRandomizationSeed, ReRandomizationSeedHa
use crate::shortint::Ciphertext;
use crate::Result;
#[cfg(feature = "zk-pok")]
use super::ProvenCompactCiphertextList;
#[derive(Clone, Copy)]
pub enum ReRandomizationKey<'key> {
LegacyDedicatedCPK {
@@ -106,6 +109,26 @@ impl ReRandomizationContext {
self.ct_count += 1;
}
#[cfg(feature = "zk-pok")]
pub fn add_proven_ciphertext_list(&mut self, list: &ProvenCompactCiphertextList) {
self.ct_coeffs_buffer.extend(
list.ct_list
.proved_lists
.iter()
.flat_map(|list| list.0.ct_list.as_ref()),
);
self.meta_buffer.extend(
list.ct_list
.proved_lists
.iter()
.flat_map(|list| list.1.to_le_bytes()),
);
// We draw only one seed for the full list
self.ct_count += 1;
}
/// Add a metadata buffer to the context.
///
/// These bytes will be added to a temporary buffer and will only be hashed during the

View File

@@ -219,3 +219,258 @@ fn test_ciphertext_re_randomization_after_compression_impl(
}
}
}
#[cfg(feature = "zk-pok")]
mod zk {
use crate::core_crypto::prelude::LweCiphertextCount;
use crate::integer::ciphertext::{ProvenCompactCiphertextList, ReRandomizationContext};
use crate::integer::key_switching_key::KeySwitchingKey;
use crate::integer::parameters::IntegerCompactCiphertextListExpansionMode;
use crate::integer::{
BooleanBlock, ClientKey, CompactPrivateKey, CompactPublicKey, RadixCiphertext, ServerKey,
SignedRadixCiphertext,
};
use crate::shortint::parameters::test_params::{
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::zk::{CompactPkeCrs, ZkComputeLoad};
use rand::Rng;
#[test]
fn test_proven_compact_ciphertext_list_re_randomization() {
let pke_params = TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
let ksk_params = TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let fhe_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let num_blocks = 4usize;
let metadata = [b't', b'e', b's', b't'];
let rerand_domain_separator = *b"TFHE_Rrd";
let compact_public_encryption_domain_separator = *b"TFHE_Enc";
let cks = ClientKey::new(fhe_params);
let sks = ServerKey::new_radix_server_key(&cks);
let compact_private_key = CompactPrivateKey::new(pke_params);
let ksk = KeySwitchingKey::new((&compact_private_key, None), (&cks, &sks), ksk_params);
let pk = CompactPublicKey::new(&compact_private_key);
let crs = CompactPkeCrs::from_shortint_params(pke_params, LweCiphertextCount(512)).unwrap();
let mut rng = rand::thread_rng();
let message_modulus = pke_params.message_modulus.0 as u128;
// Unsigned
{
let modulus = message_modulus.pow(num_blocks as u32);
let message = rng.gen::<u128>() % modulus;
let mut builder = ProvenCompactCiphertextList::builder(&pk);
builder.push_with_num_blocks(message, num_blocks);
let proven_ct = builder
.build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)
.unwrap();
let mut re_rand_context = ReRandomizationContext::new(
rerand_domain_separator,
[metadata.as_slice()],
compact_public_encryption_domain_separator,
);
re_rand_context.add_proven_ciphertext_list(&proven_ct);
let mut seed_gen = re_rand_context.finalize();
let mut re_randomized = proven_ct.clone();
re_randomized
.re_randomize(&pk, seed_gen.next_seed().unwrap())
.unwrap();
assert!(proven_ct != re_randomized);
let expander = re_randomized
.expand_without_verification(
IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(
ksk.as_view(),
),
)
.unwrap();
let expanded: RadixCiphertext = expander.get(0).unwrap().unwrap();
let decrypted: u128 = cks.decrypt_radix(&expanded);
assert_eq!(decrypted, message);
}
// Signed
{
let modulus = message_modulus.pow((num_blocks - 1) as u32) as i128;
let message = rng.gen::<i128>() % modulus;
let mut builder = ProvenCompactCiphertextList::builder(&pk);
builder.push_with_num_blocks(message, num_blocks);
let proven_ct = builder
.build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)
.unwrap();
let mut re_rand_context = ReRandomizationContext::new(
rerand_domain_separator,
[metadata.as_slice()],
compact_public_encryption_domain_separator,
);
re_rand_context.add_proven_ciphertext_list(&proven_ct);
let mut seed_gen = re_rand_context.finalize();
let mut re_randomized = proven_ct.clone();
re_randomized
.re_randomize(&pk, seed_gen.next_seed().unwrap())
.unwrap();
assert!(proven_ct != re_randomized);
let expander = re_randomized
.expand_without_verification(
IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(
ksk.as_view(),
),
)
.unwrap();
let expanded: SignedRadixCiphertext = expander.get(0).unwrap().unwrap();
let decrypted: i128 = cks.decrypt_signed_radix(&expanded);
assert_eq!(decrypted, message);
}
// Boolean
{
for message in [false, true] {
let mut builder = ProvenCompactCiphertextList::builder(&pk);
builder.push(message);
let proven_ct = builder
.build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)
.unwrap();
let mut re_rand_context = ReRandomizationContext::new(
rerand_domain_separator,
[metadata.as_slice()],
compact_public_encryption_domain_separator,
);
re_rand_context.add_proven_ciphertext_list(&proven_ct);
let mut seed_gen = re_rand_context.finalize();
let mut re_randomized = proven_ct.clone();
re_randomized
.re_randomize(&pk, seed_gen.next_seed().unwrap())
.unwrap();
assert!(proven_ct != re_randomized);
let expander = re_randomized
.expand_without_verification(
IntegerCompactCiphertextListExpansionMode::CastAndUnpackIfNecessary(
ksk.as_view(),
),
)
.unwrap();
let expanded: BooleanBlock = expander.get(0).unwrap().unwrap();
let decrypted = cks.decrypt_bool(&expanded);
assert_eq!(decrypted, message);
}
}
}
#[cfg(feature = "gpu")]
#[test]
fn test_proven_compact_ciphertext_list_re_rand_cpu_gpu_compatibility() {
use crate::core_crypto::gpu::CudaStreams;
use crate::integer::gpu::zk::CudaProvenCompactCiphertextList;
use crate::shortint::parameters::test_params::TEST_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
let pke_params = TEST_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
let compact_private_key = CompactPrivateKey::new(pke_params);
let pk = CompactPublicKey::new(&compact_private_key);
let compact_public_encryption_domain_separator = *b"TFHE_Enc";
let rerand_domain_separator = *b"TFHE_Rrd";
// Intentionally low so that we test when multiple lists and proofs are needed
let crs = CompactPkeCrs::from_shortint_params(pke_params, LweCiphertextCount(8)).unwrap();
let metadata = [b'r', b'e', b'r', b'a', b'n', b'd'];
let clear_a = rand::random::<u64>();
let clear_b = rand::random::<i8>();
let proven_ct = ProvenCompactCiphertextList::builder(&pk)
.push(clear_a)
.push(clear_b)
.push(false)
.build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)
.unwrap();
// Clone the list so both CPU and GPU start from the same state
let mut cpu_list = proven_ct.clone();
// Simulate a 256 bits nonce
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rand::random());
// Create two identical seeds from the same context inputs
let cpu_seed = {
let mut ctx = ReRandomizationContext::new(
rerand_domain_separator,
[b"expand".as_slice(), nonce.as_slice()],
compact_public_encryption_domain_separator,
);
ctx.add_proven_ciphertext_list(&proven_ct);
ctx.finalize().next_seed().unwrap()
};
let gpu_seed = {
let mut ctx = ReRandomizationContext::new(
rerand_domain_separator,
[b"expand".as_slice(), nonce.as_slice()],
compact_public_encryption_domain_separator,
);
ctx.add_proven_ciphertext_list(&proven_ct);
ctx.finalize().next_seed().unwrap()
};
// Re-randomize on CPU
cpu_list.re_randomize(&pk, cpu_seed).unwrap();
// Re-randomize on GPU
let streams = CudaStreams::new_multi_gpu();
let mut gpu_list = CudaProvenCompactCiphertextList::from_proven_compact_ciphertext_list(
&proven_ct, &streams,
);
gpu_list.re_randomize(&pk, gpu_seed, &streams).unwrap();
// Read ciphertext data back from GPU and reconstruct an integer proven list
let gpu_compact_lists = gpu_list
.d_flattened_compact_lists
.to_vec_shortint_compact_ciphertext_list(&streams)
.unwrap();
let gpu_proved_lists: Vec<_> = gpu_compact_lists
.into_iter()
.zip(gpu_list.h_proved_lists.ct_list.proved_lists.iter())
.map(|(ct, (_, proof))| (ct, proof.clone()))
.collect();
let gpu_on_cpu = ProvenCompactCiphertextList {
ct_list: crate::shortint::ciphertext::ProvenCompactCiphertextList {
proved_lists: gpu_proved_lists,
},
info: gpu_list.h_proved_lists.info.clone(),
};
assert!(cpu_list == gpu_on_cpu);
}
}

View File

@@ -3084,6 +3084,7 @@ pub(crate) unsafe fn cuda_backend_grouped_oprf_custom_range<
has_at_least_one_set: &[T],
shift: u32,
bootstrapping_key: &CudaVec<B>,
compute_bootstrapping_key: &CudaVec<B>,
key_switching_key: &CudaVec<KST>,
lwe_dimension: LweDimension,
glwe_dimension: GlweDimension,
@@ -3106,6 +3107,10 @@ pub(crate) unsafe fn cuda_backend_grouped_oprf_custom_range<
);
assert_eq!(streams.gpu_indexes[0], seeded_lwe_input.gpu_index(0));
assert_eq!(streams.gpu_indexes[0], bootstrapping_key.gpu_index(0));
assert_eq!(
streams.gpu_indexes[0],
compute_bootstrapping_key.gpu_index(0)
);
assert_eq!(streams.gpu_indexes[0], key_switching_key.gpu_index(0));
let noise_reduction_type = resolve_ms_noise_reduction_config(ms_noise_reduction_configuration);
@@ -3162,6 +3167,7 @@ pub(crate) unsafe fn cuda_backend_grouped_oprf_custom_range<
shift,
mem_ptr,
bootstrapping_key.ptr.as_ptr(),
compute_bootstrapping_key.ptr.as_ptr(),
key_switching_key.ptr.as_ptr(),
);

View File

@@ -9,4 +9,6 @@ pub mod server_key;
pub mod zk;
pub use ffi::*;
pub use server_key::CudaServerKey;
pub use server_key::{
CudaOprfServerKey, CudaOprfServerKeyView, CudaServerKey, GenericCudaOprfServerKey,
};

View File

@@ -6,8 +6,8 @@ use crate::core_crypto::gpu::lwe_multi_bit_bootstrap_key::CudaLweMultiBitBootstr
use crate::core_crypto::gpu::CudaStreams;
use crate::core_crypto::prelude::{
allocate_and_generate_new_lwe_keyswitch_key, par_allocate_and_generate_new_lwe_bootstrap_key,
par_allocate_and_generate_new_lwe_multi_bit_bootstrap_key, LweBootstrapKeyOwned, LweDimension,
LweMultiBitBootstrapKeyOwned, UnsignedInteger,
par_allocate_and_generate_new_lwe_multi_bit_bootstrap_key, GlweSize, LweBootstrapKeyOwned,
LweDimension, LweMultiBitBootstrapKeyOwned, UnsignedInteger,
};
use crate::high_level_api::keys::expanded::{
ShortintExpandedBootstrappingKey, ShortintExpandedServerKey,
@@ -21,8 +21,11 @@ use crate::shortint::atomic_pattern::expanded::{
use crate::shortint::ciphertext::{MaxDegree, MaxNoiseLevel};
use crate::shortint::client_key::atomic_pattern::AtomicPatternClientKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::oprf::ExpandedOprfBootstrappingKey;
use crate::shortint::parameters::ModulusSwitchType;
use crate::shortint::prelude::PolynomialSize;
use crate::shortint::{CarryModulus, CiphertextModulus, MessageModulus, PBSOrder};
pub use radix::{CudaOprfServerKey, CudaOprfServerKeyView, GenericCudaOprfServerKey};
mod radix;
@@ -72,15 +75,60 @@ where
}
}
}
}
impl<Scalar: UnsignedInteger> CudaBootstrappingKey<Scalar> {
pub(crate) fn polynomial_size(&self) -> PolynomialSize {
match self {
Self::Classic(bsk) => bsk.polynomial_size,
Self::MultiBit(mb_bsk) => mb_bsk.polynomial_size,
}
}
pub(crate) fn input_lwe_dimension(&self) -> LweDimension {
match self {
Self::Classic(bsk) => bsk.input_lwe_dimension,
Self::MultiBit(mb_bsk) => mb_bsk.input_lwe_dimension,
}
}
pub(crate) fn output_lwe_dimension(&self) -> LweDimension {
match self {
Self::Classic(bsk) => bsk.output_lwe_dimension(),
Self::MultiBit(mb_bsk) => mb_bsk.output_lwe_dimension(),
}
}
pub(crate) fn glwe_size(&self) -> GlweSize {
match self {
Self::Classic(bsk) => bsk.glwe_dimension().to_glwe_size(),
Self::MultiBit(mb_bsk) => mb_bsk.glwe_dimension().to_glwe_size(),
}
}
}
impl CudaBootstrappingKey<u64> {
pub(crate) fn from_expanded_oprf_server_key(
expanded_bsk: &ExpandedOprfBootstrappingKey,
streams: &CudaStreams,
) -> Self {
match expanded_bsk {
ExpandedOprfBootstrappingKey::Classic { bsk, .. } => {
let d_bootstrap_key =
CudaLweBootstrapKey::from_lwe_bootstrap_key(bsk, None, streams);
Self::Classic(d_bootstrap_key)
}
ExpandedOprfBootstrappingKey::MultiBit {
bsk,
thread_count: _,
deterministic_execution: _,
} => {
let d_bootstrap_key =
CudaLweMultiBitBootstrapKey::from_lwe_multi_bit_bootstrap_key(bsk, streams);
Self::MultiBit(d_bootstrap_key)
}
}
}
}
pub enum CudaDynamicKeyswitchingKey {

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