@@ -26,7 +26,7 @@ use crate::keygen::{
2626use crate :: mpc_context:: { do_destroy_mpc_context, do_new_mpc_context} ;
2727use crate :: mpc_epoch:: { do_destroy_mpc_epoch, do_new_epoch} ;
2828use aes_prng:: AesRng ;
29- use clap:: { Args , Parser , Subcommand , ValueEnum } ;
29+ use clap:: { Args , Parser , Subcommand } ;
3030use core:: str;
3131use kms_grpc:: identifiers:: EpochId ;
3232use kms_grpc:: kms:: v1:: { CiphertextFormat , FheParameter , TypedCiphertext , TypedPlaintext } ;
@@ -562,37 +562,19 @@ pub struct CipherWithParams {
562562 cipher : Vec < u8 > ,
563563}
564564
565- /// Keyset type for key generation, matching the KeySetType in the protofile.
566- ///
567- /// It only supports the standard keyset type for now, which is to generate the full keyset
568- /// rather than individual keys from a standard keyset.
569- #[ derive( ValueEnum , Debug , Clone , Default ) ]
570- pub enum KeySetType {
571- #[ default]
572- Standard ,
573- // TODO(#2799)
574- // DecompressionOnly, // we'll support this in the future
575- }
576-
577- impl From < KeySetType > for kms_grpc:: kms:: v1:: KeySetType {
578- fn from ( value : KeySetType ) -> Self {
579- match value {
580- KeySetType :: Standard => kms_grpc:: kms:: v1:: KeySetType :: Standard ,
581- }
582- }
583- }
584-
585565#[ derive( Args , Debug , Clone , Default ) ]
586566pub struct SharedKeyGenParameters {
587- /// Keyset type for key generation (e.g., "standard")
588- #[ clap( value_enum, long, short = 't' ) ]
589- pub keyset_type : Option < KeySetType > ,
590567 /// Generate compressed keys using XOF-seeded compression
591568 #[ clap( long, short = 'c' , default_value_t = false ) ]
592569 pub compressed : bool ,
593- // TODO(#2799)
594- // #[command(flatten)]
595- // pub keyset_added_info: Option<KeySetAddedInfo>,
570+ /// Existing keyset ID to reuse all secret shares from.
571+ /// When set, generates new public keys from existing private key shares
572+ /// instead of running full distributed keygen.
573+ #[ clap( long) ]
574+ pub existing_keyset_id : Option < RequestId > ,
575+ /// Epoch ID for the existing keyset (optional, defaults to the request's epoch).
576+ #[ clap( long) ]
577+ pub existing_epoch_id : Option < EpochId > ,
596578 pub context_id : Option < ContextId > ,
597579 pub epoch_id : Option < EpochId > ,
598580}
@@ -746,6 +728,12 @@ pub struct KeyGenPreprocParameters {
746728 /// Defaults to the default epoch if not specified.
747729 #[ clap( long) ]
748730 pub epoch_id : Option < EpochId > ,
731+ /// Generate compressed keys using XOF-seeded compression
732+ #[ clap( long, short = 'c' , default_value_t = false ) ]
733+ pub compressed : bool ,
734+ /// Do preprocessing that's needed to generate a key from existing shares.
735+ #[ clap( long, default_value_t = false ) ]
736+ pub from_existing_shares : bool ,
749737}
750738
751739#[ derive( Debug , Parser , Clone ) ]
@@ -899,6 +887,51 @@ pub async fn fetch_ctxt_from_file(
899887}
900888
901889/// encrypt a given value and return the ciphertext
890+ /// Try to fetch keys for the given key ID, auto-detecting whether they are regular or compressed.
891+ ///
892+ /// If `compressed_keys` is explicitly `true`, fetches `[CompressedXofKeySet]` only.
893+ /// Otherwise, tries `[PublicKey, ServerKey]` first; on failure, falls back to `[CompressedXofKeySet]`.
894+ /// Returns the fetched party confs and a boolean indicating whether compressed keys were found.
895+ async fn fetch_keys_auto_detect (
896+ key_id : & str ,
897+ compressed_keys : bool ,
898+ cc_conf : & CoreClientConfig ,
899+ destination_prefix : & Path ,
900+ ) -> anyhow:: Result < ( Vec < CoreConf > , bool ) > {
901+ let compressed_key_types = vec ! [ PubDataType :: CompressedXofKeySet ] ;
902+
903+ if compressed_keys {
904+ let confs = fetch_public_elements (
905+ key_id,
906+ & compressed_key_types,
907+ cc_conf,
908+ destination_prefix,
909+ false ,
910+ )
911+ . await ?;
912+ return Ok ( ( confs, true ) ) ;
913+ }
914+
915+ let key_types = vec ! [ PubDataType :: PublicKey , PubDataType :: ServerKey ] ;
916+ match fetch_public_elements ( key_id, & key_types, cc_conf, destination_prefix, false ) . await {
917+ Ok ( confs) => Ok ( ( confs, false ) ) ,
918+ Err ( _) => {
919+ tracing:: info!(
920+ "Regular keys [PublicKey, ServerKey] not found, trying CompressedXofKeySet..."
921+ ) ;
922+ let confs = fetch_public_elements (
923+ key_id,
924+ & compressed_key_types,
925+ cc_conf,
926+ destination_prefix,
927+ false ,
928+ )
929+ . await ?;
930+ Ok ( ( confs, true ) )
931+ }
932+ }
933+ }
934+
902935/// parameters:
903936/// - `keys_folder`: the root of the storage of the core client
904937/// - `party_id`: the 1-indexed ID of the KMS core whose public keys we will use (should not matter as long as the server is online)
@@ -1231,9 +1264,6 @@ pub async fn execute_cmd(
12311264
12321265 let kms_addrs = Arc :: new ( addr_vec) ;
12331266
1234- let key_types = vec ! [ PubDataType :: PublicKey , PubDataType :: ServerKey ] ;
1235- let compressed_key_types = vec ! [ PubDataType :: CompressedXofKeySet ] ;
1236-
12371267 let command_timer_start = tokio:: time:: Instant :: now ( ) ;
12381268 // Execute the command
12391269 let res = match command {
@@ -1257,18 +1287,11 @@ pub async fn execute_cmd(
12571287 }
12581288 CipherArguments :: FromArgs ( cipher_parameters) => {
12591289 //Only need to fetch tfhe keys if we are not sourcing the ctxt from file
1260- let fetch_types = if cipher_parameters. compressed_keys {
1261- & compressed_key_types
1262- } else {
1263- & key_types
1264- } ;
1265- tracing:: info!( "Fetching keys {fetch_types:?}. ({command:?})" ) ;
1266- let party_confs = fetch_public_elements (
1290+ let ( party_confs, detected_compressed) = fetch_keys_auto_detect (
12671291 & cipher_parameters. key_id . as_str ( ) ,
1268- fetch_types ,
1292+ cipher_parameters . compressed_keys ,
12691293 & cc_conf,
12701294 destination_prefix,
1271- false ,
12721295 )
12731296 . await ?;
12741297 let storage_prefix = Some (
@@ -1280,12 +1303,9 @@ pub async fn execute_cmd(
12801303 . object_folder
12811304 . as_str ( ) ,
12821305 ) ;
1283- encrypt (
1284- destination_prefix,
1285- storage_prefix,
1286- cipher_parameters. clone ( ) ,
1287- )
1288- . await ?
1306+ let mut cipher_parameters = cipher_parameters. clone ( ) ;
1307+ cipher_parameters. compressed_keys = detected_compressed;
1308+ encrypt ( destination_prefix, storage_prefix, cipher_parameters) . await ?
12891309 }
12901310 } ;
12911311
@@ -1342,18 +1362,11 @@ pub async fn execute_cmd(
13421362 }
13431363 CipherArguments :: FromArgs ( cipher_parameters) => {
13441364 //Only need to fetch tfhe keys if we are not sourcing the ctxt from file
1345- let fetch_types = if cipher_parameters. compressed_keys {
1346- & compressed_key_types
1347- } else {
1348- & key_types
1349- } ;
1350- tracing:: info!( "Fetching keys {fetch_types:?}. ({command:?})" ) ;
1351- let party_confs = fetch_public_elements (
1365+ let ( party_confs, detected_compressed) = fetch_keys_auto_detect (
13521366 & cipher_parameters. key_id . as_str ( ) ,
1353- fetch_types ,
1367+ cipher_parameters . compressed_keys ,
13541368 & cc_conf,
13551369 destination_prefix,
1356- false ,
13571370 )
13581371 . await ?;
13591372 let storage_prefix = Some (
@@ -1365,13 +1378,9 @@ pub async fn execute_cmd(
13651378 . object_folder
13661379 . as_str ( ) ,
13671380 ) ;
1368-
1369- encrypt (
1370- destination_prefix,
1371- storage_prefix,
1372- cipher_parameters. clone ( ) ,
1373- )
1374- . await ?
1381+ let mut cipher_parameters = cipher_parameters. clone ( ) ;
1382+ cipher_parameters. compressed_keys = detected_compressed;
1383+ encrypt ( destination_prefix, storage_prefix, cipher_parameters) . await ?
13751384 }
13761385 } ;
13771386
@@ -1505,10 +1514,13 @@ pub async fn execute_cmd(
15051514 CCCommand :: PreprocKeyGen ( KeyGenPreprocParameters {
15061515 context_id,
15071516 epoch_id,
1517+ compressed,
1518+ from_existing_shares,
15081519 } ) => {
15091520 let mut internal_client = internal_client. unwrap ( ) ;
15101521 tracing:: info!( "Preprocessing with parameter {}." , fhe_params. as_str_name( ) ) ;
15111522
1523+ let keyset_config = keygen:: build_keyset_config ( * compressed, * from_existing_shares) ;
15121524 let req_id = do_preproc (
15131525 & mut internal_client,
15141526 & core_endpoints_req,
@@ -1518,6 +1530,7 @@ pub async fn execute_cmd(
15181530 fhe_params,
15191531 context_id. as_ref ( ) ,
15201532 epoch_id. as_ref ( ) ,
1533+ keyset_config,
15211534 )
15221535 . await ?;
15231536 vec ! [ ( Some ( req_id) , "preproc done" . to_string( ) ) ]
@@ -1554,13 +1567,11 @@ pub async fn execute_cmd(
15541567 vec ! [ ( None , String :: new( ) ) ]
15551568 }
15561569 CCCommand :: Encrypt ( cipher_parameters) => {
1557- tracing:: info!( "Fetching keys {key_types:?}. ({command:?})" ) ;
1558- let party_confs = fetch_public_elements (
1570+ let ( party_confs, detected_compressed) = fetch_keys_auto_detect (
15591571 & cipher_parameters. key_id . as_str ( ) ,
1560- & key_types ,
1572+ cipher_parameters . compressed_keys ,
15611573 & cc_conf,
15621574 destination_prefix,
1563- false ,
15641575 )
15651576 . await ?;
15661577 let storage_prefix = Some (
@@ -1572,12 +1583,9 @@ pub async fn execute_cmd(
15721583 . object_folder
15731584 . as_str ( ) ,
15741585 ) ;
1575- encrypt (
1576- destination_prefix,
1577- storage_prefix,
1578- cipher_parameters. clone ( ) ,
1579- )
1580- . await ?;
1586+ let mut cipher_parameters = cipher_parameters. clone ( ) ;
1587+ cipher_parameters. compressed_keys = detected_compressed;
1588+ encrypt ( destination_prefix, storage_prefix, cipher_parameters) . await ?;
15811589 vec ! [ ( None , "Encryption generated" . to_string( ) ) ]
15821590 }
15831591 CCCommand :: PreprocKeyGenResult ( result_parameters) => {
0 commit comments