Compare commits
17 Commits
as/benchma
...
ns/chore/u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea3b1a7f76 | ||
|
|
a18e5f3834 | ||
|
|
48bb3833e7 | ||
|
|
2ad2f522db | ||
|
|
2333a5591e | ||
|
|
9e3e283741 | ||
|
|
e3b9fd56df | ||
|
|
05b1c9a651 | ||
|
|
8d2caa108a | ||
|
|
dea1b81b06 | ||
|
|
a1dc91af4f | ||
|
|
b34b7d39f1 | ||
|
|
dc14834559 | ||
|
|
10ab4f4409 | ||
|
|
d5439a9f48 | ||
|
|
e299dc2af7 | ||
|
|
bdb75ec806 |
1
.github/workflows/benchmark_gpu.yml
vendored
@@ -38,7 +38,6 @@ on:
|
||||
- integer_aes
|
||||
- integer_aes256
|
||||
- hlapi_erc7984
|
||||
- hlapi_erc7984_multi_group
|
||||
- hlapi_dex
|
||||
- hlapi_noise_squash
|
||||
op_flavor:
|
||||
|
||||
35
.github/workflows/benchmark_gpu_common.yml
vendored
@@ -237,10 +237,8 @@ jobs:
|
||||
BENCH_PARAMS_TYPE: ${{ matrix.params_type }}
|
||||
BENCH_COMMAND: ${{ matrix.command }}
|
||||
PRECISIONS_SET: ${{ inputs.precisions_set }}
|
||||
__TFHE_RS_BENCH_MULTI_PROC_GROUPS: 2
|
||||
|
||||
- name: Parse results
|
||||
if: ${{ inputs.command != 'hlapi_erc7984_multi_group' }}
|
||||
run: |
|
||||
python3 ./ci/benchmark_parser.py target/criterion "${RESULTS_FILENAME}" \
|
||||
--database tfhe_rs \
|
||||
@@ -258,39 +256,6 @@ jobs:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
BENCH_TYPE: ${{ matrix.bench_type }}
|
||||
|
||||
- name: Parse and merge erc7984_multi_group results
|
||||
if: ${{ inputs.command == 'hlapi_erc7984_multi_group' }}
|
||||
run: |
|
||||
python3 ./ci/benchmark_parser.py tfhe-benchmark/target_p0/criterion "${RESULTS_FILENAME_P0}" \
|
||||
--database tfhe_rs \
|
||||
--hardware "${INPUTS_HARDWARE_NAME}" \
|
||||
--backend gpu \
|
||||
--project-version "${COMMIT_HASH}" \
|
||||
--branch "${REF_NAME}" \
|
||||
--commit-date "${COMMIT_DATE}" \
|
||||
--bench-date "${BENCH_DATE}" \
|
||||
--walk-subdirs \
|
||||
--name-suffix avx512 \
|
||||
--bench-type "${BENCH_TYPE}"
|
||||
python3 ./ci/benchmark_parser.py tfhe-benchmark/target_p1/criterion "${RESULTS_FILENAME_P1}" \
|
||||
--database tfhe_rs \
|
||||
--hardware "${INPUTS_HARDWARE_NAME}" \
|
||||
--backend gpu \
|
||||
--project-version "${COMMIT_HASH}" \
|
||||
--branch "${REF_NAME}" \
|
||||
--commit-date "${COMMIT_DATE}" \
|
||||
--bench-date "${BENCH_DATE}" \
|
||||
--walk-subdirs \
|
||||
--name-suffix avx512 \
|
||||
--bench-type "${BENCH_TYPE}"
|
||||
python3 ./ci/merge_multi_group_results.py --bench-type "${BENCH_TYPE}" --output "${RESULTS_FILENAME}" "${RESULTS_FILENAME_P0}" "${RESULTS_FILENAME_P1}"
|
||||
env:
|
||||
INPUTS_HARDWARE_NAME: ${{ inputs.hardware_name }}
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
BENCH_TYPE: ${{ matrix.bench_type }}
|
||||
RESULTS_FILENAME_P0: parsed_benchmark_results_p0_${{ github.sha }}.json
|
||||
RESULTS_FILENAME_P1: parsed_benchmark_results_p1_${{ github.sha }}.json
|
||||
|
||||
- name: Parse additional benchmarks results files
|
||||
if: ${{ inputs.additional_file_to_parse }}
|
||||
run: |
|
||||
|
||||
21
.github/workflows/benchmark_summary.yml
vendored
@@ -114,27 +114,6 @@ jobs:
|
||||
SLAB_URL: ${{ secrets.SLAB_URL }}
|
||||
SLAB_BASE_URL: ${{ secrets.SLAB_BASE_URL }}
|
||||
|
||||
run-benchmarks-gpu-erc7984-multi-group:
|
||||
name: benchmark_documentation/run-benchmarks-gpu-erc7984-multi-group
|
||||
uses: ./.github/workflows/benchmark_gpu_common.yml
|
||||
if: inputs.run-gpu-benchmarks
|
||||
needs: parse-gpu-inputs
|
||||
with:
|
||||
profile: ${{ needs.parse-gpu-inputs.outputs.profile }}
|
||||
hardware_name: ${{ needs.parse-gpu-inputs.outputs.hardware_name }}
|
||||
command: hlapi_erc7984_multi_group
|
||||
bench_type: throughput
|
||||
params_type: multi_bit
|
||||
secrets:
|
||||
BOT_USERNAME: ${{ secrets.BOT_USERNAME }}
|
||||
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
|
||||
REPO_CHECKOUT_TOKEN: ${{ secrets.REPO_CHECKOUT_TOKEN }}
|
||||
JOB_SECRET: ${{ secrets.JOB_SECRET }}
|
||||
SLAB_ACTION_TOKEN: ${{ secrets.SLAB_ACTION_TOKEN }}
|
||||
SLAB_URL: ${{ secrets.SLAB_URL }}
|
||||
SLAB_BASE_URL: ${{ secrets.SLAB_BASE_URL }}
|
||||
|
||||
# TODO add make recipe for HPU benchmarks
|
||||
# run-benchmarks-hpu:
|
||||
# name: benchmark_documentation/run-benchmarks-hpu
|
||||
|
||||
57
Makefile
@@ -314,8 +314,6 @@ semgrep_and_lint_gpu_code: semgrep_lint_setup_venv
|
||||
| grep -v '/build/' \
|
||||
| xargs venv/bin/semgrep --error --config "$(TFHECUDA_SRC)/.semgrep/release-ordering.yaml" --scan-unknown-extensions
|
||||
venv/bin/python3 "scripts/check_scratch_cleanup.py"
|
||||
@# Split the search string using shell string concatenation so the Makefile line doesn't match itself
|
||||
! git ls-files | xargs grep -n 'TODO: ADD COMM''ENT'
|
||||
|
||||
.PHONY: semver_check_cuda_backend # Run semver checks on tfhe-cuda-backend
|
||||
semver_check_cuda_backend:
|
||||
@@ -589,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 \
|
||||
@@ -1957,40 +1966,6 @@ bench_hlapi_erc7984_gpu_classical: install_rs_check_toolchain
|
||||
--bench hlapi-erc7984 \
|
||||
--features=integer,gpu,internal-keycache,pbs-stats -p tfhe-benchmark --profile release_lto_off --
|
||||
|
||||
.PHONY: bench_hlapi_erc7984_multi_group_gpu # Runs ERC7984 bench in two processes (half of gpus for each) and aggregates results
|
||||
bench_hlapi_erc7984_multi_group_gpu: install_rs_check_toolchain
|
||||
# This next line must be kept here: the code can not remove this file without a risk of concurrency issues
|
||||
# we don't know which process starts first and which one deletes the files - file deletion may also be not atomic)
|
||||
rm -f /dev/shm/sem.tfhe_bench_*
|
||||
NUM_GROUPS=$${__TFHE_RS_BENCH_MULTI_PROC_GROUPS:-2}; \
|
||||
[ "$$NUM_GROUPS" -ge 2 ] || { echo "Error: __TFHE_RS_BENCH_MULTI_PROC_GROUPS must be at least 2, got $$NUM_GROUPS"; exit 1; }; \
|
||||
trap "echo 'User interrupted the benchmark, stopping all workers!'; rm -f /dev/shm/sem.tfhe_bench_*; kill 0" INT TERM; \
|
||||
for i in $$(seq 0 $$((NUM_GROUPS - 1))); do \
|
||||
GPU_LIST=$$(python3 ci/split_gpus.py $$i $$NUM_GROUPS) || exit 1; \
|
||||
echo "Starting benchmark group $$i with CUDA_VISIBLE_DEVICES=$$GPU_LIST"; \
|
||||
CUDA_VISIBLE_DEVICES=$$GPU_LIST CARGO_TARGET_DIR=target_p$$i RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_TYPE=$(BENCH_TYPE) __TFHE_RS_PARAM_TYPE=$(BENCH_PARAM_TYPE) __TFHE_RS_BENCH_GPU_PROCESS_COUNT=$$NUM_GROUPS \
|
||||
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench hlapi-erc7984 \
|
||||
--features=integer,gpu,internal-keycache,pbs-stats -p tfhe-benchmark --profile release_lto_off -- '::transfer::overflow' & \
|
||||
done; \
|
||||
wait
|
||||
|
||||
.PHONY: bench_hlapi_erc7984_multi_group_fake_multi_gpu # Runs ERC7984 bench in two processes in parallel on a single GPU (use to debug bench_hlapi_erc7984_multi_group_gpu)
|
||||
bench_hlapi_erc7984_multi_group_fake_multi_gpu: install_rs_check_toolchain
|
||||
# This next line must be kept here: the code can not remove this file without a risk of concurrency issues
|
||||
# we don't know which process starts first and which one deletes the files - file deletion may also be not atomic)
|
||||
rm -f /dev/shm/sem.tfhe_bench_*
|
||||
trap "echo 'User interrupted the benchmark, stopping all workers!'; rm -f /dev/shm/sem.tfhe_bench_*; kill 0" INT TERM; \
|
||||
CARGO_TARGET_DIR=target_p0 RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_TYPE=throughput __TFHE_RS_PARAM_TYPE=$(BENCH_PARAM_TYPE) __TFHE_RS_BENCH_GPU_PROCESS_COUNT=2 \
|
||||
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench hlapi-erc7984 \
|
||||
--features=integer,gpu,internal-keycache,pbs-stats -p tfhe-benchmark --profile release_lto_off -- '::transfer::overflow' & \
|
||||
CARGO_TARGET_DIR=target_p1 RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_TYPE=throughput __TFHE_RS_PARAM_TYPE=$(BENCH_PARAM_TYPE) __TFHE_RS_BENCH_GPU_PROCESS_COUNT=2 \
|
||||
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench hlapi-erc7984 \
|
||||
--features=integer,gpu,internal-keycache,pbs-stats -p tfhe-benchmark --profile release_lto_off -- '::transfer::overflow' & \
|
||||
wait
|
||||
|
||||
.PHONY: bench_hlapi_dex # Run benchmarks for DEX operations
|
||||
bench_hlapi_dex: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_TYPE=$(BENCH_TYPE) \
|
||||
@@ -2119,16 +2094,11 @@ bench_summary_gpu: install_rs_check_toolchain
|
||||
--bench hlapi-noise-squash \
|
||||
--features=integer,gpu,internal-keycache,pbs-stats -p tfhe-benchmark --profile release_lto_off -- '::decomp_noise_squash_comp::'
|
||||
|
||||
# This make target only runs the latency benchmark. This is because
|
||||
# summary benchmarks must use the multi-process-multi-group throughput target
|
||||
# to measure throughput. That target must be followed by specific post-processing steps.
|
||||
# Thus that target is run in a separate step in benchmark_summary.yml.
|
||||
ifneq ($(filter latency both,$(BENCH_TYPE)),)
|
||||
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_TYPE=latency __TFHE_RS_PARAM_TYPE=$(BENCH_PARAM_TYPE) \
|
||||
# ERC7984
|
||||
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_TYPE=$(BENCH_TYPE) __TFHE_RS_PARAM_TYPE=$(BENCH_PARAM_TYPE) \
|
||||
cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench hlapi-erc7984 \
|
||||
--features=integer,gpu,internal-keycache -p tfhe-benchmark --profile release_lto_off -- '::transfer::overflow'
|
||||
endif
|
||||
|
||||
# DEX
|
||||
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_BENCH_TYPE=$(BENCH_TYPE) __TFHE_RS_PARAM_TYPE=$(BENCH_PARAM_TYPE) \
|
||||
@@ -2306,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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
"p4d.24xlarge": 32.7726,
|
||||
"p5.48xlarge": 98.32,
|
||||
"rtx4090": 0.04,
|
||||
"n3-L40x4": 3.2,
|
||||
"n3-H100x1": 1.52,
|
||||
"n3-H100x8-NVLink": 12.48,
|
||||
"n3-H100x8": 12.16,
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# This script aggregates multi-process-group benchmark results
|
||||
# that are obtained by running benchmarks in a multi-process approach
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
ACCEPTED_TEST_PREFIXES = {
|
||||
"throughput": ["hlapi::cuda::erc7984::throughput"],
|
||||
"latency": ["hlapi::cuda::erc7984::latency"],
|
||||
}
|
||||
|
||||
|
||||
# Looks at the Slab JSON benchmark results and aggregates the "value" field.
|
||||
# For throughput, values are summed across groups.
|
||||
# For latency, values are averaged across groups.
|
||||
def merge_multi_group_results(input_files, output_file, bench_type):
|
||||
accumulated = {}
|
||||
counts = {}
|
||||
metadata = None
|
||||
accepted_prefixes = ACCEPTED_TEST_PREFIXES[bench_type]
|
||||
|
||||
for path in input_files:
|
||||
with open(path) as f:
|
||||
data = json.load(f)
|
||||
if metadata is None:
|
||||
metadata = {k: v for k, v in data.items() if k != "points"}
|
||||
for point in data["points"]:
|
||||
test = point["test"]
|
||||
if not any(test.startswith(prefix) for prefix in accepted_prefixes):
|
||||
print(
|
||||
f"Error: unexpected test '{test}' in {path}: "
|
||||
f"this script only supports aggregation of: {accepted_prefixes}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
if test in accumulated:
|
||||
accumulated[test]["value"] += point["value"]
|
||||
counts[test] += 1
|
||||
else:
|
||||
accumulated[test] = dict(point)
|
||||
counts[test] = 1
|
||||
|
||||
if bench_type == "latency":
|
||||
for test in accumulated:
|
||||
accumulated[test]["value"] /= counts[test]
|
||||
|
||||
result = dict(metadata)
|
||||
result["points"] = list(accumulated.values())
|
||||
|
||||
with open(output_file, "w") as f:
|
||||
json.dump(result, f, indent=2)
|
||||
|
||||
|
||||
# The output is a positional argument, for file names we accept 2+
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("input_files", nargs="+")
|
||||
parser.add_argument("--output", required=True)
|
||||
parser.add_argument("--bench-type", required=True, choices=["throughput", "latency"])
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parser.parse_args()
|
||||
if len(args.input_files) < 2:
|
||||
print("Error: at least 2 input files required", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
merge_multi_group_results(args.input_files, args.output, args.bench_type)
|
||||
@@ -1,55 +0,0 @@
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
# List the gpus for a sub-group (group_index) of gpus grouped
|
||||
# in num_groups groups. The output string is passed to CUDA_VISIBLE_DEVICES
|
||||
def get_gpu_count() -> int:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
print("Error: nvidia-smi not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except subprocess.CalledProcessError as err:
|
||||
print(f"Error: nvidia-smi failed: {err.stderr.strip()}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return len(result.stdout.strip().splitlines())
|
||||
|
||||
|
||||
def gpu_list_for_group(num_gpus: int, group_index: int, num_groups: int) -> str:
|
||||
# Splits the available gpus un groups and returns
|
||||
# the gpus assigned to group group_index.
|
||||
if num_gpus < num_groups:
|
||||
print(
|
||||
f"Error: cannot split {num_gpus} GPU(s) across {num_groups} group(s): "
|
||||
"not enough GPUs",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
if num_gpus % num_groups != 0:
|
||||
print(
|
||||
f"Error: {num_gpus} GPU(s) is not evenly divisible by {num_groups} group(s)",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
gpus_per_group = num_gpus // num_groups
|
||||
start = group_index * gpus_per_group
|
||||
return ",".join(str(i) for i in range(start, start + gpus_per_group))
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Print the CUDA_VISIBLE_DEVICES value for one process in a multi-GPU split."
|
||||
)
|
||||
parser.add_argument("group_index", type=int, help="0-based index of this process group")
|
||||
parser.add_argument("num_groups", type=int, help="Total number of process groups")
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parser.parse_args()
|
||||
num_gpus = get_gpu_count()
|
||||
print(gpu_list_for_group(num_gpus, args.group_index, args.num_groups))
|
||||
@@ -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"
|
||||
|
||||
@@ -14,9 +14,6 @@ publish = false
|
||||
name = "benchmark"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[dependencies]
|
||||
bincode = { workspace = true }
|
||||
# clap has to be pinned as its minimum supported rust version
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#[cfg(feature = "gpu")]
|
||||
use benchmark::utilities::{
|
||||
bench_sync_barrier, configure_gpu, get_bench_gpu_instances, get_param_type, ParamType,
|
||||
};
|
||||
use benchmark::utilities::{configure_gpu, get_param_type, ParamType};
|
||||
use benchmark::utilities::{write_to_json_unchecked, OperatorType};
|
||||
use benchmark_spec::{get_bench_type, BenchmarkType};
|
||||
use criterion::measurement::WallTime;
|
||||
@@ -562,11 +560,6 @@ fn cuda_bench_transfer_throughput<FheType, F>(
|
||||
let num_streams_per_gpu = 6; // Hard coded stream value for FheUint64
|
||||
let chunk_size = (num_elems / num_gpus) as usize;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
if let Some(n) = get_bench_gpu_instances() {
|
||||
bench_sync_barrier(n);
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
from_amounts
|
||||
.par_chunks(chunk_size) // Split into chunks of num_gpus
|
||||
|
||||
@@ -472,106 +472,6 @@ pub fn get_param_type() -> &'static ParamType {
|
||||
PARAM_TYPE.get_or_init(|| ParamType::from_env().unwrap())
|
||||
}
|
||||
|
||||
pub fn get_bench_gpu_instances() -> Option<usize> {
|
||||
env::var("__TFHE_RS_BENCH_GPU_PROCESS_COUNT").ok().map(|v| {
|
||||
v.parse::<usize>().unwrap_or_else(|_| {
|
||||
panic!("__TFHE_RS_BENCH_GPU_PROCESS_COUNT must be a positive integer, got '{v}'")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Multi-process barrier that ensures num_instances processes
|
||||
/// start at the same time
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn bench_sync_barrier(num_instances: usize) {
|
||||
use std::ffi::CString;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
const BARRIER_TIMEOUT_SECS: u64 = 120;
|
||||
const MUTEX_NAME_PREFIX: &str = "tfhe_bench";
|
||||
|
||||
// Three POSIX semaphores are used for synchronization
|
||||
// The first one is used to make sure the processes increment the
|
||||
// counter and get the value of the counter atomically .
|
||||
let sem_mutex = CString::new(format!("/{MUTEX_NAME_PREFIX}_mutex")).unwrap();
|
||||
let sem_arrive = CString::new(format!("/{MUTEX_NAME_PREFIX}_arrive")).unwrap();
|
||||
let sem_gate = CString::new(format!("/{MUTEX_NAME_PREFIX}_gate")).unwrap();
|
||||
|
||||
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let deadline_t = now + Duration::from_secs(BARRIER_TIMEOUT_SECS);
|
||||
let deadline = libc::timespec {
|
||||
tv_sec: deadline_t.as_secs() as libc::time_t,
|
||||
tv_nsec: deadline_t.subsec_nanos() as libc::c_long,
|
||||
};
|
||||
|
||||
let open_sem = |name: &CString, init: u32| {
|
||||
let sem = unsafe { libc::sem_open(name.as_ptr(), libc::O_CREAT, 0o600u32, init) };
|
||||
assert!(
|
||||
sem != libc::SEM_FAILED,
|
||||
"sem_open({:?}) failed: {}",
|
||||
name,
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
sem
|
||||
};
|
||||
|
||||
let timed_wait = |sem: *mut libc::sem_t, label: &str| {
|
||||
let ret = unsafe { libc::sem_timedwait(sem, &deadline) };
|
||||
if ret != 0 {
|
||||
panic!(
|
||||
"bench_sync_barrier: timed out on '{label}' after {BARRIER_TIMEOUT_SECS}s \
|
||||
(__TFHE_RS_BENCH_GPU_PROCESS_COUNT={num_instances}). \
|
||||
If semaphores are stale from a prior crash, clean up with: \
|
||||
rm -f /dev/shm/sem.{MUTEX_NAME_PREFIX}_*\n\
|
||||
OS error: {}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let mutex = open_sem(&sem_mutex, 1);
|
||||
let arrive = open_sem(&sem_arrive, 0);
|
||||
let gate = open_sem(&sem_gate, 0);
|
||||
|
||||
// Process 0 to arrive doesn't need to wait
|
||||
// Processes 1..N to arrive need to wait
|
||||
timed_wait(mutex, "mutex");
|
||||
// Each process posts to the arrive semaphore, incrementing its value
|
||||
unsafe { libc::sem_post(arrive) };
|
||||
// The last process to post to "arrive" will read a value equal to "num_instances"
|
||||
// The other processes read a lower value. "mutex" ensures
|
||||
// the post + get_value are atomic
|
||||
let mut count = 0i32;
|
||||
unsafe { libc::sem_getvalue(arrive, &mut count) };
|
||||
|
||||
// Once a process has posted to arrive and got the value (atomic)
|
||||
// it allows the other processes to do the same
|
||||
unsafe { libc::sem_post(mutex) };
|
||||
|
||||
// The last process reads the "num_instances" value from arrive.
|
||||
// it must then tell the others to continue work. if it doesn't
|
||||
// the other processes will time out at the "gate"
|
||||
if count as usize == num_instances {
|
||||
for _ in 0..num_instances {
|
||||
// Open the gate
|
||||
unsafe { libc::sem_post(gate) };
|
||||
}
|
||||
}
|
||||
|
||||
// Every process waits at the gate. If it doesn't open in a certain time, then we panic
|
||||
timed_wait(gate, "gate");
|
||||
|
||||
// Clean up
|
||||
unsafe {
|
||||
libc::sem_close(mutex);
|
||||
libc::sem_close(arrive);
|
||||
libc::sem_close(gate);
|
||||
libc::sem_unlink(sem_mutex.as_ptr());
|
||||
libc::sem_unlink(sem_arrive.as_ptr());
|
||||
libc::sem_unlink(sem_gate.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a number of threads to use to saturate current machine for throughput measurements.
|
||||
pub fn throughput_num_threads(num_block: usize, op_pbs_count: u64) -> u64 {
|
||||
let ref_block_count = 32; // Represent a ciphertext of 64 bits for 2_2 parameters set
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -58,6 +58,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 +92,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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1004,3 +1004,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,9 +107,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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::core_crypto::algorithms::verify_lwe_compact_ciphertext_list;
|
||||
use crate::core_crypto::gpu::CudaStreams;
|
||||
use crate::core_crypto::prelude::{CiphertextModulus, LweCiphertextCount};
|
||||
use crate::integer::ciphertext::ReRandomizationSeed;
|
||||
use crate::integer::gpu::ciphertext::compact_list::{
|
||||
CudaCompactCiphertextListExpander, CudaFlattenedVecCompactCiphertextList,
|
||||
};
|
||||
@@ -64,6 +65,42 @@ impl CudaProvenCompactCiphertextList {
|
||||
Err(crate::ErrorKind::InvalidZkProof.into())
|
||||
}
|
||||
|
||||
pub fn verify_re_randomize_and_expand(
|
||||
&self,
|
||||
crs: &CompactPkeCrs,
|
||||
public_key: &CompactPublicKey,
|
||||
metadata: &[u8],
|
||||
key: &CudaKeySwitchingKey,
|
||||
seed: ReRandomizationSeed,
|
||||
streams: &CudaStreams,
|
||||
) -> crate::Result<CudaCompactCiphertextListExpander> {
|
||||
let (all_valid, r) = rayon::join(
|
||||
|| {
|
||||
self.h_proved_lists
|
||||
.ct_list
|
||||
.proved_lists
|
||||
.par_iter()
|
||||
.all(|(ct_list, proof)| {
|
||||
verify_lwe_compact_ciphertext_list(
|
||||
&ct_list.ct_list,
|
||||
&public_key.key.key,
|
||||
proof,
|
||||
crs,
|
||||
metadata,
|
||||
)
|
||||
.is_valid()
|
||||
})
|
||||
},
|
||||
|| self.re_randomize_and_expand_without_verification(key, public_key, seed, streams),
|
||||
);
|
||||
|
||||
if all_valid {
|
||||
return r;
|
||||
}
|
||||
|
||||
Err(crate::ErrorKind::InvalidZkProof.into())
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// - [CudaStreams::synchronize] __must__ be called after this function as soon as
|
||||
@@ -77,6 +114,46 @@ impl CudaProvenCompactCiphertextList {
|
||||
.expand(key, super::ZKType::Casting, streams)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// - [CudaStreams::synchronize] __must__ be called after this function as soon as
|
||||
/// synchronization is required
|
||||
pub fn re_randomize_and_expand_without_verification(
|
||||
&self,
|
||||
key: &CudaKeySwitchingKey,
|
||||
public_key: &CompactPublicKey,
|
||||
seed: ReRandomizationSeed,
|
||||
streams: &CudaStreams,
|
||||
) -> crate::Result<CudaCompactCiphertextListExpander> {
|
||||
let mut rerandomized = self.duplicate(streams);
|
||||
rerandomized.re_randomize(public_key, seed, streams)?;
|
||||
|
||||
rerandomized.expand_without_verification(key, streams)
|
||||
}
|
||||
|
||||
pub fn re_randomize(
|
||||
&mut self,
|
||||
public_key: &CompactPublicKey,
|
||||
seed: ReRandomizationSeed,
|
||||
streams: &CudaStreams,
|
||||
) -> crate::Result<()> {
|
||||
self.h_proved_lists.re_randomize(public_key, seed)?;
|
||||
let cpu_lists = self
|
||||
.h_proved_lists
|
||||
.ct_list
|
||||
.proved_lists
|
||||
.iter()
|
||||
.map(|(list, _)| list.clone())
|
||||
.collect();
|
||||
self.d_flattened_compact_lists =
|
||||
CudaFlattenedVecCompactCiphertextList::from_vec_shortint_compact_ciphertext_list(
|
||||
cpu_lists,
|
||||
self.h_proved_lists.info.clone(),
|
||||
streams,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn from_proven_compact_ciphertext_list(
|
||||
h_proved_lists: &ProvenCompactCiphertextList,
|
||||
streams: &CudaStreams,
|
||||
|
||||
@@ -0,0 +1,712 @@
|
||||
use crate::integer::prelude::ServerKeyDefaultCMux;
|
||||
use crate::integer::server_key::radix_parallel::ilog2::{BitValue, Direction};
|
||||
use crate::integer::{BooleanBlock, IntegerCiphertext, RadixCiphertext, ServerKey};
|
||||
use crate::shortint::ciphertext::Degree;
|
||||
use crate::shortint::server_key::LookupTableOwned;
|
||||
use crate::shortint::{CarryModulus, Ciphertext, MessageModulus};
|
||||
use rayon::prelude::*;
|
||||
|
||||
impl ServerKey {
|
||||
pub(crate) fn count_consecutive_bits_2_2_unsigned(
|
||||
&self,
|
||||
in_ct: &RadixCiphertext,
|
||||
direction: Direction,
|
||||
bit_value: BitValue,
|
||||
) -> RadixCiphertext {
|
||||
assert_eq!(self.message_modulus(), MessageModulus(4));
|
||||
assert_eq!(self.carry_modulus(), CarryModulus(4));
|
||||
|
||||
let input_num_bits = 2 * in_ct.blocks.len();
|
||||
|
||||
// output
|
||||
let num_output_bits = (input_num_bits as f64 + 1.).log2().ceil() as usize;
|
||||
|
||||
let num_output_blocks = num_output_bits.div_ceil(2);
|
||||
|
||||
let CountConsecutiveBitsResult { flag, mut digits } =
|
||||
self.unchecked_count_consecutive_bits_2_2_unsigned(in_ct, direction, bit_value);
|
||||
|
||||
digits.resize(num_output_blocks, self.key.create_trivial(0));
|
||||
|
||||
let true_ct = RadixCiphertext::from_blocks(digits);
|
||||
|
||||
let condition = BooleanBlock::new_unchecked(flag);
|
||||
|
||||
self.if_then_else_parallelized(&condition, &true_ct, input_num_bits as u64)
|
||||
}
|
||||
|
||||
// If there is at least one non zero/one bit in the input:
|
||||
// - flag is 1
|
||||
// - digits is the number of trailing/leading zeros/ones of the input
|
||||
// Otherwise, the flag and the digits are equal to 0
|
||||
//
|
||||
// Let's explain how the algorithm works for leading zeros.
|
||||
// Let's suppose we have a 64 bits input and
|
||||
// the input is not 0 (this case works a bit differently).
|
||||
// The result is on 6 bits grouped by 2 (b5_b4, b3_b2, b1_b0)
|
||||
//
|
||||
// b5_b4 is the index of the first (starting from MSB) group of 16 bits
|
||||
// which has (at least) one bit equal to 1.
|
||||
// (example, if b5_b4=0, then leading_zeros < 16 thus (at least) one of the 16 MSB is not 0).
|
||||
// (example, if b5_b4=1, then 16 <= leading_zeros < 32 thus the 16 MSB are
|
||||
// all 0 and (at least) one the one of the 16 next MSB is not 0).
|
||||
//
|
||||
// In this group of 16 bits:
|
||||
// - b3_b2 is is the index of the first (starting from MSB) group of 4 bits which has (at
|
||||
// least) one bit equal to 1
|
||||
// In this group of 4 bits:
|
||||
// - b1_b0 is is the index of the first (starting from MSB) bit equal to 1
|
||||
//
|
||||
// This is the top down view
|
||||
//
|
||||
// In the algorithm, we use the bottom up view.
|
||||
// We compute the "b1_b0" of each group of 4 bits
|
||||
// and a boolean flag to know if (at least) one of the bits are not 0.
|
||||
//
|
||||
// We then group by 16 bits.
|
||||
// We compute the "b3_b2" of each group.
|
||||
// It is the index of the first (starting from MSB) group of 4 with a non zero flag.
|
||||
// We select its "b1_b0" among the 4 computed in the previous step.
|
||||
// We now have "b3_b2_b1_b0" for each group of 16.
|
||||
// We also need a flag to know if (at least) one of the bits are not 0.
|
||||
//
|
||||
// We now have 4 groups of 16.
|
||||
// "b5_b4" is the index of the first (starting from MSB) group of 16 with a non zero flag.
|
||||
// We select its "b3_b2_b1_b0" among the 4 computed in the previous step.
|
||||
// We also compute a flag to know if (at least) one of the bits are not 0.
|
||||
//
|
||||
// We now have the final result
|
||||
pub(crate) fn unchecked_count_consecutive_bits_2_2_unsigned(
|
||||
&self,
|
||||
in_ct: &RadixCiphertext,
|
||||
direction: Direction,
|
||||
bit_value: BitValue,
|
||||
) -> CountConsecutiveBitsResult {
|
||||
assert_eq!(self.message_modulus(), MessageModulus(4));
|
||||
assert_eq!(self.carry_modulus(), CarryModulus(4));
|
||||
|
||||
if in_ct.blocks().is_empty() {
|
||||
return CountConsecutiveBitsResult {
|
||||
flag: self.key.create_trivial(0),
|
||||
digits: Vec::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let num_blocks_after_init = in_ct.blocks().len() as f64 / 2_f64;
|
||||
|
||||
let reductions_depth = num_blocks_after_init.log(4_f64).ceil() as usize;
|
||||
|
||||
let mut up_scale_digits: bool = reductions_depth % 2 == 1;
|
||||
|
||||
let digit_out_scale_init = if up_scale_digits { 2 } else { 0 };
|
||||
|
||||
let mut state: Vec<BlockState> = match direction {
|
||||
Direction::Trailing => in_ct
|
||||
.blocks()
|
||||
.par_chunks(2)
|
||||
.map(|chunk| self.pack_blocks_by_pair(chunk, direction, bit_value))
|
||||
.enumerate()
|
||||
.map(|(index, ct)| {
|
||||
self.initial_state(&ct, index % 4, digit_out_scale_init, direction, bit_value)
|
||||
})
|
||||
.collect(),
|
||||
// par_rchunk(2).enumerate().rev() to:
|
||||
// - get a reverse index without changing the order
|
||||
// - align chunk on the most significant blocks (if the last chunk has only one element)
|
||||
Direction::Leading => in_ct
|
||||
.blocks()
|
||||
.par_rchunks(2)
|
||||
.map(|chunk| self.pack_blocks_by_pair(chunk, direction, bit_value))
|
||||
.enumerate()
|
||||
.rev()
|
||||
.map(|(reverse_index, ct)| {
|
||||
self.initial_state(
|
||||
&ct,
|
||||
reverse_index % 4,
|
||||
digit_out_scale_init,
|
||||
direction,
|
||||
bit_value,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
while state.len() != 1 {
|
||||
up_scale_digits = !up_scale_digits;
|
||||
|
||||
state = match direction {
|
||||
Direction::Trailing => state
|
||||
.par_chunks(4)
|
||||
.enumerate()
|
||||
.map(|(index, chunk)| {
|
||||
self.reduce_blocks(chunk, index % 4, up_scale_digits, direction)
|
||||
})
|
||||
.collect(),
|
||||
// par_rchunk(4).enumerate().rev() to:
|
||||
// - get a reverse index without changing the order
|
||||
// - align chunk on the most significant blocks (if the last chunk does not have 4
|
||||
// elements)
|
||||
Direction::Leading => state
|
||||
.par_rchunks(4)
|
||||
.enumerate()
|
||||
.rev()
|
||||
.map(|(reverse_index, chunk)| {
|
||||
self.reduce_blocks(chunk, reverse_index % 4, up_scale_digits, direction)
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
}
|
||||
|
||||
assert!(!up_scale_digits);
|
||||
|
||||
let BlockState {
|
||||
flag,
|
||||
digits: digits_state,
|
||||
} = state.pop().unwrap();
|
||||
|
||||
CountConsecutiveBitsResult {
|
||||
flag,
|
||||
digits: digits_state.select(self, up_scale_digits, direction),
|
||||
}
|
||||
}
|
||||
|
||||
fn pack_blocks_by_pair(
|
||||
&self,
|
||||
chunk: &[Ciphertext],
|
||||
direction: Direction,
|
||||
bit_value: BitValue,
|
||||
) -> Ciphertext {
|
||||
match chunk {
|
||||
[chunk0, chunk1] => {
|
||||
// chunk 1 is most significant, so we scale it to the carries
|
||||
let mut result = self.key.unchecked_scalar_mul(chunk1, 4);
|
||||
|
||||
self.key.unchecked_add_assign(&mut result, chunk0);
|
||||
|
||||
result
|
||||
}
|
||||
[chunk0] => {
|
||||
// We must pad in case the input has a even number of blocks
|
||||
// The pad must not change the result
|
||||
// This padding value will only have an impact on the final result if all other bits
|
||||
// are equal to the given bit_value In this case, we want to pad
|
||||
// with bits equal to the bit_value so the result is flag = 0,
|
||||
// digits= [0, ..., 0] as specified
|
||||
let padding_value = match bit_value {
|
||||
BitValue::Zero => 0,
|
||||
BitValue::One => 3,
|
||||
};
|
||||
|
||||
match direction {
|
||||
// We put the padding in the MSB
|
||||
Direction::Trailing => self.key.unchecked_scalar_add(chunk0, 4 * padding_value),
|
||||
// We put the padding in the LSB
|
||||
Direction::Leading => {
|
||||
let mut result = self.key.unchecked_scalar_mul(chunk0, 4);
|
||||
self.key
|
||||
.unchecked_scalar_add_assign(&mut result, padding_value);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn initial_state(
|
||||
&self,
|
||||
ct: &Ciphertext,
|
||||
flag_out_scale: usize,
|
||||
digit_out_scale: usize,
|
||||
direction: Direction,
|
||||
bit_value: BitValue,
|
||||
) -> BlockState {
|
||||
let (flag, new_digit) = rayon::join(
|
||||
|| {
|
||||
let lut_non_full_flag = self.lut_non_full_flag(flag_out_scale, bit_value);
|
||||
|
||||
self.key.apply_lookup_table(ct, &lut_non_full_flag)
|
||||
},
|
||||
|| {
|
||||
let lut_new_digit = self.lut_new_digit_init(digit_out_scale, direction, bit_value);
|
||||
|
||||
self.key.apply_lookup_table(ct, &lut_new_digit)
|
||||
},
|
||||
);
|
||||
|
||||
BlockState {
|
||||
flag,
|
||||
digits: DigitsUnselected {
|
||||
new_digit,
|
||||
old_digits_to_select: Vec::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Put blocks of n digits from a slice to groups of 4
|
||||
//
|
||||
// Each group of 4 is reduced to a single block of (n+1) digits as such:
|
||||
// The fist block with a non zero flag is selected.
|
||||
// The new digits are the digits of this block to which we add the index of this selected block
|
||||
fn reduce_blocks(
|
||||
&self,
|
||||
blocks: &[BlockState],
|
||||
out_flag_scale: usize,
|
||||
up_scale_digits: bool,
|
||||
direction: Direction,
|
||||
) -> BlockState {
|
||||
let (in_flags, digits): (Vec<_>, Vec<_>) = blocks
|
||||
.iter()
|
||||
.map(
|
||||
|BlockState {
|
||||
flag,
|
||||
digits: digits_state,
|
||||
}| (flag, digits_state),
|
||||
)
|
||||
.unzip();
|
||||
|
||||
// old digits are one step behind the flag and new_digit
|
||||
// so opposite scaling
|
||||
let up_scale_old_digits = !up_scale_digits;
|
||||
|
||||
let ((flag, new_digit), old_digits_to_select) = rayon::join(
|
||||
|| self.build_new_flag_and_digit(out_flag_scale, up_scale_digits, &in_flags),
|
||||
|| self.reduce_digit_states(&digits, up_scale_old_digits, direction),
|
||||
);
|
||||
|
||||
BlockState {
|
||||
flag,
|
||||
digits: DigitsUnselected {
|
||||
new_digit,
|
||||
old_digits_to_select,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// The input is expected to be (at most) 4 binary flags, scaled by 0, 1, 2, 3 (0_0_0_f, 0_0_f_0,
|
||||
// 0_f_0_0, f_0_0_0) The new flag is 0 if all input flags are 0, 1 otherwise
|
||||
// The new digit is the scaling of the smallest non zero flag, 0 otherwise
|
||||
// The output does not depend on the order of the input flags (as they are all summed)
|
||||
fn build_new_flag_and_digit(
|
||||
&self,
|
||||
out_flag_scale: usize,
|
||||
up_scale_digits: bool,
|
||||
flags: &[&Ciphertext],
|
||||
) -> (Ciphertext, Ciphertext) {
|
||||
let sum_flags = flags.iter().fold(self.key.create_trivial(0), |mut a, b| {
|
||||
self.key.unchecked_add_assign(&mut a, b);
|
||||
a
|
||||
});
|
||||
|
||||
let out_digit_scale = if up_scale_digits { 2 } else { 0 };
|
||||
|
||||
rayon::join(
|
||||
|| {
|
||||
let lut_non_zero_flag = self.lut_non_zero_flag(out_flag_scale);
|
||||
|
||||
self.key.apply_lookup_table(&sum_flags, &lut_non_zero_flag)
|
||||
},
|
||||
|| {
|
||||
let lut_new_digit = self.lut_new_digit_from_sum_flags(out_digit_scale);
|
||||
|
||||
self.key.apply_lookup_table(&sum_flags, &lut_new_digit)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn reduce_digit_states(
|
||||
&self,
|
||||
states: &[&DigitsUnselected],
|
||||
up_scale_digits: bool,
|
||||
direction: Direction,
|
||||
) -> Vec<DigitUnselected> {
|
||||
// we'll want to select one of the lists of digits (Vec<Ciphertext>)
|
||||
// we'll want unselected_list_of_digits[new_digit]
|
||||
let unselected_list_of_digits: Vec<Vec<Ciphertext>> = states
|
||||
.par_iter()
|
||||
.map(|digits_unselected| digits_unselected.select(self, up_scale_digits, direction))
|
||||
.collect();
|
||||
|
||||
// after transpose, each element is an UnselectedDigit (i.e. a list of digits to select
|
||||
// from) we'll want
|
||||
// [
|
||||
// list_of_unselected_digits[0][new_digit],
|
||||
// list_of_unselected_digits[1][new_digit],
|
||||
// ...
|
||||
// ]
|
||||
let list_of_unselected_digits = transpose(unselected_list_of_digits);
|
||||
|
||||
list_of_unselected_digits
|
||||
.into_iter()
|
||||
.map(|digits_to_select_from| DigitUnselected {
|
||||
digits_to_select_from,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn select_old_digit_lut(
|
||||
&self,
|
||||
up_scale_digits: bool,
|
||||
selector: usize,
|
||||
) -> crate::shortint::server_key::LookupTable<Vec<u64>> {
|
||||
self.key.generate_lookup_table(|x: u64| {
|
||||
let in_carries = x >> 2;
|
||||
let in_message = x & 3;
|
||||
|
||||
// The input of the resulting LUT is supposed to have the old/new digits in
|
||||
// carry/message depending on up_scale_digits
|
||||
let (old_digit, new_digit) = if up_scale_digits {
|
||||
(in_message, in_carries)
|
||||
} else {
|
||||
(in_carries, in_message)
|
||||
};
|
||||
|
||||
if new_digit == selector as u64 {
|
||||
if up_scale_digits {
|
||||
old_digit << 2
|
||||
} else {
|
||||
old_digit
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// build a lut which returns
|
||||
// `0` if the 4 bits input is full of the bit_value (0000 for Zero or 1111 for One)
|
||||
// `1 << out_scale` otherwise
|
||||
fn lut_non_full_flag(&self, out_scale: usize, bit_value: BitValue) -> LookupTableOwned {
|
||||
let full_value = match bit_value {
|
||||
BitValue::Zero => 0,
|
||||
BitValue::One => 15,
|
||||
};
|
||||
|
||||
self.key
|
||||
.generate_lookup_table(|x| u64::from(x != full_value) << out_scale)
|
||||
}
|
||||
|
||||
fn lut_non_zero_flag(&self, out_scale: usize) -> LookupTableOwned {
|
||||
self.key
|
||||
.generate_lookup_table(|x| u64::from(x != 0) << out_scale)
|
||||
}
|
||||
|
||||
// build a lut which
|
||||
// return `0` if the input is full of the bit_value (0000 for Zero or 1111 for One)
|
||||
// otherwise, return the trailing/leading zeros/ones of the 4 bits input, scaled by `out_scale`
|
||||
fn lut_new_digit_init(
|
||||
&self,
|
||||
out_scale: usize,
|
||||
direction: Direction,
|
||||
bit_value: BitValue,
|
||||
) -> LookupTableOwned {
|
||||
self.key.generate_lookup_table(|x: u64| {
|
||||
let full_value = match bit_value {
|
||||
BitValue::Zero => 0,
|
||||
BitValue::One => 15,
|
||||
};
|
||||
|
||||
let input_precision = 4;
|
||||
|
||||
let leading_bits_to_ignore = u64::BITS - input_precision;
|
||||
|
||||
let new_digit = if x == full_value {
|
||||
0
|
||||
} else {
|
||||
match (direction, bit_value) {
|
||||
(Direction::Trailing, BitValue::Zero) => x.trailing_zeros(),
|
||||
(Direction::Trailing, BitValue::One) => x.trailing_ones(),
|
||||
(Direction::Leading, BitValue::Zero) => {
|
||||
(x << leading_bits_to_ignore).leading_zeros()
|
||||
}
|
||||
(Direction::Leading, BitValue::One) => {
|
||||
(x << leading_bits_to_ignore).leading_ones()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(new_digit as u64) << out_scale
|
||||
})
|
||||
}
|
||||
|
||||
// build a lut
|
||||
// the input is expected to the sum of 4 binary flags, scaled by 0, 1, 2, 3 (0_0_0_f0 + 0_0_f1_0
|
||||
// + 0_f2_0_0 + f3_0_0_0 = f3_f2_f1_f0) if all the flags are 0, the result if 0
|
||||
// otherwise, the result is the index of the first of these flag which is not 0, starting by f0.
|
||||
// this function is used in all cases (trailing/leading zeros/ones) in all steps expect the
|
||||
// first one
|
||||
fn lut_new_digit_from_sum_flags(&self, out_scale: usize) -> LookupTableOwned {
|
||||
self.key.generate_lookup_table(|x: u64| {
|
||||
let new_digit = if x == 0 { 0 } else { x.trailing_zeros() as u64 };
|
||||
|
||||
new_digit << out_scale
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn transpose<T>(v: Vec<Vec<T>>) -> Vec<Vec<T>> {
|
||||
if v.is_empty() {
|
||||
return vec![];
|
||||
}
|
||||
let num_cols = v[0].len();
|
||||
let mut row_iterators: Vec<_> = v.into_iter().map(|row| row.into_iter()).collect();
|
||||
(0..num_cols)
|
||||
.map(|_| {
|
||||
row_iterators
|
||||
.iter_mut()
|
||||
.map(|row_iterator| row_iterator.next().unwrap())
|
||||
.collect::<Vec<T>>()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct BlockState {
|
||||
flag: Ciphertext,
|
||||
digits: DigitsUnselected,
|
||||
}
|
||||
|
||||
// When doing the reduction, we want to use the new_digit to select each unselected_digit
|
||||
// We then add the new digit to the end of the list
|
||||
struct DigitsUnselected {
|
||||
new_digit: Ciphertext,
|
||||
old_digits_to_select: Vec<DigitUnselected>,
|
||||
}
|
||||
|
||||
impl DigitsUnselected {
|
||||
fn select(
|
||||
&self,
|
||||
sk: &ServerKey,
|
||||
up_scale_digits: bool,
|
||||
direction: Direction,
|
||||
) -> Vec<Ciphertext> {
|
||||
let Self {
|
||||
new_digit,
|
||||
old_digits_to_select,
|
||||
} = self;
|
||||
|
||||
let mut result: Vec<_> = old_digits_to_select
|
||||
.par_iter()
|
||||
.map(|digit| digit.select(new_digit, sk, up_scale_digits, direction))
|
||||
.collect();
|
||||
|
||||
result.push(new_digit.clone());
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
// Stores a list of (at most) 4 ciphertexts each storing a digit in carries or messages
|
||||
// This type is meant to be reduced to a single selected digit
|
||||
struct DigitUnselected {
|
||||
digits_to_select_from: Vec<Ciphertext>,
|
||||
}
|
||||
|
||||
impl DigitUnselected {
|
||||
fn select(
|
||||
&self,
|
||||
selector: &Ciphertext,
|
||||
sk: &ServerKey,
|
||||
up_scale_digits: bool,
|
||||
direction: Direction,
|
||||
) -> Ciphertext {
|
||||
let digits_to_select_from: Vec<&Ciphertext> = match direction {
|
||||
Direction::Trailing => self.digits_to_select_from.iter().collect(),
|
||||
Direction::Leading => self.digits_to_select_from.iter().rev().collect(),
|
||||
};
|
||||
|
||||
// Computation is sum_i( if i==selector { digits_to_select_from[i] } else {0} )
|
||||
// Which gives digits_to_select_from[selector]
|
||||
let mut result = digits_to_select_from
|
||||
.par_iter()
|
||||
.enumerate()
|
||||
.map(|(i, old_digit)| {
|
||||
let sum = sk.key.unchecked_add(old_digit, selector);
|
||||
|
||||
let acc = sk.select_old_digit_lut(up_scale_digits, i);
|
||||
|
||||
sk.key.apply_lookup_table(&sum, &acc)
|
||||
})
|
||||
.reduce(
|
||||
|| sk.key.create_trivial(0),
|
||||
|mut sum: Ciphertext, new: Ciphertext| {
|
||||
sk.key.unchecked_add_assign(&mut sum, &new);
|
||||
|
||||
sum
|
||||
},
|
||||
);
|
||||
|
||||
result.degree = if up_scale_digits {
|
||||
Degree(12)
|
||||
} else {
|
||||
Degree(3)
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CountConsecutiveBitsResult {
|
||||
#[allow(unused)]
|
||||
pub(crate) flag: Ciphertext,
|
||||
pub(crate) digits: Vec<Ciphertext>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::integer::keycache::KEY_CACHE;
|
||||
use crate::integer::{ClientKey, IntegerKeyKind, RadixCiphertext};
|
||||
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
#[test]
|
||||
fn test_unchecked_new_count_consecutive_bits_trivial_input_param_message_2_carry_2() {
|
||||
let param = PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
|
||||
|
||||
let (cks, sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
|
||||
|
||||
for direction in [Direction::Leading, Direction::Trailing] {
|
||||
for bit_value in [BitValue::Zero, BitValue::One] {
|
||||
for num_blocks in 1..64 {
|
||||
let num_bits = 2 * num_blocks;
|
||||
|
||||
println!("num_bits: {num_bits}",);
|
||||
|
||||
for target_result in 0..=num_bits {
|
||||
for _ in 0..10 {
|
||||
test_one_random(
|
||||
&cks,
|
||||
&sks,
|
||||
num_blocks,
|
||||
direction,
|
||||
bit_value,
|
||||
target_result,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_one_random(
|
||||
cks: &ClientKey,
|
||||
sks: &ServerKey,
|
||||
num_blocks: usize,
|
||||
direction: Direction,
|
||||
bit_value: BitValue,
|
||||
target_result: usize,
|
||||
) {
|
||||
let num_bits = 2 * num_blocks;
|
||||
|
||||
let message = build_number(num_bits, target_result, direction, bit_value);
|
||||
|
||||
let (expected_flag, expected_result) =
|
||||
expected_result(num_bits, message, direction, bit_value);
|
||||
|
||||
let (flag, result) =
|
||||
get_result_for_trivial(cks, sks, num_blocks, message, direction, bit_value);
|
||||
|
||||
assert_eq!(expected_flag, flag);
|
||||
|
||||
if target_result == num_bits {
|
||||
assert!(!expected_flag);
|
||||
|
||||
assert_eq!(expected_result, 0);
|
||||
} else {
|
||||
assert_eq!(target_result as u64, expected_result);
|
||||
}
|
||||
|
||||
assert_eq!(expected_result, result);
|
||||
}
|
||||
|
||||
fn expected_result(
|
||||
num_bits: usize,
|
||||
message: u128,
|
||||
direction: Direction,
|
||||
bit_value: BitValue,
|
||||
) -> (bool, u64) {
|
||||
let full_value = match bit_value {
|
||||
BitValue::Zero => 0,
|
||||
BitValue::One => (1 << num_bits) - 1,
|
||||
};
|
||||
|
||||
if message == full_value {
|
||||
(false, 0)
|
||||
} else {
|
||||
let leading_bits_to_ignore = 128 - num_bits;
|
||||
|
||||
let expected_result = match (direction, bit_value) {
|
||||
(Direction::Trailing, BitValue::Zero) => message.trailing_zeros(),
|
||||
(Direction::Trailing, BitValue::One) => message.trailing_ones(),
|
||||
(Direction::Leading, BitValue::Zero) => {
|
||||
(message << leading_bits_to_ignore).leading_zeros()
|
||||
}
|
||||
(Direction::Leading, BitValue::One) => {
|
||||
(message << leading_bits_to_ignore).leading_ones()
|
||||
}
|
||||
};
|
||||
|
||||
(true, expected_result as u64)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_number(
|
||||
num_bits: usize,
|
||||
target_result: usize,
|
||||
direction: Direction,
|
||||
bit_value: BitValue,
|
||||
) -> u128 {
|
||||
let full_bits = num_bits - target_result;
|
||||
|
||||
let message: u128 = if full_bits == 0 {
|
||||
0
|
||||
} else {
|
||||
match direction {
|
||||
Direction::Leading => {
|
||||
(1_u128 << (full_bits - 1)) + thread_rng().gen_range(0..1 << (full_bits - 1))
|
||||
}
|
||||
Direction::Trailing => {
|
||||
let full_number =
|
||||
1_u128 + (thread_rng().gen_range(0..1 << (full_bits - 1)) << 1);
|
||||
full_number << target_result
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match bit_value {
|
||||
BitValue::Zero => message,
|
||||
//complement
|
||||
BitValue::One => (1_u128 << num_bits) - 1 - message,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_result_for_trivial(
|
||||
cks: &ClientKey,
|
||||
sks: &ServerKey,
|
||||
num_blocks: usize,
|
||||
message: u128,
|
||||
direction: Direction,
|
||||
bit_value: BitValue,
|
||||
) -> (bool, u64) {
|
||||
let input: RadixCiphertext = sks.create_trivial_radix(message, num_blocks);
|
||||
|
||||
let CountConsecutiveBitsResult { flag, digits } =
|
||||
sks.unchecked_count_consecutive_bits_2_2_unsigned(&input, direction, bit_value);
|
||||
|
||||
let flag = match cks.key.decrypt_message_and_carry(&flag) {
|
||||
0 => false,
|
||||
1 => true,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let mut result = 0;
|
||||
for (i, digit) in digits.iter().enumerate() {
|
||||
let digit = cks.key.decrypt_message_and_carry(digit);
|
||||
|
||||
result += digit << (2 * i);
|
||||
}
|
||||
|
||||
(flag, result)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ use crate::integer::{
|
||||
BooleanBlock, IntegerCiphertext, IntegerRadixCiphertext, RadixCiphertext, ServerKey,
|
||||
SignedRadixCiphertext,
|
||||
};
|
||||
use crate::shortint::Ciphertext;
|
||||
use crate::shortint::{CarryModulus, Ciphertext, MessageModulus};
|
||||
use rayon::prelude::*;
|
||||
|
||||
/// A 'bit' value
|
||||
@@ -140,6 +140,12 @@ impl ServerKey {
|
||||
return self.create_trivial_zero_radix(0);
|
||||
}
|
||||
|
||||
if self.message_modulus() == MessageModulus(4) && self.carry_modulus() == CarryModulus(4) {
|
||||
let unsigned_ct = RadixCiphertext::from_blocks(ct.blocks().to_vec());
|
||||
|
||||
return self.count_consecutive_bits_2_2_unsigned(&unsigned_ct, direction, bit_value);
|
||||
}
|
||||
|
||||
let num_bits_in_message = self.key.message_modulus.0.ilog2();
|
||||
let original_num_blocks = ct.blocks().len();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ mod bitwise_op;
|
||||
mod block_shift;
|
||||
pub(crate) mod cmux;
|
||||
mod comparison;
|
||||
mod count_consecutive_bits;
|
||||
mod div_mod;
|
||||
mod modulus_switch_compression;
|
||||
mod mul;
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::core_crypto::commons::math::random::{DefaultRandomGenerator, XofSeed}
|
||||
use crate::core_crypto::commons::parameters::{LweCiphertextCount, PlaintextCount};
|
||||
use crate::core_crypto::commons::traits::*;
|
||||
use crate::core_crypto::entities::{LweCiphertext, LweCompactCiphertextList, PlaintextList};
|
||||
use crate::core_crypto::prelude::lwe_compact_ciphertext_list_add_assign;
|
||||
use crate::shortint::ciphertext::NoiseLevel;
|
||||
use crate::shortint::key_switching_key::KeySwitchingKeyMaterialView;
|
||||
use crate::shortint::{Ciphertext, CompactPublicKey, PBSOrder};
|
||||
@@ -18,6 +19,8 @@ use rayon::prelude::*;
|
||||
use sha3::digest::{ExtendableOutput, Update};
|
||||
use std::io::Read;
|
||||
|
||||
use super::CompactCiphertextList;
|
||||
|
||||
/// Size of the re-randomization seed in bits
|
||||
const RERAND_SEED_BITS: usize = 256;
|
||||
|
||||
@@ -248,6 +251,14 @@ impl CompactPublicKey {
|
||||
let mut encryption_generator =
|
||||
NoiseRandomGenerator::<DefaultRandomGenerator>::new_from_seed(seed.0);
|
||||
|
||||
self.prepare_cpk_zero_for_rerand_with_generator(&mut encryption_generator, zero_count)
|
||||
}
|
||||
|
||||
pub(crate) fn prepare_cpk_zero_for_rerand_with_generator(
|
||||
&self,
|
||||
encryption_generator: &mut NoiseRandomGenerator<DefaultRandomGenerator>,
|
||||
zero_count: LweCiphertextCount,
|
||||
) -> LweCompactCiphertextList<Vec<u64>> {
|
||||
let mut encryption_of_zero = LweCompactCiphertextList::new(
|
||||
0,
|
||||
self.parameters().encryption_lwe_dimension.to_lwe_size(),
|
||||
@@ -268,7 +279,7 @@ impl CompactPublicKey {
|
||||
&plaintext_list,
|
||||
cpk_encryption_noise_distribution,
|
||||
cpk_encryption_noise_distribution,
|
||||
&mut encryption_generator,
|
||||
encryption_generator,
|
||||
);
|
||||
|
||||
encryption_of_zero
|
||||
@@ -310,8 +321,7 @@ impl CompactPublicKey {
|
||||
KeySwitchingKeyMaterialView.";
|
||||
return Err(crate::error!("{}", err));
|
||||
} else if ksk_output_lwe_size != ct.ct.lwe_size() {
|
||||
let err =
|
||||
"Mismatched LweSwize between Ciphertext being re-randomized and provided \
|
||||
let err = "Mismatched LweSize between Ciphertext being re-randomized and provided \
|
||||
KeySwitchingKeyMaterialView.";
|
||||
return Err(crate::error!("{}", err));
|
||||
} else if ct.noise_level() > NoiseLevel::NOMINAL {
|
||||
@@ -391,7 +401,7 @@ impl CompactPublicKey {
|
||||
|
||||
for ct in cts.iter() {
|
||||
if key_lwe_size != ct.ct.lwe_size() {
|
||||
let err = "Mismatched LweSwize between Ciphertexts \
|
||||
let err = "Mismatched LweSize between Ciphertexts \
|
||||
being re-randomized and provided CompactPublicKey";
|
||||
return Err(crate::error!("{}", err));
|
||||
} else if ct.noise_level() > NoiseLevel::NOMINAL {
|
||||
@@ -417,28 +427,54 @@ impl CompactPublicKey {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Re-randomize compact ciphertext lists using the provided seed.
|
||||
pub fn re_randomize_compact_ciphertext_lists<'a>(
|
||||
&self,
|
||||
compact_lists: impl Iterator<Item = &'a mut CompactCiphertextList>,
|
||||
seed: ReRandomizationSeed,
|
||||
) -> crate::Result<()> {
|
||||
let key_lwe_size = self.key.lwe_dimension().to_lwe_size();
|
||||
let mut encryption_generator =
|
||||
NoiseRandomGenerator::<DefaultRandomGenerator>::new_from_seed(seed.0);
|
||||
|
||||
for list in compact_lists {
|
||||
if key_lwe_size != list.ct_list.lwe_size() {
|
||||
return Err(crate::error!(
|
||||
"Mismatched LweSize between Compact Lists \
|
||||
being re-randomized and provided CompactPublicKey",
|
||||
));
|
||||
}
|
||||
let encryption_of_zero = self.prepare_cpk_zero_for_rerand_with_generator(
|
||||
&mut encryption_generator,
|
||||
list.ct_list.lwe_ciphertext_count(),
|
||||
);
|
||||
lwe_compact_ciphertext_list_add_assign(&mut list.ct_list, &encryption_of_zero);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
use super::*;
|
||||
use crate::shortint::ciphertext::ShortintCompactCiphertextListCastingMode;
|
||||
use crate::shortint::key_switching_key::{KeySwitchingKeyBuildHelper, KeySwitchingKeyMaterial};
|
||||
use crate::shortint::parameters::test_params::{
|
||||
TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2,
|
||||
};
|
||||
use crate::shortint::parameters::test_params::*;
|
||||
use crate::shortint::parameters::{
|
||||
AtomicPatternParameters, CompactPublicKeyEncryptionParameters, ReRandomizationParameters,
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS,
|
||||
};
|
||||
use crate::shortint::{gen_keys, CompactPrivateKey};
|
||||
use crate::shortint::{gen_keys, CompactPrivateKey, KeySwitchingKeyView};
|
||||
|
||||
/// Test the case where we rerand more ciphertexts that what can be stored in one cpk lwe
|
||||
/// Test the trivial case
|
||||
#[test]
|
||||
fn test_rerand_with_dedicated_cpk_ci_run_filter() {
|
||||
let compute_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||
let compute_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let cpk_params = TEST_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
|
||||
let rerand_ksk_params =
|
||||
TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
@@ -451,7 +487,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_rerand_with_derived_cpk_ci_run_filter() {
|
||||
let compute_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||
let compute_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let rerand_params = ReRandomizationParameters::DerivedCPKWithoutKeySwitch;
|
||||
|
||||
test_rerand_impl(compute_params.into(), None, rerand_params);
|
||||
@@ -560,4 +596,125 @@ mod test {
|
||||
assert_eq!(dec, 3);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rerand_compact_list_ci_run_filter() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let compute_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let cpk_params = TEST_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
|
||||
let ks_params = TEST_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
const CT_COUNT: usize = 37;
|
||||
|
||||
let (cks, sks) = gen_keys(compute_params);
|
||||
|
||||
let privk = CompactPrivateKey::new(cpk_params);
|
||||
let pubk = CompactPublicKey::new(&privk);
|
||||
|
||||
let ksk_builder = KeySwitchingKeyBuildHelper::new((&privk, None), (&cks, &sks), ks_params);
|
||||
let casting_key: KeySwitchingKeyView<'_> = ksk_builder.as_key_switching_key_view();
|
||||
|
||||
let casting_mode = ShortintCompactCiphertextListCastingMode::CastIfNecessary {
|
||||
casting_key,
|
||||
functions: None,
|
||||
};
|
||||
|
||||
let messages: [u64; CT_COUNT] =
|
||||
core::array::from_fn(|_| rng.gen_range(0..cpk_params.message_modulus.0));
|
||||
let mut enc = pubk.encrypt_slice(&messages);
|
||||
|
||||
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rng.gen());
|
||||
let mut re_rand_context = ReRandomizationContext::new(*b"TFHE_Rrd", *b"TFHE_Enc");
|
||||
|
||||
re_rand_context.add_ciphertext_data_slice(enc.ct_list.as_ref());
|
||||
re_rand_context.add_bytes(&nonce);
|
||||
re_rand_context.add_bytes(b"expand");
|
||||
|
||||
let mut seeder = re_rand_context.finalize();
|
||||
|
||||
pubk.re_randomize_compact_ciphertext_lists(std::iter::once(&mut enc), seeder.next_seed())
|
||||
.unwrap();
|
||||
|
||||
let cast = enc.expand(casting_mode).unwrap();
|
||||
|
||||
assert_eq!(cast.len(), CT_COUNT);
|
||||
for (ct, clear) in cast.iter().zip(&messages) {
|
||||
assert_eq!(cks.decrypt(ct), *clear)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zk-pok")]
|
||||
#[test]
|
||||
fn test_rerand_proven_compact_list_ci_run_filter() {
|
||||
use crate::zk::{CompactPkeCrs, ZkComputeLoad};
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let compute_params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let cpk_params = TEST_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
|
||||
let ks_params = TEST_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
// Make sure that the resulting proven list will be composed of multiple inner compact lists
|
||||
const CT_COUNT: usize = 37;
|
||||
|
||||
let (cks, sks) = gen_keys(compute_params);
|
||||
|
||||
let privk = CompactPrivateKey::new(cpk_params);
|
||||
let pubk = CompactPublicKey::new(&privk);
|
||||
|
||||
let crs = CompactPkeCrs::from_shortint_params(cpk_params, LweCiphertextCount(4)).unwrap();
|
||||
let metadata = [b's', b'h', b'o', b'r', b't', b'i', b'n', b't'];
|
||||
|
||||
let ksk_builder = KeySwitchingKeyBuildHelper::new((&privk, None), (&cks, &sks), ks_params);
|
||||
let casting_key: KeySwitchingKeyView<'_> = ksk_builder.as_key_switching_key_view();
|
||||
|
||||
let id = |x: u64| x;
|
||||
let dyn_id: &(dyn Fn(u64) -> u64 + Sync) = &id;
|
||||
|
||||
let functions = vec![Some(vec![dyn_id; 1]); CT_COUNT];
|
||||
|
||||
let casting_mode = ShortintCompactCiphertextListCastingMode::CastIfNecessary {
|
||||
casting_key,
|
||||
functions: Some(functions.as_slice()),
|
||||
};
|
||||
|
||||
let messages: [u64; CT_COUNT] =
|
||||
core::array::from_fn(|_| rng.gen_range(0..cpk_params.message_modulus.0));
|
||||
let mut enc = pubk
|
||||
.encrypt_and_prove_slice(
|
||||
&messages,
|
||||
&crs,
|
||||
&metadata,
|
||||
ZkComputeLoad::Verify,
|
||||
cpk_params.message_modulus.0,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let nonce: [u8; 256 / 8] = core::array::from_fn(|_| rng.gen());
|
||||
let mut re_rand_context = ReRandomizationContext::new(*b"TFHE_Rrd", *b"TFHE_Enc");
|
||||
|
||||
re_rand_context.add_ciphertext_data_slice(
|
||||
&enc.proved_lists
|
||||
.iter()
|
||||
.flat_map(|list| list.0.ct_list.as_ref())
|
||||
.copied()
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
re_rand_context.add_bytes(&nonce);
|
||||
re_rand_context.add_bytes(b"expand");
|
||||
|
||||
let mut seeder = re_rand_context.finalize();
|
||||
|
||||
pubk.re_randomize_compact_ciphertext_lists(
|
||||
enc.proved_lists.iter_mut().map(|(list, _)| list),
|
||||
seeder.next_seed(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cast = enc.expand_without_verification(casting_mode).unwrap();
|
||||
|
||||
assert_eq!(cast.len(), CT_COUNT);
|
||||
for (ct, clear) in cast.iter().zip(&messages) {
|
||||
assert_eq!(cks.decrypt(ct), *clear)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,10 +183,7 @@ impl ProvenCompactCiphertextList {
|
||||
}
|
||||
modes
|
||||
}
|
||||
None => vec![
|
||||
ShortintCompactCiphertextListCastingMode::NoCasting;
|
||||
self.proved_lists.len()
|
||||
],
|
||||
None => vec![casting_mode; self.proved_lists.len()],
|
||||
},
|
||||
ShortintCompactCiphertextListCastingMode::NoCasting => {
|
||||
vec![ShortintCompactCiphertextListCastingMode::NoCasting; self.proved_lists.len()]
|
||||
@@ -361,7 +358,8 @@ mod tests {
|
||||
use crate::conformance::ParameterSetConformant;
|
||||
use crate::core_crypto::prelude::LweCiphertextCount;
|
||||
use crate::shortint::ciphertext::ProvenCompactCiphertextListConformanceParams;
|
||||
use crate::shortint::parameters::*;
|
||||
use crate::shortint::parameters::test_params::*;
|
||||
use crate::shortint::parameters::ShortintCompactCiphertextListCastingMode;
|
||||
use crate::shortint::{
|
||||
ClientKey, CompactPrivateKey, CompactPublicKey, KeySwitchingKey, ServerKey,
|
||||
};
|
||||
@@ -372,9 +370,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_zk_ciphertext_encryption_ci_run_filter() {
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let ksk_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let pke_params = TEST_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let ksk_params = TEST_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let crs = CompactPkeCrs::from_shortint_params(pke_params, LweCiphertextCount(4)).unwrap();
|
||||
let priv_key = CompactPrivateKey::new(pke_params);
|
||||
@@ -434,9 +432,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_zk_compact_ciphertext_list_encryption_ci_run_filter() {
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let ksk_params = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let pke_params = TEST_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let ksk_params = TEST_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let crs = CompactPkeCrs::from_shortint_params(pke_params, LweCiphertextCount(4)).unwrap();
|
||||
let priv_key = CompactPrivateKey::new(pke_params);
|
||||
@@ -485,10 +483,59 @@ mod tests {
|
||||
assert_eq!(msgs, decrypted);
|
||||
}
|
||||
|
||||
/// Test a case where we need to keyswitch to compute params but no functions are applied
|
||||
#[test]
|
||||
fn test_zk_compact_ciphertext_list_encryption_no_fn_ci_run_filter() {
|
||||
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let pke_params = TEST_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let ksk_params = TEST_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let crs = CompactPkeCrs::from_shortint_params(pke_params, LweCiphertextCount(4)).unwrap();
|
||||
let priv_key = CompactPrivateKey::new(pke_params);
|
||||
let pub_key = CompactPublicKey::new(&priv_key);
|
||||
let ck = ClientKey::new(params);
|
||||
let sk = ServerKey::new(&ck);
|
||||
let ksk = KeySwitchingKey::new((&priv_key, None), (&ck, &sk), ksk_params);
|
||||
|
||||
let metadata = [b's', b'h', b'o', b'r', b't', b'i', b'n', b't'];
|
||||
|
||||
let msgs = (0..512)
|
||||
.map(|_| random::<u64>() % params.message_modulus.0)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let proven_ct = pub_key
|
||||
.encrypt_and_prove_slice(
|
||||
&msgs,
|
||||
&crs,
|
||||
&metadata,
|
||||
ZkComputeLoad::Proof,
|
||||
params.message_modulus.0,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(proven_ct.verify(&crs, &pub_key, &metadata).is_valid());
|
||||
|
||||
let expanded = proven_ct
|
||||
.verify_and_expand(
|
||||
&crs,
|
||||
&pub_key,
|
||||
&metadata,
|
||||
ShortintCompactCiphertextListCastingMode::CastIfNecessary {
|
||||
casting_key: ksk.as_view(),
|
||||
functions: None,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let decrypted = expanded
|
||||
.iter()
|
||||
.map(|ciphertext| ck.decrypt(ciphertext))
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(msgs, decrypted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zk_proof_conformance_ci_run_filter() {
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
let pke_params = TEST_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let max_lwe_count_per_compact_list = LweCiphertextCount(320);
|
||||
let total_lwe_count = 512;
|
||||
|
||||
@@ -120,13 +120,13 @@ impl NoiseSquashingCompressionKey {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::shortint::ciphertext::MaxDegree;
|
||||
use crate::shortint::ciphertext::{Degree, MaxDegree};
|
||||
use crate::shortint::keycache::KEY_CACHE;
|
||||
use crate::shortint::list_compression::private_key::NoiseSquashingCompressionPrivateKey;
|
||||
use crate::shortint::noise_squashing::{
|
||||
NoiseSquashingKey, NoiseSquashingPrivateKey, NoiseSquashingPrivateKeyView,
|
||||
};
|
||||
use crate::shortint::parameters::*;
|
||||
use crate::shortint::parameters::test_params::*;
|
||||
|
||||
use rand::prelude::*;
|
||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||
@@ -134,15 +134,15 @@ mod test {
|
||||
#[test]
|
||||
fn test_noise_squashing_compression_ci_run_filter() {
|
||||
let keycache_entry =
|
||||
KEY_CACHE.get_from_param(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
|
||||
KEY_CACHE.get_from_param(TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128);
|
||||
let (cks, sks) = (keycache_entry.client_key(), keycache_entry.server_key());
|
||||
let noise_squashing_private_key = NoiseSquashingPrivateKey::new(
|
||||
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
);
|
||||
let noise_squashing_key = NoiseSquashingKey::new(cks, &noise_squashing_private_key);
|
||||
|
||||
let compression_private_key = NoiseSquashingCompressionPrivateKey::new(
|
||||
NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
);
|
||||
|
||||
let compression_key = noise_squashing_private_key
|
||||
@@ -152,7 +152,8 @@ mod test {
|
||||
|
||||
let id_lut = sks.generate_lookup_table(|x| x);
|
||||
let max_ct_count =
|
||||
NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128.lwe_per_glwe;
|
||||
TEST_PARAM_NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
|
||||
.lwe_per_glwe;
|
||||
|
||||
for ct_count in [0, 1, max_ct_count.0] {
|
||||
// Generate random msgs
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::shortint::keycache::KEY_CACHE;
|
||||
use crate::shortint::noise_squashing::{
|
||||
CompressedNoiseSquashingKey, NoiseSquashingKey, NoiseSquashingPrivateKey,
|
||||
};
|
||||
use crate::shortint::parameters::test_params::*;
|
||||
use crate::shortint::parameters::*;
|
||||
use rand::prelude::*;
|
||||
use rand::thread_rng;
|
||||
@@ -9,15 +10,15 @@ use rand::thread_rng;
|
||||
#[test]
|
||||
fn test_classic_noise_squashing_ci_run_filter() {
|
||||
test_noise_squashing(
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_bit_noise_squashing_ci_run_filter() {
|
||||
test_noise_squashing(
|
||||
PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
NOISE_SQUASHING_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
);
|
||||
}
|
||||
@@ -25,8 +26,8 @@ fn test_multi_bit_noise_squashing_ci_run_filter() {
|
||||
#[test]
|
||||
fn test_ks32_noise_squashing_ci_run_filter() {
|
||||
test_noise_squashing(
|
||||
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
|
||||
NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -342,11 +342,13 @@ pub(crate) mod test {
|
||||
#[test]
|
||||
fn oprf_compare_plain_ci_run_filter() {
|
||||
use crate::shortint::gen_keys;
|
||||
use crate::shortint::parameters::test_params::TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
|
||||
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||
use crate::shortint::parameters::test_params::{
|
||||
TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
};
|
||||
|
||||
for params in [
|
||||
ShortintParameterSet::from(PARAM_MESSAGE_2_CARRY_2_KS_PBS),
|
||||
ShortintParameterSet::from(TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128),
|
||||
ShortintParameterSet::from(TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128),
|
||||
] {
|
||||
let (ck, sk) = gen_keys(params);
|
||||
@@ -447,15 +449,15 @@ pub(crate) mod test {
|
||||
use crate::shortint::gen_keys;
|
||||
use crate::shortint::parameters::test_params::{
|
||||
TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
TEST_PARAM_MULTI_BIT_GROUP_3_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128,
|
||||
};
|
||||
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||
|
||||
for params in [
|
||||
ShortintParameterSet::from(
|
||||
TEST_PARAM_MULTI_BIT_GROUP_3_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128,
|
||||
),
|
||||
ShortintParameterSet::from(PARAM_MESSAGE_2_CARRY_2_KS_PBS),
|
||||
ShortintParameterSet::from(TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128),
|
||||
ShortintParameterSet::from(TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128),
|
||||
] {
|
||||
let (ck, sk) = gen_keys(params);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use super::aliases::*;
|
||||
use super::current_params::meta::cpu::*;
|
||||
use super::current_params::meta::gpu::*;
|
||||
use super::current_params::*;
|
||||
@@ -85,7 +86,7 @@ pub const TEST_PARAM_MESSAGE_4_CARRY_4_COMPACT_PK_PBS_KS_GAUSSIAN_2M128: Classic
|
||||
pub const TEST_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M64: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M64;
|
||||
pub const TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M64: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M64;
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M64;
|
||||
pub const TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M64: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M64;
|
||||
pub const TEST_PARAM_MESSAGE_4_CARRY_4_KS_PBS_GAUSSIAN_2M64: ClassicPBSParameters =
|
||||
@@ -109,7 +110,7 @@ pub const TEST_PARAM_MESSAGE_1_CARRY_7_KS_PBS_GAUSSIAN_2M128: ClassicPBSParamete
|
||||
pub const TEST_PARAM_MESSAGE_2_CARRY_1_KS_PBS_GAUSSIAN_2M128: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_2_CARRY_1_KS_PBS_GAUSSIAN_2M128;
|
||||
pub const TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128;
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128;
|
||||
pub const TEST_PARAM_MESSAGE_2_CARRY_3_KS_PBS_GAUSSIAN_2M128: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_2_CARRY_3_KS_PBS_GAUSSIAN_2M128;
|
||||
pub const TEST_PARAM_MESSAGE_2_CARRY_4_KS_PBS_GAUSSIAN_2M128: ClassicPBSParameters =
|
||||
@@ -123,7 +124,7 @@ pub const TEST_PARAM_MESSAGE_3_CARRY_1_KS_PBS_GAUSSIAN_2M128: ClassicPBSParamete
|
||||
pub const TEST_PARAM_MESSAGE_3_CARRY_2_KS_PBS_GAUSSIAN_2M128: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_3_CARRY_2_KS_PBS_GAUSSIAN_2M128;
|
||||
pub const TEST_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128;
|
||||
PARAM_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M128;
|
||||
pub const TEST_PARAM_MESSAGE_3_CARRY_4_KS_PBS_GAUSSIAN_2M128: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_3_CARRY_4_KS_PBS_GAUSSIAN_2M128;
|
||||
pub const TEST_PARAM_MESSAGE_3_CARRY_5_KS_PBS_GAUSSIAN_2M128: ClassicPBSParameters =
|
||||
@@ -153,7 +154,7 @@ pub const TEST_PARAM_MESSAGE_2_CARRY_2_PBS_KS_GAUSSIAN_2M128: ClassicPBSParamete
|
||||
|
||||
// KS PBS TUniform
|
||||
pub const TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128: ClassicPBSParameters =
|
||||
V1_6_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
// MultiBit
|
||||
// CPU Gaussian
|
||||
@@ -179,8 +180,7 @@ pub const TEST_PARAM_GPU_MULTI_BIT_GROUP_3_MESSAGE_3_CARRY_3_KS_PBS_GAUSSIAN_2M6
|
||||
|
||||
// GPU TUniform
|
||||
pub const TEST_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
|
||||
MultiBitPBSParameters =
|
||||
V1_6_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
MultiBitPBSParameters = PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
// PKE ZK V1
|
||||
pub const TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV1:
|
||||
@@ -189,7 +189,7 @@ pub const TEST_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV1:
|
||||
|
||||
// PKE ZK V2
|
||||
pub const TEST_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
|
||||
CompactPublicKeyEncryptionParameters = V1_6_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
CompactPublicKeyEncryptionParameters = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
pub const TEST_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2:
|
||||
CompactPublicKeyEncryptionParameters =
|
||||
V1_6_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV2;
|
||||
@@ -202,14 +202,13 @@ pub const TEST_PARAM_KEYSWITCH_1_1_KS_PBS_TO_2_2_KS_PBS_GAUSSIAN_2M128:
|
||||
ShortintKeySwitchingParameters = V1_6_PARAM_KEYSWITCH_1_1_KS_PBS_TO_2_2_KS_PBS_GAUSSIAN_2M128;
|
||||
|
||||
pub const TEST_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
|
||||
ShortintKeySwitchingParameters = V1_6_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
ShortintKeySwitchingParameters = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
pub const TEST_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
|
||||
ShortintKeySwitchingParameters =
|
||||
V1_6_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
PARAM_KEYSWITCH_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
pub const TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
|
||||
ShortintKeySwitchingParameters =
|
||||
V1_6_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
ShortintKeySwitchingParameters = PARAM_KEYSWITCH_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
// ZKV1
|
||||
pub const TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128_ZKV1:
|
||||
ShortintKeySwitchingParameters =
|
||||
@@ -217,21 +216,21 @@ pub const TEST_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M12
|
||||
|
||||
// Compression
|
||||
pub const TEST_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128: CompressionParameters =
|
||||
V1_6_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
pub const TEST_COMP_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
|
||||
CompressionParameters =
|
||||
V1_6_COMP_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
COMP_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
// KS32 PBS AP
|
||||
pub const TEST_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128: KeySwitch32PBSParameters =
|
||||
V1_6_PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
|
||||
PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
|
||||
|
||||
pub const TEST_PARAM_NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
|
||||
NoiseSquashingCompressionParameters =
|
||||
V1_6_NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
NOISE_SQUASHING_COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
pub const TEST_PARAM_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128:
|
||||
NoiseSquashingParameters = V1_6_NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
NoiseSquashingParameters = NOISE_SQUASHING_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
// Meta params
|
||||
pub const TEST_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128: MetaParameters =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::shortint::ciphertext::NoiseLevel;
|
||||
use crate::shortint::keycache::KEY_CACHE;
|
||||
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||
use crate::shortint::parameters::test_params::TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
use crate::shortint::{Ciphertext, MaxNoiseLevel, ServerKey};
|
||||
|
||||
fn test_ct_unary_op_noise_level_propagation(sk: &ServerKey, ct: &Ciphertext) {
|
||||
@@ -319,7 +319,7 @@ fn test_ct_scalar_op_assign_noise_level_propagation(sk: &ServerKey, ct: &Ciphert
|
||||
#[cfg(not(tarpaulin))] // This test is ignored in coverage, it takes around 4 hours to run otherwise.
|
||||
#[test]
|
||||
fn test_noise_level_propagation_ci_run_filter() {
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||
let params = TEST_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
|
||||
|
||||
let keys = KEY_CACHE.get_from_param(params);
|
||||
let (ck, sk) = (keys.client_key(), keys.server_key());
|
||||
|
||||
@@ -46,6 +46,15 @@ impl Named for CompactPkeProof {
|
||||
const NAME: &'static str = "zk::CompactPkeProof";
|
||||
}
|
||||
|
||||
impl CompactPkeProof {
|
||||
pub fn to_le_bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
Self::PkeV1(proof) => proof.to_le_bytes(),
|
||||
Self::PkeV2(proof) => proof.to_le_bytes(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
/// Used to specify the kind of proofs that are allowed to be checked by the verifier.
|
||||
///
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::ExitCode;
|
||||
@@ -375,6 +376,15 @@ impl Registry {
|
||||
fn diff_enum(old_enum: &EnumSnapshot, new_enum: &EnumSnapshot, entries: &mut Vec<DiffEntry>) {
|
||||
let name = &old_enum.enum_name;
|
||||
|
||||
let mut rename_map: HashMap<&str, &str> = HashMap::new();
|
||||
for ov in &old_enum.variants {
|
||||
if let Some(nv) = new_enum.variants.iter().find(|nv| nv.index == ov.index) {
|
||||
if ov.inner_type_def_path != nv.inner_type_def_path {
|
||||
rename_map.insert(&ov.inner_type_def_path, &nv.inner_type_def_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Variant additions & modifications
|
||||
for nv in &new_enum.variants {
|
||||
match old_enum.variants.iter().find(|ov| ov.index == nv.index) {
|
||||
@@ -396,7 +406,11 @@ impl Registry {
|
||||
// Upgrade additions & modifications
|
||||
for nu in &new_enum.upgrades {
|
||||
match old_enum.upgrades.iter().find(|ou| {
|
||||
ou.source_def_path == nu.source_def_path && ou.target_def_path == nu.target_def_path
|
||||
let resolved_target = rename_map
|
||||
.get(ou.target_def_path.as_str())
|
||||
.copied()
|
||||
.unwrap_or(ou.target_def_path.as_str());
|
||||
ou.source_def_path == nu.source_def_path && resolved_target == nu.target_def_path
|
||||
}) {
|
||||
None => entries.push(DiffEntry::upgrade_added(name, nu)),
|
||||
Some(ou) if ou.body_hash != nu.body_hash => {
|
||||
@@ -409,7 +423,11 @@ impl Registry {
|
||||
// Upgrade removals
|
||||
for ou in &old_enum.upgrades {
|
||||
if !new_enum.upgrades.iter().any(|nu| {
|
||||
nu.source_def_path == ou.source_def_path && nu.target_def_path == ou.target_def_path
|
||||
let resolved_target = rename_map
|
||||
.get(ou.target_def_path.as_str())
|
||||
.copied()
|
||||
.unwrap_or(ou.target_def_path.as_str());
|
||||
nu.source_def_path == ou.source_def_path && resolved_target == nu.target_def_path
|
||||
}) {
|
||||
entries.push(DiffEntry::upgrade_removed(name, ou));
|
||||
}
|
||||
@@ -676,6 +694,110 @@ mod tests {
|
||||
assert_eq!(count_by_severity(&entries, Severity::Error), 0);
|
||||
}
|
||||
|
||||
// ---- upgrade target rename (adding a new enum version) ----
|
||||
|
||||
/// Simulates adding V2 to an enum: Foo (at V1) becomes FooV1, new Foo is V2.
|
||||
/// The existing upgrade FooV0 → Foo should be recognized as FooV0 → FooV1
|
||||
/// (same upgrade, just renamed target) and NOT produce a false UpgradeRemoved + UpgradeAdded.
|
||||
#[test]
|
||||
fn no_false_positive_when_new_version_renames_target() {
|
||||
// Before: V0(FooV0), V1(Foo) with upgrade FooV0 → Foo
|
||||
let old = registry(vec![enum_snap(
|
||||
"FooVersions",
|
||||
vec![variant(0, "FooV0", "aaa"), variant(1, "Foo", "bbb")],
|
||||
vec![upgrade("FooV0", "Foo", "uuu")],
|
||||
)]);
|
||||
// After: V0(FooV0), V1(FooV1), V2(Foo) with upgrades FooV0 → FooV1, FooV1 → Foo
|
||||
let new = registry(vec![enum_snap(
|
||||
"FooVersions",
|
||||
vec![
|
||||
variant(0, "FooV0", "aaa"),
|
||||
variant(1, "FooV1", "bbb"), // same hash, just renamed
|
||||
variant(2, "Foo", "ccc"),
|
||||
],
|
||||
vec![
|
||||
upgrade("FooV0", "FooV1", "uuu"), // same body hash as the old FooV0 → Foo
|
||||
upgrade("FooV1", "Foo", "vvv"), // genuinely new upgrade
|
||||
],
|
||||
)]);
|
||||
|
||||
let entries = old.diff(&new);
|
||||
|
||||
// Expected: new variant V2 + new upgrade FooV1→Foo = 2 neutral, 0 warnings, 0 errors
|
||||
assert_eq!(count_by_severity(&entries, Severity::Neutral), 2);
|
||||
assert_eq!(count_by_severity(&entries, Severity::Warning), 0);
|
||||
assert_eq!(count_by_severity(&entries, Severity::Error), 0);
|
||||
|
||||
// Verify the 2 neutral entries are exactly: variant added + upgrade added
|
||||
assert!(
|
||||
entries
|
||||
.iter()
|
||||
.any(|e| matches!(e, DiffEntry::VersionsDispatchVariantAdded { index: 2, .. }))
|
||||
);
|
||||
assert!(entries.iter().any(|e| matches!(
|
||||
e,
|
||||
DiffEntry::UpgradeAdded {
|
||||
source,
|
||||
target,
|
||||
..
|
||||
} if source == "FooV1" && target == "Foo"
|
||||
)));
|
||||
}
|
||||
|
||||
/// Same scenario but the upgrade body also changed — should produce a hash-changed warning
|
||||
/// instead of a false removed+added pair.
|
||||
#[test]
|
||||
fn renamed_target_with_changed_upgrade_body() {
|
||||
let old = registry(vec![enum_snap(
|
||||
"FooVersions",
|
||||
vec![variant(0, "FooV0", "aaa"), variant(1, "Foo", "bbb")],
|
||||
vec![upgrade("FooV0", "Foo", "uuu")],
|
||||
)]);
|
||||
let new = registry(vec![enum_snap(
|
||||
"FooVersions",
|
||||
vec![
|
||||
variant(0, "FooV0", "aaa"),
|
||||
variant(1, "FooV1", "bbb"),
|
||||
variant(2, "Foo", "ccc"),
|
||||
],
|
||||
vec![
|
||||
upgrade("FooV0", "FooV1", "CHANGED"), // same logical upgrade, body changed
|
||||
upgrade("FooV1", "Foo", "vvv"),
|
||||
],
|
||||
)]);
|
||||
|
||||
let entries = old.diff(&new);
|
||||
|
||||
// The renamed upgrade has a changed body → 1 warning (UpgradeHashChanged)
|
||||
// New variant + new upgrade → 2 neutral
|
||||
assert_eq!(count_by_severity(&entries, Severity::Neutral), 2);
|
||||
assert_eq!(count_by_severity(&entries, Severity::Warning), 1);
|
||||
assert_eq!(count_by_severity(&entries, Severity::Error), 0);
|
||||
assert!(
|
||||
entries
|
||||
.iter()
|
||||
.any(|e| matches!(e, DiffEntry::UpgradeHashChanged { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
/// When no rename happens (target name is stable), upgrades still match normally.
|
||||
#[test]
|
||||
fn no_rename_upgrades_still_match() {
|
||||
let old = registry(vec![enum_snap(
|
||||
"E",
|
||||
vec![variant(0, "V0", "aaa"), variant(1, "V1", "bbb")],
|
||||
vec![upgrade("V0", "V1", "uuu")],
|
||||
)]);
|
||||
let new = registry(vec![enum_snap(
|
||||
"E",
|
||||
vec![variant(0, "V0", "aaa"), variant(1, "V1", "bbb")],
|
||||
vec![upgrade("V0", "V1", "uuu")],
|
||||
)]);
|
||||
|
||||
let entries = old.diff(&new);
|
||||
assert!(entries.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diff_full_flow_mixed_changes() {
|
||||
let old = registry(vec![
|
||||
|
||||
@@ -994,6 +994,7 @@ dependencies = [
|
||||
"tfhe-csprng",
|
||||
"tfhe-fft",
|
||||
"tfhe-ntt",
|
||||
"tfhe-safe-serialize",
|
||||
"tfhe-versionable",
|
||||
"tfhe-zk-pok",
|
||||
]
|
||||
@@ -1045,6 +1046,15 @@ dependencies = [
|
||||
"pulp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tfhe-safe-serialize"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"serde",
|
||||
"tfhe-versionable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tfhe-versionable"
|
||||
version = "0.7.0"
|
||||
@@ -1073,11 +1083,13 @@ dependencies = [
|
||||
"ark-ff",
|
||||
"ark-poly",
|
||||
"getrandom",
|
||||
"itertools 0.14.0",
|
||||
"num-bigint",
|
||||
"rand",
|
||||
"rayon",
|
||||
"serde",
|
||||
"sha3",
|
||||
"tfhe-safe-serialize",
|
||||
"tfhe-versionable",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||