Skip to content

Commit

Permalink
Rotate parent netowrk key takes 2 steps
Browse files Browse the repository at this point in the history
  • Loading branch information
JesseAbram committed Aug 21, 2024
1 parent 305c4be commit 160f8a8
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 9 deletions.
3 changes: 3 additions & 0 deletions crates/shared/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ pub const DEVICE_KEY_PROXY: &[u8] = include_bytes!("../device_key_proxy.wasm");
/// Network parent key specific size to fit into [u8; 32] to save extra code
pub const NETWORK_PARENT_KEY: &str = "NETWORK_PARENT_KEY_FOR_ENTROPY_";

// Next Network parent key ready to be swapped in to new one
pub const NEXT_NETWORK_PARENT_KEY: &str = "NEXT_NETWORK_PARENT_KEY";

/// Total signers on the network with the parent key
pub const TOTAL_SIGNERS: u8 = 3;

Expand Down
3 changes: 2 additions & 1 deletion crates/threshold-signature-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ use crate::{
r#unsafe::api::{delete, put, remove_keys, unsafe_get},
signing_client::{api::*, ListenerState},
user::api::*,
validator::api::new_reshare,
validator::api::{new_reshare, rotate_network_key},
};

#[derive(Clone)]
Expand All @@ -180,6 +180,7 @@ pub fn app(app_state: AppState) -> Router {
.route("/user/sign_tx", post(sign_tx))
.route("/signer/proactive_refresh", post(proactive_refresh))
.route("/validator/reshare", post(new_reshare))
.route("/validator/rotate_network_key", post(rotate_network_key))
.route("/attest", post(attest))
.route("/healthz", get(healthz))
.route("/version", get(get_version))
Expand Down
37 changes: 31 additions & 6 deletions crates/threshold-signature-server/src/validator/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub use entropy_protocol::{
execute_protocol::{execute_protocol_generic, execute_reshare, Channels, PairWrapper},
KeyParams, KeyShareWithAuxInfo, Listener, PartyId, SessionId, ValidatorInfo,
};
use entropy_shared::{OcwMessageReshare, NETWORK_PARENT_KEY};
use entropy_shared::{OcwMessageReshare, NETWORK_PARENT_KEY, NEXT_NETWORK_PARENT_KEY};
use parity_scale_codec::{Decode, Encode};
use sp_core::Pair;
use std::{collections::BTreeSet, str::FromStr};
Expand Down Expand Up @@ -176,20 +176,45 @@ pub async fn new_reshare(

let serialized_key_share = key_serialize(&(new_key_share, aux_info))
.map_err(|_| ProtocolErr::KvSerialize("Kv Serialize Error".to_string()))?;
let network_parent_key = hex::encode(NETWORK_PARENT_KEY);
// TODO: should this be a two step process? see # https://github.com/entropyxyz/entropy-core/issues/968
if app_state.kv_store.kv().exists(&network_parent_key).await? {
app_state.kv_store.kv().delete(&network_parent_key).await?
let next_network_parent_key = hex::encode(NEXT_NETWORK_PARENT_KEY);

if app_state.kv_store.kv().exists(&next_network_parent_key).await? {
app_state.kv_store.kv().delete(&next_network_parent_key).await?
};

let reservation = app_state.kv_store.kv().reserve_key(network_parent_key).await?;
let reservation = app_state.kv_store.kv().reserve_key(next_network_parent_key).await?;
app_state.kv_store.kv().put(reservation, serialized_key_share.clone()).await?;

// TODO: Error handling really complex needs to be thought about.
confirm_key_reshare(&api, &rpc, &signer).await?;
Ok(StatusCode::OK)
}

// HTTP POST endpoint called by the off-chain worker (propagation pallet) after network reshare.
///
/// This roatates network key.
#[tracing::instrument(skip_all)]
pub async fn rotate_network_key(
State(app_state): State<AppState>,
) -> Result<StatusCode, ValidatorErr> {
// validate from chain

let network_parent_key_heading = hex::encode(NETWORK_PARENT_KEY);
let next_network_parent_key_heading = hex::encode(NEXT_NETWORK_PARENT_KEY);

let new_parent_key = app_state.kv_store.kv().get(&next_network_parent_key_heading).await?;

if app_state.kv_store.kv().exists(&network_parent_key_heading).await? {
app_state.kv_store.kv().delete(&network_parent_key_heading).await?;
};

app_state.kv_store.kv().delete(&next_network_parent_key_heading).await?;

let reservation = app_state.kv_store.kv().reserve_key(network_parent_key_heading).await?;
app_state.kv_store.kv().put(reservation, new_parent_key).await?;
Ok(StatusCode::OK)
}

// Validates new reshare endpoint
/// Checks the chain for validity of data and block number of data matches current block
pub async fn validate_new_reshare(
Expand Down
26 changes: 24 additions & 2 deletions crates/threshold-signature-server/src/validator/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,31 @@ async fn test_reshare() {
deserialize(&key_share_and_aux_data_after).unwrap();

// Check key share has changed
assert_ne!(serialize(&key_share_before).unwrap(), serialize(&key_share_after).unwrap());
assert_eq!(serialize(&key_share_before).unwrap(), serialize(&key_share_after).unwrap());
// Check aux info has changed
assert_ne!(serialize(&aux_info_before).unwrap(), serialize(&aux_info_after).unwrap());
assert_eq!(serialize(&aux_info_before).unwrap(), serialize(&aux_info_after).unwrap());

let _ = client
.post(format!("http://127.0.0.1:{}/validator/rotate_network_key", validator_ports[i]))
.send()
.await
.unwrap();

let key_share_and_aux_data_after_rotate =
unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), validator_ports[i]).await;
let (key_share_after_rotate, aux_info_after_rotate): KeyShareWithAuxInfo =
deserialize(&key_share_and_aux_data_after_rotate).unwrap();

// Check key share has changed
assert_ne!(
serialize(&key_share_before).unwrap(),
serialize(&key_share_after_rotate).unwrap()
);
// Check aux info has changed
assert_ne!(
serialize(&aux_info_before).unwrap(),
serialize(&aux_info_after_rotate).unwrap()
);
}
// TODO #981 - test signing a message with the new keyshare set
clean_tests();
Expand Down

0 comments on commit 160f8a8

Please sign in to comment.