docs: add UpgradeKeyChain

This commit is contained in:
tmontaigu
2025-07-15 11:06:29 +02:00
parent c7785b7214
commit 82cc9d3884
3 changed files with 93 additions and 0 deletions

View File

@@ -53,6 +53,7 @@
* [Zero-knowledge proofs](fhe-computation/advanced-features/zk-pok.md)
* [Multi-threading with Rayon crate](fhe-computation/advanced-features/rayon-crate.md)
* [Noise squashing](fhe-computation/advanced-features/noise-squashing.md)
* [Key upgrade](fhe-computation/advanced-features/upgrade-key-chain.md)
* [Tooling](fhe-computation/tooling/README.md)
* [PBS statistics](fhe-computation/tooling/pbs-stats.md)
* [Generic trait bounds](fhe-computation/tooling/trait-bounds.md)

View File

@@ -0,0 +1,88 @@
# Upgrade Key Chain
This document describes how one can use the `UpgradeKeyChain` to be able to
easily upgrade a ciphertext that is under older parameters to newer parameters.
It is different and complementary to the data versioning feature, as the
data versioning feature allows loading ciphertexts generated
with a previous TFHE-rs version if the ciphertext structurally changed.
The `UpgradeKeyChain` first needs to know about possible parameters, for that,
`add_key_set` should be called with all the different server keys.
Note that the `Tag` of the keys is used to differentiate them.
Then, the `UpgradeKeyChain` requires upgrade keys to be able to upgrade ciphertexts,
there are two types of these keys:
- `KeySwitchingKey` to upgrade a FheUint/FheInt/FheBool to another FheUint/FheInt/FheBool with different parameters
- `DecompressionUpgradeKey` to upgrade ciphertexts from a `CompressedCiphertextList` to FheUint/FheInt/FheBool with different parameters
```rust
use tfhe::shortint::parameters::{
COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
};
use tfhe::prelude::*;
use tfhe::{ConfigBuilder, set_server_key, ServerKey, ClientKey, FheUint32, KeySwitchingKey, Device};
use tfhe::upgrade::UpgradeKeyChain;
fn main() {
let compute_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let compression_parameters = COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128;
let config = ConfigBuilder::with_custom_parameters(compute_params)
.enable_compression(compression_parameters)
.build();
let (cks_1, sks_1) = {
let mut ck = ClientKey::generate(config);
ck.tag_mut().set_u64(1);
let sk = ServerKey::new(&ck);
(ck, sk)
};
let (cks_2, sks_2) = {
let mut ck = ClientKey::generate(config);
ck.tag_mut().set_u64(2);
let sk = ServerKey::new(&ck);
(ck, sk)
};
// Create a ksk that upgrades from the first key, to the second key
let ksk = KeySwitchingKey::with_parameters(
(&cks_1, &sks_1),
(&cks_2, &sks_2),
PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
);
let mut upgrader = UpgradeKeyChain::default();
// First, add the server keys
// to register the different possible parameters
upgrader.add_key_set(&sks_1);
upgrader.add_key_set(&sks_2);
// Add our upgrade key
upgrader.add_upgrade_key(ksk).unwrap();
let clear_a = rand::random::<u32>();
let clear_b = rand::random::<u32>();
let a = FheUint32::encrypt(clear_a, &cks_1);
let b = FheUint32::encrypt(clear_b, &cks_1);
let upgraded_a = upgrader
.upgrade(&a, sks_2.tag(), Device::Cpu)
.unwrap();
let upgraded_b = upgrader
.upgrade(&b, sks_2.tag(), Device::Cpu)
.unwrap();
set_server_key(sks_2.clone());
let c = upgraded_a + upgraded_b;
let dc: u32 = c.decrypt(&cks_2);
assert_eq!(dc, clear_a.wrapping_add(clear_b));
}
```

View File

@@ -46,6 +46,10 @@ mod test_cpu_doc {
"../docs/fhe-computation/advanced-features/zk-pok.md",
advanced_features_zk_pok
);
doctest!(
"../docs/fhe-computation/advanced-features/upgrade-key-chain.md",
upgrade_key_chain
);
// COMPUTE
doctest!(