mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-09 22:57:59 -05:00
feat(tfhe): plug zk-pok into all layers
This commit is contained in:
32
Makefile
32
Makefile
@@ -175,10 +175,18 @@ fmt_gpu: install_rs_check_toolchain
|
|||||||
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt
|
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt
|
||||||
cd "$(TFHECUDA_SRC)" && ./format_tfhe_cuda_backend.sh
|
cd "$(TFHECUDA_SRC)" && ./format_tfhe_cuda_backend.sh
|
||||||
|
|
||||||
|
.PHONY: fmt_c_tests # Format c tests
|
||||||
|
fmt_c_tests:
|
||||||
|
find tfhe/c_api_tests/ -regex '.*\.\(cpp\|hpp\|cu\|c\|h\)' -exec clang-format -style=file -i {} \;
|
||||||
|
|
||||||
.PHONY: check_fmt # Check rust code format
|
.PHONY: check_fmt # Check rust code format
|
||||||
check_fmt: install_rs_check_toolchain
|
check_fmt: install_rs_check_toolchain
|
||||||
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt --check
|
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt --check
|
||||||
|
|
||||||
|
.PHONY: check_fmt_c_tests # Check C tests format
|
||||||
|
check_fmt_c_tests:
|
||||||
|
find tfhe/c_api_tests/ -regex '.*\.\(cpp\|hpp\|cu\|c\|h\)' -exec clang-format --dry-run --Werror -style=file {} \;
|
||||||
|
|
||||||
.PHONY: check_fmt_gpu # Check rust and cuda code format
|
.PHONY: check_fmt_gpu # Check rust and cuda code format
|
||||||
check_fmt_gpu: install_rs_check_toolchain
|
check_fmt_gpu: install_rs_check_toolchain
|
||||||
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt --check
|
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt --check
|
||||||
@@ -274,7 +282,7 @@ clippy_trivium: install_rs_check_toolchain
|
|||||||
.PHONY: clippy_all_targets # Run clippy lints on all targets (benches, examples, etc.)
|
.PHONY: clippy_all_targets # Run clippy lints on all targets (benches, examples, etc.)
|
||||||
clippy_all_targets:
|
clippy_all_targets:
|
||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
|
||||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache \
|
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,zk-pok-experimental \
|
||||||
-p $(TFHE_SPEC) -- --no-deps -D warnings
|
-p $(TFHE_SPEC) -- --no-deps -D warnings
|
||||||
|
|
||||||
.PHONY: clippy_concrete_csprng # Run clippy lints on concrete-csprng
|
.PHONY: clippy_concrete_csprng # Run clippy lints on concrete-csprng
|
||||||
@@ -353,14 +361,14 @@ symlink_c_libs_without_fingerprint:
|
|||||||
.PHONY: build_c_api # Build the C API for boolean, shortint and integer
|
.PHONY: build_c_api # Build the C API for boolean, shortint and integer
|
||||||
build_c_api: install_rs_check_toolchain
|
build_c_api: install_rs_check_toolchain
|
||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
|
||||||
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api,$(FORWARD_COMPAT_FEATURE) \
|
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api,zk-pok-experimental,$(FORWARD_COMPAT_FEATURE) \
|
||||||
-p $(TFHE_SPEC)
|
-p $(TFHE_SPEC)
|
||||||
@"$(MAKE)" symlink_c_libs_without_fingerprint
|
@"$(MAKE)" symlink_c_libs_without_fingerprint
|
||||||
|
|
||||||
.PHONY: build_c_api_gpu # Build the C API for boolean, shortint and integer
|
.PHONY: build_c_api_gpu # Build the C API for boolean, shortint and integer
|
||||||
build_c_api_gpu: install_rs_check_toolchain
|
build_c_api_gpu: install_rs_check_toolchain
|
||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) build --profile $(CARGO_PROFILE) \
|
||||||
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api,gpu \
|
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api,high-level-c-api,zk-pok-experimental,gpu \
|
||||||
-p $(TFHE_SPEC)
|
-p $(TFHE_SPEC)
|
||||||
@"$(MAKE)" symlink_c_libs_without_fingerprint
|
@"$(MAKE)" symlink_c_libs_without_fingerprint
|
||||||
|
|
||||||
@@ -376,7 +384,7 @@ build_web_js_api: install_rs_build_toolchain install_wasm_pack
|
|||||||
cd tfhe && \
|
cd tfhe && \
|
||||||
RUSTFLAGS="$(WASM_RUSTFLAGS)" rustup run "$(RS_BUILD_TOOLCHAIN)" \
|
RUSTFLAGS="$(WASM_RUSTFLAGS)" rustup run "$(RS_BUILD_TOOLCHAIN)" \
|
||||||
wasm-pack build --release --target=web \
|
wasm-pack build --release --target=web \
|
||||||
-- --features=boolean-client-js-wasm-api,shortint-client-js-wasm-api,integer-client-js-wasm-api
|
-- --features=boolean-client-js-wasm-api,shortint-client-js-wasm-api,integer-client-js-wasm-api,zk-pok-experimental
|
||||||
|
|
||||||
.PHONY: build_web_js_api_parallel # Build the js API targeting the web browser with parallelism support
|
.PHONY: build_web_js_api_parallel # Build the js API targeting the web browser with parallelism support
|
||||||
build_web_js_api_parallel: install_rs_check_toolchain install_wasm_pack
|
build_web_js_api_parallel: install_rs_check_toolchain install_wasm_pack
|
||||||
@@ -384,7 +392,7 @@ build_web_js_api_parallel: install_rs_check_toolchain install_wasm_pack
|
|||||||
rustup component add rust-src --toolchain $(RS_CHECK_TOOLCHAIN) && \
|
rustup component add rust-src --toolchain $(RS_CHECK_TOOLCHAIN) && \
|
||||||
RUSTFLAGS="$(WASM_RUSTFLAGS) -C target-feature=+atomics,+bulk-memory,+mutable-globals" rustup run $(RS_CHECK_TOOLCHAIN) \
|
RUSTFLAGS="$(WASM_RUSTFLAGS) -C target-feature=+atomics,+bulk-memory,+mutable-globals" rustup run $(RS_CHECK_TOOLCHAIN) \
|
||||||
wasm-pack build --release --target=web \
|
wasm-pack build --release --target=web \
|
||||||
-- --features=boolean-client-js-wasm-api,shortint-client-js-wasm-api,integer-client-js-wasm-api,parallel-wasm-api \
|
-- --features=boolean-client-js-wasm-api,shortint-client-js-wasm-api,integer-client-js-wasm-api,parallel-wasm-api,zk-pok-experimental \
|
||||||
-Z build-std=panic_abort,std
|
-Z build-std=panic_abort,std
|
||||||
|
|
||||||
.PHONY: build_node_js_api # Build the js API targeting nodejs
|
.PHONY: build_node_js_api # Build the js API targeting nodejs
|
||||||
@@ -392,7 +400,7 @@ build_node_js_api: install_rs_build_toolchain install_wasm_pack
|
|||||||
cd tfhe && \
|
cd tfhe && \
|
||||||
RUSTFLAGS="$(WASM_RUSTFLAGS)" rustup run "$(RS_BUILD_TOOLCHAIN)" \
|
RUSTFLAGS="$(WASM_RUSTFLAGS)" rustup run "$(RS_BUILD_TOOLCHAIN)" \
|
||||||
wasm-pack build --release --target=nodejs \
|
wasm-pack build --release --target=nodejs \
|
||||||
-- --features=boolean-client-js-wasm-api,shortint-client-js-wasm-api,integer-client-js-wasm-api
|
-- --features=boolean-client-js-wasm-api,shortint-client-js-wasm-api,integer-client-js-wasm-api,zk-pok-experimental
|
||||||
|
|
||||||
.PHONY: build_concrete_csprng # Build concrete_csprng
|
.PHONY: build_concrete_csprng # Build concrete_csprng
|
||||||
build_concrete_csprng: install_rs_build_toolchain
|
build_concrete_csprng: install_rs_build_toolchain
|
||||||
@@ -402,10 +410,10 @@ build_concrete_csprng: install_rs_build_toolchain
|
|||||||
.PHONY: test_core_crypto # Run the tests of the core_crypto module including experimental ones
|
.PHONY: test_core_crypto # Run the tests of the core_crypto module including experimental ones
|
||||||
test_core_crypto: install_rs_build_toolchain install_rs_check_toolchain
|
test_core_crypto: install_rs_build_toolchain install_rs_check_toolchain
|
||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||||
--features=$(TARGET_ARCH_FEATURE),experimental -p $(TFHE_SPEC) -- core_crypto::
|
--features=$(TARGET_ARCH_FEATURE),experimental,zk-pok-experimental -p $(TFHE_SPEC) -- core_crypto::
|
||||||
@if [[ "$(AVX512_SUPPORT)" == "ON" ]]; then \
|
@if [[ "$(AVX512_SUPPORT)" == "ON" ]]; then \
|
||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||||
--features=$(TARGET_ARCH_FEATURE),experimental,$(AVX512_FEATURE) -p $(TFHE_SPEC) -- core_crypto::; \
|
--features=$(TARGET_ARCH_FEATURE),experimental,zk-pok-experimental,$(AVX512_FEATURE) -p $(TFHE_SPEC) -- core_crypto::; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
.PHONY: test_core_crypto_cov # Run the tests of the core_crypto module with code coverage
|
.PHONY: test_core_crypto_cov # Run the tests of the core_crypto module with code coverage
|
||||||
@@ -576,7 +584,7 @@ test_integer_cov: install_rs_check_toolchain install_tarpaulin
|
|||||||
.PHONY: test_high_level_api # Run all the tests for high_level_api
|
.PHONY: test_high_level_api # Run all the tests for high_level_api
|
||||||
test_high_level_api: install_rs_build_toolchain
|
test_high_level_api: install_rs_build_toolchain
|
||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache -p $(TFHE_SPEC) \
|
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,zk-pok-experimental -p $(TFHE_SPEC) \
|
||||||
-- high_level_api::
|
-- high_level_api::
|
||||||
|
|
||||||
test_high_level_api_gpu: install_rs_build_toolchain install_cargo_nextest
|
test_high_level_api_gpu: install_rs_build_toolchain install_cargo_nextest
|
||||||
@@ -587,14 +595,14 @@ test_high_level_api_gpu: install_rs_build_toolchain install_cargo_nextest
|
|||||||
.PHONY: test_user_doc # Run tests from the .md documentation
|
.PHONY: test_user_doc # Run tests from the .md documentation
|
||||||
test_user_doc: install_rs_build_toolchain
|
test_user_doc: install_rs_build_toolchain
|
||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) --doc \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) --doc \
|
||||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,pbs-stats \
|
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,pbs-stats,zk-pok-experimental \
|
||||||
-p $(TFHE_SPEC) \
|
-p $(TFHE_SPEC) \
|
||||||
-- test_user_docs::
|
-- test_user_docs::
|
||||||
|
|
||||||
.PHONY: test_user_doc_gpu # Run tests for GPU from the .md documentation
|
.PHONY: test_user_doc_gpu # Run tests for GPU from the .md documentation
|
||||||
test_user_doc_gpu: install_rs_build_toolchain
|
test_user_doc_gpu: install_rs_build_toolchain
|
||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) --doc \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) --doc \
|
||||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,gpu -p $(TFHE_SPEC) \
|
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer,internal-keycache,gpu,zk-pok-experimental -p $(TFHE_SPEC) \
|
||||||
-- test_user_docs::
|
-- test_user_docs::
|
||||||
|
|
||||||
.PHONY: test_fhe_strings # Run tests for fhe_strings example
|
.PHONY: test_fhe_strings # Run tests for fhe_strings example
|
||||||
@@ -633,7 +641,7 @@ test_concrete_csprng:
|
|||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||||
--features=$(TARGET_ARCH_FEATURE) -p concrete-csprng
|
--features=$(TARGET_ARCH_FEATURE) -p concrete-csprng
|
||||||
|
|
||||||
.PHONY: test_zk_pok # Run tfhe-zk-pok tests
|
.PHONY: test_zk_pok # Run tfhe-zk-pok-experimental tests
|
||||||
test_zk_pok:
|
test_zk_pok:
|
||||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||||
-p tfhe-zk-pok
|
-p tfhe-zk-pok
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ cargo "${RUST_TOOLCHAIN}" nextest run \
|
|||||||
--cargo-profile "${cargo_profile}" \
|
--cargo-profile "${cargo_profile}" \
|
||||||
--package "${tfhe_package}" \
|
--package "${tfhe_package}" \
|
||||||
--profile ci \
|
--profile ci \
|
||||||
--features="${ARCH_FEATURE}",integer,internal-keycache,"${avx512_feature}" \
|
--features="${ARCH_FEATURE}",integer,internal-keycache,zk-pok-experimental,"${avx512_feature}" \
|
||||||
--test-threads "${test_threads}" \
|
--test-threads "${test_threads}" \
|
||||||
-E "$filter_expression"
|
-E "$filter_expression"
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ and not test(~smart_add_and_mul)""" # This test is too slow
|
|||||||
--cargo-profile "${cargo_profile}" \
|
--cargo-profile "${cargo_profile}" \
|
||||||
--package "${tfhe_package}" \
|
--package "${tfhe_package}" \
|
||||||
--profile ci \
|
--profile ci \
|
||||||
--features="${ARCH_FEATURE}",shortint,internal-keycache \
|
--features="${ARCH_FEATURE}",shortint,internal-keycache,zk-pok-experimental \
|
||||||
--test-threads "${n_threads_small}" \
|
--test-threads "${n_threads_small}" \
|
||||||
-E "${filter_expression_small_params}"
|
-E "${filter_expression_small_params}"
|
||||||
|
|
||||||
|
|||||||
@@ -51,12 +51,6 @@ impl<G: Curve> PublicParams<G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct PrivateParams<G: Curve> {
|
|
||||||
alpha: G::Zp,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Proof<G: Curve> {
|
pub struct Proof<G: Curve> {
|
||||||
c_hat: G::G2,
|
c_hat: G::G2,
|
||||||
@@ -104,27 +98,24 @@ pub fn crs_gen<G: Curve>(
|
|||||||
q: u64,
|
q: u64,
|
||||||
t: u64,
|
t: u64,
|
||||||
rng: &mut dyn RngCore,
|
rng: &mut dyn RngCore,
|
||||||
) -> (PublicParams<G>, PrivateParams<G>) {
|
) -> PublicParams<G> {
|
||||||
let alpha = G::Zp::rand(rng);
|
let alpha = G::Zp::rand(rng);
|
||||||
let b_r = d as u64 / 2 + 1;
|
let b_r = d as u64 / 2 + 1;
|
||||||
|
|
||||||
let big_d =
|
let big_d =
|
||||||
d + k * t.ilog2() as usize + (d + k) * (2 + b.ilog2() as usize + b_r.ilog2() as usize);
|
d + k * t.ilog2() as usize + (d + k) * (2 + b.ilog2() as usize + b_r.ilog2() as usize);
|
||||||
let n = big_d + 1;
|
let n = big_d + 1;
|
||||||
(
|
PublicParams {
|
||||||
PublicParams {
|
g_lists: GroupElements::<G>::new(n, alpha),
|
||||||
g_lists: GroupElements::<G>::new(n, alpha),
|
big_d,
|
||||||
big_d,
|
n,
|
||||||
n,
|
d,
|
||||||
d,
|
k,
|
||||||
k,
|
b,
|
||||||
b,
|
b_r,
|
||||||
b_r,
|
q,
|
||||||
q,
|
t,
|
||||||
t,
|
}
|
||||||
},
|
|
||||||
PrivateParams { alpha },
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
@@ -990,8 +981,7 @@ mod tests {
|
|||||||
m_roundtrip[i] = result;
|
m_roundtrip[i] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (public_param, _private_param) =
|
let public_param = crs_gen::<crate::curve_api::Bls12_446>(d, k, b_i, q, t, rng);
|
||||||
crs_gen::<crate::curve_api::Bls12_446>(d, k, b_i, q, t, rng);
|
|
||||||
|
|
||||||
for use_fake_e1 in [false, true] {
|
for use_fake_e1 in [false, true] {
|
||||||
for use_fake_e2 in [false, true] {
|
for use_fake_e2 in [false, true] {
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ paste = "1.0.7"
|
|||||||
fs2 = { version = "0.4.3", optional = true }
|
fs2 = { version = "0.4.3", optional = true }
|
||||||
# While we wait for repeat_n in rust standard library
|
# While we wait for repeat_n in rust standard library
|
||||||
itertools = "0.11.0"
|
itertools = "0.11.0"
|
||||||
|
rand_core = { version = "0.6.4", features = ["std"] }
|
||||||
|
tfhe-zk-pok = { version = "0.1.0", path = "../tfhe-zk-pok", optional = true }
|
||||||
|
|
||||||
# wasm deps
|
# wasm deps
|
||||||
wasm-bindgen = { version = "0.2.86", features = [
|
wasm-bindgen = { version = "0.2.86", features = [
|
||||||
@@ -87,6 +89,7 @@ shortint = []
|
|||||||
integer = ["shortint"]
|
integer = ["shortint"]
|
||||||
internal-keycache = ["dep:lazy_static", "dep:fs2"]
|
internal-keycache = ["dep:lazy_static", "dep:fs2"]
|
||||||
gpu = ["tfhe-cuda-backend"]
|
gpu = ["tfhe-cuda-backend"]
|
||||||
|
zk-pok-experimental = ["dep:tfhe-zk-pok"]
|
||||||
|
|
||||||
pbs-stats = []
|
pbs-stats = []
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ fn gen_c_api() {
|
|||||||
"integer",
|
"integer",
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
"gpu",
|
"gpu",
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
"zk-pok-experimental",
|
||||||
];
|
];
|
||||||
|
|
||||||
let parse_expand_vec = if parse_expand_features_vec.is_empty() {
|
let parse_expand_vec = if parse_expand_features_vec.is_empty() {
|
||||||
|
|||||||
109
tfhe/c_api_tests/test_high_level_zk.c
Normal file
109
tfhe/c_api_tests/test_high_level_zk.c
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#include "tfhe.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <tfhe.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// We want to use zk-proof, which requires bounded random distributions
|
||||||
|
// tfhe-rs has the `TUniform` as an available bounded distribution.
|
||||||
|
|
||||||
|
// Note that simply changing parameters like this does not yield secure parameters
|
||||||
|
// Its only done for the example / tests
|
||||||
|
ShortintPBSParameters params = SHORTINT_PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||||
|
params.glwe_noise_distribution = new_t_uniform(9);
|
||||||
|
assert(params.encryption_key_choice == ShortintEncryptionKeyChoiceBig);
|
||||||
|
|
||||||
|
int status;
|
||||||
|
|
||||||
|
ConfigBuilder *builder;
|
||||||
|
status = config_builder_default(&builder);
|
||||||
|
assert(status == 0);
|
||||||
|
status = config_builder_use_custom_parameters(&builder, params);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
Config *config;
|
||||||
|
status = config_builder_build(builder, &config);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
// Compute the CRS
|
||||||
|
// Note that we do that before generating the client key
|
||||||
|
// as client_key_generate thakes ownership of the config
|
||||||
|
CompactPkeCrs *crs;
|
||||||
|
size_t max_num_bits = 32;
|
||||||
|
status = compact_pke_crs_from_config(config, max_num_bits, &crs);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
CompactPkePublicParams *public_params;
|
||||||
|
status = compact_pke_crs_public_params(crs, &public_params);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
ClientKey *client_key;
|
||||||
|
status = client_key_generate(config, &client_key);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
// zk proofs of encryption works only using the CompactPublicKey
|
||||||
|
CompactPublicKey *pk;
|
||||||
|
status = compact_public_key_new(client_key, &pk);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
// Demo of ProvenCompactFheUint32
|
||||||
|
{
|
||||||
|
uint32_t msg = 8328937;
|
||||||
|
ProvenCompactFheUint32 *proven_fhe_uint;
|
||||||
|
status = proven_compact_fhe_uint32_try_encrypt(msg, public_params, pk, ZkComputeLoadProof,
|
||||||
|
&proven_fhe_uint);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
FheUint32 *fhe_uint;
|
||||||
|
// This function does not take ownership of the proven fhe uint, so we have to cleanup later
|
||||||
|
status =
|
||||||
|
proven_compact_fhe_uint32_verify_and_expand(proven_fhe_uint, public_params, pk, &fhe_uint);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
uint32_t decrypted;
|
||||||
|
status = fhe_uint32_decrypt(fhe_uint, client_key, &decrypted);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
assert(decrypted == msg);
|
||||||
|
fhe_uint32_destroy(fhe_uint);
|
||||||
|
proven_compact_fhe_uint32_destroy(proven_fhe_uint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo of ProvenCompactFheUint32List
|
||||||
|
{
|
||||||
|
uint32_t msgs[4] = {8328937, 217521191, 2753219039, 91099540};
|
||||||
|
ProvenCompactFheUint32List *proven_fhe_list;
|
||||||
|
status = proven_compact_fhe_uint32_list_try_encrypt(msgs, 4, public_params, pk,
|
||||||
|
ZkComputeLoadProof, &proven_fhe_list);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
size_t list_len;
|
||||||
|
status = proven_compact_fhe_uint32_list_len(proven_fhe_list, &list_len);
|
||||||
|
assert(status == 0);
|
||||||
|
assert(list_len == 4);
|
||||||
|
|
||||||
|
FheUint32 *fhe_uints[4];
|
||||||
|
// This function does not take ownership of the proven fhe uint, so we have to cleanup later
|
||||||
|
status = proven_compact_fhe_uint32_list_verify_and_expand(proven_fhe_list, public_params, pk,
|
||||||
|
&fhe_uints[0], 4);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 4; ++i) {
|
||||||
|
uint32_t decrypted;
|
||||||
|
status = fhe_uint32_decrypt(fhe_uints[i], client_key, &decrypted);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
assert(decrypted == msgs[i]);
|
||||||
|
fhe_uint32_destroy(fhe_uints[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
proven_compact_fhe_uint32_list_destroy(proven_fhe_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
compact_pke_public_params_destroy(public_params);
|
||||||
|
compact_pke_crs_destroy(crs);
|
||||||
|
compact_public_key_destroy(pk);
|
||||||
|
client_key_destroy(client_key);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -28,6 +28,8 @@ fn main() {
|
|||||||
|
|
||||||
This example shows how to use compact public keys. The main difference is in the ConfigBuilder, where the parameter set has been changed.
|
This example shows how to use compact public keys. The main difference is in the ConfigBuilder, where the parameter set has been changed.
|
||||||
|
|
||||||
|
See [the guide on ZK proofs](zk-pok.md) to see how to encrypt data using compact public keys and generate a zero knowledge proof of correct encryption at the same time.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use tfhe::prelude::*;
|
use tfhe::prelude::*;
|
||||||
use tfhe::{ConfigBuilder, generate_keys, set_server_key, FheUint8, CompactPublicKey};
|
use tfhe::{ConfigBuilder, generate_keys, set_server_key, FheUint8, CompactPublicKey};
|
||||||
|
|||||||
69
tfhe/docs/guides/zk-pok.md
Normal file
69
tfhe/docs/guides/zk-pok.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Zero Knowledge proof for Compact Public Key encryption
|
||||||
|
|
||||||
|
TFHE-rs enables the generation of a zero-knowledge proof to verify that a compact public key encryption process has been correctly performed. In other words, the creation of a proof reveals nothing about the encrypted message, except for its already known range. This technique is derived from [Libert’s work](https://eprint.iacr.org/2023/800).
|
||||||
|
|
||||||
|
{% hint style="info" %}
|
||||||
|
You can enable this feature using the flag: `--features=zk-pok-experimental` when building TFHE-rs.
|
||||||
|
{% endhint %}
|
||||||
|
|
||||||
|
|
||||||
|
Deploying this feature is straightforward: the client generates the proof at the time of encryption, while the server verifies it before proceeding with homomorphic computations. Below is an example demonstrating how a client can encrypt and prove a ciphertext, and how a server can verify the ciphertext and carry out computations on it:
|
||||||
|
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rand::prelude::*;
|
||||||
|
use tfhe::prelude::FheDecrypt;
|
||||||
|
use tfhe::shortint::parameters::DynamicDistribution;
|
||||||
|
use tfhe::set_server_key;
|
||||||
|
use tfhe::zk::{CompactPkeCrs, ZkComputeLoad};
|
||||||
|
|
||||||
|
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
let max_num_message = 1;
|
||||||
|
|
||||||
|
let mut params = tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS;
|
||||||
|
params.glwe_noise_distribution = DynamicDistribution::new_t_uniform(9);
|
||||||
|
|
||||||
|
let client_key = tfhe::ClientKey::generate(tfhe::ConfigBuilder::with_custom_parameters(params, None));
|
||||||
|
// This is done in an offline phase and the CRS is shared to all clients and the server
|
||||||
|
let crs = CompactPkeCrs::from_shortint_params(params, max_num_message).unwrap();
|
||||||
|
let public_zk_params = crs.public_params();
|
||||||
|
let server_key = tfhe::ServerKey::new(&client_key);
|
||||||
|
let public_key = tfhe::CompactPublicKey::try_new(&client_key).unwrap();
|
||||||
|
|
||||||
|
let clear_a = rng.gen::<u64>();
|
||||||
|
let clear_b = rng.gen::<u64>();
|
||||||
|
|
||||||
|
let a = tfhe::ProvenCompactFheUint64::try_encrypt(
|
||||||
|
clear_a,
|
||||||
|
public_zk_params,
|
||||||
|
&public_key,
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)?;
|
||||||
|
let b = tfhe::ProvenCompactFheUint64::try_encrypt(
|
||||||
|
clear_b,
|
||||||
|
public_zk_params,
|
||||||
|
&public_key,
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Server side
|
||||||
|
let result = {
|
||||||
|
set_server_key(server_key);
|
||||||
|
|
||||||
|
// Verify the ciphertexts
|
||||||
|
let a = a.verify_and_expand(&public_zk_params, &public_key)?;
|
||||||
|
let b = b.verify_and_expand(&public_zk_params, &public_key)?;
|
||||||
|
|
||||||
|
a + b
|
||||||
|
};
|
||||||
|
|
||||||
|
// Back on the client side
|
||||||
|
let a_plus_b: u64 = result.decrypt(&client_key);
|
||||||
|
assert_eq!(a_plus_b, clear_a.wrapping_add(clear_b));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Encrypting and proving a CompactFheUint64 takes 6.9 s on a Dell XPS 15 9500, simulating a client machine, the verification on an hpc7a.96xlarge available on AWS takes 123 ms.
|
||||||
@@ -3,6 +3,7 @@ const assert = require('node:assert').strict;
|
|||||||
const {performance} = require('perf_hooks');
|
const {performance} = require('perf_hooks');
|
||||||
const {
|
const {
|
||||||
init_panic_hook,
|
init_panic_hook,
|
||||||
|
Shortint,
|
||||||
ShortintParametersName,
|
ShortintParametersName,
|
||||||
ShortintParameters,
|
ShortintParameters,
|
||||||
TfheClientKey,
|
TfheClientKey,
|
||||||
@@ -21,9 +22,15 @@ const {
|
|||||||
CompressedFheUint256,
|
CompressedFheUint256,
|
||||||
CompactFheUint256,
|
CompactFheUint256,
|
||||||
CompactFheUint256List,
|
CompactFheUint256List,
|
||||||
|
ProvenCompactFheUint64,
|
||||||
|
ProvenCompactFheUint64List,
|
||||||
|
CompactPkeCrs,
|
||||||
|
ZkComputeLoad,
|
||||||
FheUint256
|
FheUint256
|
||||||
} = require("../pkg/tfhe.js");
|
} = require("../pkg/tfhe.js");
|
||||||
|
const {
|
||||||
|
randomBytes,
|
||||||
|
} = require('node:crypto');
|
||||||
|
|
||||||
const U256_MAX = BigInt("115792089237316195423570985008687907853269984665640564039457584007913129639935");
|
const U256_MAX = BigInt("115792089237316195423570985008687907853269984665640564039457584007913129639935");
|
||||||
const U128_MAX = BigInt("340282366920938463463374607431768211455");
|
const U128_MAX = BigInt("340282366920938463463374607431768211455");
|
||||||
@@ -639,3 +646,50 @@ test('hlapi_compact_public_key_encrypt_decrypt_uint256_big_list_compact', (t) =>
|
|||||||
|
|
||||||
hlapi_compact_public_key_encrypt_decrypt_uint256_list_compact(config);
|
hlapi_compact_public_key_encrypt_decrypt_uint256_list_compact(config);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function generateRandomBigInt(bitLength) {
|
||||||
|
const bytesNeeded = Math.ceil(bitLength / 8);
|
||||||
|
const randomBytesBuffer = randomBytes(bytesNeeded);
|
||||||
|
|
||||||
|
// Convert random bytes to BigInt
|
||||||
|
const randomBigInt = BigInt(`0x${randomBytesBuffer.toString('hex')}`);
|
||||||
|
|
||||||
|
return randomBigInt;
|
||||||
|
}
|
||||||
|
|
||||||
|
test('hlapi_compact_public_key_encrypt_and_prove_compact_uint256', (t) => {
|
||||||
|
let block_params = new ShortintParameters(ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_PBS_KS);
|
||||||
|
block_params.set_lwe_noise_distribution(Shortint.try_new_t_uniform(9));
|
||||||
|
|
||||||
|
let config = TfheConfigBuilder.default()
|
||||||
|
.use_custom_parameters(block_params)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let clientKey = TfheClientKey.generate(config);
|
||||||
|
let publicKey = TfheCompactPublicKey.new(clientKey);
|
||||||
|
|
||||||
|
let crs = CompactPkeCrs.from_parameters(block_params, 128);
|
||||||
|
let public_params = crs.public_params();
|
||||||
|
|
||||||
|
{
|
||||||
|
let input = generateRandomBigInt(64)
|
||||||
|
let encrypted = ProvenCompactFheUint64.encrypt_with_compact_public_key(
|
||||||
|
input, public_params, publicKey, ZkComputeLoad.Proof);
|
||||||
|
assert.deepStrictEqual(encrypted.verifies(public_params, publicKey), true);
|
||||||
|
let expanded = encrypted.verify_and_expand(public_params, publicKey);
|
||||||
|
let decrypted = expanded.decrypt(clientKey);
|
||||||
|
assert.deepStrictEqual(decrypted, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let inputs = [generateRandomBigInt(64), generateRandomBigInt(64), generateRandomBigInt(64), generateRandomBigInt(64)];
|
||||||
|
let encrypted = ProvenCompactFheUint64List.encrypt_with_compact_public_key(
|
||||||
|
inputs, public_params, publicKey, ZkComputeLoad.Proof);
|
||||||
|
assert.deepStrictEqual(encrypted.verifies(public_params, publicKey), true);
|
||||||
|
let expanded_list = encrypted.verify_and_expand(public_params, publicKey);
|
||||||
|
for (let i = 0; i < inputs.length; i++) {
|
||||||
|
let decrypted = expanded_list[i].decrypt(clientKey);
|
||||||
|
assert.deepStrictEqual(decrypted, inputs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -139,3 +139,122 @@ pub unsafe extern "C" fn compact_fhe_bool_list_expand(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
mod zk {
|
||||||
|
use crate::c_api::high_level_api::utils::{
|
||||||
|
impl_clone_on_type, impl_destroy_on_type, impl_safe_serialize_on_type,
|
||||||
|
impl_serialize_deserialize_on_type,
|
||||||
|
};
|
||||||
|
use std::ffi::c_int;
|
||||||
|
|
||||||
|
pub struct ProvenCompactFheBool(crate::high_level_api::ProvenCompactFheBool);
|
||||||
|
|
||||||
|
impl_destroy_on_type!(ProvenCompactFheBool);
|
||||||
|
impl_clone_on_type!(ProvenCompactFheBool);
|
||||||
|
impl_serialize_deserialize_on_type!(ProvenCompactFheBool);
|
||||||
|
impl_safe_serialize_on_type!(ProvenCompactFheBool);
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn proven_compact_fhe_bool_try_encrypt(
|
||||||
|
message: bool,
|
||||||
|
public_params: &crate::c_api::high_level_api::zk::CompactPkePublicParams,
|
||||||
|
pk: &crate::c_api::high_level_api::keys::CompactPublicKey,
|
||||||
|
compute_load: crate::c_api::high_level_api::zk::ZkComputeLoad,
|
||||||
|
out_result: *mut *mut ProvenCompactFheBool,
|
||||||
|
) -> c_int {
|
||||||
|
crate::c_api::utils::catch_panic(|| {
|
||||||
|
let result = crate::high_level_api::ProvenCompactFheBool::try_encrypt(
|
||||||
|
message,
|
||||||
|
&public_params.0,
|
||||||
|
&pk.0,
|
||||||
|
compute_load.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
*out_result = Box::into_raw(Box::new(ProvenCompactFheBool(result)));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn proven_compact_fhe_bool_verify_and_expand(
|
||||||
|
ct: *const ProvenCompactFheBool,
|
||||||
|
public_params: &crate::c_api::high_level_api::zk::CompactPkePublicParams,
|
||||||
|
pk: &crate::c_api::high_level_api::keys::CompactPublicKey,
|
||||||
|
out_result: *mut *mut super::FheBool,
|
||||||
|
) -> c_int {
|
||||||
|
crate::c_api::utils::catch_panic(|| {
|
||||||
|
let ct = crate::c_api::utils::get_ref_checked(ct).unwrap();
|
||||||
|
|
||||||
|
let result =
|
||||||
|
ct.0.clone()
|
||||||
|
.verify_and_expand(&public_params.0, &pk.0)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
*out_result = Box::into_raw(Box::new(super::FheBool(result)));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProvenCompactFheBoolList(crate::high_level_api::ProvenCompactFheBoolList);
|
||||||
|
|
||||||
|
impl_destroy_on_type!(ProvenCompactFheBoolList);
|
||||||
|
impl_clone_on_type!(ProvenCompactFheBoolList);
|
||||||
|
impl_serialize_deserialize_on_type!(ProvenCompactFheBoolList);
|
||||||
|
impl_safe_serialize_on_type!(ProvenCompactFheBoolList);
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn proven_compact_fhe_bool_list_try_encrypt(
|
||||||
|
input: *const bool,
|
||||||
|
input_len: usize,
|
||||||
|
public_params: &crate::c_api::high_level_api::zk::CompactPkePublicParams,
|
||||||
|
pk: &crate::c_api::high_level_api::keys::CompactPublicKey,
|
||||||
|
compute_load: crate::c_api::high_level_api::zk::ZkComputeLoad,
|
||||||
|
out_result: *mut *mut ProvenCompactFheBoolList,
|
||||||
|
) -> ::std::os::raw::c_int {
|
||||||
|
crate::c_api::utils::catch_panic(|| {
|
||||||
|
let messages = std::slice::from_raw_parts(input, input_len);
|
||||||
|
|
||||||
|
let result = crate::high_level_api::ProvenCompactFheBoolList::try_encrypt(
|
||||||
|
messages,
|
||||||
|
&public_params.0,
|
||||||
|
&pk.0,
|
||||||
|
compute_load.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
*out_result = Box::into_raw(Box::new(ProvenCompactFheBoolList(result)));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn proven_compact_fhe_bool_list_len(
|
||||||
|
sself: *const ProvenCompactFheBoolList,
|
||||||
|
result: *mut usize,
|
||||||
|
) -> ::std::os::raw::c_int {
|
||||||
|
crate::c_api::utils::catch_panic(|| {
|
||||||
|
let list = crate::c_api::utils::get_ref_checked(sself).unwrap();
|
||||||
|
|
||||||
|
*result = list.0.len();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn proven_compact_fhe_bool_list_verify_and_expand(
|
||||||
|
list: &ProvenCompactFheBoolList,
|
||||||
|
public_params: &crate::c_api::high_level_api::zk::CompactPkePublicParams,
|
||||||
|
pk: &crate::c_api::high_level_api::keys::CompactPublicKey,
|
||||||
|
output: *mut *mut super::FheBool,
|
||||||
|
output_len: usize,
|
||||||
|
) -> ::std::os::raw::c_int {
|
||||||
|
crate::c_api::utils::catch_panic(|| {
|
||||||
|
let expanded = list.0.verify_and_expand(&public_params.0, &pk.0).unwrap();
|
||||||
|
|
||||||
|
let num_to_take = output_len.max(list.0.len());
|
||||||
|
let iter = expanded.into_iter().take(num_to_take).enumerate();
|
||||||
|
for (i, fhe_uint) in iter {
|
||||||
|
let ptr = output.wrapping_add(i);
|
||||||
|
*ptr = Box::into_raw(Box::new(super::FheBool(fhe_uint)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -388,6 +388,7 @@ macro_rules! create_integer_wrapper_type {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The compact list version of the ciphertext type
|
// The compact list version of the ciphertext type
|
||||||
::paste::paste! {
|
::paste::paste! {
|
||||||
pub struct [<Compact $name List>]($crate::high_level_api::[<Compact $name List>]);
|
pub struct [<Compact $name List>]($crate::high_level_api::[<Compact $name List>]);
|
||||||
@@ -434,6 +435,135 @@ macro_rules! create_integer_wrapper_type {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The zk compact proven version of the compact ciphertext type
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
::paste::paste! {
|
||||||
|
pub struct [<ProvenCompact $name>]($crate::high_level_api::[<ProvenCompact $name>]);
|
||||||
|
|
||||||
|
impl_destroy_on_type!([<ProvenCompact $name>]);
|
||||||
|
|
||||||
|
impl_clone_on_type!([<ProvenCompact $name>]);
|
||||||
|
|
||||||
|
impl_serialize_deserialize_on_type!([<ProvenCompact $name>]);
|
||||||
|
|
||||||
|
impl_safe_serialize_on_type!([<ProvenCompact $name>]);
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn [<proven_compact_ $name:snake _try_encrypt>](
|
||||||
|
message: $clear_scalar_type,
|
||||||
|
public_params: &$crate::c_api::high_level_api::zk::CompactPkePublicParams,
|
||||||
|
pk: &$crate::c_api::high_level_api::keys::CompactPublicKey,
|
||||||
|
compute_load: $crate::c_api::high_level_api::zk::ZkComputeLoad,
|
||||||
|
out_result: *mut *mut [<ProvenCompact $name>],
|
||||||
|
) -> c_int {
|
||||||
|
$crate::c_api::utils::catch_panic(|| {
|
||||||
|
let message = <$clear_scalar_type as $crate::c_api::high_level_api::utils::CApiIntegerType>::to_rust(message);
|
||||||
|
|
||||||
|
let result = $crate::high_level_api::[<ProvenCompact $name>]::try_encrypt(
|
||||||
|
message,
|
||||||
|
&public_params.0,
|
||||||
|
&pk.0,
|
||||||
|
compute_load.into()
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
*out_result = Box::into_raw(Box::new([<ProvenCompact $name>](result)));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn [<proven_compact_ $name:snake _verify_and_expand>](
|
||||||
|
ct: *const [<ProvenCompact $name>],
|
||||||
|
public_params: &$crate::c_api::high_level_api::zk::CompactPkePublicParams,
|
||||||
|
pk: &$crate::c_api::high_level_api::keys::CompactPublicKey,
|
||||||
|
out_result: *mut *mut $name,
|
||||||
|
) -> c_int {
|
||||||
|
$crate::c_api::utils::catch_panic(|| {
|
||||||
|
let ct = $crate::c_api::utils::get_ref_checked(ct).unwrap();
|
||||||
|
|
||||||
|
let result = ct.0.clone().verify_and_expand(&public_params.0, &pk.0).unwrap();
|
||||||
|
|
||||||
|
*out_result = Box::into_raw(Box::new($name(result)));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The zk compact proven version of the compact ciphertext list type
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
::paste::paste! {
|
||||||
|
pub struct [<ProvenCompact $name List>]($crate::high_level_api::[<ProvenCompact $name List>]);
|
||||||
|
|
||||||
|
impl_destroy_on_type!([<ProvenCompact $name List>]);
|
||||||
|
|
||||||
|
impl_clone_on_type!([<ProvenCompact $name List>]);
|
||||||
|
|
||||||
|
impl_serialize_deserialize_on_type!([<ProvenCompact $name List>]);
|
||||||
|
|
||||||
|
impl_safe_serialize_on_type!([<ProvenCompact $name List>]);
|
||||||
|
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn [<proven_compact_ $name:snake _list_try_encrypt>](
|
||||||
|
input: *const $clear_scalar_type,
|
||||||
|
input_len: usize,
|
||||||
|
public_params: &$crate::c_api::high_level_api::zk::CompactPkePublicParams,
|
||||||
|
pk: &$crate::c_api::high_level_api::keys::CompactPublicKey,
|
||||||
|
compute_load: $crate::c_api::high_level_api::zk::ZkComputeLoad,
|
||||||
|
out_result: *mut *mut [<ProvenCompact $name List>],
|
||||||
|
) -> ::std::os::raw::c_int {
|
||||||
|
$crate::c_api::utils::catch_panic(|| {
|
||||||
|
let messages = std::slice::from_raw_parts(input, input_len)
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|value| {
|
||||||
|
<$clear_scalar_type as $crate::c_api::high_level_api::utils::CApiIntegerType>::to_rust(value)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let result = $crate::high_level_api::[<ProvenCompact $name List>]::try_encrypt(
|
||||||
|
&messages,
|
||||||
|
&public_params.0,
|
||||||
|
&pk.0,
|
||||||
|
compute_load.into()
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
*out_result = Box::into_raw(Box::new([<ProvenCompact $name List>](result)));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn [<proven_compact_ $name:snake _list_len>](
|
||||||
|
sself: *const [<ProvenCompact $name List>],
|
||||||
|
result: *mut usize,
|
||||||
|
) -> ::std::os::raw::c_int {
|
||||||
|
$crate::c_api::utils::catch_panic(|| {
|
||||||
|
let list = $crate::c_api::utils::get_ref_checked(sself).unwrap();
|
||||||
|
|
||||||
|
*result = list.0.len();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn [<proven_compact_ $name:snake _list_verify_and_expand>](
|
||||||
|
list: &[<ProvenCompact $name List>],
|
||||||
|
public_params: &$crate::c_api::high_level_api::zk::CompactPkePublicParams,
|
||||||
|
pk: &$crate::c_api::high_level_api::keys::CompactPublicKey,
|
||||||
|
output: *mut *mut $name,
|
||||||
|
output_len: usize
|
||||||
|
) -> ::std::os::raw::c_int {
|
||||||
|
$crate::c_api::utils::catch_panic(|| {
|
||||||
|
let expanded = list.0.verify_and_expand(&public_params.0, &pk.0).unwrap();
|
||||||
|
|
||||||
|
let num_to_take = output_len.max(list.0.len());
|
||||||
|
let iter = expanded.into_iter().take(num_to_take).enumerate();
|
||||||
|
for (i, fhe_uint) in iter {
|
||||||
|
let ptr = output.wrapping_add(i);
|
||||||
|
*ptr = Box::into_raw(Box::new($name(fhe_uint)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This entry point is meant for unsigned types
|
// This entry point is meant for unsigned types
|
||||||
@@ -803,7 +933,6 @@ macro_rules! impl_oprf_for_int {
|
|||||||
crate::high_level_api::SignedRandomizationSpec::FullSigned,
|
crate::high_level_api::SignedRandomizationSpec::FullSigned,
|
||||||
);
|
);
|
||||||
*out_result = Box::into_raw(Box::new($name(result)));
|
*out_result = Box::into_raw(Box::new($name(result)));
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,3 +9,5 @@ mod threading;
|
|||||||
pub mod u128;
|
pub mod u128;
|
||||||
pub mod u256;
|
pub mod u256;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
mod zk;
|
||||||
|
|||||||
59
tfhe/src/c_api/high_level_api/zk.rs
Normal file
59
tfhe/src/c_api/high_level_api/zk.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
use super::utils::*;
|
||||||
|
use crate::c_api::high_level_api::config::Config;
|
||||||
|
use crate::c_api::utils::get_ref_checked;
|
||||||
|
use std::ffi::c_int;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum ZkComputeLoad {
|
||||||
|
ZkComputeLoadProof,
|
||||||
|
ZkComputeLoadVerify,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ZkComputeLoad> for crate::zk::ZkComputeLoad {
|
||||||
|
fn from(value: ZkComputeLoad) -> Self {
|
||||||
|
match value {
|
||||||
|
ZkComputeLoad::ZkComputeLoadProof => Self::Proof,
|
||||||
|
ZkComputeLoad::ZkComputeLoadVerify => Self::Verify,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CompactPkePublicParams(pub(crate) crate::core_crypto::entities::CompactPkePublicParams);
|
||||||
|
impl_destroy_on_type!(CompactPkePublicParams);
|
||||||
|
impl_serialize_deserialize_on_type!(CompactPkePublicParams);
|
||||||
|
|
||||||
|
pub struct CompactPkeCrs(pub(crate) crate::core_crypto::entities::CompactPkeCrs);
|
||||||
|
|
||||||
|
impl_destroy_on_type!(CompactPkeCrs);
|
||||||
|
impl_serialize_deserialize_on_type!(CompactPkeCrs);
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn compact_pke_crs_from_config(
|
||||||
|
config: *const Config,
|
||||||
|
max_num_bits: usize,
|
||||||
|
out_result: *mut *mut CompactPkeCrs,
|
||||||
|
) -> c_int {
|
||||||
|
crate::c_api::utils::catch_panic(|| {
|
||||||
|
let config = get_ref_checked(config).unwrap();
|
||||||
|
|
||||||
|
let crs = crate::core_crypto::entities::CompactPkeCrs::from_config(config.0, max_num_bits)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
*out_result = Box::into_raw(Box::new(CompactPkeCrs(crs)));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn compact_pke_crs_public_params(
|
||||||
|
crs: *const CompactPkeCrs,
|
||||||
|
out_public_params: *mut *mut CompactPkePublicParams,
|
||||||
|
) -> c_int {
|
||||||
|
crate::c_api::utils::catch_panic(|| {
|
||||||
|
let crs = get_ref_checked(crs).unwrap();
|
||||||
|
|
||||||
|
*out_public_params = Box::into_raw(Box::new(CompactPkePublicParams(
|
||||||
|
crs.0.public_params().clone(),
|
||||||
|
)));
|
||||||
|
})
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
|||||||
|
use crate::core_crypto::entities::{LweCompactCiphertextList, LweCompactPublicKey};
|
||||||
|
use crate::core_crypto::prelude::{CastFrom, Container, LweCiphertext, UnsignedInteger};
|
||||||
|
use crate::zk::{CompactPkeProof, CompactPkePublicParams, ZkVerificationOutCome};
|
||||||
|
use tfhe_zk_pok::proofs::pke::{verify, PublicCommit};
|
||||||
|
|
||||||
|
/// Verifies with the given proof that a [`LweCompactCiphertextList`](LweCompactCiphertextList)
|
||||||
|
/// is valid.
|
||||||
|
pub fn verify_lwe_compact_ciphertext_list<Scalar, ListCont, KeyCont>(
|
||||||
|
lwe_compact_list: &LweCompactCiphertextList<ListCont>,
|
||||||
|
compact_public_key: &LweCompactPublicKey<KeyCont>,
|
||||||
|
proof: &CompactPkeProof,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
) -> ZkVerificationOutCome
|
||||||
|
where
|
||||||
|
Scalar: UnsignedInteger,
|
||||||
|
i64: CastFrom<Scalar>,
|
||||||
|
ListCont: Container<Element = Scalar>,
|
||||||
|
KeyCont: Container<Element = Scalar>,
|
||||||
|
{
|
||||||
|
if Scalar::BITS > 64 {
|
||||||
|
return ZkVerificationOutCome::Invalid;
|
||||||
|
}
|
||||||
|
let public_commit = PublicCommit::new(
|
||||||
|
compact_public_key
|
||||||
|
.get_mask()
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|x| i64::cast_from(x))
|
||||||
|
.collect(),
|
||||||
|
compact_public_key
|
||||||
|
.get_body()
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|x| i64::cast_from(x))
|
||||||
|
.collect(),
|
||||||
|
lwe_compact_list
|
||||||
|
.get_mask_list()
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|x| i64::cast_from(x))
|
||||||
|
.collect(),
|
||||||
|
lwe_compact_list
|
||||||
|
.get_body_list()
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|x| i64::cast_from(x))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
match verify(proof, (public_params, &public_commit)) {
|
||||||
|
Ok(_) => ZkVerificationOutCome::Valid,
|
||||||
|
Err(_) => ZkVerificationOutCome::Invalid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_lwe_ciphertext<Scalar, Cont, KeyCont>(
|
||||||
|
lwe_ciphertext: &LweCiphertext<Cont>,
|
||||||
|
compact_public_key: &LweCompactPublicKey<KeyCont>,
|
||||||
|
proof: &CompactPkeProof,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
) -> ZkVerificationOutCome
|
||||||
|
where
|
||||||
|
Scalar: UnsignedInteger,
|
||||||
|
i64: CastFrom<Scalar>,
|
||||||
|
Cont: Container<Element = Scalar>,
|
||||||
|
KeyCont: Container<Element = Scalar>,
|
||||||
|
{
|
||||||
|
if Scalar::BITS > 64 {
|
||||||
|
return ZkVerificationOutCome::Invalid;
|
||||||
|
}
|
||||||
|
let public_commit = PublicCommit::new(
|
||||||
|
compact_public_key
|
||||||
|
.get_mask()
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|x| i64::cast_from(x))
|
||||||
|
.collect(),
|
||||||
|
compact_public_key
|
||||||
|
.get_body()
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|x| i64::cast_from(x))
|
||||||
|
.collect(),
|
||||||
|
lwe_ciphertext
|
||||||
|
.get_mask()
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|x| i64::cast_from(x))
|
||||||
|
.collect(),
|
||||||
|
vec![i64::cast_from(*lwe_ciphertext.get_body().data); 1],
|
||||||
|
);
|
||||||
|
match verify(proof, (public_params, &public_commit)) {
|
||||||
|
Ok(_) => ZkVerificationOutCome::Valid,
|
||||||
|
Err(_) => ZkVerificationOutCome::Invalid,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,8 @@ pub mod lwe_programmable_bootstrapping;
|
|||||||
pub mod lwe_public_key_generation;
|
pub mod lwe_public_key_generation;
|
||||||
pub mod lwe_secret_key_generation;
|
pub mod lwe_secret_key_generation;
|
||||||
pub mod lwe_wopbs;
|
pub mod lwe_wopbs;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub mod lwe_zero_knowledge_verification;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
pub mod polynomial_algorithms;
|
pub mod polynomial_algorithms;
|
||||||
pub mod seeded_ggsw_ciphertext_decompression;
|
pub mod seeded_ggsw_ciphertext_decompression;
|
||||||
@@ -73,6 +75,8 @@ pub use lwe_programmable_bootstrapping::*;
|
|||||||
pub use lwe_public_key_generation::*;
|
pub use lwe_public_key_generation::*;
|
||||||
pub use lwe_secret_key_generation::*;
|
pub use lwe_secret_key_generation::*;
|
||||||
pub use lwe_wopbs::*;
|
pub use lwe_wopbs::*;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub use lwe_zero_knowledge_verification::*;
|
||||||
pub use seeded_ggsw_ciphertext_decompression::*;
|
pub use seeded_ggsw_ciphertext_decompression::*;
|
||||||
pub use seeded_ggsw_ciphertext_list_decompression::*;
|
pub use seeded_ggsw_ciphertext_list_decompression::*;
|
||||||
pub use seeded_glwe_ciphertext_decompression::*;
|
pub use seeded_glwe_ciphertext_decompression::*;
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::core_crypto::commons::generators::DeterministicSeeder;
|
use crate::core_crypto::commons::generators::DeterministicSeeder;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
use crate::core_crypto::commons::math::random::RandomGenerator;
|
||||||
use crate::core_crypto::commons::test_tools;
|
use crate::core_crypto::commons::test_tools;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
#[cfg(not(tarpaulin))]
|
#[cfg(not(tarpaulin))]
|
||||||
const NB_TESTS: usize = 10;
|
const NB_TESTS: usize = 10;
|
||||||
@@ -182,7 +186,7 @@ fn lwe_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: ClassicTestPara
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&ct,
|
&ct,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
@@ -237,7 +241,7 @@ fn lwe_allocate_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&ct,
|
&ct,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
@@ -290,7 +294,7 @@ fn lwe_trivial_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&ct,
|
&ct,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
@@ -340,7 +344,7 @@ fn lwe_allocate_trivial_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&ct,
|
&ct,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
@@ -403,7 +407,7 @@ fn lwe_list_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: ClassicTes
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&list,
|
&list,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut plaintext_list =
|
let mut plaintext_list =
|
||||||
@@ -474,7 +478,7 @@ fn lwe_list_par_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus + Sync + Send>(
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&list,
|
&list,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut plaintext_list =
|
let mut plaintext_list =
|
||||||
@@ -548,7 +552,7 @@ fn lwe_public_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: ClassicT
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&ct,
|
&ct,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
@@ -623,7 +627,7 @@ fn lwe_seeded_public_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&ct,
|
&ct,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
@@ -689,7 +693,7 @@ fn lwe_seeded_list_par_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus + Sync +
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&seeded_list,
|
&seeded_list,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut plaintext_list = PlaintextList::new(
|
let mut plaintext_list = PlaintextList::new(
|
||||||
@@ -701,7 +705,7 @@ fn lwe_seeded_list_par_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus + Sync +
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&lwe_list,
|
&lwe_list,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
decrypt_lwe_ciphertext_list(&lwe_sk, &lwe_list, &mut plaintext_list);
|
decrypt_lwe_ciphertext_list(&lwe_sk, &lwe_list, &mut plaintext_list);
|
||||||
@@ -765,14 +769,14 @@ fn lwe_seeded_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(params: ClassicT
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&std::slice::from_ref(seeded_ct.get_body().data),
|
&std::slice::from_ref(seeded_ct.get_body().data),
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let ct = seeded_ct.decompress_into_lwe_ciphertext();
|
let ct = seeded_ct.decompress_into_lwe_ciphertext();
|
||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&ct,
|
&ct,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
@@ -826,14 +830,14 @@ fn lwe_seeded_allocate_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&std::slice::from_ref(seeded_ct.get_body().data),
|
&std::slice::from_ref(seeded_ct.get_body().data),
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let ct = seeded_ct.decompress_into_lwe_ciphertext();
|
let ct = seeded_ct.decompress_into_lwe_ciphertext();
|
||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&ct,
|
&ct,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
@@ -971,7 +975,7 @@ fn lwe_compact_public_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
|
|||||||
|
|
||||||
assert!(check_encrypted_content_respects_mod(
|
assert!(check_encrypted_content_respects_mod(
|
||||||
&ct,
|
&ct,
|
||||||
ciphertext_modulus
|
ciphertext_modulus,
|
||||||
));
|
));
|
||||||
|
|
||||||
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
@@ -991,3 +995,324 @@ fn lwe_compact_public_encrypt_decrypt_custom_mod<Scalar: UnsignedTorus>(
|
|||||||
create_parametrized_test!(lwe_compact_public_encrypt_decrypt_custom_mod {
|
create_parametrized_test!(lwe_compact_public_encrypt_decrypt_custom_mod {
|
||||||
TEST_PARAMS_4_BITS_NATIVE_U64
|
TEST_PARAMS_4_BITS_NATIVE_U64
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
fn lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod<Scalar>(
|
||||||
|
params: ClassicTestParams<Scalar>,
|
||||||
|
) where
|
||||||
|
Scalar: UnsignedTorus + CastFrom<u64>,
|
||||||
|
Scalar::Signed: CastFrom<u64>,
|
||||||
|
i64: CastFrom<Scalar>,
|
||||||
|
u64: CastFrom<Scalar> + CastInto<Scalar::Signed>,
|
||||||
|
rand_distr::Standard: rand_distr::Distribution<Scalar>,
|
||||||
|
{
|
||||||
|
let lwe_dimension = LweDimension(params.polynomial_size.0);
|
||||||
|
let glwe_noise_distribution = TUniform::new(9);
|
||||||
|
let ciphertext_modulus = params.ciphertext_modulus;
|
||||||
|
let message_modulus_log = params.message_modulus_log;
|
||||||
|
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
|
||||||
|
|
||||||
|
let mut rsc = TestResources::new();
|
||||||
|
let mut random_generator = RandomGenerator::<ActivatedRandomGenerator>::new(rsc.seeder.seed());
|
||||||
|
|
||||||
|
let msg_modulus = Scalar::ONE.shl(message_modulus_log.0);
|
||||||
|
let mut msg = msg_modulus;
|
||||||
|
let delta: Scalar = encoding_with_padding / msg_modulus;
|
||||||
|
|
||||||
|
let crs = CompactPkeCrs::new(
|
||||||
|
lwe_dimension,
|
||||||
|
1,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
ciphertext_modulus,
|
||||||
|
msg_modulus * Scalar::TWO,
|
||||||
|
&mut random_generator,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
while msg != Scalar::ZERO {
|
||||||
|
msg = msg.wrapping_sub(Scalar::ONE);
|
||||||
|
for _ in 0..NB_TESTS {
|
||||||
|
let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key(
|
||||||
|
lwe_dimension,
|
||||||
|
&mut rsc.secret_random_generator,
|
||||||
|
);
|
||||||
|
|
||||||
|
let pk = allocate_and_generate_new_lwe_compact_public_key(
|
||||||
|
&lwe_sk,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
ciphertext_modulus,
|
||||||
|
&mut rsc.encryption_random_generator,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut ct = LweCiphertext::new(
|
||||||
|
Scalar::ZERO,
|
||||||
|
lwe_dimension.to_lwe_size(),
|
||||||
|
ciphertext_modulus,
|
||||||
|
);
|
||||||
|
|
||||||
|
let proof = encrypt_and_prove_lwe_ciphertext_with_compact_public_key(
|
||||||
|
&pk,
|
||||||
|
&mut ct,
|
||||||
|
Cleartext(msg),
|
||||||
|
delta,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
&mut rsc.secret_random_generator,
|
||||||
|
&mut rsc.encryption_random_generator,
|
||||||
|
&mut random_generator,
|
||||||
|
crs.public_params(),
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(check_encrypted_content_respects_mod(
|
||||||
|
&ct,
|
||||||
|
ciphertext_modulus,
|
||||||
|
));
|
||||||
|
|
||||||
|
let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct);
|
||||||
|
|
||||||
|
let decoded = round_decode(decrypted.0, delta) % msg_modulus;
|
||||||
|
|
||||||
|
assert_eq!(msg, decoded);
|
||||||
|
|
||||||
|
// Verify the proof
|
||||||
|
assert!(verify_lwe_ciphertext(&ct, &pk, &proof, crs.public_params()).is_valid());
|
||||||
|
|
||||||
|
// verify proof with invalid ciphertext
|
||||||
|
let index = random_generator.gen::<usize>() % ct.as_ref().len();
|
||||||
|
let value_to_add = random_generator.gen::<Scalar>();
|
||||||
|
ct.as_mut()[index] = ct.as_mut()[index].wrapping_add(value_to_add);
|
||||||
|
assert!(verify_lwe_ciphertext(&ct, &pk, &proof, crs.public_params()).is_invalid());
|
||||||
|
}
|
||||||
|
|
||||||
|
// In coverage, we break after one while loop iteration, changing message values does not
|
||||||
|
// yield higher coverage
|
||||||
|
#[cfg(tarpaulin)]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
create_parametrized_test!(lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod {
|
||||||
|
TEST_PARAMS_4_BITS_NATIVE_U64
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[test]
|
||||||
|
fn test_par_compact_lwe_list_public_key_encryption_and_proof() {
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
let lwe_dimension = LweDimension(2048);
|
||||||
|
let glwe_noise_distribution = TUniform::new(9);
|
||||||
|
let ciphertext_modulus = CiphertextModulus::new_native();
|
||||||
|
|
||||||
|
let delta_log = 59;
|
||||||
|
let delta = 1u64 << delta_log;
|
||||||
|
let message_modulus = 1u64 << (64 - (delta_log + 1));
|
||||||
|
let plaintext_modulus = 1u64 << (64 - delta_log);
|
||||||
|
let mut thread_rng = rand::thread_rng();
|
||||||
|
|
||||||
|
let max_num_body = 512;
|
||||||
|
let crs = CompactPkeCrs::new(
|
||||||
|
lwe_dimension,
|
||||||
|
max_num_body,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
ciphertext_modulus,
|
||||||
|
plaintext_modulus,
|
||||||
|
&mut thread_rng,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for _ in 0..4 {
|
||||||
|
let ct_count = thread_rng.gen_range(1..=max_num_body);
|
||||||
|
let lwe_ciphertext_count = LweCiphertextCount(ct_count);
|
||||||
|
|
||||||
|
println!("{lwe_dimension:?} {ct_count:?}");
|
||||||
|
|
||||||
|
let seed = test_tools::random_seed();
|
||||||
|
let cleartexts = (0..ct_count)
|
||||||
|
.map(|_| thread_rng.gen::<u64>() % message_modulus)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let par_lwe_ct_list = {
|
||||||
|
let mut deterministic_seeder =
|
||||||
|
DeterministicSeeder::<ActivatedRandomGenerator>::new(seed);
|
||||||
|
let mut random_generator =
|
||||||
|
RandomGenerator::<ActivatedRandomGenerator>::new(deterministic_seeder.seed());
|
||||||
|
let mut secret_random_generator =
|
||||||
|
SecretRandomGenerator::<ActivatedRandomGenerator>::new(deterministic_seeder.seed());
|
||||||
|
let mut encryption_random_generator =
|
||||||
|
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(
|
||||||
|
deterministic_seeder.seed(),
|
||||||
|
&mut deterministic_seeder,
|
||||||
|
);
|
||||||
|
|
||||||
|
let lwe_sk =
|
||||||
|
LweSecretKey::generate_new_binary(lwe_dimension, &mut secret_random_generator);
|
||||||
|
|
||||||
|
let mut compact_lwe_pk =
|
||||||
|
LweCompactPublicKey::new(0u64, lwe_dimension, ciphertext_modulus);
|
||||||
|
|
||||||
|
generate_lwe_compact_public_key(
|
||||||
|
&lwe_sk,
|
||||||
|
&mut compact_lwe_pk,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
&mut encryption_random_generator,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut output_compact_ct_list = LweCompactCiphertextList::new(
|
||||||
|
0u64,
|
||||||
|
lwe_dimension.to_lwe_size(),
|
||||||
|
lwe_ciphertext_count,
|
||||||
|
ciphertext_modulus,
|
||||||
|
);
|
||||||
|
|
||||||
|
let proof = par_encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key(
|
||||||
|
&compact_lwe_pk,
|
||||||
|
&mut output_compact_ct_list,
|
||||||
|
&cleartexts,
|
||||||
|
delta,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
&mut secret_random_generator,
|
||||||
|
&mut encryption_random_generator,
|
||||||
|
&mut random_generator,
|
||||||
|
crs.public_params(),
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(verify_lwe_compact_ciphertext_list(
|
||||||
|
&output_compact_ct_list,
|
||||||
|
&compact_lwe_pk,
|
||||||
|
&proof,
|
||||||
|
crs.public_params()
|
||||||
|
)
|
||||||
|
.is_valid());
|
||||||
|
|
||||||
|
let mut output_plaintext_list = PlaintextList::new(0u64, PlaintextCount(ct_count));
|
||||||
|
|
||||||
|
let lwe_ciphertext_list = output_compact_ct_list
|
||||||
|
.clone()
|
||||||
|
.par_expand_into_lwe_ciphertext_list();
|
||||||
|
|
||||||
|
decrypt_lwe_ciphertext_list(&lwe_sk, &lwe_ciphertext_list, &mut output_plaintext_list);
|
||||||
|
|
||||||
|
let signed_decomposer =
|
||||||
|
SignedDecomposer::new(DecompositionBaseLog(5), DecompositionLevelCount(1));
|
||||||
|
|
||||||
|
output_plaintext_list
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|x| *x.0 = signed_decomposer.closest_representable(*x.0) >> delta_log);
|
||||||
|
|
||||||
|
assert_eq!(cleartexts.as_slice(), output_plaintext_list.as_ref());
|
||||||
|
|
||||||
|
// verify proof with invalid ciphertext
|
||||||
|
let index = random_generator.gen::<usize>() % output_compact_ct_list.as_ref().len();
|
||||||
|
let value_to_add = random_generator.gen();
|
||||||
|
output_compact_ct_list.as_mut()[index] =
|
||||||
|
output_compact_ct_list.as_mut()[index].wrapping_add(value_to_add);
|
||||||
|
assert!(verify_lwe_compact_ciphertext_list(
|
||||||
|
&output_compact_ct_list,
|
||||||
|
&compact_lwe_pk,
|
||||||
|
&proof,
|
||||||
|
crs.public_params()
|
||||||
|
)
|
||||||
|
.is_invalid());
|
||||||
|
|
||||||
|
lwe_ciphertext_list
|
||||||
|
};
|
||||||
|
|
||||||
|
let ser_lwe_ct_list = {
|
||||||
|
let mut deterministic_seeder =
|
||||||
|
DeterministicSeeder::<ActivatedRandomGenerator>::new(seed);
|
||||||
|
let mut random_generator =
|
||||||
|
RandomGenerator::<ActivatedRandomGenerator>::new(deterministic_seeder.seed());
|
||||||
|
let mut secret_random_generator =
|
||||||
|
SecretRandomGenerator::<ActivatedRandomGenerator>::new(deterministic_seeder.seed());
|
||||||
|
let mut encryption_random_generator =
|
||||||
|
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(
|
||||||
|
deterministic_seeder.seed(),
|
||||||
|
&mut deterministic_seeder,
|
||||||
|
);
|
||||||
|
|
||||||
|
let lwe_sk =
|
||||||
|
LweSecretKey::generate_new_binary(lwe_dimension, &mut secret_random_generator);
|
||||||
|
|
||||||
|
let mut compact_lwe_pk =
|
||||||
|
LweCompactPublicKey::new(0u64, lwe_dimension, ciphertext_modulus);
|
||||||
|
|
||||||
|
generate_lwe_compact_public_key(
|
||||||
|
&lwe_sk,
|
||||||
|
&mut compact_lwe_pk,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
&mut encryption_random_generator,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut output_compact_ct_list = LweCompactCiphertextList::new(
|
||||||
|
0u64,
|
||||||
|
lwe_dimension.to_lwe_size(),
|
||||||
|
lwe_ciphertext_count,
|
||||||
|
ciphertext_modulus,
|
||||||
|
);
|
||||||
|
|
||||||
|
let proof = par_encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key(
|
||||||
|
&compact_lwe_pk,
|
||||||
|
&mut output_compact_ct_list,
|
||||||
|
&cleartexts,
|
||||||
|
delta,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
glwe_noise_distribution,
|
||||||
|
&mut secret_random_generator,
|
||||||
|
&mut encryption_random_generator,
|
||||||
|
&mut random_generator,
|
||||||
|
crs.public_params(),
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(verify_lwe_compact_ciphertext_list(
|
||||||
|
&output_compact_ct_list,
|
||||||
|
&compact_lwe_pk,
|
||||||
|
&proof,
|
||||||
|
crs.public_params()
|
||||||
|
)
|
||||||
|
.is_valid());
|
||||||
|
|
||||||
|
let mut output_plaintext_list = PlaintextList::new(0u64, PlaintextCount(ct_count));
|
||||||
|
|
||||||
|
let lwe_ciphertext_list = output_compact_ct_list
|
||||||
|
.clone()
|
||||||
|
.expand_into_lwe_ciphertext_list();
|
||||||
|
|
||||||
|
decrypt_lwe_ciphertext_list(&lwe_sk, &lwe_ciphertext_list, &mut output_plaintext_list);
|
||||||
|
|
||||||
|
let signed_decomposer =
|
||||||
|
SignedDecomposer::new(DecompositionBaseLog(5), DecompositionLevelCount(1));
|
||||||
|
|
||||||
|
output_plaintext_list
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|x| *x.0 = signed_decomposer.closest_representable(*x.0) >> delta_log);
|
||||||
|
|
||||||
|
assert_eq!(cleartexts.as_slice(), output_plaintext_list.as_ref());
|
||||||
|
|
||||||
|
// verify proof with invalid ciphertext
|
||||||
|
let index = random_generator.gen::<usize>() % output_compact_ct_list.as_ref().len();
|
||||||
|
let value_to_add = random_generator.gen();
|
||||||
|
output_compact_ct_list.as_mut()[index] =
|
||||||
|
output_compact_ct_list.as_mut()[index].wrapping_add(value_to_add);
|
||||||
|
assert!(verify_lwe_compact_ciphertext_list(
|
||||||
|
&output_compact_ct_list,
|
||||||
|
&compact_lwe_pk,
|
||||||
|
&proof,
|
||||||
|
crs.public_params()
|
||||||
|
)
|
||||||
|
.is_invalid());
|
||||||
|
|
||||||
|
lwe_ciphertext_list
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(ser_lwe_ct_list, par_lwe_ct_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::core_crypto::commons::math::torus::FromTorus;
|
use crate::core_crypto::commons::math::torus::FromTorus;
|
||||||
use crate::core_crypto::commons::numeric::{CastInto, Numeric};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// Clippy false positive, does not repro with smaller code
|
// Clippy false positive, does not repro with smaller code
|
||||||
|
|||||||
@@ -796,3 +796,28 @@ impl<G: ParallelByteRandomGenerator> RandomGenerator<G> {
|
|||||||
.map(|iter| iter.map(Self))
|
.map(|iter| iter.map(Self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<G: ByteRandomGenerator> rand_core::RngCore for RandomGenerator<G> {
|
||||||
|
fn next_u32(&mut self) -> u32 {
|
||||||
|
<u32 as RandomGenerable<Uniform>>::generate_one(self, Uniform)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_u64(&mut self) -> u64 {
|
||||||
|
<u64 as RandomGenerable<Uniform>>::generate_one(self, Uniform)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||||
|
dest.iter_mut().for_each(|b| *b = self.generate_next());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
|
||||||
|
if let Some(limit) = self.remaining_bytes() {
|
||||||
|
if limit < dest.len() {
|
||||||
|
return Err(rand_core::Error::new(format!("The random generator is bounded and cannot fill the slice {} bytes requested, {limit} possible", dest.len()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.fill_bytes(dest);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
//! [`RandomGenerator`] instead.
|
//! [`RandomGenerator`] instead.
|
||||||
use crate::core_crypto::commons::dispersion::{DispersionParameter, StandardDev, Variance};
|
use crate::core_crypto::commons::dispersion::{DispersionParameter, StandardDev, Variance};
|
||||||
use crate::core_crypto::commons::numeric::{FloatingPoint, UnsignedInteger};
|
use crate::core_crypto::commons::numeric::{FloatingPoint, UnsignedInteger};
|
||||||
|
use std::ops::Bound;
|
||||||
|
|
||||||
|
use crate::core_crypto::prelude::{CastInto, Numeric};
|
||||||
/// Convenience alias for the most efficient CSPRNG implementation available.
|
/// Convenience alias for the most efficient CSPRNG implementation available.
|
||||||
pub use activated_random_generator::ActivatedRandomGenerator;
|
pub use activated_random_generator::ActivatedRandomGenerator;
|
||||||
pub use gaussian::*;
|
pub use gaussian::*;
|
||||||
@@ -102,6 +104,82 @@ impl Distribution for UniformTernary {}
|
|||||||
impl<T: FloatingPoint> Distribution for Gaussian<T> {}
|
impl<T: FloatingPoint> Distribution for Gaussian<T> {}
|
||||||
impl<T: UnsignedInteger> Distribution for TUniform<T> {}
|
impl<T: UnsignedInteger> Distribution for TUniform<T> {}
|
||||||
|
|
||||||
|
pub trait BoundedDistribution<T>: Distribution {
|
||||||
|
fn low_bound(&self) -> Bound<T>;
|
||||||
|
fn high_bound(&self) -> Bound<T>;
|
||||||
|
|
||||||
|
fn contains(self, value: T) -> bool
|
||||||
|
where
|
||||||
|
T: Numeric,
|
||||||
|
{
|
||||||
|
{
|
||||||
|
match self.low_bound() {
|
||||||
|
Bound::Included(inclusive_low) => {
|
||||||
|
if value < inclusive_low {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bound::Excluded(exclusive_low) => {
|
||||||
|
if value <= exclusive_low {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bound::Unbounded => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
match self.high_bound() {
|
||||||
|
Bound::Included(inclusive_high) => {
|
||||||
|
if value > inclusive_high {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bound::Excluded(exclusive_high) => {
|
||||||
|
if value >= exclusive_high {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bound::Unbounded => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> BoundedDistribution<T::Signed> for TUniform<T>
|
||||||
|
where
|
||||||
|
T: UnsignedInteger,
|
||||||
|
{
|
||||||
|
fn low_bound(&self) -> Bound<T::Signed> {
|
||||||
|
Bound::Included(self.min_value_inclusive())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn high_bound(&self) -> Bound<T::Signed> {
|
||||||
|
Bound::Included(self.max_value_inclusive())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> BoundedDistribution<T::Signed> for DynamicDistribution<T>
|
||||||
|
where
|
||||||
|
T: UnsignedInteger,
|
||||||
|
{
|
||||||
|
fn low_bound(&self) -> Bound<T::Signed> {
|
||||||
|
match self {
|
||||||
|
Self::Gaussian(_) => Bound::Unbounded,
|
||||||
|
Self::TUniform(tu) => tu.low_bound(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn high_bound(&self) -> Bound<T::Signed> {
|
||||||
|
match self {
|
||||||
|
Self::Gaussian(_) => Bound::Unbounded,
|
||||||
|
Self::TUniform(tu) => tu.high_bound(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
||||||
pub enum DynamicDistribution<T: UnsignedInteger> {
|
pub enum DynamicDistribution<T: UnsignedInteger> {
|
||||||
Gaussian(Gaussian<f64>),
|
Gaussian(Gaussian<f64>),
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::core_crypto::commons::numeric::Numeric;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// The distribution $TUniform(1, -2^b, 2^b)$ is defined as follows, any value in the interval
|
/// The distribution $TUniform(1, -2^b, 2^b)$ is defined as follows, any value in the interval
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ pub trait SignedInteger:
|
|||||||
/// Return a bit representation of the integer, where blocks of length `block_length` are
|
/// Return a bit representation of the integer, where blocks of length `block_length` are
|
||||||
/// separated by whitespaces to increase the readability.
|
/// separated by whitespaces to increase the readability.
|
||||||
fn to_bits_string(&self, block_length: usize) -> String;
|
fn to_bits_string(&self, block_length: usize) -> String;
|
||||||
|
|
||||||
|
/// Return the absoluted balue
|
||||||
|
#[must_use]
|
||||||
|
fn wrapping_abs(self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! implement {
|
macro_rules! implement {
|
||||||
@@ -77,6 +81,11 @@ macro_rules! implement {
|
|||||||
}
|
}
|
||||||
strn
|
strn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn wrapping_abs(self) -> Self {
|
||||||
|
self.wrapping_abs()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ pub trait UnsignedInteger:
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
fn is_power_of_two(self) -> bool;
|
fn is_power_of_two(self) -> bool;
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
fn next_power_of_two(self) -> Self;
|
||||||
|
#[must_use]
|
||||||
fn ilog2(self) -> u32;
|
fn ilog2(self) -> u32;
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn ceil_ilog2(self) -> u32 {
|
fn ceil_ilog2(self) -> u32 {
|
||||||
@@ -240,6 +242,10 @@ macro_rules! implement {
|
|||||||
self.is_power_of_two()
|
self.is_power_of_two()
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
fn next_power_of_two(self) -> Self {
|
||||||
|
self.next_power_of_two()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
fn ilog2(self) -> u32 {
|
fn ilog2(self) -> u32 {
|
||||||
self.ilog2()
|
self.ilog2()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ pub use crate::core_crypto::fft_impl::fft64::crypto::ggsw::{
|
|||||||
FourierGgswCiphertext, FourierGgswCiphertextList, FourierGgswLevelMatrix, FourierGgswLevelRow,
|
FourierGgswCiphertext, FourierGgswCiphertextList, FourierGgswLevelMatrix, FourierGgswLevelRow,
|
||||||
};
|
};
|
||||||
pub use crate::core_crypto::fft_impl::fft64::math::polynomial::FourierPolynomial;
|
pub use crate::core_crypto::fft_impl::fft64::math::polynomial::FourierPolynomial;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub use crate::zk::*;
|
||||||
pub use cleartext::*;
|
pub use cleartext::*;
|
||||||
pub use ggsw_ciphertext::*;
|
pub use ggsw_ciphertext::*;
|
||||||
pub use ggsw_ciphertext_list::*;
|
pub use ggsw_ciphertext_list::*;
|
||||||
|
|||||||
59
tfhe/src/error.rs
Normal file
59
tfhe/src/error.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub enum ErrorKind {
|
||||||
|
Message(String),
|
||||||
|
/// The zero knowledge proof and the content it is supposed to prove
|
||||||
|
/// failed to correctly prove
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
InvalidZkProof,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Error {
|
||||||
|
kind: ErrorKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub(crate) fn new(message: String) -> Self {
|
||||||
|
Self::from(ErrorKind::Message(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kind(&self) -> &ErrorKind {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self.kind() {
|
||||||
|
ErrorKind::Message(msg) => {
|
||||||
|
write!(f, "{msg}")
|
||||||
|
}
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
ErrorKind::InvalidZkProof => {
|
||||||
|
write!(f, "The zero knowledge proof and the content it is supposed to prove were not valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ErrorKind> for Error {
|
||||||
|
fn from(kind: ErrorKind) -> Self {
|
||||||
|
Self { kind }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for Error {
|
||||||
|
fn from(message: &'a str) -> Self {
|
||||||
|
Self::new(message.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Error {
|
||||||
|
fn from(message: String) -> Self {
|
||||||
|
Self::new(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {}
|
||||||
@@ -36,7 +36,7 @@ use crate::{CompactPublicKey, FheBoolConformanceParams, ServerKey};
|
|||||||
#[cfg_attr(all(doc, not(doctest)), doc(cfg(feature = "integer")))]
|
#[cfg_attr(all(doc, not(doctest)), doc(cfg(feature = "integer")))]
|
||||||
#[derive(Clone, serde::Deserialize, serde::Serialize)]
|
#[derive(Clone, serde::Deserialize, serde::Serialize)]
|
||||||
pub struct CompactFheBool {
|
pub struct CompactFheBool {
|
||||||
list: CompactCiphertextList,
|
pub(in crate::high_level_api) list: CompactCiphertextList,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompactFheBool {
|
impl CompactFheBool {
|
||||||
@@ -55,7 +55,7 @@ impl CompactFheBool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FheTryEncrypt<bool, CompactPublicKey> for CompactFheBool {
|
impl FheTryEncrypt<bool, CompactPublicKey> for CompactFheBool {
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: bool, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: bool, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
||||||
let mut ciphertext = key.key.try_encrypt_compact(&[u8::from(value)], 1);
|
let mut ciphertext = key.key.try_encrypt_compact(&[u8::from(value)], 1);
|
||||||
@@ -145,7 +145,7 @@ impl CompactFheBoolList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FheTryEncrypt<&'a [bool], CompactPublicKey> for CompactFheBoolList {
|
impl<'a> FheTryEncrypt<&'a [bool], CompactPublicKey> for CompactFheBoolList {
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
/// Encrypts a slice of bool
|
/// Encrypts a slice of bool
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ impl CompressedFheBool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FheTryEncrypt<bool, ClientKey> for CompressedFheBool {
|
impl FheTryEncrypt<bool, ClientKey> for CompressedFheBool {
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
/// Creates a compressed encryption of a boolean value
|
/// Creates a compressed encryption of a boolean value
|
||||||
fn try_encrypt(value: bool, key: &ClientKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: bool, key: &ClientKey) -> Result<Self, Self::Error> {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::shortint::ciphertext::Degree;
|
|||||||
use crate::{ClientKey, CompactPublicKey, CompressedPublicKey, PublicKey};
|
use crate::{ClientKey, CompactPublicKey, CompressedPublicKey, PublicKey};
|
||||||
|
|
||||||
impl FheTryEncrypt<bool, ClientKey> for FheBool {
|
impl FheTryEncrypt<bool, ClientKey> for FheBool {
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: bool, key: &ClientKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: bool, key: &ClientKey) -> Result<Self, Self::Error> {
|
||||||
let integer_client_key = &key.key.key;
|
let integer_client_key = &key.key.key;
|
||||||
@@ -23,7 +23,7 @@ impl FheTryEncrypt<bool, ClientKey> for FheBool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FheTryEncrypt<bool, CompactPublicKey> for FheBool {
|
impl FheTryEncrypt<bool, CompactPublicKey> for FheBool {
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: bool, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: bool, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
||||||
let mut ciphertext = key.key.key.encrypt_radix(value as u8, 1);
|
let mut ciphertext = key.key.key.encrypt_radix(value as u8, 1);
|
||||||
@@ -66,7 +66,7 @@ impl FheTrivialEncrypt<bool> for FheBool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FheTryEncrypt<bool, CompressedPublicKey> for FheBool {
|
impl FheTryEncrypt<bool, CompressedPublicKey> for FheBool {
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: bool, key: &CompressedPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: bool, key: &CompressedPublicKey) -> Result<Self, Self::Error> {
|
||||||
let key = &key.key;
|
let key = &key.key;
|
||||||
@@ -77,7 +77,7 @@ impl FheTryEncrypt<bool, CompressedPublicKey> for FheBool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FheTryEncrypt<bool, PublicKey> for FheBool {
|
impl FheTryEncrypt<bool, PublicKey> for FheBool {
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: bool, key: &PublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: bool, key: &PublicKey) -> Result<Self, Self::Error> {
|
||||||
let key = &key.key;
|
let key = &key.key;
|
||||||
@@ -95,7 +95,7 @@ impl FheDecrypt<bool> for FheBool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FheTryTrivialEncrypt<bool> for FheBool {
|
impl FheTryTrivialEncrypt<bool> for FheBool {
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt_trivial(value: bool) -> Result<Self, Self::Error> {
|
fn try_encrypt_trivial(value: bool) -> Result<Self, Self::Error> {
|
||||||
let ciphertext = global_state::with_internal_keys(|key| match key {
|
let ciphertext = global_state::with_internal_keys(|key| match key {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
pub use base::{FheBool, FheBoolConformanceParams};
|
pub use base::{FheBool, FheBoolConformanceParams};
|
||||||
pub use compact::{CompactFheBool, CompactFheBoolList, CompactFheBoolListConformanceParams};
|
pub use compact::{CompactFheBool, CompactFheBoolList, CompactFheBoolListConformanceParams};
|
||||||
pub use compressed::CompressedFheBool;
|
pub use compressed::CompressedFheBool;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub use zk::{ProvenCompactFheBool, ProvenCompactFheBoolList};
|
||||||
|
|
||||||
mod base;
|
mod base;
|
||||||
mod compact;
|
mod compact;
|
||||||
@@ -9,3 +11,5 @@ mod encrypt;
|
|||||||
mod inner;
|
mod inner;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
mod zk;
|
||||||
|
|||||||
@@ -825,7 +825,57 @@ mod cpu {
|
|||||||
let expanded_list = deserialized_list.expand();
|
let expanded_list = deserialized_list.expand();
|
||||||
for (fhe_uint, expected) in expanded_list.iter().zip(clears.into_iter()) {
|
for (fhe_uint, expected) in expanded_list.iter().zip(clears.into_iter()) {
|
||||||
let decrypted: bool = fhe_uint.decrypt(&client_key);
|
let decrypted: bool = fhe_uint.decrypt(&client_key);
|
||||||
assert_eq!(decrypted, expected);
|
assert_eq!(decrypted, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[test]
|
||||||
|
fn test_fhe_bool_zk() {
|
||||||
|
use crate::core_crypto::prelude::DynamicDistribution;
|
||||||
|
use crate::zk::{CompactPkeCrs, ZkComputeLoad};
|
||||||
|
|
||||||
|
let mut params = crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||||
|
params.glwe_noise_distribution = DynamicDistribution::new_t_uniform(9);
|
||||||
|
|
||||||
|
let config = ConfigBuilder::with_custom_parameters(params, None).build();
|
||||||
|
let crs = CompactPkeCrs::from_config(config, 2).unwrap();
|
||||||
|
let ck = ClientKey::generate(config);
|
||||||
|
let pk = CompactPublicKey::new(&ck);
|
||||||
|
|
||||||
|
for msg in [true, false] {
|
||||||
|
let proven_compact_fhe_bool = crate::ProvenCompactFheBool::try_encrypt(
|
||||||
|
msg,
|
||||||
|
crs.public_params(),
|
||||||
|
&pk,
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let fhe_bool = proven_compact_fhe_bool
|
||||||
|
.verify_and_expand(crs.public_params(), &pk)
|
||||||
|
.unwrap();
|
||||||
|
let decrypted = fhe_bool.decrypt(&ck);
|
||||||
|
assert_eq!(decrypted, msg);
|
||||||
|
assert_degree_is_ok(&fhe_bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
let proven_compact_fhe_bool_list = crate::ProvenCompactFheBoolList::try_encrypt(
|
||||||
|
&[true, false],
|
||||||
|
crs.public_params(),
|
||||||
|
&pk,
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let fhe_bools = proven_compact_fhe_bool_list
|
||||||
|
.verify_and_expand(crs.public_params(), &pk)
|
||||||
|
.unwrap();
|
||||||
|
let decrypted = fhe_bools
|
||||||
|
.iter()
|
||||||
|
.map(|fb| fb.decrypt(&ck))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(decrypted.as_slice(), &[true, false]);
|
||||||
|
for fhe_bool in fhe_bools {
|
||||||
|
assert_degree_is_ok(&fhe_bool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
134
tfhe/src/high_level_api/booleans/zk.rs
Normal file
134
tfhe/src/high_level_api/booleans/zk.rs
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
use crate::integer::{BooleanBlock, ProvenCompactCiphertextList, RadixCiphertext};
|
||||||
|
use crate::named::Named;
|
||||||
|
use crate::shortint::ciphertext::Degree;
|
||||||
|
use crate::zk::{CompactPkePublicParams, ZkComputeLoad, ZkVerificationOutCome};
|
||||||
|
use crate::{CompactPublicKey, FheBool};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// A `CompactFheBool` tied to a Zero-Knowledge proof
|
||||||
|
///
|
||||||
|
/// The zero-knowledge proof allows to verify that the ciphertext is correctly
|
||||||
|
/// encrypted.
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProvenCompactFheBool {
|
||||||
|
inner: ProvenCompactCiphertextList,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Named for ProvenCompactFheBool {
|
||||||
|
const NAME: &'static str = "high_level_api::ProvenCompactFheBool";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProvenCompactFheBool {
|
||||||
|
/// Encrypts the message while also generating the zero-knowledge proof
|
||||||
|
pub fn try_encrypt(
|
||||||
|
value: bool,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
key: &CompactPublicKey,
|
||||||
|
load: ZkComputeLoad,
|
||||||
|
) -> crate::Result<Self> {
|
||||||
|
let value = value as u8;
|
||||||
|
let inner = key.key.key.encrypt_and_prove_radix_compact(
|
||||||
|
&[value],
|
||||||
|
1, /* num blocks */
|
||||||
|
public_params,
|
||||||
|
load,
|
||||||
|
)?;
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies the ciphertext and the proof
|
||||||
|
///
|
||||||
|
/// If the proof and ciphertext are valid, it returns an `Ok` with
|
||||||
|
/// the underlying `FheBool`.
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> crate::Result<FheBool> {
|
||||||
|
let mut radix = self
|
||||||
|
.inner
|
||||||
|
.verify_and_expand_one::<RadixCiphertext>(public_params, &public_key.key.key)?;
|
||||||
|
assert_eq!(radix.blocks.len(), 1);
|
||||||
|
radix.blocks[0].degree = Degree::new(1);
|
||||||
|
Ok(FheBool::new(BooleanBlock::new_unchecked(
|
||||||
|
radix.blocks.pop().unwrap(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> ZkVerificationOutCome {
|
||||||
|
self.inner.verify(public_params, &public_key.key.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `CompactFheBoolList` tied to a Zero-Knowledge proof
|
||||||
|
///
|
||||||
|
/// The zero-knowledge proof allows to verify that the ciphertext list is correctly
|
||||||
|
/// encrypted.
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProvenCompactFheBoolList {
|
||||||
|
inner: ProvenCompactCiphertextList,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Named for ProvenCompactFheBoolList {
|
||||||
|
const NAME: &'static str = "high_level_api::ProvenCompactFheBoolList";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProvenCompactFheBoolList {
|
||||||
|
/// Encrypts the message while also generating the zero-knowledge proof
|
||||||
|
pub fn try_encrypt(
|
||||||
|
values: &[bool],
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
key: &CompactPublicKey,
|
||||||
|
load: ZkComputeLoad,
|
||||||
|
) -> crate::Result<Self> {
|
||||||
|
let values = values.iter().copied().map(u8::from).collect::<Vec<_>>();
|
||||||
|
let inner = key.key.key.encrypt_and_prove_radix_compact(
|
||||||
|
&values,
|
||||||
|
1, /* num_blocks */
|
||||||
|
public_params,
|
||||||
|
load,
|
||||||
|
)?;
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.inner.ciphertext_count()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies the ciphertext and the proof
|
||||||
|
///
|
||||||
|
/// If the proof and ciphertext are valid, it returns an `Ok` with
|
||||||
|
/// the underlying `FheBool`s.
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> crate::Result<Vec<FheBool>> {
|
||||||
|
Ok(self
|
||||||
|
.inner
|
||||||
|
.verify_and_expand::<RadixCiphertext>(public_params, &public_key.key.key)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|mut radix| {
|
||||||
|
assert_eq!(radix.blocks.len(), 1);
|
||||||
|
radix.blocks[0].degree = Degree::new(1);
|
||||||
|
FheBool::new(BooleanBlock::new_unchecked(radix.blocks.pop().unwrap()))
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> ZkVerificationOutCome {
|
||||||
|
self.inner.verify(public_params, &public_key.key.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::high_level_api::keys::IntegerConfig;
|
use crate::high_level_api::keys::IntegerConfig;
|
||||||
|
|
||||||
/// The config type
|
/// The config type
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub(crate) inner: IntegerConfig,
|
pub(crate) inner: IntegerConfig,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,43 +38,3 @@ impl Display for UninitializedServerKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for UninitializedServerKey {}
|
impl std::error::Error for UninitializedServerKey {}
|
||||||
|
|
||||||
/// Error when trying to create a short integer from a value that was too big to be represented
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct OutOfRangeError;
|
|
||||||
|
|
||||||
impl Display for OutOfRangeError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "Value is out of range")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for OutOfRangeError {}
|
|
||||||
|
|
||||||
#[non_exhaustive]
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
|
||||||
pub enum Error {
|
|
||||||
OutOfRange,
|
|
||||||
UninitializedServerKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<OutOfRangeError> for Error {
|
|
||||||
fn from(_: OutOfRangeError) -> Self {
|
|
||||||
Self::OutOfRange
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Error {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::OutOfRange => {
|
|
||||||
write!(f, "{OutOfRangeError}")
|
|
||||||
}
|
|
||||||
Self::UninitializedServerKey => {
|
|
||||||
write!(f, "{UninitializedServerKey}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for Error {}
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ where
|
|||||||
T: crate::integer::block_decomposition::DecomposableInto<u64>,
|
T: crate::integer::block_decomposition::DecomposableInto<u64>,
|
||||||
Id: FheIntId,
|
Id: FheIntId,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
||||||
let id = Id::default();
|
let id = Id::default();
|
||||||
@@ -169,7 +169,7 @@ where
|
|||||||
T: crate::integer::block_decomposition::DecomposableInto<u64>,
|
T: crate::integer::block_decomposition::DecomposableInto<u64>,
|
||||||
Id: FheIntId,
|
Id: FheIntId,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(values: &'a [T], key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(values: &'a [T], key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
||||||
let id = Id::default();
|
let id = Id::default();
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ where
|
|||||||
Id: FheIntId,
|
Id: FheIntId,
|
||||||
T: DecomposableInto<u64> + SignedNumeric,
|
T: DecomposableInto<u64> + SignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &ClientKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &ClientKey) -> Result<Self, Self::Error> {
|
||||||
let integer_client_key = &key.key.key;
|
let integer_client_key = &key.key.key;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ where
|
|||||||
Id: FheIntId,
|
Id: FheIntId,
|
||||||
T: DecomposableInto<u64> + SignedNumeric,
|
T: DecomposableInto<u64> + SignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &ClientKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &ClientKey) -> Result<Self, Self::Error> {
|
||||||
let ciphertext = key
|
let ciphertext = key
|
||||||
@@ -59,7 +59,7 @@ where
|
|||||||
Id: FheIntId,
|
Id: FheIntId,
|
||||||
T: DecomposableInto<u64> + SignedNumeric,
|
T: DecomposableInto<u64> + SignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &PublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &PublicKey) -> Result<Self, Self::Error> {
|
||||||
let ciphertext = key
|
let ciphertext = key
|
||||||
@@ -74,7 +74,7 @@ where
|
|||||||
Id: FheIntId,
|
Id: FheIntId,
|
||||||
T: DecomposableInto<u64> + SignedNumeric,
|
T: DecomposableInto<u64> + SignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &CompressedPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &CompressedPublicKey) -> Result<Self, Self::Error> {
|
||||||
let ciphertext = key
|
let ciphertext = key
|
||||||
@@ -89,7 +89,7 @@ where
|
|||||||
Id: FheIntId,
|
Id: FheIntId,
|
||||||
T: DecomposableInto<u64> + SignedNumeric,
|
T: DecomposableInto<u64> + SignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
||||||
let ciphertext = key
|
let ciphertext = key
|
||||||
@@ -105,7 +105,7 @@ where
|
|||||||
T: DecomposableInto<u64>,
|
T: DecomposableInto<u64>,
|
||||||
Id: FheIntId,
|
Id: FheIntId,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
/// Creates a trivial encryption of a signed integer.
|
/// Creates a trivial encryption of a signed integer.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ mod scalar_ops;
|
|||||||
mod static_;
|
mod static_;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
mod zk;
|
||||||
|
|
||||||
pub use base::{FheInt, FheIntId};
|
pub use base::{FheInt, FheIntId};
|
||||||
pub use compact::{CompactFheInt, CompactFheIntList};
|
pub use compact::{CompactFheInt, CompactFheIntList};
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
use super::zk::{ProvenCompactFheInt, ProvenCompactFheIntList};
|
||||||
use crate::high_level_api::integers::signed::base::{FheInt, FheIntConformanceParams, FheIntId};
|
use crate::high_level_api::integers::signed::base::{FheInt, FheIntConformanceParams, FheIntId};
|
||||||
use crate::high_level_api::integers::signed::compact::{
|
use crate::high_level_api::integers::signed::compact::{
|
||||||
CompactFheInt, CompactFheIntList, CompactFheIntListConformanceParams,
|
CompactFheInt, CompactFheIntList, CompactFheIntListConformanceParams,
|
||||||
@@ -57,6 +59,13 @@ macro_rules! static_int_type {
|
|||||||
|
|
||||||
#[cfg_attr(all(doc, not(doctest)), cfg(feature = "integer"))]
|
#[cfg_attr(all(doc, not(doctest)), cfg(feature = "integer"))]
|
||||||
pub type [<Compact FheInt $num_bits ListConformanceParams>] = CompactFheIntListConformanceParams<[<FheInt $num_bits Id>]>;
|
pub type [<Compact FheInt $num_bits ListConformanceParams>] = CompactFheIntListConformanceParams<[<FheInt $num_bits Id>]>;
|
||||||
|
|
||||||
|
// Zero-knowledge Stuff
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub type [<ProvenCompactFheInt $num_bits>] = ProvenCompactFheInt<[<FheInt $num_bits Id>]>;
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub type [<ProvenCompactFheInt $num_bits List>] = ProvenCompactFheIntList<[<FheInt $num_bits Id>]>;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -801,3 +801,50 @@ fn test_safe_deserialize_conformant_compact_fhe_int32_list() {
|
|||||||
));
|
));
|
||||||
assert!(deserialized_list.is_conformant(¶ms));
|
assert!(deserialized_list.is_conformant(¶ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[test]
|
||||||
|
fn test_fhe_int_zk() {
|
||||||
|
use crate::core_crypto::prelude::DynamicDistribution;
|
||||||
|
use crate::zk::{CompactPkeCrs, ZkComputeLoad};
|
||||||
|
|
||||||
|
let mut params = crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||||
|
params.glwe_noise_distribution = DynamicDistribution::new_t_uniform(9);
|
||||||
|
|
||||||
|
let config = ConfigBuilder::with_custom_parameters(params, None).build();
|
||||||
|
let crs = CompactPkeCrs::from_config(config, 32).unwrap();
|
||||||
|
let ck = ClientKey::generate(config);
|
||||||
|
let pk = CompactPublicKey::new(&ck);
|
||||||
|
|
||||||
|
let msg = random::<i32>();
|
||||||
|
|
||||||
|
let proven_compact_fhe_uint = crate::ProvenCompactFheInt32::try_encrypt(
|
||||||
|
msg,
|
||||||
|
crs.public_params(),
|
||||||
|
&pk,
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let fhe_uint = proven_compact_fhe_uint
|
||||||
|
.verify_and_expand(crs.public_params(), &pk)
|
||||||
|
.unwrap();
|
||||||
|
let decrypted: i32 = fhe_uint.decrypt(&ck);
|
||||||
|
assert_eq!(decrypted, msg);
|
||||||
|
|
||||||
|
let messages = (0..4).map(|_| random()).collect::<Vec<i32>>();
|
||||||
|
let proven_compact_fhe_uint_list = crate::ProvenCompactFheInt32List::try_encrypt(
|
||||||
|
&messages,
|
||||||
|
crs.public_params(),
|
||||||
|
&pk,
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let fhe_uints = proven_compact_fhe_uint_list
|
||||||
|
.verify_and_expand(crs.public_params(), &pk)
|
||||||
|
.unwrap();
|
||||||
|
let decrypted = fhe_uints
|
||||||
|
.iter()
|
||||||
|
.map(|fb| fb.decrypt(&ck))
|
||||||
|
.collect::<Vec<i32>>();
|
||||||
|
assert_eq!(decrypted.as_slice(), &messages);
|
||||||
|
}
|
||||||
|
|||||||
140
tfhe/src/high_level_api/integers/signed/zk.rs
Normal file
140
tfhe/src/high_level_api/integers/signed/zk.rs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
use crate::core_crypto::commons::math::random::{Deserialize, Serialize};
|
||||||
|
use crate::core_crypto::prelude::SignedNumeric;
|
||||||
|
use crate::high_level_api::integers::FheIntId;
|
||||||
|
use crate::integer::block_decomposition::DecomposableInto;
|
||||||
|
use crate::integer::{ProvenCompactCiphertextList, SignedRadixCiphertext};
|
||||||
|
use crate::named::Named;
|
||||||
|
use crate::zk::{CompactPkePublicParams, ZkComputeLoad, ZkVerificationOutCome};
|
||||||
|
use crate::{CompactPublicKey, FheInt};
|
||||||
|
|
||||||
|
/// A `CompactFheInt` tied to a Zero-Knowledge proof
|
||||||
|
///
|
||||||
|
/// The zero-knowledge proof allows to verify that the ciphertext is correctly
|
||||||
|
/// encrypted.
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProvenCompactFheInt<Id: FheIntId> {
|
||||||
|
inner: ProvenCompactCiphertextList,
|
||||||
|
_id: Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Id: FheIntId> Named for ProvenCompactFheInt<Id> {
|
||||||
|
const NAME: &'static str = "high_level_api::ProvenCompactFheUintList";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Id> ProvenCompactFheInt<Id>
|
||||||
|
where
|
||||||
|
Id: FheIntId,
|
||||||
|
{
|
||||||
|
/// Encrypts the message while also generating the zero-knowledge proof
|
||||||
|
pub fn try_encrypt<Clear>(
|
||||||
|
value: Clear,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
key: &CompactPublicKey,
|
||||||
|
load: ZkComputeLoad,
|
||||||
|
) -> crate::Result<Self>
|
||||||
|
where
|
||||||
|
Clear: DecomposableInto<u64> + SignedNumeric,
|
||||||
|
{
|
||||||
|
let inner = key.key.key.encrypt_and_prove_radix_compact(
|
||||||
|
&[value],
|
||||||
|
Id::num_blocks(key.key.key.key.parameters.message_modulus()),
|
||||||
|
public_params,
|
||||||
|
load,
|
||||||
|
)?;
|
||||||
|
Ok(Self {
|
||||||
|
inner,
|
||||||
|
_id: Id::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies the ciphertext and the proof
|
||||||
|
///
|
||||||
|
/// If the proof and ciphertext are valid, it returns an `Ok` with
|
||||||
|
/// the underlying `FheInt`
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> crate::Result<FheInt<Id>> {
|
||||||
|
let expanded_inner = self
|
||||||
|
.inner
|
||||||
|
.verify_and_expand_one::<SignedRadixCiphertext>(public_params, &public_key.key.key)?;
|
||||||
|
Ok(FheInt::new(expanded_inner))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> ZkVerificationOutCome {
|
||||||
|
self.inner.verify(public_params, &public_key.key.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `CompactFheIntList` tied to a Zero-Knowledge proof
|
||||||
|
///
|
||||||
|
/// The zero-knowledge proof allows to verify that the ciphertext list is correctly
|
||||||
|
/// encrypted.
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProvenCompactFheIntList<Id: FheIntId> {
|
||||||
|
inner: ProvenCompactCiphertextList,
|
||||||
|
_id: Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Id: FheIntId> Named for ProvenCompactFheIntList<Id> {
|
||||||
|
const NAME: &'static str = "high_level_api::ProvenCompactFheIntList";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Id> ProvenCompactFheIntList<Id>
|
||||||
|
where
|
||||||
|
Id: FheIntId,
|
||||||
|
{
|
||||||
|
/// Encrypts the message while also generating the zero-knowledge proof
|
||||||
|
pub fn try_encrypt<Clear>(
|
||||||
|
values: &[Clear],
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
key: &CompactPublicKey,
|
||||||
|
load: ZkComputeLoad,
|
||||||
|
) -> crate::Result<Self>
|
||||||
|
where
|
||||||
|
Clear: DecomposableInto<u64> + SignedNumeric,
|
||||||
|
{
|
||||||
|
let inner = key.key.key.encrypt_and_prove_radix_compact(
|
||||||
|
values,
|
||||||
|
Id::num_blocks(key.key.key.key.parameters.message_modulus()),
|
||||||
|
public_params,
|
||||||
|
load,
|
||||||
|
)?;
|
||||||
|
Ok(Self {
|
||||||
|
inner,
|
||||||
|
_id: Id::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.inner.ciphertext_count()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies the ciphertext and the proof
|
||||||
|
///
|
||||||
|
/// If the proof and ciphertext are valid, it returns an `Ok` with
|
||||||
|
/// the underlying `FheInt`s.
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> crate::Result<Vec<FheInt<Id>>> {
|
||||||
|
let expanded_inners = self
|
||||||
|
.inner
|
||||||
|
.verify_and_expand::<SignedRadixCiphertext>(public_params, &public_key.key.key)?;
|
||||||
|
Ok(expanded_inners.into_iter().map(FheInt::new).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> ZkVerificationOutCome {
|
||||||
|
self.inner.verify(public_params, &public_key.key.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -69,7 +69,7 @@ where
|
|||||||
T: crate::integer::block_decomposition::DecomposableInto<u64>,
|
T: crate::integer::block_decomposition::DecomposableInto<u64>,
|
||||||
Id: FheUintId,
|
Id: FheUintId,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
||||||
let ciphertext = key
|
let ciphertext = key
|
||||||
@@ -175,7 +175,7 @@ where
|
|||||||
T: crate::integer::block_decomposition::DecomposableInto<u64>,
|
T: crate::integer::block_decomposition::DecomposableInto<u64>,
|
||||||
Id: FheUintId,
|
Id: FheUintId,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(values: &'a [T], key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(values: &'a [T], key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
||||||
let ciphertext = key
|
let ciphertext = key
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ where
|
|||||||
Id: FheUintId,
|
Id: FheUintId,
|
||||||
T: DecomposableInto<u64> + UnsignedNumeric,
|
T: DecomposableInto<u64> + UnsignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &ClientKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &ClientKey) -> Result<Self, Self::Error> {
|
||||||
let inner = key
|
let inner = key
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ where
|
|||||||
Id: FheUintId,
|
Id: FheUintId,
|
||||||
T: DecomposableInto<u64> + UnsignedNumeric,
|
T: DecomposableInto<u64> + UnsignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &ClientKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &ClientKey) -> Result<Self, Self::Error> {
|
||||||
let cpu_ciphertext = key
|
let cpu_ciphertext = key
|
||||||
@@ -65,7 +65,7 @@ where
|
|||||||
Id: FheUintId,
|
Id: FheUintId,
|
||||||
T: DecomposableInto<u64> + UnsignedNumeric,
|
T: DecomposableInto<u64> + UnsignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &PublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &PublicKey) -> Result<Self, Self::Error> {
|
||||||
let cpu_ciphertext = key
|
let cpu_ciphertext = key
|
||||||
@@ -84,7 +84,7 @@ where
|
|||||||
Id: FheUintId,
|
Id: FheUintId,
|
||||||
T: DecomposableInto<u64> + UnsignedNumeric,
|
T: DecomposableInto<u64> + UnsignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &CompressedPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &CompressedPublicKey) -> Result<Self, Self::Error> {
|
||||||
let cpu_ciphertext = key
|
let cpu_ciphertext = key
|
||||||
@@ -102,7 +102,7 @@ where
|
|||||||
Id: FheUintId,
|
Id: FheUintId,
|
||||||
T: DecomposableInto<u64> + UnsignedNumeric,
|
T: DecomposableInto<u64> + UnsignedNumeric,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt(value: T, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
fn try_encrypt(value: T, key: &CompactPublicKey) -> Result<Self, Self::Error> {
|
||||||
let cpu_ciphertext = key
|
let cpu_ciphertext = key
|
||||||
@@ -121,7 +121,7 @@ where
|
|||||||
T: DecomposableInto<u64> + UnsignedNumeric,
|
T: DecomposableInto<u64> + UnsignedNumeric,
|
||||||
Id: FheUintId,
|
Id: FheUintId,
|
||||||
{
|
{
|
||||||
type Error = crate::high_level_api::errors::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_encrypt_trivial(value: T) -> Result<Self, Self::Error> {
|
fn try_encrypt_trivial(value: T) -> Result<Self, Self::Error> {
|
||||||
global_state::with_internal_keys(|key| match key {
|
global_state::with_internal_keys(|key| match key {
|
||||||
|
|||||||
@@ -23,3 +23,5 @@ mod overflowing_ops;
|
|||||||
mod scalar_ops;
|
mod scalar_ops;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
mod zk;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
use super::zk::{ProvenCompactFheUint, ProvenCompactFheUintList};
|
||||||
use crate::high_level_api::integers::unsigned::base::{
|
use crate::high_level_api::integers::unsigned::base::{
|
||||||
FheUint, FheUintConformanceParams, FheUintId,
|
FheUint, FheUintConformanceParams, FheUintId,
|
||||||
};
|
};
|
||||||
@@ -56,6 +58,12 @@ macro_rules! static_int_type {
|
|||||||
|
|
||||||
#[cfg_attr(all(doc, not(doctest)), cfg(feature = "integer"))]
|
#[cfg_attr(all(doc, not(doctest)), cfg(feature = "integer"))]
|
||||||
pub type [<Compact FheUint $num_bits ListConformanceParams>] = CompactFheUintListConformanceParams<[<FheUint $num_bits Id>]>;
|
pub type [<Compact FheUint $num_bits ListConformanceParams>] = CompactFheUintListConformanceParams<[<FheUint $num_bits Id>]>;
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub type [<ProvenCompactFheUint $num_bits>] = ProvenCompactFheUint<[<FheUint $num_bits Id>]>;
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub type [<ProvenCompactFheUint $num_bits List>] = ProvenCompactFheUintList<[<FheUint $num_bits Id>]>;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
CompressedPublicKey, Config, FheInt16, FheInt32, FheInt8, FheUint128, FheUint16, FheUint256,
|
CompressedPublicKey, Config, FheInt16, FheInt32, FheInt8, FheUint128, FheUint16, FheUint256,
|
||||||
FheUint32, FheUint32ConformanceParams,
|
FheUint32, FheUint32ConformanceParams,
|
||||||
};
|
};
|
||||||
use rand::{random, Rng};
|
use rand::prelude::*;
|
||||||
|
|
||||||
fn setup_cpu(params: Option<impl Into<PBSParameters>>) -> ClientKey {
|
fn setup_cpu(params: Option<impl Into<PBSParameters>>) -> ClientKey {
|
||||||
let config = params
|
let config = params
|
||||||
@@ -543,3 +543,49 @@ fn test_safe_deserialize_conformant_compact_fhe_uint32_list() {
|
|||||||
assert_eq!(decrypted, expected);
|
assert_eq!(decrypted, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[test]
|
||||||
|
fn test_fhe_uint_zk() {
|
||||||
|
use crate::zk::{CompactPkeCrs, ZkComputeLoad};
|
||||||
|
|
||||||
|
let mut params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||||
|
params.glwe_noise_distribution = DynamicDistribution::new_t_uniform(9);
|
||||||
|
|
||||||
|
let config = ConfigBuilder::with_custom_parameters(params, None).build();
|
||||||
|
let crs = CompactPkeCrs::from_config(config, 32).unwrap();
|
||||||
|
let ck = ClientKey::generate(config);
|
||||||
|
let pk = CompactPublicKey::new(&ck);
|
||||||
|
|
||||||
|
let msg = random::<u32>();
|
||||||
|
|
||||||
|
let proven_compact_fhe_uint = crate::ProvenCompactFheUint32::try_encrypt(
|
||||||
|
msg,
|
||||||
|
crs.public_params(),
|
||||||
|
&pk,
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let fhe_uint = proven_compact_fhe_uint
|
||||||
|
.verify_and_expand(crs.public_params(), &pk)
|
||||||
|
.unwrap();
|
||||||
|
let decrypted: u32 = fhe_uint.decrypt(&ck);
|
||||||
|
assert_eq!(decrypted, msg);
|
||||||
|
|
||||||
|
let messages = (0..4).map(|_| random()).collect::<Vec<u32>>();
|
||||||
|
let proven_compact_fhe_uint_list = crate::ProvenCompactFheUint32List::try_encrypt(
|
||||||
|
&messages,
|
||||||
|
crs.public_params(),
|
||||||
|
&pk,
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let fhe_uints = proven_compact_fhe_uint_list
|
||||||
|
.verify_and_expand(crs.public_params(), &pk)
|
||||||
|
.unwrap();
|
||||||
|
let decrypted = fhe_uints
|
||||||
|
.iter()
|
||||||
|
.map(|fb| fb.decrypt(&ck))
|
||||||
|
.collect::<Vec<u32>>();
|
||||||
|
assert_eq!(decrypted.as_slice(), &messages);
|
||||||
|
}
|
||||||
|
|||||||
140
tfhe/src/high_level_api/integers/unsigned/zk.rs
Normal file
140
tfhe/src/high_level_api/integers/unsigned/zk.rs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
use super::FheUintId;
|
||||||
|
use crate::core_crypto::commons::math::random::{Deserialize, Serialize};
|
||||||
|
use crate::core_crypto::prelude::UnsignedNumeric;
|
||||||
|
use crate::integer::block_decomposition::DecomposableInto;
|
||||||
|
use crate::integer::{ProvenCompactCiphertextList, RadixCiphertext};
|
||||||
|
use crate::named::Named;
|
||||||
|
use crate::zk::{CompactPkePublicParams, ZkComputeLoad, ZkVerificationOutCome};
|
||||||
|
use crate::{CompactPublicKey, FheUint};
|
||||||
|
|
||||||
|
/// A `CompactFheUint` tied to a Zero-Knowledge proof
|
||||||
|
///
|
||||||
|
/// The zero-knowledge proof allows to verify that the ciphertext is correctly
|
||||||
|
/// encrypted.
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProvenCompactFheUint<Id: FheUintId> {
|
||||||
|
inner: ProvenCompactCiphertextList,
|
||||||
|
_id: Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Id: FheUintId> Named for ProvenCompactFheUint<Id> {
|
||||||
|
const NAME: &'static str = "high_level_api::ProvenCompactFheUint";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Id> ProvenCompactFheUint<Id>
|
||||||
|
where
|
||||||
|
Id: FheUintId,
|
||||||
|
{
|
||||||
|
/// Encrypts the message while also generating the zero-knowledge proof
|
||||||
|
pub fn try_encrypt<Clear>(
|
||||||
|
value: Clear,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
key: &CompactPublicKey,
|
||||||
|
load: ZkComputeLoad,
|
||||||
|
) -> crate::Result<Self>
|
||||||
|
where
|
||||||
|
Clear: DecomposableInto<u64> + UnsignedNumeric,
|
||||||
|
{
|
||||||
|
let inner = key.key.key.encrypt_and_prove_radix_compact(
|
||||||
|
&[value],
|
||||||
|
Id::num_blocks(key.key.key.key.parameters.message_modulus()),
|
||||||
|
public_params,
|
||||||
|
load,
|
||||||
|
)?;
|
||||||
|
Ok(Self {
|
||||||
|
inner,
|
||||||
|
_id: Id::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies the ciphertext and the proof
|
||||||
|
///
|
||||||
|
/// If the proof and ciphertext are valid, it returns an `Ok` with
|
||||||
|
/// the underlying `FheUint`
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> crate::Result<FheUint<Id>> {
|
||||||
|
let expanded_inner = self
|
||||||
|
.inner
|
||||||
|
.verify_and_expand_one::<RadixCiphertext>(public_params, &public_key.key.key)?;
|
||||||
|
Ok(FheUint::new(expanded_inner))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> ZkVerificationOutCome {
|
||||||
|
self.inner.verify(public_params, &public_key.key.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `CompactFheUintList` tied to a Zero-Knowledge proof
|
||||||
|
///
|
||||||
|
/// The zero-knowledge proof allows to verify that the ciphertext list is correctly
|
||||||
|
/// encrypted.
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProvenCompactFheUintList<Id: FheUintId> {
|
||||||
|
inner: ProvenCompactCiphertextList,
|
||||||
|
_id: Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Id: FheUintId> Named for ProvenCompactFheUintList<Id> {
|
||||||
|
const NAME: &'static str = "high_level_api::ProvenCompactFheUintList";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Id> ProvenCompactFheUintList<Id>
|
||||||
|
where
|
||||||
|
Id: FheUintId,
|
||||||
|
{
|
||||||
|
/// Encrypts the message while also generating the zero-knowledge proof
|
||||||
|
pub fn try_encrypt<Clear>(
|
||||||
|
values: &[Clear],
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
key: &CompactPublicKey,
|
||||||
|
load: ZkComputeLoad,
|
||||||
|
) -> crate::Result<Self>
|
||||||
|
where
|
||||||
|
Clear: DecomposableInto<u64> + UnsignedNumeric,
|
||||||
|
{
|
||||||
|
let inner = key.key.key.encrypt_and_prove_radix_compact(
|
||||||
|
values,
|
||||||
|
Id::num_blocks(key.key.key.key.parameters.message_modulus()),
|
||||||
|
public_params,
|
||||||
|
load,
|
||||||
|
)?;
|
||||||
|
Ok(Self {
|
||||||
|
inner,
|
||||||
|
_id: Id::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.inner.ciphertext_count()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies the ciphertext and the proof
|
||||||
|
///
|
||||||
|
/// If the proof and ciphertext are valid, it returns an `Ok` with
|
||||||
|
/// the underlying `FheUint`s.
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> crate::Result<Vec<FheUint<Id>>> {
|
||||||
|
let expanded_inners = self
|
||||||
|
.inner
|
||||||
|
.verify_and_expand::<RadixCiphertext>(public_params, &public_key.key.key)?;
|
||||||
|
Ok(expanded_inners.into_iter().map(FheUint::new).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> ZkVerificationOutCome {
|
||||||
|
self.inner.verify(public_params, &public_key.key.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,13 @@ macro_rules! expand_pub_use_fhe_type(
|
|||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub use $module_path::{
|
||||||
|
$(
|
||||||
|
[<ProvenCompact $fhe_type_name>],
|
||||||
|
[<ProvenCompact $fhe_type_name List>],
|
||||||
|
)*
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -30,7 +37,6 @@ macro_rules! expand_pub_use_fhe_type(
|
|||||||
pub use crate::core_crypto::commons::math::random::Seed;
|
pub use crate::core_crypto::commons::math::random::Seed;
|
||||||
pub use crate::integer::oprf::SignedRandomizationSpec;
|
pub use crate::integer::oprf::SignedRandomizationSpec;
|
||||||
pub use config::{Config, ConfigBuilder};
|
pub use config::{Config, ConfigBuilder};
|
||||||
pub use errors::{Error, OutOfRangeError};
|
|
||||||
pub use global_state::{set_server_key, unset_server_key, with_server_key_as_context};
|
pub use global_state::{set_server_key, unset_server_key, with_server_key_as_context};
|
||||||
|
|
||||||
pub use integers::{
|
pub use integers::{
|
||||||
@@ -51,6 +57,8 @@ pub use crate::high_level_api::booleans::{
|
|||||||
CompactFheBool, CompactFheBoolList, CompactFheBoolListConformanceParams, CompressedFheBool,
|
CompactFheBool, CompactFheBoolList, CompactFheBoolListConformanceParams, CompressedFheBool,
|
||||||
FheBool, FheBoolConformanceParams,
|
FheBool, FheBoolConformanceParams,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub use crate::high_level_api::booleans::{ProvenCompactFheBool, ProvenCompactFheBoolList};
|
||||||
expand_pub_use_fhe_type!(
|
expand_pub_use_fhe_type!(
|
||||||
pub use crate::high_level_api::integers{
|
pub use crate::high_level_api::integers{
|
||||||
FheUint2, FheUint4, FheUint6, FheUint8, FheUint10, FheUint12, FheUint14, FheUint16,
|
FheUint2, FheUint4, FheUint6, FheUint8, FheUint10, FheUint12, FheUint14, FheUint16,
|
||||||
@@ -60,6 +68,7 @@ expand_pub_use_fhe_type!(
|
|||||||
FheInt32, FheInt64, FheInt128, FheInt160, FheInt256
|
FheInt32, FheInt64, FheInt128, FheInt160, FheInt256
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
|
||||||
pub use safe_serialize::safe_serialize;
|
pub use safe_serialize::safe_serialize;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
@@ -68,12 +77,14 @@ mod keys;
|
|||||||
mod traits;
|
mod traits;
|
||||||
|
|
||||||
mod booleans;
|
mod booleans;
|
||||||
pub mod errors;
|
mod errors;
|
||||||
mod integers;
|
mod integers;
|
||||||
|
|
||||||
pub(in crate::high_level_api) mod details;
|
pub(in crate::high_level_api) mod details;
|
||||||
/// The tfhe prelude.
|
/// The tfhe prelude.
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
mod zk;
|
||||||
|
|
||||||
/// Devices supported by tfhe-rs
|
/// Devices supported by tfhe-rs
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
|||||||
@@ -99,9 +99,9 @@ fn test_with_seed() {
|
|||||||
let builder = ConfigBuilder::default();
|
let builder = ConfigBuilder::default();
|
||||||
let config = builder.build();
|
let config = builder.build();
|
||||||
|
|
||||||
let cks1 = ClientKey::generate_with_seed(config.clone(), Seed(125));
|
let cks1 = ClientKey::generate_with_seed(config, Seed(125));
|
||||||
let cks2 = ClientKey::generate(config.clone());
|
let cks2 = ClientKey::generate(config);
|
||||||
let cks3 = ClientKey::generate_with_seed(config.clone(), Seed(125));
|
let cks3 = ClientKey::generate_with_seed(config, Seed(125));
|
||||||
let cks4 = ClientKey::generate_with_seed(config, Seed(127));
|
let cks4 = ClientKey::generate_with_seed(config, Seed(127));
|
||||||
|
|
||||||
let cks1_serialized = bincode::serialize(&cks1).unwrap();
|
let cks1_serialized = bincode::serialize(&cks1).unwrap();
|
||||||
|
|||||||
11
tfhe/src/high_level_api/zk.rs
Normal file
11
tfhe/src/high_level_api/zk.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use crate::zk::CompactPkeCrs;
|
||||||
|
use crate::Config;
|
||||||
|
|
||||||
|
impl CompactPkeCrs {
|
||||||
|
pub fn from_config(config: Config, max_bit_size: usize) -> crate::Result<Self> {
|
||||||
|
let max_num_message =
|
||||||
|
max_bit_size / config.inner.block_parameters.message_modulus().0.ilog2() as usize;
|
||||||
|
let crs = Self::from_shortint_params(config.inner.block_parameters, max_num_message)?;
|
||||||
|
Ok(crs)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,11 @@ pub trait Recomposable:
|
|||||||
+ Shl<u32, Output = Self>
|
+ Shl<u32, Output = Self>
|
||||||
+ Sub<Self, Output = Self>
|
+ Sub<Self, Output = Self>
|
||||||
{
|
{
|
||||||
|
// TODO: need for wrapping arithmetic traits
|
||||||
|
// This is a wrapping add but to avoid conflicts with other parts of the code using external
|
||||||
|
// wrapping traits definition we change the name here
|
||||||
|
#[must_use]
|
||||||
|
fn recomposable_wrapping_add(self, other: Self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience traits have simpler bounds
|
// Convenience traits have simpler bounds
|
||||||
@@ -39,7 +44,12 @@ macro_rules! impl_recomposable_decomposable {
|
|||||||
) => {
|
) => {
|
||||||
$(
|
$(
|
||||||
impl Decomposable for $type { }
|
impl Decomposable for $type { }
|
||||||
impl Recomposable for $type { }
|
impl Recomposable for $type {
|
||||||
|
#[inline]
|
||||||
|
fn recomposable_wrapping_add(self, other: Self) -> Self {
|
||||||
|
self.wrapping_add(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl RecomposableFrom<u64> for $type { }
|
impl RecomposableFrom<u64> for $type { }
|
||||||
impl DecomposableInto<u64> for $type { }
|
impl DecomposableInto<u64> for $type { }
|
||||||
impl RecomposableFrom<u8> for $type { }
|
impl RecomposableFrom<u8> for $type { }
|
||||||
@@ -51,14 +61,26 @@ macro_rules! impl_recomposable_decomposable {
|
|||||||
impl_recomposable_decomposable!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128,);
|
impl_recomposable_decomposable!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128,);
|
||||||
|
|
||||||
impl<const N: usize> Decomposable for StaticSignedBigInt<N> {}
|
impl<const N: usize> Decomposable for StaticSignedBigInt<N> {}
|
||||||
impl<const N: usize> Recomposable for StaticSignedBigInt<N> {}
|
impl<const N: usize> Recomposable for StaticSignedBigInt<N> {
|
||||||
|
#[inline]
|
||||||
|
fn recomposable_wrapping_add(mut self, other: Self) -> Self {
|
||||||
|
self.add_assign(other);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<const N: usize> RecomposableFrom<u64> for StaticSignedBigInt<N> {}
|
impl<const N: usize> RecomposableFrom<u64> for StaticSignedBigInt<N> {}
|
||||||
impl<const N: usize> RecomposableFrom<u8> for StaticSignedBigInt<N> {}
|
impl<const N: usize> RecomposableFrom<u8> for StaticSignedBigInt<N> {}
|
||||||
impl<const N: usize> DecomposableInto<u64> for StaticSignedBigInt<N> {}
|
impl<const N: usize> DecomposableInto<u64> for StaticSignedBigInt<N> {}
|
||||||
impl<const N: usize> DecomposableInto<u8> for StaticSignedBigInt<N> {}
|
impl<const N: usize> DecomposableInto<u8> for StaticSignedBigInt<N> {}
|
||||||
|
|
||||||
impl<const N: usize> Decomposable for StaticUnsignedBigInt<N> {}
|
impl<const N: usize> Decomposable for StaticUnsignedBigInt<N> {}
|
||||||
impl<const N: usize> Recomposable for StaticUnsignedBigInt<N> {}
|
impl<const N: usize> Recomposable for StaticUnsignedBigInt<N> {
|
||||||
|
#[inline]
|
||||||
|
fn recomposable_wrapping_add(mut self, other: Self) -> Self {
|
||||||
|
self.add_assign(other);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<const N: usize> RecomposableFrom<u64> for StaticUnsignedBigInt<N> {}
|
impl<const N: usize> RecomposableFrom<u64> for StaticUnsignedBigInt<N> {}
|
||||||
impl<const N: usize> RecomposableFrom<u8> for StaticUnsignedBigInt<N> {}
|
impl<const N: usize> RecomposableFrom<u8> for StaticUnsignedBigInt<N> {}
|
||||||
impl<const N: usize> DecomposableInto<u64> for StaticUnsignedBigInt<N> {}
|
impl<const N: usize> DecomposableInto<u64> for StaticUnsignedBigInt<N> {}
|
||||||
@@ -258,7 +280,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
block <<= self.bit_pos;
|
block <<= self.bit_pos;
|
||||||
self.data += block;
|
self.data = self.data.recomposable_wrapping_add(block);
|
||||||
self.bit_pos += self.num_bits_in_block;
|
self.bit_pos += self.num_bits_in_block;
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ pub mod wopbs;
|
|||||||
|
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
pub mod gpu;
|
pub mod gpu;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
mod zk;
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub use zk::ProvenCompactCiphertextList;
|
||||||
|
|
||||||
pub use bigint::i256::I256;
|
pub use bigint::i256::I256;
|
||||||
pub use bigint::i512::I512;
|
pub use bigint::i512::I512;
|
||||||
@@ -76,7 +81,9 @@ pub use ciphertext::{
|
|||||||
SignedRadixCiphertext,
|
SignedRadixCiphertext,
|
||||||
};
|
};
|
||||||
pub use client_key::{ClientKey, CrtClientKey, RadixClientKey};
|
pub use client_key::{ClientKey, CrtClientKey, RadixClientKey};
|
||||||
pub use public_key::{CompressedCompactPublicKey, CompressedPublicKey, PublicKey};
|
pub use public_key::{
|
||||||
|
CompactPublicKey, CompressedCompactPublicKey, CompressedPublicKey, PublicKey,
|
||||||
|
};
|
||||||
pub use server_key::{CheckError, CompressedServerKey, ServerKey};
|
pub use server_key::{CheckError, CompressedServerKey, ServerKey};
|
||||||
|
|
||||||
/// Enum to indicate which kind of computations the [`ServerKey`] will be performing, this changes
|
/// Enum to indicate which kind of computations the [`ServerKey`] will be performing, this changes
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ impl ServerKey {
|
|||||||
let counter_num_blocks = ((num_bits_in_ciphertext - 1).ilog2() + 1 + 1)
|
let counter_num_blocks = ((num_bits_in_ciphertext - 1).ilog2() + 1 + 1)
|
||||||
.div_ceil(self.message_modulus().0.ilog2()) as usize;
|
.div_ceil(self.message_modulus().0.ilog2()) as usize;
|
||||||
|
|
||||||
|
// 11111000
|
||||||
// x.ilog2() = (x.num_bit() - 1) - x.leading_zeros()
|
// x.ilog2() = (x.num_bit() - 1) - x.leading_zeros()
|
||||||
// - (x.num_bit() - 1) is trivially known
|
// - (x.num_bit() - 1) is trivially known
|
||||||
// - we can get leading zeros via a sum
|
// - we can get leading zeros via a sum
|
||||||
|
|||||||
139
tfhe/src/integer/zk.rs
Normal file
139
tfhe/src/integer/zk.rs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
use crate::integer::block_decomposition::{BlockDecomposer, DecomposableInto};
|
||||||
|
use crate::integer::encryption::KnowsMessageModulus;
|
||||||
|
use crate::integer::public_key::CompactPublicKey;
|
||||||
|
use crate::integer::IntegerRadixCiphertext;
|
||||||
|
use crate::zk::{CompactPkePublicParams, ZkComputeLoad, ZkVerificationOutCome};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
impl CompactPublicKey {
|
||||||
|
pub fn encrypt_and_prove_radix_compact<T: DecomposableInto<u64>>(
|
||||||
|
&self,
|
||||||
|
messages: &[T],
|
||||||
|
num_blocks_per_integer: usize,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
load: ZkComputeLoad,
|
||||||
|
) -> crate::Result<ProvenCompactCiphertextList> {
|
||||||
|
let messages = messages
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.flat_map(|message| {
|
||||||
|
BlockDecomposer::new(message, self.key.message_modulus().0.ilog2())
|
||||||
|
.iter_as::<u64>()
|
||||||
|
.take(num_blocks_per_integer)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let proved_list = self
|
||||||
|
.key
|
||||||
|
.encrypt_and_prove_slice(&messages, public_params, load)?;
|
||||||
|
|
||||||
|
Ok(ProvenCompactCiphertextList {
|
||||||
|
proved_list,
|
||||||
|
num_blocks_per_integer,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProvenCompactCiphertextList {
|
||||||
|
pub(crate) proved_list: crate::shortint::ciphertext::ProvenCompactCiphertextList,
|
||||||
|
// Keep track of the num_blocks, as we allow
|
||||||
|
// storing many integer that have the same num_blocks
|
||||||
|
// into ct_list
|
||||||
|
pub(crate) num_blocks_per_integer: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProvenCompactCiphertextList {
|
||||||
|
pub fn verify_and_expand_one<T: IntegerRadixCiphertext>(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> crate::Result<T> {
|
||||||
|
let blocks = self
|
||||||
|
.proved_list
|
||||||
|
.verify_and_expand(public_params, &public_key.key)?;
|
||||||
|
assert_eq!(blocks.len(), self.num_blocks_per_integer);
|
||||||
|
|
||||||
|
Ok(T::from_blocks(blocks))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ciphertext_count(&self) -> usize {
|
||||||
|
self.proved_list.ciphertext_count() / self.num_blocks_per_integer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_and_expand<T: IntegerRadixCiphertext>(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> crate::Result<Vec<T>> {
|
||||||
|
let blocks = self
|
||||||
|
.proved_list
|
||||||
|
.verify_and_expand(public_params, &public_key.key)?;
|
||||||
|
|
||||||
|
let mut integers = Vec::with_capacity(self.ciphertext_count());
|
||||||
|
let mut blocks_iter = blocks.into_iter();
|
||||||
|
for _ in 0..self.ciphertext_count() {
|
||||||
|
let radix_blocks = blocks_iter
|
||||||
|
.by_ref()
|
||||||
|
.take(self.num_blocks_per_integer)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
integers.push(T::from_blocks(radix_blocks));
|
||||||
|
}
|
||||||
|
Ok(integers)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> ZkVerificationOutCome {
|
||||||
|
self.proved_list.verify(public_params, &public_key.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::integer::{ClientKey, CompactPublicKey};
|
||||||
|
use crate::shortint::parameters::DynamicDistribution;
|
||||||
|
use crate::shortint::prelude::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||||
|
use crate::zk::{CompactPkeCrs, ZkComputeLoad};
|
||||||
|
use rand::random;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zk_compact_ciphertext_list_encryption_ci_run_filter() {
|
||||||
|
let mut params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||||
|
params.glwe_noise_distribution = DynamicDistribution::new_t_uniform(9);
|
||||||
|
|
||||||
|
let num_blocks = 4usize;
|
||||||
|
let modulus = (params.message_modulus.0 as u64)
|
||||||
|
.checked_pow(num_blocks as u32)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let crs = CompactPkeCrs::from_shortint_params(params, 512).unwrap();
|
||||||
|
let cks = ClientKey::new(params);
|
||||||
|
let pk = CompactPublicKey::new(&cks);
|
||||||
|
|
||||||
|
let msgs = (0..512)
|
||||||
|
.map(|_| random::<u64>() % modulus)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let proven_ct = pk
|
||||||
|
.encrypt_and_prove_radix_compact(
|
||||||
|
&msgs,
|
||||||
|
num_blocks,
|
||||||
|
crs.public_params(),
|
||||||
|
ZkComputeLoad::Proof,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(proven_ct.verify(crs.public_params(), &pk).is_valid());
|
||||||
|
|
||||||
|
let expanded = proven_ct
|
||||||
|
.verify_and_expand(crs.public_params(), &pk)
|
||||||
|
.unwrap();
|
||||||
|
let decrypted = expanded
|
||||||
|
.iter()
|
||||||
|
.map(|ciphertext| cks.decrypt_radix::<u64>(ciphertext))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(msgs, decrypted);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,6 +91,9 @@ macro_rules! create_wrapper_type_non_native_type (
|
|||||||
compressed_type_name: $compressed_type_name:ident,
|
compressed_type_name: $compressed_type_name:ident,
|
||||||
compact_type_name: $compact_type_name:ident,
|
compact_type_name: $compact_type_name:ident,
|
||||||
compact_list_type_name: $compact_list_type_name:ident,
|
compact_list_type_name: $compact_list_type_name:ident,
|
||||||
|
proven_type: $proven_type:ident,
|
||||||
|
proven_compact_type_name: $proven_compact_type_name:ident,
|
||||||
|
proven_compact_list_type_name: $proven_compact_list_type_name:ident,
|
||||||
rust_type: $rust_type:ty $(,)?
|
rust_type: $rust_type:ty $(,)?
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
@@ -376,6 +379,146 @@ macro_rules! create_wrapper_type_non_native_type (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct $proven_compact_type_name(pub(crate) crate::high_level_api::$proven_compact_type_name);
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl $proven_compact_type_name {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn encrypt_with_compact_public_key(
|
||||||
|
value: JsValue,
|
||||||
|
public_params: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey,
|
||||||
|
compute_load: crate::js_on_wasm_api::js_high_level_api::zk::ZkComputeLoad,
|
||||||
|
) -> Result<$proven_compact_type_name, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
let value = <$rust_type>::try_from(value)
|
||||||
|
.map_err(|_| JsError::new(&format!("Failed to convert the value to a {}", stringify!($rust_type))))?;
|
||||||
|
crate::high_level_api::$proven_compact_type_name::try_encrypt(
|
||||||
|
value,
|
||||||
|
&public_params.0,
|
||||||
|
&public_key.0,
|
||||||
|
compute_load.into()
|
||||||
|
).map($proven_compact_type_name)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn verifies(
|
||||||
|
&self,
|
||||||
|
public_parameters: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey
|
||||||
|
) -> bool {
|
||||||
|
self.0.verify(&public_parameters.0, &public_key.0).is_valid()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
&self,
|
||||||
|
public_parameters: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey
|
||||||
|
) -> Result<$type_name, JsError> {
|
||||||
|
catch_panic(||{
|
||||||
|
self.0
|
||||||
|
.clone()
|
||||||
|
.verify_and_expand(&public_parameters.0, &public_key.0)
|
||||||
|
.map($type_name)
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn serialize(&self) -> Result<Vec<u8>, JsError> {
|
||||||
|
catch_panic_result(|| bincode::serialize(&self.0).map_err(into_js_error))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn deserialize(buffer: &[u8]) -> Result<$proven_compact_type_name, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
bincode::deserialize(buffer)
|
||||||
|
.map($proven_compact_type_name)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct $proven_compact_list_type_name(pub(crate) crate::high_level_api::$proven_compact_list_type_name);
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl $proven_compact_list_type_name {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn encrypt_with_compact_public_key(
|
||||||
|
values: Vec<JsValue>,
|
||||||
|
public_params: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey,
|
||||||
|
compute_load: crate::js_on_wasm_api::js_high_level_api::zk::ZkComputeLoad,
|
||||||
|
) -> Result<$proven_compact_list_type_name, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
let values = values
|
||||||
|
.into_iter()
|
||||||
|
.map(|value| {
|
||||||
|
<$rust_type>::try_from(value)
|
||||||
|
.map_err(|_| {
|
||||||
|
JsError::new(&format!("Failed to convert the value to a {}", stringify!($rust_type)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
crate::high_level_api::$proven_compact_list_type_name::try_encrypt(
|
||||||
|
&values,
|
||||||
|
&public_params.0,
|
||||||
|
&public_key.0,
|
||||||
|
compute_load.into()
|
||||||
|
).map($proven_compact_list_type_name)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn verifies(
|
||||||
|
&self,
|
||||||
|
public_parameters: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey
|
||||||
|
) -> bool {
|
||||||
|
self.0.verify(&public_parameters.0, &public_key.0).is_valid()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
&self,
|
||||||
|
public_parameters: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey
|
||||||
|
) -> Result<Vec<$type_name>, JsError> {
|
||||||
|
catch_panic(||{
|
||||||
|
self.0
|
||||||
|
.clone()
|
||||||
|
.verify_and_expand(&public_parameters.0, &public_key.0)
|
||||||
|
.map(|vec| vec.into_iter().map($type_name).collect::<Vec<_>>())
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn serialize(&self) -> Result<Vec<u8>, JsError> {
|
||||||
|
catch_panic_result(|| bincode::serialize(&self.0).map_err(into_js_error))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn deserialize(buffer: &[u8]) -> Result<$proven_compact_list_type_name, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
bincode::deserialize(buffer)
|
||||||
|
.map($proven_compact_list_type_name)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
@@ -385,6 +528,9 @@ macro_rules! create_wrapper_type_non_native_type (
|
|||||||
compressed_type_name: $compressed_type_name:ident,
|
compressed_type_name: $compressed_type_name:ident,
|
||||||
compact_type_name: $compact_type_name:ident,
|
compact_type_name: $compact_type_name:ident,
|
||||||
compact_list_type_name: $compact_list_type_name:ident,
|
compact_list_type_name: $compact_list_type_name:ident,
|
||||||
|
proven_type: $proven_type:ident,
|
||||||
|
proven_compact_type_name: $proven_compact_type_name:ident,
|
||||||
|
proven_compact_list_type_name: $proven_compact_list_type_name:ident,
|
||||||
rust_type: $rust_type:ty $(,)?
|
rust_type: $rust_type:ty $(,)?
|
||||||
}
|
}
|
||||||
),*
|
),*
|
||||||
@@ -397,6 +543,9 @@ macro_rules! create_wrapper_type_non_native_type (
|
|||||||
compressed_type_name: $compressed_type_name,
|
compressed_type_name: $compressed_type_name,
|
||||||
compact_type_name: $compact_type_name,
|
compact_type_name: $compact_type_name,
|
||||||
compact_list_type_name: $compact_list_type_name,
|
compact_list_type_name: $compact_list_type_name,
|
||||||
|
proven_type: $proven_type,
|
||||||
|
proven_compact_type_name: $proven_compact_type_name,
|
||||||
|
proven_compact_list_type_name: $proven_compact_list_type_name,
|
||||||
rust_type: $rust_type
|
rust_type: $rust_type
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -405,25 +554,34 @@ macro_rules! create_wrapper_type_non_native_type (
|
|||||||
);
|
);
|
||||||
|
|
||||||
create_wrapper_type_non_native_type!(
|
create_wrapper_type_non_native_type!(
|
||||||
{
|
|
||||||
type_name: FheUint160,
|
|
||||||
compressed_type_name: CompressedFheUint160,
|
|
||||||
compact_type_name: CompactFheUint160,
|
|
||||||
compact_list_type_name: CompactFheUint160List,
|
|
||||||
rust_type: U256,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type_name: FheUint128,
|
type_name: FheUint128,
|
||||||
compressed_type_name: CompressedFheUint128,
|
compressed_type_name: CompressedFheUint128,
|
||||||
compact_type_name: CompactFheUint128,
|
compact_type_name: CompactFheUint128,
|
||||||
compact_list_type_name: CompactFheUint128List,
|
compact_list_type_name: CompactFheUint128List,
|
||||||
|
proven_type: ProvenFheUint128,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint128,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint128List,
|
||||||
rust_type: u128,
|
rust_type: u128,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type_name: FheUint160,
|
||||||
|
compressed_type_name: CompressedFheUint160,
|
||||||
|
compact_type_name: CompactFheUint160,
|
||||||
|
compact_list_type_name: CompactFheUint160List,
|
||||||
|
proven_type: ProvenFheUint160,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint160,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint160List,
|
||||||
|
rust_type: U256,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type_name: FheUint256,
|
type_name: FheUint256,
|
||||||
compressed_type_name: CompressedFheUint256,
|
compressed_type_name: CompressedFheUint256,
|
||||||
compact_type_name: CompactFheUint256,
|
compact_type_name: CompactFheUint256,
|
||||||
compact_list_type_name: CompactFheUint256List,
|
compact_list_type_name: CompactFheUint256List,
|
||||||
|
proven_type: ProvenFheUint256,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint256,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint256List,
|
||||||
rust_type: U256,
|
rust_type: U256,
|
||||||
},
|
},
|
||||||
// Signed
|
// Signed
|
||||||
@@ -432,6 +590,9 @@ create_wrapper_type_non_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt128,
|
compressed_type_name: CompressedFheInt128,
|
||||||
compact_type_name: CompactFheInt128,
|
compact_type_name: CompactFheInt128,
|
||||||
compact_list_type_name: CompactFheInt128List,
|
compact_list_type_name: CompactFheInt128List,
|
||||||
|
proven_type: ProvenFheInt128,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt128,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt128List,
|
||||||
rust_type: i128,
|
rust_type: i128,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -439,6 +600,9 @@ create_wrapper_type_non_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt160,
|
compressed_type_name: CompressedFheInt160,
|
||||||
compact_type_name: CompactFheInt160,
|
compact_type_name: CompactFheInt160,
|
||||||
compact_list_type_name: CompactFheInt160List,
|
compact_list_type_name: CompactFheInt160List,
|
||||||
|
proven_type: ProvenFheInt160,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt160,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt160List,
|
||||||
rust_type: I256,
|
rust_type: I256,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -446,6 +610,9 @@ create_wrapper_type_non_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt256,
|
compressed_type_name: CompressedFheInt256,
|
||||||
compact_type_name: CompactFheInt256,
|
compact_type_name: CompactFheInt256,
|
||||||
compact_list_type_name: CompactFheInt256List,
|
compact_list_type_name: CompactFheInt256List,
|
||||||
|
proven_type: ProvenFheInt256,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt256,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt256List,
|
||||||
rust_type: I256,
|
rust_type: I256,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -460,6 +627,9 @@ macro_rules! create_wrapper_type_that_has_native_type (
|
|||||||
compressed_type_name: $compressed_type_name:ident,
|
compressed_type_name: $compressed_type_name:ident,
|
||||||
compact_type_name: $compact_type_name:ident,
|
compact_type_name: $compact_type_name:ident,
|
||||||
compact_list_type_name: $compact_list_type_name:ident,
|
compact_list_type_name: $compact_list_type_name:ident,
|
||||||
|
proven_type: $proven_type:ident,
|
||||||
|
proven_compact_type_name: $proven_compact_type_name:ident,
|
||||||
|
proven_compact_list_type_name: $proven_compact_list_type_name:ident,
|
||||||
native_type: $native_type:ty $(,)?
|
native_type: $native_type:ty $(,)?
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
@@ -708,6 +878,116 @@ macro_rules! create_wrapper_type_that_has_native_type (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct $proven_compact_type_name(pub(crate) crate::high_level_api::$proven_compact_type_name);
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl $proven_compact_type_name {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn encrypt_with_compact_public_key(
|
||||||
|
value: $native_type,
|
||||||
|
public_params: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey,
|
||||||
|
compute_load: crate::js_on_wasm_api::js_high_level_api::zk::ZkComputeLoad,
|
||||||
|
) -> Result<$proven_compact_type_name, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
crate::high_level_api::$proven_compact_type_name::try_encrypt(
|
||||||
|
value,
|
||||||
|
&public_params.0,
|
||||||
|
&public_key.0,
|
||||||
|
compute_load.into()
|
||||||
|
).map($proven_compact_type_name)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn verifies(
|
||||||
|
&self,
|
||||||
|
public_parameters: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey
|
||||||
|
) -> bool {
|
||||||
|
self.0.verify(&public_parameters.0, &public_key.0).is_valid()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
&self,
|
||||||
|
public_parameters: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey
|
||||||
|
) -> Result<$type_name, JsError> {
|
||||||
|
catch_panic(||{
|
||||||
|
self.0
|
||||||
|
.clone()
|
||||||
|
.verify_and_expand(&public_parameters.0, &public_key.0)
|
||||||
|
.map($type_name)
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn serialize(&self) -> Result<Vec<u8>, JsError> {
|
||||||
|
catch_panic_result(|| bincode::serialize(&self.0).map_err(into_js_error))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn deserialize(buffer: &[u8]) -> Result<$proven_compact_type_name, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
bincode::deserialize(buffer)
|
||||||
|
.map($proven_compact_type_name)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct $proven_compact_list_type_name(pub(crate) crate::high_level_api::$proven_compact_list_type_name);
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl $proven_compact_list_type_name {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn verifies(
|
||||||
|
&self,
|
||||||
|
public_parameters: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey
|
||||||
|
) -> bool {
|
||||||
|
self.0.verify(&public_parameters.0, &public_key.0).is_valid()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
&self,
|
||||||
|
public_parameters: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey
|
||||||
|
) -> Result<Vec<$type_name>, JsError> {
|
||||||
|
catch_panic(||{
|
||||||
|
self.0
|
||||||
|
.clone()
|
||||||
|
.verify_and_expand(&public_parameters.0, &public_key.0)
|
||||||
|
.map(|vec| vec.into_iter().map($type_name).collect::<Vec<_>>())
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn serialize(&self) -> Result<Vec<u8>, JsError> {
|
||||||
|
catch_panic_result(|| bincode::serialize(&self.0).map_err(into_js_error))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn deserialize(buffer: &[u8]) -> Result<$proven_compact_list_type_name, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
bincode::deserialize(buffer)
|
||||||
|
.map($proven_compact_list_type_name)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
$(
|
$(
|
||||||
@@ -716,6 +996,9 @@ macro_rules! create_wrapper_type_that_has_native_type (
|
|||||||
compressed_type_name: $compressed_type_name:ident,
|
compressed_type_name: $compressed_type_name:ident,
|
||||||
compact_type_name: $compact_type_name:ident,
|
compact_type_name: $compact_type_name:ident,
|
||||||
compact_list_type_name: $compact_list_type_name:ident,
|
compact_list_type_name: $compact_list_type_name:ident,
|
||||||
|
proven_type: $proven_type:ident,
|
||||||
|
proven_compact_type_name: $proven_compact_type_name:ident,
|
||||||
|
proven_compact_list_type_name: $proven_compact_list_type_name:ident,
|
||||||
native_type: $native_type:ty $(,)?
|
native_type: $native_type:ty $(,)?
|
||||||
}
|
}
|
||||||
),*
|
),*
|
||||||
@@ -728,6 +1011,9 @@ macro_rules! create_wrapper_type_that_has_native_type (
|
|||||||
compressed_type_name: $compressed_type_name,
|
compressed_type_name: $compressed_type_name,
|
||||||
compact_type_name: $compact_type_name,
|
compact_type_name: $compact_type_name,
|
||||||
compact_list_type_name: $compact_list_type_name,
|
compact_list_type_name: $compact_list_type_name,
|
||||||
|
proven_type: $proven_type,
|
||||||
|
proven_compact_type_name: $proven_compact_type_name,
|
||||||
|
proven_compact_list_type_name: $proven_compact_list_type_name,
|
||||||
native_type: $native_type
|
native_type: $native_type
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -741,6 +1027,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheBool,
|
compressed_type_name: CompressedFheBool,
|
||||||
compact_type_name: CompactFheBool,
|
compact_type_name: CompactFheBool,
|
||||||
compact_list_type_name: CompactFheBoolList,
|
compact_list_type_name: CompactFheBoolList,
|
||||||
|
proven_type: ProvenFheBool,
|
||||||
|
proven_compact_type_name: ProvenCompactFheBool,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheBoolList,
|
||||||
native_type: bool,
|
native_type: bool,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -748,6 +1037,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint2,
|
compressed_type_name: CompressedFheUint2,
|
||||||
compact_type_name: CompactFheUint2,
|
compact_type_name: CompactFheUint2,
|
||||||
compact_list_type_name: CompactFheUint2List,
|
compact_list_type_name: CompactFheUint2List,
|
||||||
|
proven_type: ProvenFheUint2,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint2,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint2List,
|
||||||
native_type: u8,
|
native_type: u8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -755,6 +1047,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint4,
|
compressed_type_name: CompressedFheUint4,
|
||||||
compact_type_name: CompactFheUint4,
|
compact_type_name: CompactFheUint4,
|
||||||
compact_list_type_name: CompactFheUint4List,
|
compact_list_type_name: CompactFheUint4List,
|
||||||
|
proven_type: ProvenFheUint4,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint4,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint4List,
|
||||||
native_type: u8,
|
native_type: u8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -762,6 +1057,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint6,
|
compressed_type_name: CompressedFheUint6,
|
||||||
compact_type_name: CompactFheUint6,
|
compact_type_name: CompactFheUint6,
|
||||||
compact_list_type_name: CompactFheUint6List,
|
compact_list_type_name: CompactFheUint6List,
|
||||||
|
proven_type: ProvenFheUint6,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint6,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint6List,
|
||||||
native_type: u8,
|
native_type: u8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -769,6 +1067,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint8,
|
compressed_type_name: CompressedFheUint8,
|
||||||
compact_type_name: CompactFheUint8,
|
compact_type_name: CompactFheUint8,
|
||||||
compact_list_type_name: CompactFheUint8List,
|
compact_list_type_name: CompactFheUint8List,
|
||||||
|
proven_type: ProvenFheUint8,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint8,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint8List,
|
||||||
native_type: u8,
|
native_type: u8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -776,6 +1077,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint10,
|
compressed_type_name: CompressedFheUint10,
|
||||||
compact_type_name: CompactFheUint10,
|
compact_type_name: CompactFheUint10,
|
||||||
compact_list_type_name: CompactFheUint10List,
|
compact_list_type_name: CompactFheUint10List,
|
||||||
|
proven_type: ProvenFheUint10,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint10,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint10List,
|
||||||
native_type: u16,
|
native_type: u16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -783,6 +1087,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint12,
|
compressed_type_name: CompressedFheUint12,
|
||||||
compact_type_name: CompactFheUint12,
|
compact_type_name: CompactFheUint12,
|
||||||
compact_list_type_name: CompactFheUint12List,
|
compact_list_type_name: CompactFheUint12List,
|
||||||
|
proven_type: ProvenFheUint12,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint12,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint12List,
|
||||||
native_type: u16,
|
native_type: u16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -790,6 +1097,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint14,
|
compressed_type_name: CompressedFheUint14,
|
||||||
compact_type_name: CompactFheUint14,
|
compact_type_name: CompactFheUint14,
|
||||||
compact_list_type_name: CompactFheUint14List,
|
compact_list_type_name: CompactFheUint14List,
|
||||||
|
proven_type: ProvenFheUint14,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint14,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint14List,
|
||||||
native_type: u16,
|
native_type: u16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -797,6 +1107,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint16,
|
compressed_type_name: CompressedFheUint16,
|
||||||
compact_type_name: CompactFheUint16,
|
compact_type_name: CompactFheUint16,
|
||||||
compact_list_type_name: CompactFheUint16List,
|
compact_list_type_name: CompactFheUint16List,
|
||||||
|
proven_type: ProvenFheUint16,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint16,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint16List,
|
||||||
native_type: u16,
|
native_type: u16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -804,6 +1117,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint32,
|
compressed_type_name: CompressedFheUint32,
|
||||||
compact_type_name: CompactFheUint32,
|
compact_type_name: CompactFheUint32,
|
||||||
compact_list_type_name: CompactFheUint32List,
|
compact_list_type_name: CompactFheUint32List,
|
||||||
|
proven_type: ProvenFheUint32,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint32,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint32List,
|
||||||
native_type: u32,
|
native_type: u32,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -811,6 +1127,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheUint64,
|
compressed_type_name: CompressedFheUint64,
|
||||||
compact_type_name: CompactFheUint64,
|
compact_type_name: CompactFheUint64,
|
||||||
compact_list_type_name: CompactFheUint64List,
|
compact_list_type_name: CompactFheUint64List,
|
||||||
|
proven_type: ProvenFheUint64,
|
||||||
|
proven_compact_type_name: ProvenCompactFheUint64,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheUint64List,
|
||||||
native_type: u64,
|
native_type: u64,
|
||||||
},
|
},
|
||||||
// Signed
|
// Signed
|
||||||
@@ -819,6 +1138,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt2,
|
compressed_type_name: CompressedFheInt2,
|
||||||
compact_type_name: CompactFheInt2,
|
compact_type_name: CompactFheInt2,
|
||||||
compact_list_type_name: CompactFheInt2List,
|
compact_list_type_name: CompactFheInt2List,
|
||||||
|
proven_type: ProvenFheInt2,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt2,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt2List,
|
||||||
native_type: i8,
|
native_type: i8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -826,6 +1148,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt4,
|
compressed_type_name: CompressedFheInt4,
|
||||||
compact_type_name: CompactFheInt4,
|
compact_type_name: CompactFheInt4,
|
||||||
compact_list_type_name: CompactFheInt4List,
|
compact_list_type_name: CompactFheInt4List,
|
||||||
|
proven_type: ProvenFheInt4,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt4,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt4List,
|
||||||
native_type: i8,
|
native_type: i8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -833,6 +1158,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt6,
|
compressed_type_name: CompressedFheInt6,
|
||||||
compact_type_name: CompactFheInt6,
|
compact_type_name: CompactFheInt6,
|
||||||
compact_list_type_name: CompactFheInt6List,
|
compact_list_type_name: CompactFheInt6List,
|
||||||
|
proven_type: ProvenFheInt6,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt6,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt6List,
|
||||||
native_type: i8,
|
native_type: i8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -840,6 +1168,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt8,
|
compressed_type_name: CompressedFheInt8,
|
||||||
compact_type_name: CompactFheInt8,
|
compact_type_name: CompactFheInt8,
|
||||||
compact_list_type_name: CompactFheInt8List,
|
compact_list_type_name: CompactFheInt8List,
|
||||||
|
proven_type: ProvenFheInt8,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt8,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt8List,
|
||||||
native_type: i8,
|
native_type: i8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -847,6 +1178,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt10,
|
compressed_type_name: CompressedFheInt10,
|
||||||
compact_type_name: CompactFheInt10,
|
compact_type_name: CompactFheInt10,
|
||||||
compact_list_type_name: CompactFheInt10List,
|
compact_list_type_name: CompactFheInt10List,
|
||||||
|
proven_type: ProvenFheInt10,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt10,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt10List,
|
||||||
native_type: i16,
|
native_type: i16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -854,6 +1188,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt12,
|
compressed_type_name: CompressedFheInt12,
|
||||||
compact_type_name: CompactFheInt12,
|
compact_type_name: CompactFheInt12,
|
||||||
compact_list_type_name: CompactFheInt12List,
|
compact_list_type_name: CompactFheInt12List,
|
||||||
|
proven_type: ProvenFheInt12,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt12,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt12List,
|
||||||
native_type: i16,
|
native_type: i16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -861,6 +1198,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt14,
|
compressed_type_name: CompressedFheInt14,
|
||||||
compact_type_name: CompactFheInt14,
|
compact_type_name: CompactFheInt14,
|
||||||
compact_list_type_name: CompactFheInt14List,
|
compact_list_type_name: CompactFheInt14List,
|
||||||
|
proven_type: ProvenFheInt14,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt14,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt14List,
|
||||||
native_type: i16,
|
native_type: i16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -868,6 +1208,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt16,
|
compressed_type_name: CompressedFheInt16,
|
||||||
compact_type_name: CompactFheInt16,
|
compact_type_name: CompactFheInt16,
|
||||||
compact_list_type_name: CompactFheInt16List,
|
compact_list_type_name: CompactFheInt16List,
|
||||||
|
proven_type: ProvenFheInt16,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt16,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt16List,
|
||||||
native_type: i16,
|
native_type: i16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -875,6 +1218,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt32,
|
compressed_type_name: CompressedFheInt32,
|
||||||
compact_type_name: CompactFheInt32,
|
compact_type_name: CompactFheInt32,
|
||||||
compact_list_type_name: CompactFheInt32List,
|
compact_list_type_name: CompactFheInt32List,
|
||||||
|
proven_type: ProvenFheInt32,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt32,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt32List,
|
||||||
native_type: i32,
|
native_type: i32,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -882,6 +1228,9 @@ create_wrapper_type_that_has_native_type!(
|
|||||||
compressed_type_name: CompressedFheInt64,
|
compressed_type_name: CompressedFheInt64,
|
||||||
compact_type_name: CompactFheInt64,
|
compact_type_name: CompactFheInt64,
|
||||||
compact_list_type_name: CompactFheInt64List,
|
compact_list_type_name: CompactFheInt64List,
|
||||||
|
proven_type: ProvenFheInt64,
|
||||||
|
proven_compact_type_name: ProvenCompactFheInt64,
|
||||||
|
proven_compact_list_type_name: ProvenCompactFheInt64List,
|
||||||
native_type: i64,
|
native_type: i64,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -967,3 +1316,93 @@ impl CompactFheBoolList {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
macro_rules! define_prove_and_encrypt_list_with_compact_public_key {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
{$proven_compact_list_type_name:ident, $native_type:ty}
|
||||||
|
),*
|
||||||
|
$(,)?
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl $proven_compact_list_type_name {
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn encrypt_with_compact_public_key(
|
||||||
|
values: Vec<$native_type>,
|
||||||
|
public_params: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey,
|
||||||
|
compute_load: crate::js_on_wasm_api::js_high_level_api::zk::ZkComputeLoad,
|
||||||
|
) -> Result<$proven_compact_list_type_name, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
$crate::high_level_api::$proven_compact_list_type_name::try_encrypt(
|
||||||
|
&values,
|
||||||
|
&public_params.0,
|
||||||
|
&public_key.0,
|
||||||
|
compute_load.into(),
|
||||||
|
).map($proven_compact_list_type_name)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
define_prove_and_encrypt_list_with_compact_public_key!(
|
||||||
|
{ProvenCompactFheUint2List, u8},
|
||||||
|
{ProvenCompactFheUint4List, u8},
|
||||||
|
{ProvenCompactFheUint6List, u8},
|
||||||
|
{ProvenCompactFheUint8List, u8},
|
||||||
|
{ProvenCompactFheUint12List, u16},
|
||||||
|
{ProvenCompactFheUint14List, u16},
|
||||||
|
{ProvenCompactFheUint16List, u16},
|
||||||
|
{ProvenCompactFheUint32List, u32},
|
||||||
|
{ProvenCompactFheUint64List, u64},
|
||||||
|
// Signed
|
||||||
|
{ProvenCompactFheInt2List, i8},
|
||||||
|
{ProvenCompactFheInt4List, i8},
|
||||||
|
{ProvenCompactFheInt6List, i8},
|
||||||
|
{ProvenCompactFheInt8List, i8},
|
||||||
|
{ProvenCompactFheInt12List, i16},
|
||||||
|
{ProvenCompactFheInt14List, i16},
|
||||||
|
{ProvenCompactFheInt16List, i16},
|
||||||
|
{ProvenCompactFheInt32List, i32},
|
||||||
|
{ProvenCompactFheInt64List, i64},
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
#[allow(clippy::use_self)]
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl ProvenCompactFheBoolList {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn encrypt_with_compact_public_key(
|
||||||
|
values: Vec<JsValue>,
|
||||||
|
public_params: &crate::js_on_wasm_api::js_high_level_api::zk::CompactPkePublicParams,
|
||||||
|
public_key: &crate::js_on_wasm_api::js_high_level_api::keys::TfheCompactPublicKey,
|
||||||
|
compute_load: crate::js_on_wasm_api::js_high_level_api::zk::ZkComputeLoad,
|
||||||
|
) -> Result<ProvenCompactFheBoolList, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
let booleans = values
|
||||||
|
.iter()
|
||||||
|
.map(|jsvalue| {
|
||||||
|
jsvalue
|
||||||
|
.as_bool()
|
||||||
|
.ok_or_else(|| JsError::new("Value is not a boolean"))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, JsError>>()?;
|
||||||
|
crate::high_level_api::ProvenCompactFheBoolList::try_encrypt(
|
||||||
|
&booleans,
|
||||||
|
&public_params.0,
|
||||||
|
&public_key.0,
|
||||||
|
compute_load.into(),
|
||||||
|
)
|
||||||
|
.map(ProvenCompactFheBoolList)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub struct TfheClientKey(pub(crate) hlapi::ClientKey);
|
|||||||
impl TfheClientKey {
|
impl TfheClientKey {
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn generate(config: &TfheConfig) -> Result<TfheClientKey, JsError> {
|
pub fn generate(config: &TfheConfig) -> Result<TfheClientKey, JsError> {
|
||||||
catch_panic(|| Self(hlapi::ClientKey::generate(config.0.clone())))
|
catch_panic(|| Self(hlapi::ClientKey::generate(config.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
@@ -26,7 +26,7 @@ impl TfheClientKey {
|
|||||||
catch_panic_result(|| {
|
catch_panic_result(|| {
|
||||||
let seed =
|
let seed =
|
||||||
u128::try_from(seed).map_err(|_| JsError::new("Value does not fit in a u128"))?;
|
u128::try_from(seed).map_err(|_| JsError::new("Value does not fit in a u128"))?;
|
||||||
let key = hlapi::ClientKey::generate_with_seed(config.0.clone(), crate::Seed(seed));
|
let key = hlapi::ClientKey::generate_with_seed(config.0, crate::Seed(seed));
|
||||||
Ok(Self(key))
|
Ok(Self(key))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ pub(crate) mod integers;
|
|||||||
// using Self does not work well with #[wasm_bindgen] macro
|
// using Self does not work well with #[wasm_bindgen] macro
|
||||||
#[allow(clippy::use_self)]
|
#[allow(clippy::use_self)]
|
||||||
pub(crate) mod keys;
|
pub(crate) mod keys;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
mod zk;
|
||||||
|
|
||||||
pub(crate) fn into_js_error<E: std::fmt::Debug>(e: E) -> wasm_bindgen::JsError {
|
pub(crate) fn into_js_error<E: std::fmt::Debug>(e: E) -> wasm_bindgen::JsError {
|
||||||
wasm_bindgen::JsError::new(format!("{e:?}").as_str())
|
wasm_bindgen::JsError::new(format!("{e:?}").as_str())
|
||||||
|
|||||||
76
tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs
Normal file
76
tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
use crate::js_on_wasm_api::js_high_level_api::config::TfheConfig;
|
||||||
|
use crate::js_on_wasm_api::js_high_level_api::{catch_panic_result, into_js_error};
|
||||||
|
use crate::js_on_wasm_api::shortint::ShortintParameters;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub enum ZkComputeLoad {
|
||||||
|
Proof,
|
||||||
|
Verify,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<crate::zk::ZkComputeLoad> for ZkComputeLoad {
|
||||||
|
fn into(self) -> crate::zk::ZkComputeLoad {
|
||||||
|
match self {
|
||||||
|
Self::Proof => crate::zk::ZkComputeLoad::Proof,
|
||||||
|
Self::Verify => crate::zk::ZkComputeLoad::Verify,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct CompactPkeCrs(pub(crate) crate::core_crypto::entities::CompactPkeCrs);
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct CompactPkePublicParams(pub(crate) crate::zk::CompactPkePublicParams);
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl CompactPkePublicParams {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn serialize(&self) -> Result<Vec<u8>, JsError> {
|
||||||
|
catch_panic_result(|| bincode::serialize(&self.0).map_err(into_js_error))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn deserialize(buffer: &[u8]) -> Result<CompactPkePublicParams, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
bincode::deserialize(buffer)
|
||||||
|
.map(CompactPkePublicParams)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl CompactPkeCrs {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn from_parameters(
|
||||||
|
parameters: ShortintParameters,
|
||||||
|
max_num_message: usize,
|
||||||
|
) -> Result<CompactPkeCrs, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
crate::core_crypto::entities::CompactPkeCrs::from_shortint_params(
|
||||||
|
parameters.0,
|
||||||
|
max_num_message,
|
||||||
|
)
|
||||||
|
.map(CompactPkeCrs)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn from_config(config: &TfheConfig, max_num_bits: usize) -> Result<CompactPkeCrs, JsError> {
|
||||||
|
catch_panic_result(|| {
|
||||||
|
crate::core_crypto::entities::CompactPkeCrs::from_config(config.0, max_num_bits)
|
||||||
|
.map(CompactPkeCrs)
|
||||||
|
.map_err(into_js_error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn public_params(&self) -> CompactPkePublicParams {
|
||||||
|
CompactPkePublicParams(self.0.public_params().clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,13 +30,136 @@ pub struct Shortint {}
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct ShortintParameters(pub(crate) crate::shortint::ClassicPBSParameters);
|
pub struct ShortintParameters(pub(crate) crate::shortint::ClassicPBSParameters);
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl ShortintParameters {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn lwe_dimension(&self) -> usize {
|
||||||
|
self.0.lwe_dimension.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_lwe_dimension(&mut self, new_value: usize) {
|
||||||
|
self.0.lwe_dimension.0 = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn glwe_dimension(&self) -> usize {
|
||||||
|
self.0.glwe_dimension.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_glwe_dimension(&mut self, new_value: usize) {
|
||||||
|
self.0.glwe_dimension.0 = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn polynomial_size(&self) -> usize {
|
||||||
|
self.0.polynomial_size.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_polynomial_size(&mut self, new_value: usize) {
|
||||||
|
self.0.polynomial_size.0 = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn lwe_noise_distribution(&self) -> ShortintNoiseDistribution {
|
||||||
|
ShortintNoiseDistribution(self.0.lwe_noise_distribution)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_lwe_noise_distribution(&mut self, new_value: &ShortintNoiseDistribution) {
|
||||||
|
self.0.lwe_noise_distribution = new_value.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn glwe_noise_distribution(&self) -> ShortintNoiseDistribution {
|
||||||
|
ShortintNoiseDistribution(self.0.lwe_noise_distribution)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_glwe_noise_distribution(&mut self, new_value: &ShortintNoiseDistribution) {
|
||||||
|
self.0.glwe_noise_distribution = new_value.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn pbs_base_log(&self) -> usize {
|
||||||
|
self.0.pbs_base_log.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_pbs_base_log(&mut self, new_value: usize) {
|
||||||
|
self.0.pbs_base_log.0 = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn pbs_level(&self) -> usize {
|
||||||
|
self.0.pbs_level.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_pbs_level(&mut self, new_value: usize) {
|
||||||
|
self.0.pbs_level.0 = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn ks_base_log(&self) -> usize {
|
||||||
|
self.0.ks_base_log.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_ks_base_log(&mut self, new_value: usize) {
|
||||||
|
self.0.ks_base_log.0 = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn ks_level(&self) -> usize {
|
||||||
|
self.0.ks_level.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_ks_level(&mut self, new_value: usize) {
|
||||||
|
self.0.ks_level.0 = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn message_modulus(&self) -> usize {
|
||||||
|
self.0.message_modulus.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_message_modulus(&mut self, new_value: usize) {
|
||||||
|
self.0.message_modulus.0 = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn carry_modulus(&self) -> usize {
|
||||||
|
self.0.carry_modulus.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_carry_modulus(&mut self, new_value: usize) {
|
||||||
|
self.0.carry_modulus.0 = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn encryption_key_choice(&self) -> ShortintEncryptionKeyChoice {
|
||||||
|
self.0.encryption_key_choice.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_encryption_key_choice(&mut self, new_value: ShortintEncryptionKeyChoice) {
|
||||||
|
self.0.encryption_key_choice = new_value.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub enum ShortintEncryptionKeyChoice {
|
pub enum ShortintEncryptionKeyChoice {
|
||||||
Big,
|
Big,
|
||||||
Small,
|
Small,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ShortintEncryptionKeyChoice> for crate::shortint::parameters::EncryptionKeyChoice {
|
impl From<ShortintEncryptionKeyChoice> for EncryptionKeyChoice {
|
||||||
fn from(value: ShortintEncryptionKeyChoice) -> Self {
|
fn from(value: ShortintEncryptionKeyChoice) -> Self {
|
||||||
match value {
|
match value {
|
||||||
ShortintEncryptionKeyChoice::Big => Self::Big,
|
ShortintEncryptionKeyChoice::Big => Self::Big,
|
||||||
@@ -45,6 +168,15 @@ impl From<ShortintEncryptionKeyChoice> for crate::shortint::parameters::Encrypti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<EncryptionKeyChoice> for ShortintEncryptionKeyChoice {
|
||||||
|
fn from(value: EncryptionKeyChoice) -> Self {
|
||||||
|
match value {
|
||||||
|
EncryptionKeyChoice::Big => Self::Big,
|
||||||
|
EncryptionKeyChoice::Small => Self::Small,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct ShortintNoiseDistribution(
|
pub struct ShortintNoiseDistribution(
|
||||||
pub(crate) crate::core_crypto::commons::math::random::DynamicDistribution<u64>,
|
pub(crate) crate::core_crypto::commons::math::random::DynamicDistribution<u64>,
|
||||||
|
|||||||
@@ -109,7 +109,8 @@ mod js_on_wasm_api;
|
|||||||
doctest,
|
doctest,
|
||||||
feature = "shortint",
|
feature = "shortint",
|
||||||
feature = "boolean",
|
feature = "boolean",
|
||||||
feature = "integer"
|
feature = "integer",
|
||||||
|
feature = "zk-pok-experimental"
|
||||||
))]
|
))]
|
||||||
mod test_user_docs;
|
mod test_user_docs;
|
||||||
|
|
||||||
@@ -129,3 +130,10 @@ pub mod safe_deserialization;
|
|||||||
pub mod conformance;
|
pub mod conformance;
|
||||||
|
|
||||||
pub mod named;
|
pub mod named;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub mod zk;
|
||||||
|
|
||||||
|
pub use error::{Error, ErrorKind};
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -9,3 +9,8 @@ pub use compact_list::*;
|
|||||||
pub use compressed::*;
|
pub use compressed::*;
|
||||||
pub use compressed_modulus_switched_ciphertext::*;
|
pub use compressed_modulus_switched_ciphertext::*;
|
||||||
pub use standard::*;
|
pub use standard::*;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub use zk::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
mod zk;
|
||||||
|
|||||||
194
tfhe/src/shortint/ciphertext/zk.rs
Normal file
194
tfhe/src/shortint/ciphertext/zk.rs
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
use crate::core_crypto::algorithms::verify_lwe_compact_ciphertext_list;
|
||||||
|
use crate::core_crypto::prelude::verify_lwe_ciphertext;
|
||||||
|
use crate::shortint::ciphertext::CompactCiphertextList;
|
||||||
|
use crate::shortint::{Ciphertext, CompactPublicKey, EncryptionKeyChoice};
|
||||||
|
use crate::zk::{CompactPkeCrs, CompactPkeProof, CompactPkePublicParams, ZkVerificationOutCome};
|
||||||
|
use rayon::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
impl CompactPkeCrs {
|
||||||
|
/// Construct the CRS that corresponds to the given parameters
|
||||||
|
///
|
||||||
|
/// max_num_message is how many message a single proof can prove
|
||||||
|
pub fn from_shortint_params(
|
||||||
|
params: impl Into<crate::shortint::PBSParameters>,
|
||||||
|
max_num_message: usize,
|
||||||
|
) -> crate::Result<Self> {
|
||||||
|
let params = params.into();
|
||||||
|
let (size, noise_distribution) = match params.encryption_key_choice() {
|
||||||
|
EncryptionKeyChoice::Big => {
|
||||||
|
let size = params
|
||||||
|
.glwe_dimension()
|
||||||
|
.to_equivalent_lwe_dimension(params.polynomial_size());
|
||||||
|
(size, params.glwe_noise_distribution())
|
||||||
|
}
|
||||||
|
EncryptionKeyChoice::Small => (params.lwe_dimension(), params.lwe_noise_distribution()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut plaintext_modulus = (params.message_modulus().0 * params.carry_modulus().0) as u64;
|
||||||
|
// Our plaintext modulus does not take into account the bit of padding
|
||||||
|
plaintext_modulus *= 2;
|
||||||
|
|
||||||
|
crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
|
||||||
|
Self::new(
|
||||||
|
size,
|
||||||
|
max_num_message,
|
||||||
|
noise_distribution,
|
||||||
|
params.ciphertext_modulus(),
|
||||||
|
plaintext_modulus,
|
||||||
|
&mut engine.random_generator,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Ciphertext tied to a zero-knowledge proof
|
||||||
|
///
|
||||||
|
/// The proof can only be generated during the encryption with a [CompactPublicKey]
|
||||||
|
pub struct ProvenCiphertext {
|
||||||
|
pub(crate) ciphertext: Ciphertext,
|
||||||
|
pub(crate) proof: CompactPkeProof,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProvenCiphertext {
|
||||||
|
pub fn ciphertext(&self) -> &Ciphertext {
|
||||||
|
&self.ciphertext
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> ZkVerificationOutCome {
|
||||||
|
verify_lwe_ciphertext(
|
||||||
|
&self.ciphertext.ct,
|
||||||
|
&public_key.key,
|
||||||
|
&self.proof,
|
||||||
|
public_params,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A List of CompactCiphertext with their zero-knowledge proofs
|
||||||
|
///
|
||||||
|
/// The proofs can only be generated during the encryption with a [CompactPublicKey]
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ProvenCompactCiphertextList {
|
||||||
|
pub(crate) proved_lists: Vec<(CompactCiphertextList, CompactPkeProof)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProvenCompactCiphertextList {
|
||||||
|
pub fn ciphertext_count(&self) -> usize {
|
||||||
|
self.proved_lists
|
||||||
|
.iter()
|
||||||
|
.map(|(list, _)| list.ct_list.lwe_ciphertext_count().0)
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_and_expand(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> crate::Result<Vec<Ciphertext>> {
|
||||||
|
let not_all_valid = self.proved_lists.par_iter().any(|(ct_list, proof)| {
|
||||||
|
verify_lwe_compact_ciphertext_list(
|
||||||
|
&ct_list.ct_list,
|
||||||
|
&public_key.key,
|
||||||
|
proof,
|
||||||
|
public_params,
|
||||||
|
)
|
||||||
|
.is_invalid()
|
||||||
|
});
|
||||||
|
|
||||||
|
if not_all_valid {
|
||||||
|
return Err(crate::ErrorKind::InvalidZkProof.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let expanded = self
|
||||||
|
.proved_lists
|
||||||
|
.iter()
|
||||||
|
.flat_map(|(ct_list, _proof)| ct_list.expand())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(expanded)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
public_key: &CompactPublicKey,
|
||||||
|
) -> ZkVerificationOutCome {
|
||||||
|
let all_valid = self.proved_lists.par_iter().all(|(ct_list, proof)| {
|
||||||
|
verify_lwe_compact_ciphertext_list(
|
||||||
|
&ct_list.ct_list,
|
||||||
|
&public_key.key,
|
||||||
|
proof,
|
||||||
|
public_params,
|
||||||
|
)
|
||||||
|
.is_valid()
|
||||||
|
});
|
||||||
|
|
||||||
|
if all_valid {
|
||||||
|
ZkVerificationOutCome::Valid
|
||||||
|
} else {
|
||||||
|
ZkVerificationOutCome::Invalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::shortint::parameters::DynamicDistribution;
|
||||||
|
use crate::shortint::prelude::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||||
|
use crate::shortint::{ClientKey, CompactPublicKey};
|
||||||
|
use crate::zk::{CompactPkeCrs, ZkComputeLoad};
|
||||||
|
use rand::random;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zk_ciphertext_encryption_ci_run_filter() {
|
||||||
|
let mut params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||||
|
params.glwe_noise_distribution = DynamicDistribution::new_t_uniform(9);
|
||||||
|
|
||||||
|
let crs = CompactPkeCrs::from_shortint_params(params, 4).unwrap();
|
||||||
|
let cks = ClientKey::new(params);
|
||||||
|
let pk = CompactPublicKey::new(&cks);
|
||||||
|
|
||||||
|
let msg = random::<u64>() % params.message_modulus.0 as u64;
|
||||||
|
|
||||||
|
let proven_ct = pk
|
||||||
|
.encrypt_and_prove(msg, crs.public_params(), ZkComputeLoad::Proof)
|
||||||
|
.unwrap();
|
||||||
|
assert!(proven_ct.verify(crs.public_params(), &pk).is_valid());
|
||||||
|
|
||||||
|
let decrypted = cks.decrypt(proven_ct.ciphertext());
|
||||||
|
assert_eq!(msg, decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zk_compact_ciphertext_list_encryption_ci_run_filter() {
|
||||||
|
let mut params = PARAM_MESSAGE_2_CARRY_2_KS_PBS;
|
||||||
|
params.glwe_noise_distribution = DynamicDistribution::new_t_uniform(9);
|
||||||
|
|
||||||
|
let crs = CompactPkeCrs::from_shortint_params(params, 512).unwrap();
|
||||||
|
let cks = ClientKey::new(params);
|
||||||
|
let pk = CompactPublicKey::new(&cks);
|
||||||
|
|
||||||
|
let msgs = (0..512)
|
||||||
|
.map(|_| random::<u64>() % params.message_modulus.0 as u64)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let proven_ct = pk
|
||||||
|
.encrypt_and_prove_slice(&msgs, crs.public_params(), ZkComputeLoad::Proof)
|
||||||
|
.unwrap();
|
||||||
|
assert!(proven_ct.verify(crs.public_params(), &pk).is_valid());
|
||||||
|
|
||||||
|
let expanded = proven_ct
|
||||||
|
.verify_and_expand(crs.public_params(), &pk)
|
||||||
|
.unwrap();
|
||||||
|
let decrypted = expanded
|
||||||
|
.iter()
|
||||||
|
.map(|ciphertext| cks.decrypt(ciphertext))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(msgs, decrypted);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ use crate::core_crypto::commons::computation_buffers::ComputationBuffers;
|
|||||||
use crate::core_crypto::commons::generators::{
|
use crate::core_crypto::commons::generators::{
|
||||||
DeterministicSeeder, EncryptionRandomGenerator, SecretRandomGenerator,
|
DeterministicSeeder, EncryptionRandomGenerator, SecretRandomGenerator,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
use crate::core_crypto::commons::math::random::RandomGenerator;
|
||||||
use crate::core_crypto::commons::math::random::{ActivatedRandomGenerator, Seeder};
|
use crate::core_crypto::commons::math::random::{ActivatedRandomGenerator, Seeder};
|
||||||
use crate::core_crypto::entities::*;
|
use crate::core_crypto::entities::*;
|
||||||
use crate::core_crypto::prelude::ContainerMut;
|
use crate::core_crypto::prelude::ContainerMut;
|
||||||
@@ -284,6 +286,8 @@ pub struct ShortintEngine {
|
|||||||
/// A seeder that can be called to generate 128 bits seeds, useful to create new
|
/// A seeder that can be called to generate 128 bits seeds, useful to create new
|
||||||
/// [`EncryptionRandomGenerator`] to encrypt seeded types.
|
/// [`EncryptionRandomGenerator`] to encrypt seeded types.
|
||||||
pub(crate) seeder: DeterministicSeeder<ActivatedRandomGenerator>,
|
pub(crate) seeder: DeterministicSeeder<ActivatedRandomGenerator>,
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub(crate) random_generator: RandomGenerator<ActivatedRandomGenerator>,
|
||||||
pub(crate) computation_buffers: ComputationBuffers,
|
pub(crate) computation_buffers: ComputationBuffers,
|
||||||
ciphertext_buffers: Memory,
|
ciphertext_buffers: Memory,
|
||||||
}
|
}
|
||||||
@@ -327,6 +331,8 @@ impl ShortintEngine {
|
|||||||
deterministic_seeder.seed(),
|
deterministic_seeder.seed(),
|
||||||
&mut deterministic_seeder,
|
&mut deterministic_seeder,
|
||||||
),
|
),
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
random_generator: RandomGenerator::new(deterministic_seeder.seed()),
|
||||||
seeder: deterministic_seeder,
|
seeder: deterministic_seeder,
|
||||||
computation_buffers: ComputationBuffers::default(),
|
computation_buffers: ComputationBuffers::default(),
|
||||||
ciphertext_buffers: Memory::default(),
|
ciphertext_buffers: Memory::default(),
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
use crate::core_crypto::algorithms::encrypt_and_prove_lwe_ciphertext_with_compact_public_key;
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
use crate::core_crypto::entities::Cleartext;
|
||||||
use crate::core_crypto::prelude::{
|
use crate::core_crypto::prelude::{
|
||||||
allocate_and_generate_new_seeded_lwe_compact_public_key,
|
allocate_and_generate_new_seeded_lwe_compact_public_key,
|
||||||
encrypt_lwe_ciphertext_with_compact_public_key, generate_lwe_compact_public_key,
|
encrypt_lwe_ciphertext_with_compact_public_key, generate_lwe_compact_public_key,
|
||||||
@@ -5,8 +9,12 @@ use crate::core_crypto::prelude::{
|
|||||||
LweCompactPublicKeyOwned, Plaintext, PlaintextList, SeededLweCompactPublicKeyOwned,
|
LweCompactPublicKeyOwned, Plaintext, PlaintextList, SeededLweCompactPublicKeyOwned,
|
||||||
};
|
};
|
||||||
use crate::shortint::ciphertext::{CompactCiphertextList, Degree, NoiseLevel};
|
use crate::shortint::ciphertext::{CompactCiphertextList, Degree, NoiseLevel};
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
use crate::shortint::ciphertext::{ProvenCiphertext, ProvenCompactCiphertextList};
|
||||||
use crate::shortint::engine::ShortintEngine;
|
use crate::shortint::engine::ShortintEngine;
|
||||||
use crate::shortint::{Ciphertext, ClientKey, PBSOrder, ShortintParameterSet};
|
use crate::shortint::{Ciphertext, ClientKey, PBSOrder, ShortintParameterSet};
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
use crate::zk::{CompactPkePublicParams, ZkComputeLoad};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
@@ -162,12 +170,8 @@ impl CompactPublicKey {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let encryption_noise_distribution = match self.pbs_order {
|
let encryption_noise_distribution = match self.pbs_order {
|
||||||
crate::shortint::PBSOrder::KeyswitchBootstrap => {
|
PBSOrder::KeyswitchBootstrap => self.parameters.glwe_noise_distribution(),
|
||||||
self.parameters.glwe_noise_distribution()
|
PBSOrder::BootstrapKeyswitch => self.parameters.lwe_noise_distribution(),
|
||||||
}
|
|
||||||
crate::shortint::PBSOrder::BootstrapKeyswitch => {
|
|
||||||
self.parameters.lwe_noise_distribution()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ShortintEngine::with_thread_local_mut(|engine| {
|
ShortintEngine::with_thread_local_mut(|engine| {
|
||||||
@@ -193,6 +197,58 @@ impl CompactPublicKey {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub fn encrypt_and_prove(
|
||||||
|
&self,
|
||||||
|
message: u64,
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
load: ZkComputeLoad,
|
||||||
|
) -> crate::Result<ProvenCiphertext> {
|
||||||
|
// This allocates the required ct
|
||||||
|
let mut encrypted_ct = LweCiphertextOwned::new(
|
||||||
|
0u64,
|
||||||
|
self.key.lwe_dimension().to_lwe_size(),
|
||||||
|
self.parameters.ciphertext_modulus(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let encryption_noise_distribution = match self.pbs_order {
|
||||||
|
PBSOrder::KeyswitchBootstrap => self.parameters.glwe_noise_distribution(),
|
||||||
|
PBSOrder::BootstrapKeyswitch => self.parameters.lwe_noise_distribution(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let plaintext_modulus =
|
||||||
|
(self.parameters.message_modulus().0 * self.parameters.carry_modulus().0) as u64;
|
||||||
|
let delta = (1u64 << 63) / plaintext_modulus;
|
||||||
|
|
||||||
|
let proof = ShortintEngine::with_thread_local_mut(|engine| {
|
||||||
|
encrypt_and_prove_lwe_ciphertext_with_compact_public_key(
|
||||||
|
&self.key,
|
||||||
|
&mut encrypted_ct,
|
||||||
|
Cleartext(message),
|
||||||
|
delta,
|
||||||
|
encryption_noise_distribution,
|
||||||
|
encryption_noise_distribution,
|
||||||
|
&mut engine.secret_generator,
|
||||||
|
&mut engine.encryption_generator,
|
||||||
|
&mut engine.random_generator,
|
||||||
|
public_params,
|
||||||
|
load,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let message_modulus = self.parameters.message_modulus();
|
||||||
|
let ciphertext = Ciphertext::new(
|
||||||
|
encrypted_ct,
|
||||||
|
Degree::new(message_modulus.0 - 1),
|
||||||
|
NoiseLevel::NOMINAL,
|
||||||
|
message_modulus,
|
||||||
|
self.parameters.carry_modulus(),
|
||||||
|
self.pbs_order,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(ProvenCiphertext { ciphertext, proof })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn encrypt_slice(&self, messages: &[u64]) -> CompactCiphertextList {
|
pub fn encrypt_slice(&self, messages: &[u64]) -> CompactCiphertextList {
|
||||||
self.encrypt_iter(messages.iter().copied())
|
self.encrypt_iter(messages.iter().copied())
|
||||||
}
|
}
|
||||||
@@ -211,12 +267,8 @@ impl CompactPublicKey {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let encryption_noise_distribution = match self.pbs_order {
|
let encryption_noise_distribution = match self.pbs_order {
|
||||||
crate::shortint::PBSOrder::KeyswitchBootstrap => {
|
PBSOrder::KeyswitchBootstrap => self.parameters.glwe_noise_distribution(),
|
||||||
self.parameters.glwe_noise_distribution()
|
PBSOrder::BootstrapKeyswitch => self.parameters.lwe_noise_distribution(),
|
||||||
}
|
|
||||||
crate::shortint::PBSOrder::BootstrapKeyswitch => {
|
|
||||||
self.parameters.lwe_noise_distribution()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// No parallelism allowed
|
// No parallelism allowed
|
||||||
@@ -264,6 +316,91 @@ impl CompactPublicKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "zk-pok-experimental")]
|
||||||
|
pub fn encrypt_and_prove_slice(
|
||||||
|
&self,
|
||||||
|
messages: &[u64],
|
||||||
|
public_params: &CompactPkePublicParams,
|
||||||
|
load: ZkComputeLoad,
|
||||||
|
) -> crate::Result<ProvenCompactCiphertextList> {
|
||||||
|
let plaintext_modulus =
|
||||||
|
(self.parameters.message_modulus().0 * self.parameters.carry_modulus().0) as u64;
|
||||||
|
let delta = (1u64 << 63) / plaintext_modulus;
|
||||||
|
|
||||||
|
let max_num_message = public_params.k;
|
||||||
|
let num_lists = messages.len().div_ceil(max_num_message);
|
||||||
|
let mut proved_lists = Vec::with_capacity(num_lists);
|
||||||
|
for message_chunk in messages.chunks(max_num_message) {
|
||||||
|
let mut ct_list = LweCompactCiphertextListOwned::new(
|
||||||
|
0u64,
|
||||||
|
self.key.lwe_dimension().to_lwe_size(),
|
||||||
|
LweCiphertextCount(message_chunk.len()),
|
||||||
|
self.parameters.ciphertext_modulus(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let encryption_noise_distribution = match self.pbs_order {
|
||||||
|
PBSOrder::KeyswitchBootstrap => self.parameters.glwe_noise_distribution(),
|
||||||
|
PBSOrder::BootstrapKeyswitch => self.parameters.lwe_noise_distribution(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// No parallelism allowed
|
||||||
|
#[cfg(all(feature = "__wasm_api", not(feature = "parallel-wasm-api")))]
|
||||||
|
let proof = {
|
||||||
|
use crate::core_crypto::prelude::encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key;
|
||||||
|
ShortintEngine::with_thread_local_mut(|engine| {
|
||||||
|
encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key(
|
||||||
|
&self.key,
|
||||||
|
&mut ct_list,
|
||||||
|
&message_chunk,
|
||||||
|
delta,
|
||||||
|
encryption_noise_distribution,
|
||||||
|
encryption_noise_distribution,
|
||||||
|
&mut engine.secret_generator,
|
||||||
|
&mut engine.encryption_generator,
|
||||||
|
&mut engine.random_generator,
|
||||||
|
public_params,
|
||||||
|
load,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}?;
|
||||||
|
|
||||||
|
// Parallelism allowed /
|
||||||
|
#[cfg(any(not(feature = "__wasm_api"), feature = "parallel-wasm-api"))]
|
||||||
|
let proof = {
|
||||||
|
use crate::core_crypto::prelude::par_encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key;
|
||||||
|
ShortintEngine::with_thread_local_mut(|engine| {
|
||||||
|
par_encrypt_and_prove_lwe_compact_ciphertext_list_with_compact_public_key(
|
||||||
|
&self.key,
|
||||||
|
&mut ct_list,
|
||||||
|
&message_chunk,
|
||||||
|
delta,
|
||||||
|
encryption_noise_distribution,
|
||||||
|
encryption_noise_distribution,
|
||||||
|
&mut engine.secret_generator,
|
||||||
|
&mut engine.encryption_generator,
|
||||||
|
&mut engine.random_generator,
|
||||||
|
public_params,
|
||||||
|
load,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let message_modulus = self.parameters.message_modulus();
|
||||||
|
let ciphertext = CompactCiphertextList {
|
||||||
|
ct_list,
|
||||||
|
degree: Degree::new(message_modulus.0 - 1),
|
||||||
|
message_modulus,
|
||||||
|
carry_modulus: self.parameters.carry_modulus(),
|
||||||
|
pbs_order: self.pbs_order,
|
||||||
|
noise_level: NoiseLevel::NOMINAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
proved_lists.push((ciphertext, proof));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ProvenCompactCiphertextList { proved_lists })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn size_elements(&self) -> usize {
|
pub fn size_elements(&self) -> usize {
|
||||||
self.key.size_elements()
|
self.key.size_elements()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ mod test_cpu_doc {
|
|||||||
"../docs/guides/trivial_ciphertext.md",
|
"../docs/guides/trivial_ciphertext.md",
|
||||||
guides_trivial_ciphertext
|
guides_trivial_ciphertext
|
||||||
);
|
);
|
||||||
|
doctest!("../docs/guides/zk-pok.md", guides_zk_pok);
|
||||||
|
|
||||||
// REFERENCES
|
// REFERENCES
|
||||||
|
|
||||||
|
|||||||
140
tfhe/src/zk.rs
Normal file
140
tfhe/src/zk.rs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
use crate::core_crypto::commons::math::random::{BoundedDistribution, Deserialize, Serialize};
|
||||||
|
use crate::core_crypto::prelude::*;
|
||||||
|
use rand_core::RngCore;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::Bound;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use tfhe_zk_pok::proofs::pke::crs_gen;
|
||||||
|
|
||||||
|
pub use tfhe_zk_pok::proofs::ComputeLoad as ZkComputeLoad;
|
||||||
|
type Curve = tfhe_zk_pok::curve_api::Bls12_446;
|
||||||
|
pub type CompactPkeProof = tfhe_zk_pok::proofs::pke::Proof<Curve>;
|
||||||
|
pub type CompactPkePublicParams = tfhe_zk_pok::proofs::pke::PublicParams<Curve>;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum ZkVerificationOutCome {
|
||||||
|
/// The proof ands its entity were valid
|
||||||
|
Valid,
|
||||||
|
/// The proof ands its entity were not
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZkVerificationOutCome {
|
||||||
|
pub fn is_valid(self) -> bool {
|
||||||
|
self == Self::Valid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_invalid(self) -> bool {
|
||||||
|
self == Self::Invalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct CompactPkeCrs {
|
||||||
|
public_params: CompactPkePublicParams,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompactPkeCrs {
|
||||||
|
pub fn new<Scalar, NoiseDistribution>(
|
||||||
|
lwe_dim: LweDimension,
|
||||||
|
max_num_cleartext: usize,
|
||||||
|
noise_distribution: NoiseDistribution,
|
||||||
|
ciphertext_modulus: CiphertextModulus<Scalar>,
|
||||||
|
plaintext_modulus: Scalar,
|
||||||
|
rng: &mut impl RngCore,
|
||||||
|
) -> crate::Result<Self>
|
||||||
|
where
|
||||||
|
Scalar: UnsignedInteger + CastInto<u64> + Debug,
|
||||||
|
NoiseDistribution: BoundedDistribution<Scalar::Signed>,
|
||||||
|
{
|
||||||
|
// The bound for the crs has to be a power of two,
|
||||||
|
// it is [-b, b) (non-inclusive for the high bound)
|
||||||
|
// so we may have to give a bound that is bigger than
|
||||||
|
// what the distribution generates
|
||||||
|
let high_bound = match noise_distribution.high_bound() {
|
||||||
|
Bound::Included(high_b) => {
|
||||||
|
let high_b = high_b.wrapping_abs().into_unsigned();
|
||||||
|
if high_b.is_power_of_two() {
|
||||||
|
high_b * Scalar::TWO
|
||||||
|
} else {
|
||||||
|
high_b.next_power_of_two()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bound::Excluded(high_b) => {
|
||||||
|
let high_b = high_b.wrapping_abs().into_unsigned();
|
||||||
|
if high_b.is_power_of_two() {
|
||||||
|
high_b
|
||||||
|
} else {
|
||||||
|
high_b.next_power_of_two()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bound::Unbounded => {
|
||||||
|
return Err("requires bounded distribution".into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let abs_low_bound = match noise_distribution.low_bound() {
|
||||||
|
Bound::Included(low_b) => {
|
||||||
|
let low_b = low_b.wrapping_abs().into_unsigned();
|
||||||
|
if low_b.is_power_of_two() {
|
||||||
|
low_b * Scalar::TWO
|
||||||
|
} else {
|
||||||
|
low_b.next_power_of_two()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bound::Excluded(low_b) => {
|
||||||
|
let low_b = low_b.wrapping_abs().into_unsigned();
|
||||||
|
if low_b.is_power_of_two() {
|
||||||
|
low_b
|
||||||
|
} else {
|
||||||
|
low_b.next_power_of_two()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bound::Unbounded => {
|
||||||
|
return Err("requires bounded distribution".into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let noise_bound = abs_low_bound.max(high_bound);
|
||||||
|
|
||||||
|
if Scalar::BITS > 64 && noise_bound >= (Scalar::ONE << 64usize) {
|
||||||
|
return Err("noise bounds exceeds 64 bits modulus".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if Scalar::BITS > 64 && plaintext_modulus >= (Scalar::ONE << 64usize) {
|
||||||
|
return Err("Plaintext modulus exceeds 64 bits modulus".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let q = if ciphertext_modulus.is_native_modulus() {
|
||||||
|
match Scalar::BITS.cmp(&64) {
|
||||||
|
Ordering::Greater => Err(
|
||||||
|
"Zero Knowledge proof do not support ciphertext modulus > 64 bits".to_string(),
|
||||||
|
),
|
||||||
|
Ordering::Equal => Ok(0u64),
|
||||||
|
Ordering::Less => Ok(1u64 << Scalar::BITS),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let custom_modulus = ciphertext_modulus.get_custom_modulus();
|
||||||
|
if custom_modulus > (u64::MAX) as u128 {
|
||||||
|
Err("Zero Knowledge proof do not support ciphertext modulus > 64 bits".to_string())
|
||||||
|
} else {
|
||||||
|
Ok(custom_modulus as u64)
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let public_params = crs_gen(
|
||||||
|
lwe_dim.0,
|
||||||
|
max_num_cleartext,
|
||||||
|
noise_bound.cast_into(),
|
||||||
|
q,
|
||||||
|
plaintext_modulus.cast_into(),
|
||||||
|
rng,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Self { public_params })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn public_params(&self) -> &CompactPkePublicParams {
|
||||||
|
&self.public_params
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -68,7 +68,12 @@
|
|||||||
value="Compressed Compact Public Key Test 256 Bits Big"
|
value="Compressed Compact Public Key Test 256 Bits Big"
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
|
<input
|
||||||
|
type="button"
|
||||||
|
id="compactPublicKeyZeroKnowledge"
|
||||||
|
value="Compact Public Key Test 64 Bits Big With Zero Knowledge Proof"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
<input type="checkbox" id="testSuccess" disabled />
|
<input type="checkbox" id="testSuccess" disabled />
|
||||||
<label for="testSuccess"> TestSuccess </label><br />
|
<label for="testSuccess"> TestSuccess </label><br />
|
||||||
|
|
||||||
@@ -110,6 +115,12 @@
|
|||||||
value="Compressed Server Key Bench 2_2"
|
value="Compressed Server Key Bench 2_2"
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
|
<input
|
||||||
|
type="button"
|
||||||
|
id="compactPublicKeyZeroKnowledgeBench"
|
||||||
|
value="Compact ZK Bench"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
|
||||||
<input type="text" id="benchmarkResults" disabled />
|
<input type="text" id="benchmarkResults" disabled />
|
||||||
<label for="benchmarkResults"> BenchmarkResults </label><br />
|
<label for="benchmarkResults"> BenchmarkResults </label><br />
|
||||||
|
|||||||
@@ -31,12 +31,14 @@ async function setup() {
|
|||||||
"compactPublicKeyTest256BitSmall",
|
"compactPublicKeyTest256BitSmall",
|
||||||
"compressedCompactPublicKeyTest256BitBig",
|
"compressedCompactPublicKeyTest256BitBig",
|
||||||
"compressedCompactPublicKeyTest256BitSmall",
|
"compressedCompactPublicKeyTest256BitSmall",
|
||||||
|
"compactPublicKeyZeroKnowledge",
|
||||||
"compactPublicKeyBench32BitBig",
|
"compactPublicKeyBench32BitBig",
|
||||||
"compactPublicKeyBench32BitSmall",
|
"compactPublicKeyBench32BitSmall",
|
||||||
"compactPublicKeyBench256BitBig",
|
"compactPublicKeyBench256BitBig",
|
||||||
"compactPublicKeyBench256BitSmall",
|
"compactPublicKeyBench256BitSmall",
|
||||||
"compressedServerKeyBenchMessage1Carry1",
|
"compressedServerKeyBenchMessage1Carry1",
|
||||||
"compressedServerKeyBenchMessage2Carry2",
|
"compressedServerKeyBenchMessage2Carry2",
|
||||||
|
"compactPublicKeyZeroKnowledgeBench",
|
||||||
];
|
];
|
||||||
|
|
||||||
function setupBtn(id) {
|
function setupBtn(id) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const secs = 60;
|
const secs = 1200; // 20 Minutes
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
verbose: true,
|
verbose: true,
|
||||||
|
|||||||
@@ -50,22 +50,26 @@ async function runActualTest(page, buttonId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TWENTY_MINUTES = 1200 * 1000;
|
||||||
|
|
||||||
async function runTestAttachedToButton(buttonId) {
|
async function runTestAttachedToButton(buttonId) {
|
||||||
let browser;
|
let browser;
|
||||||
if (isRoot()) {
|
if (isRoot()) {
|
||||||
browser = await puppeteer.launch({
|
browser = await puppeteer.launch({
|
||||||
headless: "new",
|
headless: "new",
|
||||||
args: ["--no-sandbox"],
|
args: ["--no-sandbox"],
|
||||||
|
protocolTimeout: TWENTY_MINUTES,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
browser = await puppeteer.launch({
|
browser = await puppeteer.launch({
|
||||||
headless: "new",
|
headless: "new",
|
||||||
|
protocolTimeout: TWENTY_MINUTES,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let page = await browser.newPage();
|
let page = await browser.newPage();
|
||||||
|
|
||||||
await page.setDefaultTimeout(300000); // Five minutes timeout
|
await page.setDefaultTimeout(TWENTY_MINUTES);
|
||||||
await page.goto("http://localhost:3000");
|
await page.goto("http://localhost:3000");
|
||||||
page.on("console", (msg) => console.log("PAGE LOG:", msg.text()));
|
page.on("console", (msg) => console.log("PAGE LOG:", msg.text()));
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,11 @@ it("Compressed Compact Public Key Test Small 256 Bit", async () => {
|
|||||||
it("Compressed Compact Public Key Test Big 256 Bit", async () => {
|
it("Compressed Compact Public Key Test Big 256 Bit", async () => {
|
||||||
await runTestAttachedToButton("compressedCompactPublicKeyTest256BitBig");
|
await runTestAttachedToButton("compressedCompactPublicKeyTest256BitBig");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(
|
||||||
|
"Compact Public Key Test Big 64 Bit With Zero Knowledge",
|
||||||
|
async () => {
|
||||||
|
await runTestAttachedToButton("compactPublicKeyZeroKnowledge");
|
||||||
|
},
|
||||||
|
1200 * 1000,
|
||||||
|
); // 20 minutes timeout
|
||||||
|
|||||||
@@ -11,17 +11,15 @@ import init, {
|
|||||||
TfheCompressedCompactPublicKey,
|
TfheCompressedCompactPublicKey,
|
||||||
TfheCompactPublicKey,
|
TfheCompactPublicKey,
|
||||||
TfheConfigBuilder,
|
TfheConfigBuilder,
|
||||||
CompressedFheUint8,
|
|
||||||
FheUint8,
|
FheUint8,
|
||||||
FheUint32,
|
|
||||||
CompactFheUint32,
|
|
||||||
CompactFheUint32List,
|
CompactFheUint32List,
|
||||||
CompressedFheUint128,
|
|
||||||
FheUint128,
|
|
||||||
CompressedFheUint256,
|
|
||||||
FheUint256,
|
|
||||||
CompactFheUint256,
|
|
||||||
CompactFheUint256List,
|
CompactFheUint256List,
|
||||||
|
ZkComputeLoad,
|
||||||
|
ProvenCompactFheUint64,
|
||||||
|
ProvenCompactFheUint64List,
|
||||||
|
CompactPkeCrs,
|
||||||
|
Shortint,
|
||||||
|
CompactFheUint64,
|
||||||
} from "./pkg/tfhe.js";
|
} from "./pkg/tfhe.js";
|
||||||
|
|
||||||
function assert(cond, text) {
|
function assert(cond, text) {
|
||||||
@@ -74,7 +72,7 @@ async function compressedPublicKeyTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function publicKeyTest() {
|
async function publicKeyTest() {
|
||||||
let config = TfheConfigBuilder.default().use_small_encryption().build();
|
let config = TfheConfigBuilder.default_with_small_encryption().build();
|
||||||
|
|
||||||
console.time("ClientKey Gen");
|
console.time("ClientKey Gen");
|
||||||
let clientKey = TfheClientKey.generate(config);
|
let clientKey = TfheClientKey.generate(config);
|
||||||
@@ -379,6 +377,106 @@ async function compressedCompactPublicKeyTest256BitOnConfig(config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateRandomBigInt(bitLen) {
|
||||||
|
let result = BigInt(0);
|
||||||
|
for (let i = 0; i < bitLen; i++) {
|
||||||
|
result << 1n;
|
||||||
|
result |= BigInt(Math.random() < 0.5);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function compactPublicKeyZeroKnowledge() {
|
||||||
|
let block_params = new ShortintParameters(
|
||||||
|
ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_KS_PBS,
|
||||||
|
);
|
||||||
|
block_params.set_glwe_noise_distribution(Shortint.try_new_t_uniform(9));
|
||||||
|
|
||||||
|
let config = TfheConfigBuilder.default()
|
||||||
|
.use_custom_parameters(block_params)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let clientKey = TfheClientKey.generate(config);
|
||||||
|
let publicKey = TfheCompactPublicKey.new(clientKey);
|
||||||
|
|
||||||
|
console.log("Start CRS generation");
|
||||||
|
console.time("CRS generation");
|
||||||
|
let crs = CompactPkeCrs.from_config(config, 4 * 64);
|
||||||
|
console.timeEnd("CRS generation");
|
||||||
|
let public_params = crs.public_params();
|
||||||
|
|
||||||
|
{
|
||||||
|
let input = generateRandomBigInt(64);
|
||||||
|
let start = performance.now();
|
||||||
|
let encrypted = ProvenCompactFheUint64.encrypt_with_compact_public_key(
|
||||||
|
input,
|
||||||
|
public_params,
|
||||||
|
publicKey,
|
||||||
|
ZkComputeLoad.Proof,
|
||||||
|
);
|
||||||
|
let end = performance.now();
|
||||||
|
console.log(
|
||||||
|
"Time to encrypt + prove CompactFheUint64: ",
|
||||||
|
end - start,
|
||||||
|
" ms",
|
||||||
|
);
|
||||||
|
|
||||||
|
let bytes = encrypted.serialize();
|
||||||
|
console.log("ProvenCompactFheUint64 size:", bytes.length);
|
||||||
|
|
||||||
|
assert_eq(encrypted.verifies(public_params, publicKey), true);
|
||||||
|
|
||||||
|
start = performance.now();
|
||||||
|
let expanded = encrypted.verify_and_expand(public_params, publicKey);
|
||||||
|
end = performance.now();
|
||||||
|
console.log(
|
||||||
|
"Time to verify + expand CompactFheUint64: ",
|
||||||
|
end - start,
|
||||||
|
" ms",
|
||||||
|
);
|
||||||
|
|
||||||
|
let decrypted = expanded.decrypt(clientKey);
|
||||||
|
assert_eq(decrypted, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let inputs = [
|
||||||
|
generateRandomBigInt(64),
|
||||||
|
generateRandomBigInt(64),
|
||||||
|
generateRandomBigInt(64),
|
||||||
|
generateRandomBigInt(64),
|
||||||
|
];
|
||||||
|
let start = performance.now();
|
||||||
|
let encrypted = ProvenCompactFheUint64List.encrypt_with_compact_public_key(
|
||||||
|
inputs,
|
||||||
|
public_params,
|
||||||
|
publicKey,
|
||||||
|
ZkComputeLoad.Proof,
|
||||||
|
);
|
||||||
|
let end = performance.now();
|
||||||
|
console.log(
|
||||||
|
"Time to encrypt + prove CompactFheUint64List of 4: ",
|
||||||
|
end - start,
|
||||||
|
" ms",
|
||||||
|
);
|
||||||
|
assert_eq(encrypted.verifies(public_params, publicKey), true);
|
||||||
|
|
||||||
|
start = performance.now();
|
||||||
|
let expanded_list = encrypted.verify_and_expand(public_params, publicKey);
|
||||||
|
end = performance.now();
|
||||||
|
console.log(
|
||||||
|
"Time to verify + expand CompactFheUint64: ",
|
||||||
|
end - start,
|
||||||
|
" ms",
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = 0; i < inputs.length; i++) {
|
||||||
|
let decrypted = expanded_list[i].decrypt(clientKey);
|
||||||
|
assert_eq(decrypted, inputs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function compressedCompactPublicKeyTest256BitBig() {
|
async function compressedCompactPublicKeyTest256BitBig() {
|
||||||
const block_params = new ShortintParameters(
|
const block_params = new ShortintParameters(
|
||||||
ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS,
|
ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS,
|
||||||
@@ -550,6 +648,60 @@ async function compressedServerKeyBenchMessage2Carry2() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function compactPublicKeyZeroKnowledgeBench() {
|
||||||
|
let block_params = new ShortintParameters(
|
||||||
|
ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_PBS_KS,
|
||||||
|
);
|
||||||
|
block_params.set_lwe_noise_distribution(Shortint.try_new_t_uniform(9));
|
||||||
|
|
||||||
|
let config = TfheConfigBuilder.default()
|
||||||
|
.use_custom_parameters(block_params)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let clientKey = TfheClientKey.generate(config);
|
||||||
|
let publicKey = TfheCompactPublicKey.new(clientKey);
|
||||||
|
|
||||||
|
console.log("Start CRS generation");
|
||||||
|
console.time("CRS generation");
|
||||||
|
let crs = CompactPkeCrs.from_config(config, 4 * 64);
|
||||||
|
console.timeEnd("CRS generation");
|
||||||
|
let public_params = crs.public_params();
|
||||||
|
|
||||||
|
const bench_loops = 4; // The computation is expensive
|
||||||
|
let bench_results = {};
|
||||||
|
let load_choices = [ZkComputeLoad.Proof, ZkComputeLoad.Verify];
|
||||||
|
const load_to_str = {
|
||||||
|
[ZkComputeLoad.Proof]: "compute_load_proof",
|
||||||
|
[ZkComputeLoad.Verify]: "compute_load_verify",
|
||||||
|
};
|
||||||
|
for (const loadChoice of load_choices) {
|
||||||
|
let timing = 0;
|
||||||
|
for (let i = 0; i < bench_loops; i++) {
|
||||||
|
let input = generateRandomBigInt(64);
|
||||||
|
|
||||||
|
const start = performance.now();
|
||||||
|
let _ = ProvenCompactFheUint64.encrypt_with_compact_public_key(
|
||||||
|
input,
|
||||||
|
public_params,
|
||||||
|
publicKey,
|
||||||
|
loadChoice,
|
||||||
|
);
|
||||||
|
const end = performance.now();
|
||||||
|
timing += end - start;
|
||||||
|
}
|
||||||
|
const mean = timing / bench_loops;
|
||||||
|
|
||||||
|
const bench_str =
|
||||||
|
"compact_fhe_uint64_proven_encryption_" +
|
||||||
|
load_to_str[loadChoice] +
|
||||||
|
"_mean";
|
||||||
|
console.log(bench_str, ": ", mean, " ms");
|
||||||
|
bench_results["compact_fhe_uint64_proven_encryption_"] = mean;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bench_results;
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
await init();
|
await init();
|
||||||
await initThreadPool(navigator.hardwareConcurrency);
|
await initThreadPool(navigator.hardwareConcurrency);
|
||||||
@@ -564,12 +716,14 @@ async function main() {
|
|||||||
compactPublicKeyTest256BitBig,
|
compactPublicKeyTest256BitBig,
|
||||||
compressedCompactPublicKeyTest256BitSmall,
|
compressedCompactPublicKeyTest256BitSmall,
|
||||||
compressedCompactPublicKeyTest256BitBig,
|
compressedCompactPublicKeyTest256BitBig,
|
||||||
|
compactPublicKeyZeroKnowledge,
|
||||||
compactPublicKeyBench32BitBig,
|
compactPublicKeyBench32BitBig,
|
||||||
compactPublicKeyBench32BitSmall,
|
compactPublicKeyBench32BitSmall,
|
||||||
compactPublicKeyBench256BitBig,
|
compactPublicKeyBench256BitBig,
|
||||||
compactPublicKeyBench256BitSmall,
|
compactPublicKeyBench256BitSmall,
|
||||||
compressedServerKeyBenchMessage1Carry1,
|
compressedServerKeyBenchMessage1Carry1,
|
||||||
compressedServerKeyBenchMessage2Carry2,
|
compressedServerKeyBenchMessage2Carry2,
|
||||||
|
compactPublicKeyZeroKnowledgeBench,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user