Compare commits
26 Commits
edm/shuffl
...
tm/shuffle
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88241fee21 | ||
|
|
7b174b1865 | ||
|
|
79cb6b6066 | ||
|
|
6ff87e94bb | ||
|
|
4c27f48968 | ||
|
|
8bf2a12e9b | ||
|
|
64b5a0fdcd | ||
|
|
49c390edef | ||
|
|
82860a0b01 | ||
|
|
39ca504ce4 | ||
|
|
61c7ffea2e | ||
|
|
48bb3833e7 | ||
|
|
2ad2f522db | ||
|
|
2333a5591e | ||
|
|
9e3e283741 | ||
|
|
e3b9fd56df | ||
|
|
05b1c9a651 | ||
|
|
8d2caa108a | ||
|
|
dea1b81b06 | ||
|
|
a1dc91af4f | ||
|
|
b34b7d39f1 | ||
|
|
dc14834559 | ||
|
|
10ab4f4409 | ||
|
|
d5439a9f48 | ||
|
|
e299dc2af7 | ||
|
|
bdb75ec806 |
@@ -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
|
||||
|
||||
2
.github/workflows/benchmark_cpu_common.yml
vendored
@@ -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 }}
|
||||
|
||||
2
.github/workflows/benchmark_ct_key_sizes.yml
vendored
@@ -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 }}
|
||||
|
||||
4
.github/workflows/benchmark_gpu_4090.yml
vendored
@@ -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 }}
|
||||
|
||||
2
.github/workflows/benchmark_gpu_common.yml
vendored
@@ -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 }}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
2
.github/workflows/benchmark_hpu_common.yml
vendored
@@ -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 }}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
2
.github/workflows/benchmark_tfhe_fft.yml
vendored
@@ -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 }}
|
||||
|
||||
2
.github/workflows/benchmark_tfhe_ntt.yml
vendored
@@ -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 }}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
4
.github/workflows/generate_svg_common.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/make_release_common.yml
vendored
@@ -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
|
||||
|
||||
19
.github/workflows/make_release_common_cuda.yml
vendored
@@ -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 }})"
|
||||
|
||||
12
Makefile
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cat /etc/os-release | grep "\<NAME\>" | sed "s/NAME=\"//g" | sed "s/\"//g"
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}")
|
||||
|
||||
35
backends/zk-cuda-backend/cuda/include/checked_arithmetic.h
Normal 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));
|
||||
}
|
||||
145
backends/zk-cuda-backend/cuda/include/device.h
Normal 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
|
||||
16
backends/zk-cuda-backend/cuda/include/helper_profile.cuh
Normal 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
|
||||
43
backends/zk-cuda-backend/cuda/src/helper_profile.cu
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
53
tfhe-benchmark/benches/high_level_api/bitonic_shuffle.rs
Normal 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);
|
||||
@@ -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,
|
||||
);
|
||||
})
|
||||
|
||||
@@ -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));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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 (&, |, ^)</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 (<<, >>)</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 |
@@ -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 |
@@ -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 (&, |, ^)</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 (<<, >>)</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 |
@@ -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 (&, |, ^)</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 (<<, >>)</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 |
@@ -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 (&, |, ^)</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 (<<, >>)</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 |
@@ -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 (&, |, ^)</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 (<<, >>)</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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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:
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
121
tfhe/src/high_level_api/integers/shuffle.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
54
tfhe/src/high_level_api/integers/signed/fused_ops.rs
Normal 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),
|
||||
);
|
||||
@@ -3,6 +3,7 @@ mod compressed;
|
||||
mod squashed_noise;
|
||||
|
||||
mod encrypt;
|
||||
mod fused_ops;
|
||||
mod inner;
|
||||
mod ops;
|
||||
mod overflowing_ops;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
186
tfhe/src/high_level_api/integers/unsigned/fused_ops.rs
Normal 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),
|
||||
);
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(¶meter_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(¶meter_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(¶meter_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(¶meter_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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
20
tfhe/src/integer/backward_compatibility/oprf.rs
Normal 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),
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||