Skip to content

Commit 28de262

Browse files
committed
feat: memory consumption during keygen
1 parent 33bde3c commit 28de262

File tree

14 files changed

+230
-125
lines changed

14 files changed

+230
-125
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/keys
44
/crs
55
/tls
6+
/test-material
67
.vscode/launch.json
78
.DS_Store
89
.vscode/

Cargo.lock

Lines changed: 39 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ crypto-bigint = { version = "=0.6.1", features = ["serde", "rand_core", "extra-s
115115
ctor = "=0.4.2" # Constructor functions - HIGH RISK: Individual maintainer (mmastrac), test-only dependency
116116
dashmap = "=6.1.0" # Concurrent hashmap - HIGH RISK: Individual maintainer (xacrimon), despite 156M+ downloads
117117
derive_more = { version = "=2.0.1", features = ["display"] } # Derive macros for common traits - HIGH RISK: Individual maintainer (JelteF), despite 180M+ downloads
118+
dhat = "=0.3.3" # Heap profiling - MEDIUM RISK: David Tolnay adjacent (rustacean), useful for memory debugging, dev-only
118119
enum_dispatch = "=0.3.13" # Enum dispatch optimization - HIGH RISK: Individual maintainer (Anton Lazarev), despite 29M+ downloads
119120
futures = "=0.3.31" # Async futures - LOW RISK: rust-lang team
120121
futures-util = "=0.3.31" # Futures utilities - LOW RISK: rust-lang team

core/service/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ cfg-if.workspace = true
6565
ciborium.workspace = true
6666
clap = { workspace = true, features = ["derive"] }
6767
console_error_panic_hook.workspace = true
68+
dhat = { workspace = true, optional = true }
6869
enum_dispatch.workspace = true
6970
futures-util.workspace = true
7071
hex.workspace = true
@@ -181,3 +182,7 @@ insecure = [
181182
"threshold-fhe/testing",
182183
"dep:nsm-nitro-enclave-utils"
183184
]
185+
# Memory profiling feature for debugging memory consumption issues
186+
# Enable with: cargo build --features memory-profiling
187+
# Produces dhat-heap.json file that can be viewed with https://nnethercote.github.io/dh_view/dh_view.html
188+
memory-profiling = ["dep:dhat"]

core/service/src/bin/kms-server.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,18 @@ async fn build_tls_config(
331331
Ok((server_config, client_config, verifier))
332332
}
333333

334+
// Memory profiling with dhat (enable with --features memory-profiling)
335+
// View results at: https://nnethercote.github.io/dh_view/dh_view.html
336+
#[cfg(feature = "memory-profiling")]
337+
#[global_allocator]
338+
static ALLOC: dhat::Alloc = dhat::Alloc;
339+
334340
fn main() -> anyhow::Result<()> {
341+
// Initialize dhat profiler when memory-profiling feature is enabled
342+
// This will produce a dhat-heap.json file on program exit
343+
#[cfg(feature = "memory-profiling")]
344+
let _profiler = dhat::Profiler::new_heap();
345+
335346
let args = KmsArgs::parse();
336347
// NOTE: this config is only needed to set up the tokio runtime
337348
// we read it again in [main_exec] to set up the rest of the server

core/service/src/engine/threshold/service/key_generator.rs

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use crate::{
5454
},
5555
keyset_configuration::InternalKeySetConfig,
5656
threshold::{
57-
service::{session::ImmutableSessionMaker, ThresholdFheKeys},
57+
service::session::ImmutableSessionMaker,
5858
traits::KeyGenerator,
5959
},
6060
utils::MetricedError,
@@ -1092,39 +1092,14 @@ impl<
10921092
}
10931093
};
10941094

1095-
let (integer_server_key, decompression_key, sns_key) = {
1096-
let (
1097-
raw_server_key,
1098-
_raw_ksk_material,
1099-
_raw_compression_key,
1100-
raw_decompression_key,
1101-
raw_noise_squashing_key,
1102-
_raw_noise_squashing_compression_key,
1103-
_raw_rerandomization_key,
1104-
_raw_tag,
1105-
) = pub_key_set.server_key.clone().into_raw_parts();
1106-
(
1107-
raw_server_key,
1108-
raw_decompression_key,
1109-
raw_noise_squashing_key,
1110-
)
1111-
};
1112-
1113-
let threshold_fhe_keys = ThresholdFheKeys {
1114-
private_keys: Arc::new(private_keys),
1115-
integer_server_key: Arc::new(integer_server_key),
1116-
sns_key: sns_key.map(Arc::new),
1117-
decompression_key: decompression_key.map(Arc::new),
1118-
meta_data: info.clone(),
1119-
};
1120-
1121-
//Note: We can't easily check here whether we succeeded writing to the meta store
1122-
//thus we can't increment the error counter if it fails
1095+
// Memory optimization: Storage function now serializes server_key first,
1096+
// then consumes it to extract components. This eliminates the need to clone the large
1097+
// server_key structure (~tens of GiB with production parameters).
11231098
crypto_storage
11241099
.write_threshold_keys_with_dkg_meta_store(
11251100
req_id,
11261101
epoch_id,
1127-
threshold_fhe_keys,
1102+
private_keys,
11281103
pub_key_set,
11291104
info,
11301105
meta_store,

core/service/src/engine/threshold/service/kms_impl.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,5 +770,26 @@ mod tests {
770770

771771
(priv_key_set, pub_key_set)
772772
}
773+
774+
/// Initializes dummy keys for storage tests.
775+
/// Returns (PrivateKeySet, FhePubKeySet) for the new memory-optimized storage API.
776+
pub fn init_dummy_for_storage<R: rand::Rng + rand::CryptoRng>(
777+
param: threshold_fhe::execution::tfhe_internals::parameters::DKGParams,
778+
tag: tfhe::Tag,
779+
rng: &mut R,
780+
) -> (PrivateKeySet<{ ResiduePolyF4Z128::EXTENSION_DEGREE }>, FhePubKeySet) {
781+
let keyset = threshold_fhe::execution::tfhe_internals::test_feature::gen_key_set(
782+
param, tag, rng,
783+
);
784+
785+
let pub_key_set = FhePubKeySet {
786+
public_key: keyset.public_keys.public_key,
787+
server_key: keyset.public_keys.server_key,
788+
};
789+
790+
let priv_key_set = PrivateKeySet::init_dummy(param);
791+
792+
(priv_key_set, pub_key_set)
793+
}
773794
}
774795
}

core/service/src/engine/threshold/service/public_decryptor.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -871,9 +871,9 @@ mod tests {
871871

872872
let key_id = RequestId::new_random(rng);
873873

874-
// make a dummy private keyset
875-
let (threshold_fhe_keys, fhe_key_set) =
876-
ThresholdFheKeys::init_dummy(param, key_id.into(), rng);
874+
// make a dummy private keyset for storage
875+
let (private_keys, fhe_key_set) =
876+
ThresholdFheKeys::init_dummy_for_storage(param, key_id.into(), rng);
877877

878878
// Not a huge deal if we clone this server key since we only use small/test parameters
879879
tfhe::set_server_key(fhe_key_set.server_key.clone());
@@ -912,7 +912,7 @@ mod tests {
912912
.write_threshold_keys_with_dkg_meta_store(
913913
&key_id,
914914
&epoch_id,
915-
threshold_fhe_keys,
915+
private_keys,
916916
fhe_key_set,
917917
info,
918918
Arc::clone(&key_meta_store),

core/service/src/engine/threshold/service/resharer.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
DSEP_PUBDATA_KEY,
77
},
88
threshold::{
9-
service::{session::ImmutableSessionMaker, ThresholdFheKeys},
9+
service::session::ImmutableSessionMaker,
1010
traits::Resharer,
1111
},
1212
utils::MetricedError,
@@ -570,9 +570,6 @@ impl<PubS: Storage + Send + Sync + 'static, PrivS: StorageExt + Send + Sync + 's
570570
)
571571
.await?;
572572

573-
let (integer_server_key, _, _, decompression_key, sns_key, _, _, _) =
574-
fhe_pubkeys.server_key.clone().into_raw_parts();
575-
576573
// Compute all the info required for storing
577574
// using the same IDs and domain as we should've had the
578575
// DKG went through successfully
@@ -594,14 +591,6 @@ impl<PubS: Storage + Send + Sync + 'static, PrivS: StorageExt + Send + Sync + 's
594591
}
595592
};
596593

597-
let threshold_fhe_keys = ThresholdFheKeys {
598-
private_keys: Arc::new(new_private_key_set),
599-
integer_server_key: Arc::new(integer_server_key),
600-
sns_key: sns_key.map(Arc::new),
601-
decompression_key: decompression_key.map(Arc::new),
602-
meta_data: info.clone(),
603-
};
604-
605594
// Purge before we can overwrite, use a dummy_meta_store
606595
// as this was meant to update the meta store of DKG upon failing
607596
let dummy_meta_store = RwLock::new(MetaStore::<KeyGenMetadata>::new(1, 1));
@@ -618,12 +607,14 @@ impl<PubS: Storage + Send + Sync + 'static, PrivS: StorageExt + Send + Sync + 's
618607
// HOTFIX(keygen-recovery): Note that this overwrites the private storage
619608
// at the given key ID. It's needed as long as reshare shortcuts the
620609
// GW, but should be fixed long term.
610+
// Memory optimization: Storage function now handles server_key
611+
// component extraction internally, avoiding the need to clone server_key here.
621612
crypto_storage
622613
.write_threshold_keys_with_reshare_meta_store(
623614
&request_id,
624615
&key_id_to_reshare,
625616
&old_epoch_id,
626-
threshold_fhe_keys,
617+
new_private_key_set,
627618
fhe_pubkeys,
628619
info.clone(),
629620
Arc::clone(&meta_store),

core/service/src/engine/threshold/service/user_decryptor.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -763,9 +763,9 @@ mod tests {
763763
RealUserDecryptor::init_test_dummy_decryptor(base_kms, session_maker.make_immutable())
764764
.await;
765765

766-
// make a dummy private keyset
767-
let (threshold_fhe_keys, fhe_key_set) =
768-
ThresholdFheKeys::init_dummy(param, key_id.into(), rng);
766+
// make a dummy private keyset for storage
767+
let (private_keys, fhe_key_set) =
768+
ThresholdFheKeys::init_dummy_for_storage(param, key_id.into(), rng);
769769

770770
// Not a huge deal if we clone this server key since we only use small/test parameters
771771
tfhe::set_server_key(fhe_key_set.server_key.clone());
@@ -794,7 +794,7 @@ mod tests {
794794
.write_threshold_keys_with_dkg_meta_store(
795795
&key_id,
796796
&epoch_id,
797-
threshold_fhe_keys,
797+
private_keys,
798798
fhe_key_set,
799799
info,
800800
Arc::clone(&key_meta_store),

0 commit comments

Comments
 (0)