Skip to content

Commit 37ecce8

Browse files
committed
chore: test vector generation tool for core algorithms
1 parent f9268b8 commit 37ecce8

38 files changed

+665
-7
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ members = [
1515
"utils/param_dedup",
1616
"tests",
1717
"mockups/tfhe-hpu-mockup",
18+
"apps/test-vectors",
1819
]
1920

2021
exclude = [

Makefile

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ BENCH_CUSTOM_COMMAND:=
2525
NODE_VERSION=22.6
2626
BACKWARD_COMPAT_DATA_DIR=utils/tfhe-backward-compat-data
2727
BACKWARD_COMPAT_DATA_GEN_VERSION:=$(TFHE_VERSION)
28+
TEST_VECTORS_DIR=apps/test-vectors
2829
CURRENT_TFHE_VERSION:=$(shell grep '^version[[:space:]]*=' tfhe/Cargo.toml | cut -d '=' -f 2 | xargs)
2930
WASM_PACK_VERSION="0.13.1"
3031
WASM_BINDGEN_VERSION:=$(shell cargo tree --target wasm32-unknown-unknown -e all --prefix none | grep "wasm-bindgen v" | head -n 1 | cut -d 'v' -f2)
@@ -525,11 +526,16 @@ clippy_backward_compat_data: install_rs_check_toolchain # the toolchain is selec
525526
echo "Cannot run clippy for backward compat crate on non x86 platform for now."; \
526527
fi
527528

529+
.PHONY: clippy_test_vectors # Run clippy lints on the test vectors app
530+
clippy_test_vectors: install_rs_check_toolchain
531+
cd apps/test-vectors; RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
532+
-p tfhe-test-vectors -- --no-deps -D warnings
533+
528534
.PHONY: clippy_all # Run all clippy targets
529535
clippy_all: clippy_rustdoc clippy clippy_boolean clippy_shortint clippy_integer clippy_all_targets \
530536
clippy_c_api clippy_js_wasm_api clippy_tasks clippy_core clippy_tfhe_csprng clippy_zk_pok clippy_trivium \
531537
clippy_versionable clippy_tfhe_lints clippy_ws_tests clippy_bench clippy_param_dedup \
532-
clippy_backward_compat_data
538+
clippy_test_vectors clippy_backward_compat_data
533539

534540
.PHONY: clippy_fast # Run main clippy targets
535541
clippy_fast: clippy_rustdoc clippy clippy_all_targets clippy_c_api clippy_js_wasm_api clippy_tasks \
@@ -1176,6 +1182,17 @@ test_backward_compatibility_ci: install_rs_build_toolchain
11761182
.PHONY: test_backward_compatibility # Same as test_backward_compatibility_ci but tries to clone the data repo first if needed
11771183
test_backward_compatibility: pull_backward_compat_data test_backward_compatibility_ci
11781184

1185+
# Generate the test vectors and update the hash file
1186+
.PHONY: gen_test_vectors
1187+
gen_test_vectors: install_rs_build_toolchain
1188+
./scripts/test_vectors.sh generate apps/test-vectors
1189+
1190+
# Generate the test vectors and check that the content matches the hash file
1191+
# `comm` is used to compare the checksums, and will also notify of any added file
1192+
.PHONY: check_test_vectors
1193+
check_test_vectors: install_rs_build_toolchain
1194+
./scripts/test_vectors.sh check apps/test-vectors
1195+
11791196
.PHONY: doc # Build rust doc
11801197
doc: install_rs_check_toolchain
11811198
@# Even though we are not in docs.rs, this allows to "just" build the doc
@@ -1701,6 +1718,10 @@ pull_backward_compat_data:
17011718
pull_hpu_files:
17021719
./scripts/pull_lfs_data.sh backends/tfhe-hpu-backend/
17031720

1721+
.PHONY: pull_test_vectors # Pull the data files needed for backward compatibility tests
1722+
pull_test_vectors:
1723+
./scripts/pull_lfs_data.sh $(TEST_VECTORS_DIR)
1724+
17041725
#
17051726
# Real use case examples
17061727
#
@@ -1752,6 +1773,8 @@ pcc_batch_2:
17521773
$(call run_recipe_with_details,clippy)
17531774
$(call run_recipe_with_details,clippy_all_targets)
17541775
$(call run_recipe_with_details,check_fmt_js)
1776+
$(call run_recipe_with_details,clippy_test_vectors)
1777+
$(call run_recipe_with_details,check_test_vectors)
17551778

17561779
.PHONY: pcc_batch_3 # duration: 6'50''
17571780
pcc_batch_3:

apps/test-vectors/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "tfhe-test-vectors"
3+
version = "0.1.0"
4+
edition = "2024"
5+
rust-version.workspace = true
6+
7+
[dependencies]
8+
ciborium = "0.2"
9+
serde = { version = "1.0", features = ["derive"] }
10+
tfhe = { path = "../../tfhe", features = ["experimental-force_fft_algo_dif4"] }
11+
tfhe-csprng = { path = "../../tfhe-csprng" }

apps/test-vectors/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Test vectors for TFHE
2+
This folder contains test vectors for the core TFHE-rs algorithms.
3+
4+
The test vectors are located in `data`, and are generated using the sample program in `src/main.rs`.
5+
6+
To re-generate the test vectors, assuming you have [rustup](https://rust-lang.org/tools/install/) installed on your system, simply run the following command in the current folder:
7+
```
8+
cargo run --release
9+
```
10+
11+
See [the data folder](data/README.md) for more information about the generated values.

apps/test-vectors/checksums.sha256

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2abec9dc5d399ece68ac227f67f7cafcb9a6acac36ed734fe3d5244021eb1cda data/toy_params/glwe_after_spec_br.cbor
2+
2c70d1d78cc3760733850a353ace2b9c4705e840141b75841739e90e51247e18 data/valid_params_128/small_lwe_secret_key.cbor
3+
36c9080b636475fcacca503ce041bbfeee800fd3e1890dee559ea18defff9fe8 data/toy_params/glwe_after_id_br.cbor
4+
377761beeb4216cf5aa2624a8b64b8259f5a75c32d28e850be8bced3a0cdd6f5 data/toy_params/ksk.cbor
5+
59dba26d457f96478eda130cab5301fce86f23c6a8807de42f2a1e78c4985ca7 data/valid_params_128/lwe_ks.cbor
6+
656f0009c7834c5bcb61621e222047516054b9bc5d0593d474ab8f1c086b67a6 data/valid_params_128/lwe_after_id_pbs.cbor
7+
699580ca92b9c2f9e1f57fb1e312c9e8cb29714f7acdef9d2ba05f798546751f data/toy_params/lwe_sum.cbor
8+
6e54ab41056984595b077baff70236d934308cf5c0c33b4482fbfb129b3756c6 data/valid_params_128/glwe_after_id_br.cbor
9+
70f5e5728822de05b49071efb5ec28551b0f5cc87aa709a455d8e7f04b9c96ee data/toy_params/lwe_after_id_pbs.cbor
10+
7cc6803f5fbc3d5a1bf597f2b979ce17eecd3d6baca12183dea21022a7b65c52 data/toy_params/bsk.cbor
11+
7f3c40a134623b44779a556212477fea26eaed22450f3b6faeb8721d63699972 data/valid_params_128/lwe_sum.cbor
12+
837b3bd3245d4d0534ed255fdef896fb4fa6998a258a14543dfdadd0bfc9b6dd data/toy_params/lwe_prod.cbor
13+
8ee68ed99dd9103fb62b1e2c7c8cf483706ae2071b792d4bd16f9f93f64871f9 data/toy_params/lwe_after_spec_pbs.cbor
14+
99a19c5d6d5f4fd81d9164d0ff96719ef362eabda256bce6a55cba6cb69e42bf data/valid_params_128/glwe_after_spec_br.cbor
15+
aa44aea29efd6d9e4d35a21a625d9cba155672e3f7ed3eddee1e211e62ad146b data/valid_params_128/lwe_ms.cbor
16+
b7a037b9eaa88d6385167579b93e26a0cb6976d9b8967416fd1173e113bda199 data/valid_params_128/large_lwe_secret_key.cbor
17+
c6df98676de04fe54b5ffc2eb30a82ebb706c9d7d5a4e0ed509700fec88761f7 data/toy_params/lwe_ms.cbor
18+
c7d5a864d5616a7d8ad50bbf40416e41e6c9b60c546dc14d4aa8fc40a418baa7 data/toy_params/large_lwe_secret_key.cbor
19+
c806533b325b1009db38be2f9bef5f3b2fad6b77b4c71f2855ccc9d3b4162e98 data/valid_params_128/lwe_b.cbor
20+
c9eb75bd2993639348a679cf48c06e3c38d1a513f48e5b0ce0047cea8cff6bbc data/toy_params/lwe_a.cbor
21+
d6da5baef0e787f6be56e218d8354e26904652602db964844156fdff08350ce6 data/toy_params/lwe_ks.cbor
22+
e44ffa6e5a50a03d32721180a051c8ce62f1791d4853aeaebed0200c183a57cf data/valid_params_128/lwe_after_spec_pbs.cbor
23+
e591ab9af1b6a0aede273f9a3abb65a4c387feb5fa06a6959e9314058ca0f7e5 data/valid_params_128/ksk.cbor
24+
e69d2d2c064fc8c0460b39191ca65338146990349954f5ec5ebd01d93610e7eb data/valid_params_128/lwe_a.cbor
25+
e76c24b2a0c9a842ad13dda35473c2514f9e7d20983b5ea0759c4521a91626d9 data/valid_params_128/lwe_prod.cbor
26+
e9afe7019acba5cda926f13e06df9930571611729d2f2e8ce41956e1f5e1db6f data/valid_params_128/bsk.cbor
27+
eadf2eff35133ffba075df11faecddd6e7af9ddc398011ec4568e5528812b3e2 data/toy_params/lwe_b.cbor
28+
ee9fcf45f1379ca3a7d7bf2b0e7a1cc920ceb496c0217e8604b0b58d2831749e data/toy_params/small_lwe_secret_key.cbor

apps/test-vectors/data/README.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Test vectors for TFHE
2+
These test vectors are generated using [TFHE-rs](https://github.com/zama-ai/tfhe-rs), with the git tag `tfhe-test-vectors-0.1.0`.
3+
4+
They are TFHE-rs objects serialized in the [cbor format](https://cbor.io/). You can deserialize them using any cbor library for the language of your choice. For example, using the [cbor2](https://pypi.org/project/cbor2/) program, run: `cbor2 --pretty toy_params/lwe_a.cbor`.
5+
6+
You will find 2 folders with test vectors for different parameter sets:
7+
- `valid_params_128`: valid classical PBS parameters using a gaussian noise distribution, providing 128bits of security in the IND-CPA model and a bootstrapping probability of failure of 2^{-64}.
8+
- `toy_params`: insecure parameters that yield smaller values
9+
10+
The values are generated for the keyswitch -> bootstrap (KS-PBS) atomic pattern. The cleartext inputs are 2 values, A and B defined below.
11+
12+
All the random values are generated from a fixed seed, that can be found in the `RAND_SEED` constant below. The PRNG used is the one based on the AES block cipher in counter mode, from tfhe `tfhe-csprng` crate.
13+
14+
The programmable bootstrap is applied twice, with 2 different lut, the identity lut and a specific one (currently a x2 operation)
15+
16+
## Vectors
17+
The following values are generated:
18+
19+
### Keys
20+
| name | description | TFHE-rs type |
21+
|------------------------|---------------------------------------------------------------------------------------|-----------------------------|
22+
| `large_lwe_secret_key` | Encryption secret key, before the KS and after the PBS | `LweSecretKey<Vec<u64>>` |
23+
| `small_lwe_secret_key` | Secret key encrypting ciphertexts between the KS and the PBS | `LweSecretKey<Vec<u64>>` |
24+
| `ksk` | The keyswitching key to convert a ct from the large key to the small one | `LweKeyswitchKey<Vec<u64>>` |
25+
| `bsk` | the bootstrapping key to perform a programmable bootstrap on the keyswitched ciphertext | `LweBootstrapKey<Vec<u64>>` |
26+
27+
28+
### Ciphertexts
29+
| name | description | TFHE-rs type | Cleartext |
30+
|----------------------|--------------------------------------------------------------------------------------------------------------|----------------------------|--------------|
31+
| `lwe_a` | Lwe encryption of A | `LweCiphertext<Vec<u64>>` | `A` |
32+
| `lwe_b` | Lwe encryption of B | `LweCiphertext<Vec<u64>>` | `B` |
33+
| `lwe_sum` | Lwe encryption of A plus lwe encryption of B | `LweCiphertext<Vec<u64>>` | `A+B` |
34+
| `lwe_prod` | Lwe encryption of A times cleartext B | `LweCiphertext<Vec<u64>>` | `A*B` |
35+
| `lwe_ms` | The lwe ciphertext after the modswitch part of the PBS ([note](#non-native-encoding)) | `LweCiphertext<Vec<u64>>` | `A` |
36+
| `lwe_ks` | The lwe ciphertext after the keyswitch | `LweCiphertext<Vec<u64>>` | `A` |
37+
| `glwe_after_id_br` | The glwe returned by the application of the identity blind rotation on the mod switched ciphertexts. | `GlweCiphertext<Vec<u64>>` | rot id LUT |
38+
| `lwe_after_id_pbs` | The lwe returned by the application of the sample extract operation on the output of the id blind rotation | `LweCiphertext<Vec<u64>>` | `A` |
39+
| `glwe_after_spec_br` | The glwe returned by the application of the spec blind rotation on the mod switched ciphertexts. | `GlweCiphertext<Vec<u64>>` | rot spec LUT |
40+
| `lwe_after_spec_pbs` | The lwe returned by the application of the sample extract operation on the output of the spec blind rotation | `LweCiphertext<Vec<u64>>` | `spec(A)` |
41+
42+
### Encodings
43+
#### Non native encoding
44+
Warning: TFHE-rs uses a specific encoding for non native (ie: u32, u64) power of two ciphertext modulus. This encoding puts the encoded value in the high bits of the native integer.
45+
For example, the value 37 with a modulus of 64 will be encoded as `0b1001010000000000000000000000000000000000000000000000000000000000`. This matters for the post modswitch lwe ciphertext.
46+
47+
#### Ciphertext modulus
48+
The ciphertext modulus encoding use a specific value for the native modulus: 0. For example, if values are stored on u64 integers, 0 means a ciphertext modulus of 2^64.
49+
50+
## Operations
51+
52+
| name | inputs | outputs |
53+
|-------------------------|-------------------------------------------------------------------|------------------------|
54+
| large secret key gen | PARAMS, RAND_SEED | `large_lwe_secret_key` |
55+
| small secret key gen | PARAMS, RAND_SEED | `small_lwe_secret_key` |
56+
| keyswitch key gen | PARAMS, RAND_SEED, `large_lwe_secret_key`, `small_lwe_secret_key` | `ksk` |
57+
| bootstrap key gen | PARAMS, RAND_SEED, `small_lwe_secret_key`, `large_lwe_secret_key` | `bsk` |
58+
| encryption A | A, `large_lwe_secret_key` | `lwe_a` |
59+
| encryption B | B, `large_lwe_secret_key` | `lwe_b` |
60+
| `E(A)+E(B)` | `lwe_a`, `lwe_b` | `lwe_sum` |
61+
| `E(A)*B` | `lwe_a`, B | `lwe_prod` |
62+
| keyswitch | `lwe_a`, `ksk` | `lwe_ks` |
63+
| modulus switch | `lwe_ks` | `lwe_ms` |
64+
| blind rotation id lut | ID_LUT, `lwe_ms`, `bsk` | `glwe_after_id_br` |
65+
| sample extract id lut | `glwe_after_id_br` | `lwe_after_id_pbs` |
66+
| blind rotation spec lut | SPEC_LUT, `lwe_ms`, `bsk` | `glwe_after_spec_br` |
67+
| sample extract spec lut | `glwe_after_spec_br` | `lwe_after_spec_pbs` |
68+
69+
## Parameters
70+
71+
```rust
72+
const RAND_SEED: u128 = 0x74666865;
73+
74+
const MSG_A: u64 = 4;
75+
const MSG_B: u64 = 3;
76+
77+
const VALID_LWE_DIMENSION: LweDimension = LweDimension(833);
78+
const VALID_GLWE_DIMENSION: GlweDimension = GlweDimension(1);
79+
const VALID_POLYNOMIAL_SIZE: PolynomialSize = PolynomialSize(2048);
80+
const VALID_GAUSSIAN_LWE_NOISE_STDDEV: f64 = 3.6158408373309336e-06;
81+
const VALID_GAUSSIAN_GLWE_NOISE_STDDEV: f64 = 2.845267479601915e-15;
82+
const VALID_PBS_DECOMPOSITION_BASE_LOG: DecompositionBaseLog = DecompositionBaseLog(23);
83+
const VALID_PBS_DECOMPOSITION_LEVEL_COUNT: DecompositionLevelCount = DecompositionLevelCount(1);
84+
const VALID_KS_DECOMPOSITION_BASE_LOG: DecompositionBaseLog = DecompositionBaseLog(3);
85+
const VALID_KS_DECOMPOSITION_LEVEL_COUNT: DecompositionLevelCount = DecompositionLevelCount(5);
86+
87+
const TOY_LWE_DIMENSION: LweDimension = LweDimension(10);
88+
const TOY_GLWE_DIMENSION: GlweDimension = GlweDimension(1);
89+
const TOY_POLYNOMIAL_SIZE: PolynomialSize = PolynomialSize(256);
90+
const TOY_GAUSSIAN_LWE_NOISE_STDDEV: f64 = 0.;
91+
const TOY_GAUSSIAN_GLWE_NOISE_STDDEV: f64 = 0.;
92+
const TOY_PBS_DECOMPOSITION_BASE_LOG: DecompositionBaseLog = DecompositionBaseLog(24);
93+
const TOY_PBS_DECOMPOSITION_LEVEL_COUNT: DecompositionLevelCount = DecompositionLevelCount(1);
94+
const TOY_KS_DECOMPOSITION_BASE_LOG: DecompositionBaseLog = DecompositionBaseLog(37);
95+
const TOY_KS_DECOMPOSITION_LEVEL_COUNT: DecompositionLevelCount = DecompositionLevelCount(1);
96+
97+
const CIPHERTEXT_MODULUS: CiphertextModulus<u64> = CiphertextModulus::new_native();
98+
const MSG_BITS: usize = 4;
99+
100+
const SPEC_LUT: fn(u64) -> u64 = |x| (x * 2) % (1u64 << MSG_BITS);
101+
const ID_LUT: fn(u64) -> u64 = |x| x;
102+
```
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:7cc6803f5fbc3d5a1bf597f2b979ce17eecd3d6baca12183dea21022a7b65c52
3+
size 92291
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:36c9080b636475fcacca503ce041bbfeee800fd3e1890dee559ea18defff9fe8
3+
size 4679
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:2abec9dc5d399ece68ac227f67f7cafcb9a6acac36ed734fe3d5244021eb1cda
3+
size 4679
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:377761beeb4216cf5aa2624a8b64b8259f5a75c32d28e850be8bced3a0cdd6f5
3+
size 25451

0 commit comments

Comments
 (0)