Skip to content

Commit 3547c87

Browse files
committed
chore: remove existing_epoch_id
1 parent 8c2e872 commit 3547c87

16 files changed

Lines changed: 812 additions & 337 deletions

File tree

core-client/src/keygen.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ pub(crate) async fn do_keygen(
111111
.existing_keyset_id
112112
.map(|id| kms_grpc::kms::v1::KeySetAddedInfo {
113113
existing_keyset_id: Some(id.into()),
114-
existing_epoch_id: shared_config.existing_epoch_id.map(Into::into),
115114
use_existing_key_tag: shared_config.use_existing_key_tag,
116115
..Default::default()
117116
});

core-client/src/lib.rs

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -615,9 +615,6 @@ pub struct SharedKeyGenParameters {
615615
/// instead of running full distributed keygen.
616616
#[clap(long)]
617617
pub existing_keyset_id: Option<RequestId>,
618-
/// Epoch ID for the existing keyset (optional, defaults to the request's epoch).
619-
#[clap(long)]
620-
pub existing_epoch_id: Option<EpochId>,
621618
/// Reuse the tag from the existing keyset instead of using the new key ID as tag.
622619
/// This is only used when generating a key from existing shares.
623620
#[clap(long, default_value_t = false)]
@@ -1263,16 +1260,16 @@ pub async fn fetch_ctxt_from_file(
12631260
/// compressed storage or the legacy uncompressed layout.
12641261
///
12651262
/// If `uncompressed_keys` is explicitly `true`, fetches `[PublicKey, ServerKey]` only.
1266-
/// Otherwise, tries `[CompressedXofKeySet]` first; on failure, falls back to
1267-
/// `[PublicKey, ServerKey]`.
1263+
/// Otherwise, tries the current compressed layout `[CompressedXofKeySet, PublicKey]`
1264+
/// first; on failure, falls back to the legacy `[PublicKey, ServerKey]`.
12681265
/// Returns the fetched party confs and a boolean indicating whether uncompressed keys were found.
12691266
async fn fetch_keys_auto_detect(
12701267
key_id: &str,
12711268
uncompressed_keys: bool,
12721269
cc_conf: &CoreClientConfig,
12731270
destination_prefix: &Path,
12741271
) -> anyhow::Result<(Vec<CoreConf>, bool)> {
1275-
let compressed_key_types = vec![PubDataType::CompressedXofKeySet];
1272+
let compressed_key_types = vec![PubDataType::CompressedXofKeySet, PubDataType::PublicKey];
12761273
let key_types = vec![PubDataType::PublicKey, PubDataType::ServerKey];
12771274

12781275
if uncompressed_keys {
@@ -1293,7 +1290,7 @@ async fn fetch_keys_auto_detect(
12931290
Ok(confs) => Ok((confs, false)),
12941291
Err(_) => {
12951292
tracing::info!(
1296-
"CompressedXofKeySet not found, trying legacy [PublicKey, ServerKey]..."
1293+
"Compressed layout [CompressedXofKeySet, PublicKey] not found, trying legacy [PublicKey, ServerKey]..."
12971294
);
12981295
let confs =
12991296
fetch_public_elements(key_id, &key_types, cc_conf, destination_prefix, false)
@@ -2387,7 +2384,13 @@ fn print_timings(cmd: &str, durations: &mut [tokio::time::Duration], start: toki
23872384
#[cfg(test)]
23882385
mod tests {
23892386
use super::*;
2387+
use kms_lib::engine::base::derive_request_id;
2388+
use kms_lib::util::key_setup::test_tools::load_pk_from_pub_storage;
2389+
use kms_lib::vault::storage::{StorageType, file::FileStorage, store_versioned_at_request_id};
23902390
use std::env;
2391+
use tempfile::tempdir;
2392+
use tfhe::core_crypto::prelude::NormalizedHammingWeightBound;
2393+
use tfhe::xof_key_set::CompressedXofKeySet;
23912394

23922395
#[test]
23932396
fn test_parse_hex() {
@@ -2563,4 +2566,120 @@ mod tests {
25632566
);
25642567
assert!(PreviousEpochParameters::from_str(&input_string).is_err());
25652568
}
2569+
2570+
#[tokio::test]
2571+
async fn fetch_keys_auto_detect_downloads_public_key_for_compressed_layout() {
2572+
let remote_root = tempdir().unwrap();
2573+
let destination_root = tempdir().unwrap();
2574+
let object_folder = "PUB-p1";
2575+
let key_id = derive_request_id("fetch_keys_auto_detect_downloads_public_key").unwrap();
2576+
2577+
let params = kms_lib::consts::TEST_PARAM;
2578+
let config = params.to_tfhe_config();
2579+
let max_norm_hwt = params
2580+
.get_params_basics_handle()
2581+
.get_sk_deviations()
2582+
.map(|x| x.pmax)
2583+
.unwrap_or(1.0);
2584+
let max_norm_hwt = NormalizedHammingWeightBound::new(max_norm_hwt).unwrap();
2585+
let (_client_key, compressed_keyset) = CompressedXofKeySet::generate(
2586+
config,
2587+
vec![1, 2, 3, 4],
2588+
params.get_params_basics_handle().get_sec() as u32,
2589+
max_norm_hwt,
2590+
key_id.into(),
2591+
)
2592+
.unwrap();
2593+
let (public_key, _server_key) = compressed_keyset
2594+
.clone()
2595+
.decompress()
2596+
.unwrap()
2597+
.into_raw_parts();
2598+
2599+
let mut remote_storage = FileStorage::new(
2600+
Some(remote_root.path()),
2601+
StorageType::PUB,
2602+
Some(object_folder),
2603+
)
2604+
.unwrap();
2605+
store_versioned_at_request_id(
2606+
&mut remote_storage,
2607+
&key_id,
2608+
&compressed_keyset,
2609+
&PubDataType::CompressedXofKeySet.to_string(),
2610+
)
2611+
.await
2612+
.unwrap();
2613+
store_versioned_at_request_id(
2614+
&mut remote_storage,
2615+
&key_id,
2616+
&public_key,
2617+
&PubDataType::PublicKey.to_string(),
2618+
)
2619+
.await
2620+
.unwrap();
2621+
2622+
let cc_conf = CoreClientConfig {
2623+
kms_type: KmsType::Threshold,
2624+
cores: vec![CoreConf {
2625+
party_id: 1,
2626+
address: "127.0.0.1:0".to_string(),
2627+
s3_endpoint: format!("file://{}", remote_root.path().display()),
2628+
object_folder: object_folder.to_string(),
2629+
#[cfg(feature = "testing")]
2630+
private_object_folder: None,
2631+
#[cfg(feature = "testing")]
2632+
config_path: None,
2633+
}],
2634+
decryption_mode: None,
2635+
num_majority: 1,
2636+
num_reconstruct: 1,
2637+
fhe_params: Some(FheParameter::Test),
2638+
};
2639+
2640+
let (party_confs, detected_uncompressed) = fetch_keys_auto_detect(
2641+
&key_id.to_string(),
2642+
false,
2643+
&cc_conf,
2644+
destination_root.path(),
2645+
)
2646+
.await
2647+
.unwrap();
2648+
2649+
assert_eq!(party_confs.len(), 1);
2650+
assert!(
2651+
!detected_uncompressed,
2652+
"compressed layout should not fall back to legacy uncompressed keys"
2653+
);
2654+
2655+
let downloaded_pk_path = destination_root
2656+
.path()
2657+
.join(object_folder)
2658+
.join(PubDataType::PublicKey.to_string())
2659+
.join(key_id.to_string());
2660+
assert!(
2661+
downloaded_pk_path.exists(),
2662+
"compressed auto-detect should download the authoritative standalone PublicKey"
2663+
);
2664+
2665+
let _downloaded_pk =
2666+
load_pk_from_pub_storage(Some(destination_root.path()), &key_id, Some(object_folder))
2667+
.await;
2668+
let (ciphertext, _format, _fhe_type) = compute_cipher_from_stored_key(
2669+
Some(destination_root.path()),
2670+
TestingPlaintext::U8(42),
2671+
&key_id,
2672+
Some(object_folder),
2673+
EncryptionConfig {
2674+
compression: true,
2675+
precompute_sns: false,
2676+
},
2677+
false,
2678+
)
2679+
.await;
2680+
assert!(
2681+
!ciphertext.is_empty(),
2682+
"encryption should succeed from freshly fetched compressed key material"
2683+
);
2684+
}
25662685
}

core-client/src/mpc_epoch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ pub(crate) async fn do_new_epoch(
261261

262262
let (party_confs_successful, is_compressed) = match fetch_public_elements(
263263
&key_id.to_string(),
264-
&[PubDataType::CompressedXofKeySet],
264+
&[PubDataType::CompressedXofKeySet, PubDataType::PublicKey],
265265
cc_conf,
266266
destination_prefix,
267267
true,

core-client/tests/integration/integration_test.rs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use kms_lib::engine::base::derive_request_id;
2222
use kms_lib::engine::base::safe_serialize_hash_element_versioned;
2323
use kms_lib::util::key_setup::test_tools::load_material_from_pub_storage;
2424
use serial_test::serial;
25-
use std::fs::create_dir_all;
25+
use std::fs::{create_dir_all, remove_file};
2626
use std::io::Write;
2727
use std::path::Path;
2828
use std::path::PathBuf;
@@ -1791,7 +1791,6 @@ async fn test_threshold_mpc_context_switch_6(ctx: &DockerComposeThresholdTestNoI
17911791
epoch_id: Some(epoch_id_2),
17921792
uncompressed: false,
17931793
existing_keyset_id: None,
1794-
existing_epoch_id: None,
17951794
use_existing_key_tag: false,
17961795
extra_data: None,
17971796
},
@@ -1889,10 +1888,39 @@ async fn test_threshold_reshare(ctx: &DockerComposeThresholdTestNoInitSixParty)
18891888
.build()
18901889
.init_conf()
18911890
.unwrap();
1891+
let clear_local_public_key_cache = |cc_conf: &CoreClientConfig, key_id: &str| {
1892+
for core in &cc_conf.cores {
1893+
let path = test_path
1894+
.join(&core.object_folder)
1895+
.join(PubDataType::PublicKey.to_string())
1896+
.join(key_id);
1897+
if path.exists() {
1898+
remove_file(&path).unwrap();
1899+
}
1900+
assert!(
1901+
!path.exists(),
1902+
"expected no cached PublicKey at {:?} before exercising fresh download",
1903+
path
1904+
);
1905+
}
1906+
};
1907+
let assert_some_public_key_cached = |cc_conf: &CoreClientConfig, key_id: &str| {
1908+
assert!(
1909+
cc_conf.cores.iter().any(|core| {
1910+
test_path
1911+
.join(&core.object_folder)
1912+
.join(PubDataType::PublicKey.to_string())
1913+
.join(key_id)
1914+
.exists()
1915+
}),
1916+
"expected at least one PublicKey artifact to be downloaded for key {}",
1917+
key_id
1918+
);
1919+
};
18921920

18931921
let party_confs = fetch_public_elements(
18941922
&key_id,
1895-
&[PubDataType::CompressedXofKeySet],
1923+
&[PubDataType::CompressedXofKeySet, PubDataType::PublicKey],
18961924
&cc_conf,
18971925
test_path,
18981926
false,
@@ -1931,6 +1959,8 @@ async fn test_threshold_reshare(ctx: &DockerComposeThresholdTestNoInitSixParty)
19311959
let crs_digest =
19321960
hex::encode(safe_serialize_hash_element_versioned(&DSEP_PUBDATA_CRS, &crs).unwrap());
19331961

1962+
clear_local_public_key_cache(&cc_conf, &key_id.to_string());
1963+
19341964
// create and store second mpc context
19351965
// create and store mpc context
19361966
println!("Creating second MPC context");
@@ -1982,6 +2012,15 @@ async fn test_threshold_reshare(ctx: &DockerComposeThresholdTestNoInitSixParty)
19822012
};
19832013
let result = execute_cmd(&epoch_config, test_path).await.unwrap();
19842014
println!("Resharing completed successfully {:?}", result);
2015+
assert_some_public_key_cached(&cc_conf, &key_id.to_string());
2016+
2017+
let cc_conf_set_2: CoreClientConfig = observability::conf::Settings::builder()
2018+
.path(config_path_set_2.to_str().unwrap())
2019+
.env_prefix("CORE_CLIENT")
2020+
.build()
2021+
.init_conf()
2022+
.unwrap();
2023+
clear_local_public_key_cache(&cc_conf_set_2, &key_id.to_string());
19852024

19862025
// Try and do a decrypt with the new set and new epoch
19872026
let ddec_command = CCCommand::PublicDecrypt(CipherArguments::FromArgs(CipherParameters {
@@ -2012,6 +2051,7 @@ async fn test_threshold_reshare(ctx: &DockerComposeThresholdTestNoInitSixParty)
20122051

20132052
let result = execute_cmd(&ddec_config, test_path).await.unwrap();
20142053
println!("Decrypt in reshared context succeeded : {:?}", result);
2054+
assert_some_public_key_cached(&cc_conf_set_2, &key_id.to_string());
20152055

20162056
// Delete the old epoch and verify it's gone
20172057
println!("Destroying old epoch");
@@ -2026,7 +2066,6 @@ async fn test_threshold_reshare(ctx: &DockerComposeThresholdTestNoInitSixParty)
20262066
epoch_id: Some(epoch_id_set_1),
20272067
uncompressed: false,
20282068
existing_keyset_id: None,
2029-
existing_epoch_id: None,
20302069
use_existing_key_tag: false,
20312070
extra_data: None,
20322071
},

core-client/tests/integration/integration_test_isolated.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3284,7 +3284,7 @@ async fn test_threshold_reshare() -> Result<()> {
32843284

32853285
let ids = fetch_public_elements(
32863286
&key_id_str,
3287-
&[PubDataType::CompressedXofKeySet],
3287+
&[PubDataType::CompressedXofKeySet, PubDataType::PublicKey],
32883288
&cc_conf,
32893289
test_path,
32903290
false,
@@ -3350,6 +3350,28 @@ async fn test_threshold_reshare() -> Result<()> {
33503350

33513351
info!("Resharing result: {:?}", resharing_result);
33523352
assert_eq!(resharing_result.len(), 2);
3353+
let ddec_config = cmd_config(
3354+
&config_path,
3355+
CCCommand::PublicDecrypt(CipherArguments::FromArgs(CipherParameters {
3356+
to_encrypt: "0x123456".to_string(),
3357+
data_type: FheType::Euint64,
3358+
no_compression: false,
3359+
no_precompute_sns: true,
3360+
key_id: KeyId::from_str(&key_id.to_string()).unwrap(),
3361+
context_id: Some(context_id),
3362+
epoch_id: Some(new_epoch_id),
3363+
batch_size: 1,
3364+
num_requests: 1,
3365+
ciphertext_output_path: None,
3366+
parallel_requests: 1,
3367+
inter_request_delay_ms: 0,
3368+
uncompressed_keys: false,
3369+
extra_data: None,
3370+
})),
3371+
200,
3372+
);
3373+
let decrypt_result = execute_cmd(&ddec_config, test_path).await.unwrap();
3374+
info!("Decrypt in reshared epoch succeeded: {:?}", decrypt_result);
33533375

33543376
// The second element is the previous epoch_id used for reshare
33553377
assert_eq!(resharing_result[1].0.unwrap(), epoch_id.into());

core/grpc/proto/kms.v1.proto

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,6 @@ message KeySetAddedInfo {
5454
// Must be set if KeyGenSecretKeyConfig::UseExisting is used
5555
RequestId existing_keyset_id = 3;
5656

57-
// Can be set if KeyGenSecretKeyConfig::UseExisting is used,
58-
// if it's not set then the epoch ID from the KeyGenRequest is used.
59-
RequestId existing_epoch_id = 4;
60-
6157
// If true, use the tag from the existing keyset's PublicKeyMaterial
6258
// instead of deriving the tag from the new request ID.
6359
//

core/service/src/client/tests/common.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ pub(crate) fn uncompressed_keygen_config() -> (Option<KeySetConfig>, Option<KeyS
6262
#[cfg(feature = "slow_tests")]
6363
pub(crate) fn keygen_config_from_existing(
6464
existing_keyset_id: &RequestId,
65-
existing_epoch_id: &kms_grpc::identifiers::EpochId,
6665
use_existing_key_tag: bool,
6766
) -> (Option<KeySetConfig>, Option<KeySetAddedInfo>) {
6867
(
@@ -78,7 +77,6 @@ pub(crate) fn keygen_config_from_existing(
7877
from_keyset_id_decompression_only: None,
7978
to_keyset_id_decompression_only: None,
8079
existing_keyset_id: Some((*existing_keyset_id).into()),
81-
existing_epoch_id: Some((*existing_epoch_id).into()),
8280
use_existing_key_tag,
8381
}),
8482
)
@@ -99,7 +97,6 @@ pub(crate) fn decompression_keygen_config(
9997
from_keyset_id_decompression_only: Some((*from_keyset_id).into()),
10098
to_keyset_id_decompression_only: Some((*to_keyset_id).into()),
10199
existing_keyset_id: None,
102-
existing_epoch_id: None,
103100
use_existing_key_tag: false,
104101
}),
105102
)

0 commit comments

Comments
 (0)