mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-09 14:47:56 -05:00
chore(hlapi): add example to measure CPK and CCTL sizes
This also includes key generation time in WASM web client side
This commit is contained in:
committed by
David Testé
parent
f8b497a4b8
commit
9e307a8945
115
.github/workflows/wasm_client_benchmark.yml
vendored
Normal file
115
.github/workflows/wasm_client_benchmark.yml
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
# Run WASM client benchmarks on an AWS instance and return parsed results to Slab CI bot.
|
||||
name: WASM client benchmarks
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
instance_id:
|
||||
description: "Instance ID"
|
||||
type: string
|
||||
instance_image_id:
|
||||
description: "Instance AMI ID"
|
||||
type: string
|
||||
instance_type:
|
||||
description: "Instance product type"
|
||||
type: string
|
||||
runner_name:
|
||||
description: "Action runner name"
|
||||
type: string
|
||||
request_id:
|
||||
description: "Slab request ID"
|
||||
type: string
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RESULTS_FILENAME: parsed_benchmark_results_${{ github.sha }}.json
|
||||
|
||||
jobs:
|
||||
run-wasm-client-benchmarks:
|
||||
name: Execute WASM client benchmarks in EC2
|
||||
runs-on: ${{ github.event.inputs.runner_name }}
|
||||
if: ${{ !cancelled() }}
|
||||
steps:
|
||||
- name: Instance configuration used
|
||||
run: |
|
||||
echo "IDs: ${{ inputs.instance_id }}"
|
||||
echo "AMI: ${{ inputs.instance_image_id }}"
|
||||
echo "Type: ${{ inputs.instance_type }}"
|
||||
echo "Request ID: ${{ inputs.request_id }}"
|
||||
|
||||
- name: Get benchmark date
|
||||
run: |
|
||||
echo "BENCH_DATE=$(date --iso-8601=seconds)" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Checkout tfhe-rs repo with tags
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up home
|
||||
# "Install rust" step require root user to have a HOME directory which is not set.
|
||||
run: |
|
||||
echo "HOME=/home/ubuntu" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Install rust
|
||||
uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af
|
||||
with:
|
||||
toolchain: nightly
|
||||
override: true
|
||||
|
||||
- name: Run benchmarks
|
||||
run: |
|
||||
make install_node
|
||||
make bench_web_js_api_parallel
|
||||
|
||||
- name: Parse results
|
||||
run: |
|
||||
make parse_wasm_benchmarks
|
||||
|
||||
COMMIT_DATE="$(git --no-pager show -s --format=%cd --date=iso8601-strict ${{ github.sha }})"
|
||||
COMMIT_HASH="$(git describe --tags --dirty)"
|
||||
python3 ./ci/benchmark_parser.py tfhe/web_wasm_parallel_tests/public_key_ct_generation_timings.csv ${{ env.RESULTS_FILENAME }} \
|
||||
--database tfhe_rs \
|
||||
--hardware ${{ inputs.instance_type }} \
|
||||
--project-version "${COMMIT_HASH}" \
|
||||
--branch ${{ github.ref_name }} \
|
||||
--commit-date "${COMMIT_DATE}" \
|
||||
--bench-date "${{ env.BENCH_DATE }}" \
|
||||
--key-gen
|
||||
|
||||
- name: Measure public key and ciphertext sizes in HL Api
|
||||
run: |
|
||||
make measure_hlapi_compact_pk_ct_sizes
|
||||
|
||||
- name: Parse key and ciphertext sizes results
|
||||
run: |
|
||||
python3 ./ci/benchmark_parser.py tfhe/hlapi_cpk_and_cctl_sizes.csv ${{ env.RESULTS_FILENAME }} \
|
||||
--key-gen \
|
||||
--append-results
|
||||
|
||||
- name: Upload parsed results artifact
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
|
||||
with:
|
||||
name: ${{ github.sha }}_wasm
|
||||
path: ${{ env.RESULTS_FILENAME }}
|
||||
|
||||
- name: Checkout Slab repo
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
repository: zama-ai/slab
|
||||
path: slab
|
||||
token: ${{ secrets.CONCRETE_ACTIONS_TOKEN }}
|
||||
|
||||
- name: Send data to Slab
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Computing HMac on results file"
|
||||
SIGNATURE="$(slab/scripts/hmac_calculator.sh ${{ env.RESULTS_FILENAME }} '${{ secrets.JOB_SECRET }}')"
|
||||
echo "Sending results to Slab..."
|
||||
curl -v -k \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Slab-Repository: ${{ github.repository }}" \
|
||||
-H "X-Slab-Command: store_data_v2" \
|
||||
-H "X-Hub-Signature-256: sha256=${SIGNATURE}" \
|
||||
-d @${{ env.RESULTS_FILENAME }} \
|
||||
${{ secrets.SLAB_URL }}
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -12,4 +12,4 @@ target/
|
||||
|
||||
# Some of our bench outputs
|
||||
/tfhe/benchmarks_parameters
|
||||
/tfhe/shortint_key_sizes.csv
|
||||
**/*.csv
|
||||
|
||||
55
Makefile
55
Makefile
@@ -370,6 +370,10 @@ ci_test_web_js_api_parallel: build_web_js_api_parallel
|
||||
no_tfhe_typo:
|
||||
@./scripts/no_tfhe_typo.sh
|
||||
|
||||
#
|
||||
# Benchmarks
|
||||
#
|
||||
|
||||
.PHONY: bench_integer # Run benchmarks for integer
|
||||
bench_integer: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
@@ -394,23 +398,54 @@ bench_pbs: install_rs_check_toolchain
|
||||
--bench pbs-bench \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,$(AVX512_FEATURE) -p tfhe
|
||||
|
||||
.PHONY: bench_web_js_api_parallel # Run benchmarks for the web wasm api
|
||||
bench_web_js_api_parallel: build_web_js_api_parallel
|
||||
$(MAKE) -C tfhe/web_wasm_parallel_tests bench
|
||||
|
||||
.PHONY: ci_bench_web_js_api_parallel # Run benchmarks for the web wasm api
|
||||
ci_bench_web_js_api_parallel: build_web_js_api_parallel
|
||||
source ~/.nvm/nvm.sh && \
|
||||
nvm use node && \
|
||||
$(MAKE) -C tfhe/web_wasm_parallel_tests bench-ci
|
||||
|
||||
#
|
||||
# Utility tools
|
||||
#
|
||||
|
||||
.PHONY: measure_hlapi_compact_pk_ct_sizes # Measure sizes of public keys and ciphertext for high-level API
|
||||
measure_hlapi_compact_pk_ct_sizes: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) run --profile $(CARGO_PROFILE) \
|
||||
--example hlapi_compact_pk_ct_sizes \
|
||||
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache
|
||||
|
||||
.PHONY: measure_shortint_key_sizes # Measure sizes of bootstrapping and key switching keys for shortint
|
||||
measure_shortint_key_sizes: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) run --profile $(CARGO_PROFILE) \
|
||||
--example shortint_key_sizes \
|
||||
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache
|
||||
|
||||
.PHONY: measure_boolean_key_sizes # Measure sizes of bootstrapping and key switching keys for boolean
|
||||
measure_boolean_key_sizes: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) run --profile $(CARGO_PROFILE) \
|
||||
--example boolean_key_sizes \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,internal-keycache
|
||||
|
||||
.PHONY: parse_integer_benches # Run python parser to output a csv containing integer benches data
|
||||
parse_integer_benches:
|
||||
python3 ./ci/parse_integer_benches_to_csv.py \
|
||||
--criterion-dir target/criterion \
|
||||
--output-file "$(PARSE_INTEGER_BENCH_CSV_FILE)"
|
||||
|
||||
.PHONY: measure_shortint_key_sizes # Measure sizes of bootstrapping and key switching keys for shortint
|
||||
measure_shortint_key_sizes: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) run \
|
||||
--example shortint_key_sizes \
|
||||
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache
|
||||
.PHONY: parse_wasm_benchmarks # Parse benchmarks performed with WASM web client into a CSV file
|
||||
parse_wasm_benchmarks: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) run --profile $(CARGO_PROFILE) \
|
||||
--example wasm_benchmarks_parser \
|
||||
--features=$(TARGET_ARCH_FEATURE),shortint,internal-keycache \
|
||||
-- tfhe/web_wasm_parallel_tests/test/benchmark_results
|
||||
|
||||
.PHONY: measure_boolean_key_sizes # Measure sizes of bootstrapping and key switching keys for boolean
|
||||
measure_boolean_key_sizes: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) run \
|
||||
--example boolean_key_sizes \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,internal-keycache
|
||||
#
|
||||
# Real use case examples
|
||||
#
|
||||
|
||||
.PHONY: regex_engine # Run regex_engine example
|
||||
regex_engine: install_rs_check_toolchain
|
||||
|
||||
@@ -39,6 +39,8 @@ parser.add_argument('--walk-subdirs', dest='walk_subdirs', action='store_true',
|
||||
help='Check for results in subdirectories')
|
||||
parser.add_argument('--key-sizes', dest='key_sizes', action='store_true',
|
||||
help='Parse only the results regarding keys size measurements')
|
||||
parser.add_argument('--key-gen', dest='key_gen', action='store_true',
|
||||
help='Parse only the results regarding keys generation time measurements')
|
||||
parser.add_argument('--throughput', dest='throughput', action='store_true',
|
||||
help='Compute and append number of operations per second and'
|
||||
'operations per dollar')
|
||||
@@ -177,9 +179,9 @@ def parse_estimate_file(directory):
|
||||
}
|
||||
|
||||
|
||||
def parse_key_sizes(result_file):
|
||||
def _parse_key_results(result_file, bench_type):
|
||||
"""
|
||||
Parse file containing key sizes results. The file must be formatted as CSV.
|
||||
Parse file containing results about operation on keys. The file must be formatted as CSV.
|
||||
|
||||
:param result_file: results file as :class:`pathlib.Path`
|
||||
|
||||
@@ -202,13 +204,35 @@ def parse_key_sizes(result_file):
|
||||
"test": test_name,
|
||||
"name": display_name,
|
||||
"class": "keygen",
|
||||
"type": "keysize",
|
||||
"type": bench_type,
|
||||
"operator": operator,
|
||||
"params": params})
|
||||
|
||||
return result_values, parsing_failures
|
||||
|
||||
|
||||
def parse_key_sizes(result_file):
|
||||
"""
|
||||
Parse file containing key sizes results. The file must be formatted as CSV.
|
||||
|
||||
:param result_file: results file as :class:`pathlib.Path`
|
||||
|
||||
:return: tuple of :class:`list` as (data points, parsing failures)
|
||||
"""
|
||||
return _parse_key_results(result_file, "keysize")
|
||||
|
||||
|
||||
def parse_key_gen_time(result_file):
|
||||
"""
|
||||
Parse file containing key generation time results. The file must be formatted as CSV.
|
||||
|
||||
:param result_file: results file as :class:`pathlib.Path`
|
||||
|
||||
:return: tuple of :class:`list` as (data points, parsing failures)
|
||||
"""
|
||||
return _parse_key_results(result_file, "latency")
|
||||
|
||||
|
||||
def get_parameters(bench_id):
|
||||
"""
|
||||
Get benchmarks parameters recorded for a given benchmark case.
|
||||
@@ -301,7 +325,7 @@ def check_mandatory_args(input_args):
|
||||
for arg_name in vars(input_args):
|
||||
if arg_name in ["results_dir", "output_file", "name_suffix",
|
||||
"append_results", "walk_subdirs", "key_sizes",
|
||||
"throughput"]:
|
||||
"key_gen", "throughput"]:
|
||||
continue
|
||||
if not getattr(input_args, arg_name):
|
||||
missing_args.append(arg_name)
|
||||
@@ -318,7 +342,15 @@ if __name__ == "__main__":
|
||||
|
||||
#failures = []
|
||||
raw_results = pathlib.Path(args.results)
|
||||
if not args.key_sizes:
|
||||
if args.key_sizes or args.key_gen:
|
||||
if args.key_sizes:
|
||||
print("Parsing key sizes results... ")
|
||||
results, failures = parse_key_sizes(raw_results)
|
||||
|
||||
if args.key_gen:
|
||||
print("Parsing key generation time results... ")
|
||||
results, failures = parse_key_gen_time(raw_results)
|
||||
else:
|
||||
print("Parsing benchmark results... ")
|
||||
hardware_cost = None
|
||||
if args.throughput:
|
||||
@@ -334,9 +366,7 @@ if __name__ == "__main__":
|
||||
|
||||
results, failures = recursive_parse(raw_results, args.walk_subdirs, args.name_suffix,
|
||||
args.throughput, hardware_cost)
|
||||
else:
|
||||
print("Parsing key sizes results... ")
|
||||
results, failures = parse_key_sizes(raw_results)
|
||||
|
||||
print("Parsing results done")
|
||||
|
||||
output_file = pathlib.Path(args.output_file)
|
||||
|
||||
@@ -10,7 +10,13 @@ repository = "https://github.com/zama-ai/tfhe-rs"
|
||||
license = "BSD-3-Clause-Clear"
|
||||
description = "TFHE-rs is a fully homomorphic encryption (FHE) library that implements Zama's variant of TFHE."
|
||||
build = "build.rs"
|
||||
exclude = ["/docs/", "/c_api_tests/", "/CMakeLists.txt", "/js_on_wasm_tests/"]
|
||||
exclude = [
|
||||
"/docs/",
|
||||
"/c_api_tests/",
|
||||
"/CMakeLists.txt",
|
||||
"/js_on_wasm_tests/",
|
||||
"/web_wasm_parallel_tests/",
|
||||
]
|
||||
rust-version = "1.67"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -23,7 +29,7 @@ lazy_static = { version = "1.4.0" }
|
||||
criterion = "0.4.0"
|
||||
doc-comment = "0.3.3"
|
||||
serde_json = "1.0.94"
|
||||
clap = "4.2.7"
|
||||
clap = { version = "4.2.7", features = ["derive"] }
|
||||
# Used in user documentation
|
||||
bincode = "1.3.3"
|
||||
fs2 = { version = "0.4.3" }
|
||||
@@ -83,12 +89,7 @@ experimental-force_fft_algo_dif4 = []
|
||||
__c_api = ["cbindgen", "bincode"]
|
||||
boolean-c-api = ["boolean", "__c_api"]
|
||||
shortint-c-api = ["shortint", "__c_api"]
|
||||
high-level-c-api = [
|
||||
"boolean-c-api",
|
||||
"shortint-c-api",
|
||||
"integer",
|
||||
"__c_api"
|
||||
]
|
||||
high-level-c-api = ["boolean-c-api", "shortint-c-api", "integer", "__c_api"]
|
||||
|
||||
__wasm_api = [
|
||||
"wasm-bindgen",
|
||||
@@ -189,30 +190,44 @@ path = "benches/utilities.rs"
|
||||
harness = false
|
||||
required-features = ["boolean", "shortint", "integer", "internal-keycache"]
|
||||
|
||||
# Examples used as tools
|
||||
|
||||
[[example]]
|
||||
name = "wasm_benchmarks_parser"
|
||||
path = "examples/utilities/wasm_benchmarks_parser.rs"
|
||||
required-features = ["shortint", "internal-keycache"]
|
||||
|
||||
[[example]]
|
||||
name = "generates_test_keys"
|
||||
path = "examples/utilities/generates_test_keys.rs"
|
||||
required-features = ["shortint", "internal-keycache"]
|
||||
|
||||
[[example]]
|
||||
name = "boolean_key_sizes"
|
||||
path = "examples/utilities/boolean_key_sizes.rs"
|
||||
required-features = ["boolean", "internal-keycache"]
|
||||
|
||||
[[example]]
|
||||
name = "dark_market"
|
||||
required-features = ["integer", "internal-keycache"]
|
||||
|
||||
[[example]]
|
||||
name = "shortint_key_sizes"
|
||||
path = "examples/utilities/shortint_key_sizes.rs"
|
||||
required-features = ["shortint", "internal-keycache"]
|
||||
|
||||
[[example]]
|
||||
name = "integer_compact_pk_ct_sizes"
|
||||
name = "hlapi_compact_pk_ct_sizes"
|
||||
path = "examples/utilities/hlapi_compact_pk_ct_sizes.rs"
|
||||
required-features = ["integer", "internal-keycache"]
|
||||
|
||||
[[example]]
|
||||
name = "micro_bench_and"
|
||||
path = "examples/utilities/micro_bench_and.rs"
|
||||
required-features = ["boolean"]
|
||||
|
||||
# Real use-case examples
|
||||
|
||||
[[example]]
|
||||
name = "dark_market"
|
||||
required-features = ["integer", "internal-keycache"]
|
||||
|
||||
[[example]]
|
||||
name = "regex_engine"
|
||||
required-features = ["integer"]
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
use rand::Rng;
|
||||
|
||||
use tfhe::core_crypto::commons::numeric::Numeric;
|
||||
use tfhe::integer::block_decomposition::{DecomposableInto, RecomposableFrom};
|
||||
use tfhe::integer::public_key::{CompactPublicKeyBig, CompactPublicKeySmall};
|
||||
use tfhe::integer::{gen_keys, U256};
|
||||
use tfhe::shortint::keycache::NamedParam;
|
||||
use tfhe::shortint::parameters::*;
|
||||
|
||||
pub fn main() {
|
||||
fn size_func<Scalar: Numeric + DecomposableInto<u64> + RecomposableFrom<u64> + From<u32>>() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let num_bits = Scalar::BITS;
|
||||
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_COMPACT_PK;
|
||||
{
|
||||
println!("Sizes for: {} and {num_bits} bits", params.name());
|
||||
let (cks, _) = gen_keys(params);
|
||||
let pk = CompactPublicKeyBig::new(&cks);
|
||||
|
||||
println!("PK size: {} bytes", bincode::serialize(&pk).unwrap().len());
|
||||
|
||||
let num_block =
|
||||
(num_bits as f64 / (params.message_modulus.0 as f64).log(2.0)).ceil() as usize;
|
||||
|
||||
const MAX_CT: usize = 20;
|
||||
|
||||
let mut clear_vec = Vec::with_capacity(MAX_CT);
|
||||
// 5 inputs to a smart contract
|
||||
let num_ct_for_this_iter = 5;
|
||||
clear_vec.truncate(0);
|
||||
for _ in 0..num_ct_for_this_iter {
|
||||
let clear = rng.gen::<u32>();
|
||||
clear_vec.push(Scalar::from(clear));
|
||||
}
|
||||
|
||||
let compact_encrypted_list = pk.encrypt_slice_radix_compact(&clear_vec, num_block);
|
||||
|
||||
println!(
|
||||
"Compact CT list for {num_ct_for_this_iter} CTs: {} bytes",
|
||||
bincode::serialize(&compact_encrypted_list).unwrap().len()
|
||||
);
|
||||
|
||||
let ciphertext_vec = compact_encrypted_list.expand();
|
||||
|
||||
for (ciphertext, clear) in ciphertext_vec.iter().zip(clear_vec.iter().copied()) {
|
||||
let decrypted: Scalar = cks.decrypt_radix(ciphertext);
|
||||
assert_eq!(decrypted, clear);
|
||||
}
|
||||
}
|
||||
|
||||
let params = PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK;
|
||||
{
|
||||
println!("Sizes for: {} and {num_bits} bits", params.name());
|
||||
let (cks, _) = gen_keys(params);
|
||||
let pk = CompactPublicKeySmall::new(&cks);
|
||||
|
||||
println!("PK size: {} bytes", bincode::serialize(&pk).unwrap().len());
|
||||
|
||||
let num_block =
|
||||
(num_bits as f64 / (params.message_modulus.0 as f64).log(2.0)).ceil() as usize;
|
||||
|
||||
const MAX_CT: usize = 20;
|
||||
|
||||
let mut clear_vec = Vec::with_capacity(MAX_CT);
|
||||
// 5 inputs to a smart contract
|
||||
let num_ct_for_this_iter = 5;
|
||||
clear_vec.truncate(0);
|
||||
for _ in 0..num_ct_for_this_iter {
|
||||
let clear = rng.gen::<u32>();
|
||||
clear_vec.push(Scalar::from(clear));
|
||||
}
|
||||
|
||||
let compact_encrypted_list = pk.encrypt_slice_radix_compact(&clear_vec, num_block);
|
||||
|
||||
println!(
|
||||
"Compact CT list for {num_ct_for_this_iter} CTs: {} bytes",
|
||||
bincode::serialize(&compact_encrypted_list).unwrap().len()
|
||||
);
|
||||
|
||||
let ciphertext_vec = compact_encrypted_list.expand();
|
||||
|
||||
for (ciphertext, clear) in ciphertext_vec.iter().zip(clear_vec.iter().copied()) {
|
||||
let decrypted: Scalar = cks.decrypt_radix(ciphertext);
|
||||
assert_eq!(decrypted, clear);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_func::<u32>();
|
||||
size_func::<U256>();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#[path = "../benches/utilities.rs"]
|
||||
#[path = "../../benches/utilities.rs"]
|
||||
mod utilities;
|
||||
use crate::utilities::{write_to_json, OperatorType};
|
||||
|
||||
@@ -81,13 +81,6 @@ fn client_server_key_sizes(results_file: &Path) {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let work_dir = std::env::current_dir().unwrap();
|
||||
println!("work_dir: {}", std::env::current_dir().unwrap().display());
|
||||
// Change workdir so that the location of the keycache matches the one for tests
|
||||
let mut new_work_dir = work_dir;
|
||||
new_work_dir.push("tfhe");
|
||||
std::env::set_current_dir(new_work_dir).unwrap();
|
||||
|
||||
let results_file = Path::new("boolean_key_sizes.csv");
|
||||
let results_file = Path::new("tfhe/boolean_key_sizes.csv");
|
||||
client_server_key_sizes(results_file)
|
||||
}
|
||||
259
tfhe/examples/utilities/hlapi_compact_pk_ct_sizes.rs
Normal file
259
tfhe/examples/utilities/hlapi_compact_pk_ct_sizes.rs
Normal file
@@ -0,0 +1,259 @@
|
||||
#[path = "../../benches/utilities.rs"]
|
||||
mod utilities;
|
||||
use crate::utilities::{write_to_json, OperatorType};
|
||||
|
||||
use rand::Rng;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use tfhe::integer::U256;
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::shortint::keycache::NamedParam;
|
||||
use tfhe::shortint::parameters::{
|
||||
PARAM_MESSAGE_2_CARRY_2_COMPACT_PK, PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK,
|
||||
};
|
||||
use tfhe::{
|
||||
generate_keys, CompactFheUint256List, CompactFheUint32List, CompactPublicKey, ConfigBuilder,
|
||||
};
|
||||
|
||||
fn write_result(file: &mut File, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
|
||||
pub fn cpk_and_cctl_sizes(results_file: &Path) {
|
||||
const NB_CTXT: usize = 5;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.write(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
|
||||
let operator = OperatorType::Atomic;
|
||||
|
||||
{
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_COMPACT_PK;
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_custom_integers(params, None)
|
||||
.build();
|
||||
let (client_key, _) = generate_keys(config);
|
||||
let test_name = format!("hlapi_sizes_{}_cpk", params.name());
|
||||
|
||||
println!("Sizes for: {} and 32 bits", params.name());
|
||||
|
||||
let public_key = CompactPublicKey::new(&client_key);
|
||||
|
||||
let cpk_size = bincode::serialize(&public_key).unwrap().len();
|
||||
|
||||
println!("PK size: {cpk_size} bytes");
|
||||
write_result(&mut file, &test_name, cpk_size);
|
||||
write_to_json(
|
||||
&test_name,
|
||||
params,
|
||||
params.name(),
|
||||
"CPK",
|
||||
&operator,
|
||||
0,
|
||||
vec![],
|
||||
);
|
||||
|
||||
let test_name = format!("hlapi_sizes_{}_cctl_{NB_CTXT}_len_32_bits", params.name());
|
||||
|
||||
let vec_inputs: Vec<_> = (0..NB_CTXT).map(|_| rng.gen::<u32>()).collect();
|
||||
|
||||
let encrypted_inputs = CompactFheUint32List::encrypt(&vec_inputs, &public_key);
|
||||
let cctl_size = bincode::serialize(&encrypted_inputs).unwrap().len();
|
||||
|
||||
println!("Compact CT list for {NB_CTXT} CTs: {} bytes", cctl_size);
|
||||
|
||||
write_result(&mut file, &test_name, cctl_size);
|
||||
write_to_json(
|
||||
&test_name,
|
||||
params,
|
||||
params.name(),
|
||||
"CCTL",
|
||||
&operator,
|
||||
0,
|
||||
vec![],
|
||||
);
|
||||
|
||||
let expanded_inputs = encrypted_inputs.expand();
|
||||
|
||||
vec_inputs
|
||||
.iter()
|
||||
.zip(expanded_inputs.iter())
|
||||
.for_each(|(&input, ct)| {
|
||||
let clear: u32 = ct.decrypt(&client_key);
|
||||
assert_eq!(clear, input);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
let params = PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK;
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_custom_integers(params, None)
|
||||
.build();
|
||||
let (client_key, _) = generate_keys(config);
|
||||
let test_name = format!("hlapi_sizes_{}_cpk", params.name());
|
||||
|
||||
println!("Sizes for: {} and 32 bits", params.name());
|
||||
let public_key = CompactPublicKey::new(&client_key);
|
||||
|
||||
let cpk_size = bincode::serialize(&public_key).unwrap().len();
|
||||
|
||||
println!("PK size: {cpk_size} bytes");
|
||||
write_result(&mut file, &test_name, cpk_size);
|
||||
write_to_json(
|
||||
&test_name,
|
||||
params,
|
||||
params.name(),
|
||||
"CPK",
|
||||
&operator,
|
||||
0,
|
||||
vec![],
|
||||
);
|
||||
|
||||
let test_name = format!("hlapi_sizes_{}_cctl_{NB_CTXT}_len_32_bits", params.name());
|
||||
|
||||
let vec_inputs: Vec<_> = (0..NB_CTXT).map(|_| rng.gen::<u32>()).collect();
|
||||
|
||||
let encrypted_inputs = CompactFheUint32List::encrypt(&vec_inputs, &public_key);
|
||||
let cctl_size = bincode::serialize(&encrypted_inputs).unwrap().len();
|
||||
|
||||
println!("Compact CT list for {NB_CTXT} CTs: {} bytes", cctl_size);
|
||||
|
||||
write_result(&mut file, &test_name, cctl_size);
|
||||
write_to_json(
|
||||
&test_name,
|
||||
params,
|
||||
params.name(),
|
||||
"CCTL",
|
||||
&operator,
|
||||
0,
|
||||
vec![],
|
||||
);
|
||||
|
||||
let expanded_inputs = encrypted_inputs.expand();
|
||||
|
||||
vec_inputs
|
||||
.iter()
|
||||
.zip(expanded_inputs.iter())
|
||||
.for_each(|(&input, ct)| {
|
||||
let clear: u32 = ct.decrypt(&client_key);
|
||||
assert_eq!(clear, input);
|
||||
});
|
||||
}
|
||||
|
||||
// 256 bits
|
||||
{
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_COMPACT_PK;
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_custom_integers(params, None)
|
||||
.build();
|
||||
let (client_key, _) = generate_keys(config);
|
||||
|
||||
println!("Sizes for: {} and 256 bits", params.name());
|
||||
|
||||
let public_key = CompactPublicKey::new(&client_key);
|
||||
|
||||
println!(
|
||||
"PK size: {} bytes",
|
||||
bincode::serialize(&public_key).unwrap().len()
|
||||
);
|
||||
|
||||
let test_name = format!("hlapi_sizes_{}_cctl_{NB_CTXT}_len_256_bits", params.name());
|
||||
|
||||
let vec_inputs: Vec<_> = (0..NB_CTXT).map(|_| rng.gen::<u32>()).collect();
|
||||
|
||||
let encrypted_inputs = CompactFheUint256List::encrypt(&vec_inputs, &public_key);
|
||||
let cctl_size = bincode::serialize(&encrypted_inputs).unwrap().len();
|
||||
|
||||
println!("Compact CT list for {NB_CTXT} CTs: {} bytes", cctl_size);
|
||||
|
||||
write_result(&mut file, &test_name, cctl_size);
|
||||
write_to_json(
|
||||
&test_name,
|
||||
params,
|
||||
params.name(),
|
||||
"CCTL",
|
||||
&operator,
|
||||
0,
|
||||
vec![],
|
||||
);
|
||||
|
||||
let expanded_inputs = encrypted_inputs.expand();
|
||||
|
||||
vec_inputs
|
||||
.iter()
|
||||
.zip(expanded_inputs.iter())
|
||||
.for_each(|(&input, ct)| {
|
||||
let clear: U256 = ct.decrypt(&client_key);
|
||||
assert_eq!(clear, U256::from(input));
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
let params = PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK;
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_custom_integers(params, None)
|
||||
.build();
|
||||
let (client_key, _) = generate_keys(config);
|
||||
|
||||
println!("Sizes for: {} and 256 bits", params.name());
|
||||
|
||||
let public_key = CompactPublicKey::new(&client_key);
|
||||
|
||||
println!(
|
||||
"PK size: {} bytes",
|
||||
bincode::serialize(&public_key).unwrap().len()
|
||||
);
|
||||
|
||||
let test_name = format!("hlapi_sizes_{}_cctl_{NB_CTXT}_len_256_bits", params.name());
|
||||
|
||||
let vec_inputs: Vec<_> = (0..NB_CTXT).map(|_| rng.gen::<u32>()).collect();
|
||||
|
||||
let encrypted_inputs = CompactFheUint256List::encrypt(&vec_inputs, &public_key);
|
||||
let cctl_size = bincode::serialize(&encrypted_inputs).unwrap().len();
|
||||
|
||||
println!("Compact CT list for {NB_CTXT} CTs: {} bytes", cctl_size);
|
||||
|
||||
write_result(&mut file, &test_name, cctl_size);
|
||||
write_to_json(
|
||||
&test_name,
|
||||
params,
|
||||
params.name(),
|
||||
"CCTL",
|
||||
&operator,
|
||||
0,
|
||||
vec![],
|
||||
);
|
||||
|
||||
let expanded_inputs = encrypted_inputs.expand();
|
||||
|
||||
vec_inputs
|
||||
.iter()
|
||||
.zip(expanded_inputs.iter())
|
||||
.for_each(|(&input, ct)| {
|
||||
let clear: U256 = ct.decrypt(&client_key);
|
||||
assert_eq!(clear, U256::from(input));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let work_dir = std::env::current_dir().unwrap();
|
||||
println!("work_dir: {}", std::env::current_dir().unwrap().display());
|
||||
// Change workdir so that the location of the keycache matches the one for tests
|
||||
let mut new_work_dir = work_dir;
|
||||
new_work_dir.push("tfhe");
|
||||
std::env::set_current_dir(new_work_dir).unwrap();
|
||||
|
||||
let results_file = Path::new("hlapi_cpk_and_cctl_sizes.csv");
|
||||
cpk_and_cctl_sizes(results_file)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#[path = "../benches/utilities.rs"]
|
||||
#[path = "../../benches/utilities.rs"]
|
||||
mod utilities;
|
||||
use crate::utilities::{write_to_json, OperatorType};
|
||||
|
||||
82
tfhe/examples/utilities/wasm_benchmarks_parser.rs
Normal file
82
tfhe/examples/utilities/wasm_benchmarks_parser.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
#[path = "../../benches/utilities.rs"]
|
||||
mod utilities;
|
||||
|
||||
use crate::utilities::{write_to_json, OperatorType};
|
||||
use clap::Parser;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use tfhe::shortint::keycache::NamedParam;
|
||||
use tfhe::shortint::parameters::{
|
||||
PARAM_MESSAGE_2_CARRY_2_COMPACT_PK, PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK,
|
||||
};
|
||||
use tfhe::shortint::ClassicPBSParameters;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
raw_results_dir: String,
|
||||
}
|
||||
|
||||
fn params_from_name(name: &str) -> ClassicPBSParameters {
|
||||
match name.to_lowercase().as_str() {
|
||||
"param_message_2_carry_2_compact_pk" => PARAM_MESSAGE_2_CARRY_2_COMPACT_PK,
|
||||
"param_small_message_2_carry_2_compact_pk" => PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK,
|
||||
_ => panic!("failed to get parameters for name '{name}'"),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_result(file: &mut File, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
|
||||
pub fn parse_wasm_benchmarks(results_file: &Path, raw_results_dir: &Path) {
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open parsed results file");
|
||||
|
||||
let operator = OperatorType::Atomic;
|
||||
|
||||
for entry in raw_results_dir
|
||||
.read_dir()
|
||||
.expect("cannot read results directory")
|
||||
.flatten()
|
||||
{
|
||||
let raw_results = fs::read_to_string(entry.path()).expect("cannot open raw results file");
|
||||
let results_as_json: HashMap<String, f32> = serde_json::from_str(&raw_results).unwrap();
|
||||
|
||||
for (full_name, val) in results_as_json.iter() {
|
||||
let name_parts = full_name.split("_mean_").collect::<Vec<_>>();
|
||||
let bench_name = name_parts[0];
|
||||
let params = params_from_name(name_parts[1]);
|
||||
let value_in_ns = (val * 1_000_000_f32) as usize;
|
||||
|
||||
write_result(&mut file, full_name, value_in_ns);
|
||||
write_to_json(
|
||||
full_name,
|
||||
params,
|
||||
params.name(),
|
||||
bench_name,
|
||||
&operator,
|
||||
0,
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
let results_file = Path::new("tfhe/wasm_pk_gen.csv");
|
||||
let raw_results_dir = Path::new(&args.raw_results_dir);
|
||||
|
||||
parse_wasm_benchmarks(results_file, raw_results_dir);
|
||||
}
|
||||
@@ -1,20 +1,25 @@
|
||||
test:
|
||||
test: script = test
|
||||
test-ci: script = test-separate-processes
|
||||
bench: script = bench
|
||||
bench-ci: script = bench-separate-processes
|
||||
|
||||
run_server:
|
||||
npm install
|
||||
npm run build
|
||||
# This runs the server in background, saving its PID
|
||||
# to a file, so we can kill it when done
|
||||
{ npm run server > /dev/null & echo $$! > server.PID; }
|
||||
npm run test
|
||||
npm run $(script)
|
||||
kill `cat server.PID` && rm server.PID
|
||||
|
||||
test-ci:
|
||||
npm install
|
||||
npm run build
|
||||
# This runs the server in background, saving its PID
|
||||
# to a file, so we can kill it when done
|
||||
{ npm run server > /dev/null & echo $$! > server.PID; }
|
||||
npm run test-separate-processes
|
||||
kill `cat server.PID` && rm server.PID
|
||||
.PHONY: test # Run web client tests
|
||||
test: run_server
|
||||
|
||||
.PHONY: test-ci # Run web client tests in CI
|
||||
test-ci: run_server
|
||||
|
||||
.PHONY: test
|
||||
.PHONY: bench # Run benchmarks on web client
|
||||
bench: run_server
|
||||
|
||||
.PHONY: bench-ci # Run benchmarks on web client in CI
|
||||
bench-ci: run_server
|
||||
|
||||
@@ -33,6 +33,15 @@
|
||||
<input type="checkbox" id="testSuccess" disabled>
|
||||
<label for="testSuccess"> TestSuccess </label><br>
|
||||
|
||||
<input type="button" id="compactPublicKeyBench32BitSmall" value="Compact Public Key Bench 32 Bits Small" disabled />
|
||||
<input type="button" id="compactPublicKeyBench32BitBig" value="Compact Public Key Bench 32 Bits Big" disabled />
|
||||
|
||||
<input type="button" id="compactPublicKeyBench256BitSmall" value="Compact Public Key Bench 256 Bits Small" disabled />
|
||||
<input type="button" id="compactPublicKeyBench256BitBig" value="Compact Public Key Bench 256 Bits Big" disabled />
|
||||
|
||||
<input type="text" id="benchmarkResults" disabled>
|
||||
<label for="benchmarkResults"> BenchmarkResults </label><br>
|
||||
|
||||
<div id="loader" class="loader" hidden></div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -32,7 +32,11 @@ async function setup() {
|
||||
'compactPublicKeyTest256BitBig',
|
||||
'compactPublicKeyTest256BitSmall',
|
||||
'compressedCompactPublicKeyTest256BitBig',
|
||||
'compressedCompactPublicKeyTest256BitSmall'
|
||||
'compressedCompactPublicKeyTest256BitSmall',
|
||||
'compactPublicKeyBench32BitBig',
|
||||
'compactPublicKeyBench32BitSmall',
|
||||
'compactPublicKeyBench256BitBig',
|
||||
'compactPublicKeyBench256BitSmall'
|
||||
]
|
||||
|
||||
function setupBtn(id) {
|
||||
@@ -54,8 +58,11 @@ async function setup() {
|
||||
|
||||
console.log("Running: ", id)
|
||||
try {
|
||||
await fn()
|
||||
let results = await fn()
|
||||
document.getElementById("testSuccess").checked = true
|
||||
if (results !== undefined) {
|
||||
document.getElementById("benchmarkResults").value = JSON.stringify(results);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Test Failed: ${error}`)
|
||||
document.getElementById("testSuccess").checked = false
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "jest ./test --runInBand",
|
||||
"test": "jest ./test --runInBand --testNamePattern=Test",
|
||||
"bench": "jest ./test --runInBand --testNamePattern=Bench",
|
||||
"build": "cp -r ../../tfhe/pkg ./ && webpack build ./index.js --mode production -o dist --output-filename index.js && cp index.html dist/ && cp favicon.ico dist/",
|
||||
"server": "serve --config ../serve.json dist/",
|
||||
"test-separate-processes": "jest --listTests | xargs -L 1 jest --runInBand",
|
||||
"test-separate-processes": "jest --listTests | xargs -L 1 jest --runInBand --testNamePattern=Test",
|
||||
"bench-separate-processes": "jest --listTests | xargs -L 1 jest --runInBand --testNamePattern=Bench",
|
||||
"test2": "mocha"
|
||||
},
|
||||
"author": "",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import puppeteer from 'puppeteer';
|
||||
import process from 'process';
|
||||
import * as fs from 'node:fs';
|
||||
|
||||
const benchmark_dir = __dirname + '/benchmark_results';
|
||||
if (!fs.existsSync(benchmark_dir)){
|
||||
fs.mkdirSync(benchmark_dir);
|
||||
}
|
||||
|
||||
function isRoot() {
|
||||
return process.getuid && process.getuid() === 0;
|
||||
@@ -8,10 +14,14 @@ function isRoot() {
|
||||
async function runActualTest(page, buttonId) {
|
||||
const buttonSelector = `input#${buttonId}`
|
||||
const successCheckBoxSelector = `input#testSuccess`
|
||||
const benchmarkResultsSelector = `input#benchmarkResults`
|
||||
|
||||
const testSuccessCheckbox = await page.waitForSelector(
|
||||
successCheckBoxSelector
|
||||
);
|
||||
const benchmarkResultsTextbox = await page.waitForSelector(
|
||||
benchmarkResultsSelector
|
||||
);
|
||||
await page.waitForSelector(buttonSelector)
|
||||
|
||||
const isCheckedBefore = await testSuccessCheckbox?.evaluate(el => el.checked);
|
||||
@@ -26,6 +36,12 @@ async function runActualTest(page, buttonId) {
|
||||
|
||||
const isCheckedAfter = await testSuccessCheckbox?.evaluate(el => el.checked);
|
||||
expect(isCheckedAfter).toBe(true);
|
||||
|
||||
const results = await benchmarkResultsTextbox?.evaluate(el => el.value);
|
||||
if (results) {
|
||||
const parsed_results = JSON.parse(results);
|
||||
fs.writeFileSync(`${benchmark_dir}/${buttonId}.json`, results, {'flag': 'w'});
|
||||
}
|
||||
}
|
||||
|
||||
async function runTestAttachedToButton(buttonId) {
|
||||
|
||||
18
tfhe/web_wasm_parallel_tests/test/public-key-ct.test.js
Normal file
18
tfhe/web_wasm_parallel_tests/test/public-key-ct.test.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { runTestAttachedToButton } from "./common.mjs";
|
||||
|
||||
|
||||
it('Compact Public Key Bench Big 32 Bit', async () => {
|
||||
await runTestAttachedToButton('compactPublicKeyBench32BitBig')
|
||||
});
|
||||
|
||||
it('Compact Public Key Bench Small 32 Bit', async () => {
|
||||
await runTestAttachedToButton('compactPublicKeyBench32BitSmall')
|
||||
});
|
||||
|
||||
it('Compact Public Key Bench Big 256 Bit', async () => {
|
||||
await runTestAttachedToButton('compactPublicKeyBench256BitBig')
|
||||
});
|
||||
|
||||
it('Compact Public Key Bench Small 256 Bit', async () => {
|
||||
await runTestAttachedToButton('compactPublicKeyBench256BitSmall')
|
||||
});
|
||||
@@ -25,17 +25,25 @@ import init, {
|
||||
CompactFheUint256List,
|
||||
} from "./pkg/tfhe.js";
|
||||
|
||||
function assert(cond, text){
|
||||
if( cond ) return;
|
||||
if( console.assert.useDebugger ) debugger;
|
||||
throw new Error(text || "Assertion failed!");
|
||||
};
|
||||
function assert(cond, text) {
|
||||
if (cond) return;
|
||||
if (console.assert.useDebugger) debugger;
|
||||
throw new Error(text || "Assertion failed!");
|
||||
}
|
||||
|
||||
function assert_eq(a, b, text){
|
||||
if( a === b ) return;
|
||||
if( console.assert.useDebugger ) debugger;
|
||||
throw new Error(text || `Equality assertion failed!: ${a} != ${b}`);
|
||||
};
|
||||
function assert_eq(a, b, text) {
|
||||
if (a === b) return;
|
||||
if (console.assert.useDebugger) debugger;
|
||||
throw new Error(text || `Equality assertion failed!: ${a} != ${b}`);
|
||||
}
|
||||
|
||||
function append_param_name(bench_results, params_name) {
|
||||
let results = {};
|
||||
for (const bench_name in bench_results) {
|
||||
results[`${bench_name}_${params_name}`] = bench_results[bench_name];
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
async function compressedPublicKeyTest() {
|
||||
let config = TfheConfigBuilder.all_disabled()
|
||||
@@ -119,8 +127,7 @@ async function compactPublicKeyTest32BitOnConfig(config) {
|
||||
|
||||
assert_eq(encrypted_list.length, values.length);
|
||||
|
||||
for (let i = 0; i < values.length; i++)
|
||||
{
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let decrypted = encrypted_list[i].decrypt(clientKey);
|
||||
assert_eq(decrypted, values[i]);
|
||||
}
|
||||
@@ -133,8 +140,7 @@ async function compactPublicKeyTest32BitOnConfig(config) {
|
||||
let encrypted_list = deserialized_list.expand();
|
||||
assert_eq(encrypted_list.length, values.length);
|
||||
|
||||
for (let i = 0; i < values.length; i++)
|
||||
{
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let decrypted = encrypted_list[i].decrypt(clientKey);
|
||||
assert_eq(decrypted, values[i]);
|
||||
}
|
||||
@@ -156,6 +162,84 @@ async function compactPublicKeyTest32BitSmall() {
|
||||
await compactPublicKeyTest32BitOnConfig(config)
|
||||
}
|
||||
|
||||
async function compactPublicKeyBench32BitOnConfig(config) {
|
||||
const bench_loops = 100;
|
||||
let bench_results = {};
|
||||
|
||||
console.time('ClientKey Gen')
|
||||
let clientKey = TfheClientKey.generate(config);
|
||||
console.timeEnd('ClientKey Gen')
|
||||
|
||||
// Generate PK for encryption for later
|
||||
console.time('CompactPublicKey Gen')
|
||||
let publicKey = TfheCompactPublicKey.new(clientKey);
|
||||
console.timeEnd('CompactPublicKey Gen')
|
||||
|
||||
// Bench the pk generation for bench_loops iterations
|
||||
let start = performance.now();
|
||||
for (let i = 0; i < bench_loops; i++) {
|
||||
let _ = TfheCompactPublicKey.new(clientKey);
|
||||
}
|
||||
let end = performance.now();
|
||||
const timing_1 = (end - start) / bench_loops
|
||||
console.log('CompactPublicKey Gen bench: ', timing_1, ' ms');
|
||||
bench_results["compact_public_key_gen_32bit_mean"] = timing_1;
|
||||
|
||||
let values = [0, 1, 2, 2394, U32_MAX];
|
||||
|
||||
// Encrypt compact CT list for serialization for later
|
||||
console.time('CompactFheUint32List Encrypt')
|
||||
let compact_list = CompactFheUint32List.encrypt_with_compact_public_key(values, publicKey);
|
||||
console.timeEnd('CompactFheUint32List Encrypt')
|
||||
|
||||
// Bench the encryption for bench_loops iterations
|
||||
start = performance.now();
|
||||
for (let i = 0; i < bench_loops; i++) {
|
||||
let _ = CompactFheUint32List.encrypt_with_compact_public_key(values, publicKey);
|
||||
}
|
||||
end = performance.now();
|
||||
const timing_2 = (end - start) / bench_loops
|
||||
console.log('CompactFheUint32List Encrypt bench: ', timing_2, ' ms');
|
||||
bench_results["compact_fheunit32_list_encrypt_mean"] = timing_2;
|
||||
|
||||
let serialized_list = compact_list.serialize();
|
||||
console.log("Serialized CompactFheUint32List size: ", serialized_list.length);
|
||||
|
||||
// Bench the serialization for bench_loops iterations
|
||||
start = performance.now();
|
||||
for (let i = 0; i < bench_loops; i++) {
|
||||
let _ = compact_list.serialize();
|
||||
}
|
||||
end = performance.now();
|
||||
const timing_3 = (end - start) / bench_loops
|
||||
console.log('CompactFheUint32List serialization bench: ', timing_3, ' ms');
|
||||
bench_results["compact_fheunit32_list_serialization_mean"] = timing_3;
|
||||
|
||||
return bench_results;
|
||||
}
|
||||
|
||||
async function compactPublicKeyBench32BitBig() {
|
||||
const block_params = new ShortintParameters(ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_COMPACT_PK);
|
||||
let config = TfheConfigBuilder.all_disabled()
|
||||
.enable_custom_integers(block_params)
|
||||
.build();
|
||||
return append_param_name(
|
||||
await compactPublicKeyBench32BitOnConfig(config),
|
||||
"PARAM_MESSAGE_2_CARRY_2_COMPACT_PK"
|
||||
);
|
||||
}
|
||||
|
||||
async function compactPublicKeyBench32BitSmall() {
|
||||
const block_params = new ShortintParameters(ShortintParametersName.PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK);
|
||||
let config = TfheConfigBuilder.all_disabled()
|
||||
.enable_custom_integers(block_params)
|
||||
.build();
|
||||
return append_param_name(
|
||||
await compactPublicKeyBench32BitOnConfig(config),
|
||||
"PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK"
|
||||
);
|
||||
}
|
||||
|
||||
async function compactPublicKeyTest256BitOnConfig(config) {
|
||||
console.time('ClientKey Gen')
|
||||
let clientKey = TfheClientKey.generate(config);
|
||||
@@ -181,8 +265,7 @@ async function compactPublicKeyTest256BitOnConfig(config) {
|
||||
|
||||
assert_eq(encrypted_list.length, values.length);
|
||||
|
||||
for (let i = 0; i < values.length; i++)
|
||||
{
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let decrypted = encrypted_list[i].decrypt(clientKey);
|
||||
assert_eq(decrypted, values[i]);
|
||||
}
|
||||
@@ -195,8 +278,7 @@ async function compactPublicKeyTest256BitOnConfig(config) {
|
||||
let encrypted_list = deserialized_list.expand();
|
||||
assert_eq(encrypted_list.length, values.length);
|
||||
|
||||
for (let i = 0; i < values.length; i++)
|
||||
{
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let decrypted = encrypted_list[i].decrypt(clientKey);
|
||||
assert_eq(decrypted, values[i]);
|
||||
}
|
||||
@@ -248,8 +330,7 @@ async function compressedCompactPublicKeyTest256BitOnConfig(config) {
|
||||
|
||||
assert_eq(encrypted_list.length, values.length);
|
||||
|
||||
for (let i = 0; i < values.length; i++)
|
||||
{
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let decrypted = encrypted_list[i].decrypt(clientKey);
|
||||
assert_eq(decrypted, values[i]);
|
||||
}
|
||||
@@ -262,8 +343,7 @@ async function compressedCompactPublicKeyTest256BitOnConfig(config) {
|
||||
let encrypted_list = deserialized_list.expand();
|
||||
assert_eq(encrypted_list.length, values.length);
|
||||
|
||||
for (let i = 0; i < values.length; i++)
|
||||
{
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let decrypted = encrypted_list[i].decrypt(clientKey);
|
||||
assert_eq(decrypted, values[i]);
|
||||
}
|
||||
@@ -285,7 +365,83 @@ async function compressedCompactPublicKeyTest256BitSmall() {
|
||||
await compressedCompactPublicKeyTest256BitOnConfig(config)
|
||||
}
|
||||
|
||||
async function compactPublicKeyBench256BitOnConfig(config) {
|
||||
const bench_loops = 100;
|
||||
let bench_results = {}
|
||||
|
||||
console.time('ClientKey Gen')
|
||||
let clientKey = TfheClientKey.generate(config);
|
||||
console.timeEnd('ClientKey Gen')
|
||||
|
||||
// Generate PK for encryption for later
|
||||
console.time('CompactPublicKey Gen')
|
||||
let publicKey = TfheCompactPublicKey.new(clientKey);
|
||||
console.timeEnd('CompactPublicKey Gen')
|
||||
|
||||
// Bench the pk generation for bench_loops iterations
|
||||
let start = performance.now();
|
||||
for (let i = 0; i < bench_loops; i++) {
|
||||
let _ = TfheCompactPublicKey.new(clientKey);
|
||||
}
|
||||
let end = performance.now();
|
||||
const timing_1 = (end - start) / bench_loops
|
||||
console.log('CompactPublicKey Gen bench: ', timing_1, ' ms');
|
||||
bench_results["compact_public_key_gen_256bit_mean"] = timing_1;
|
||||
|
||||
let values = [0, 1, 2, 2394, U32_MAX].map((e) => BigInt(e));
|
||||
|
||||
// Encrypt compact CT list for serialization for later
|
||||
console.time('CompactFheUint256List Encrypt')
|
||||
let compact_list = CompactFheUint256List.encrypt_with_compact_public_key(values, publicKey);
|
||||
console.timeEnd('CompactFheUint256List Encrypt')
|
||||
|
||||
// Bench the encryption for bench_loops iterations
|
||||
start = performance.now();
|
||||
for (let i = 0; i < bench_loops; i++) {
|
||||
let _ = CompactFheUint256List.encrypt_with_compact_public_key(values, publicKey);
|
||||
}
|
||||
end = performance.now();
|
||||
const timing_2 = (end - start) / bench_loops
|
||||
console.log('CompactFheUint256List Encrypt bench: ', timing_2, ' ms');
|
||||
bench_results["compact_fheunit256_list_encrypt_mean"] = timing_2;
|
||||
|
||||
let serialized_list = compact_list.serialize();
|
||||
console.log("Serialized CompactFheUint256List size: ", serialized_list.length);
|
||||
|
||||
// Bench the serialization for bench_loops iterations
|
||||
start = performance.now();
|
||||
for (let i = 0; i < bench_loops; i++) {
|
||||
let _ = compact_list.serialize();
|
||||
}
|
||||
end = performance.now();
|
||||
const timing_3 = (end - start) / bench_loops
|
||||
console.log('CompactFheUint256List serialization bench: ', timing_3, ' ms');
|
||||
bench_results["compact_fheunit256_list_serialization_mean"] = timing_3;
|
||||
|
||||
return bench_results
|
||||
}
|
||||
|
||||
async function compactPublicKeyBench256BitBig() {
|
||||
const block_params = new ShortintParameters(ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_COMPACT_PK);
|
||||
let config = TfheConfigBuilder.all_disabled()
|
||||
.enable_custom_integers(block_params)
|
||||
.build();
|
||||
return append_param_name(
|
||||
await compactPublicKeyBench256BitOnConfig(config),
|
||||
"PARAM_MESSAGE_2_CARRY_2_COMPACT_PK"
|
||||
);
|
||||
}
|
||||
|
||||
async function compactPublicKeyBench256BitSmall() {
|
||||
const block_params = new ShortintParameters(ShortintParametersName.PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK);
|
||||
let config = TfheConfigBuilder.all_disabled()
|
||||
.enable_custom_integers(block_params)
|
||||
.build();
|
||||
return append_param_name(
|
||||
await compactPublicKeyBench256BitOnConfig(config),
|
||||
"PARAM_SMALL_MESSAGE_2_CARRY_2_COMPACT_PK"
|
||||
);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await init()
|
||||
@@ -301,6 +457,10 @@ async function main() {
|
||||
compactPublicKeyTest256BitBig,
|
||||
compressedCompactPublicKeyTest256BitSmall,
|
||||
compressedCompactPublicKeyTest256BitBig,
|
||||
compactPublicKeyBench32BitBig,
|
||||
compactPublicKeyBench32BitSmall,
|
||||
compactPublicKeyBench256BitBig,
|
||||
compactPublicKeyBench256BitSmall,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user