Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proactive refresh #413

Merged
merged 10 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 7 additions & 103 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions crypto/kvdb/src/kv_manager/value.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{convert::TryFrom, path::PathBuf};

use entropy_protocol::{KeyParams, PartyId};
use entropy_protocol::PartyId;
use serde::{Deserialize, Serialize};
use synedrion::KeyShare;
use synedrion::{KeyShare, ProductionParams};
use tracing::{info, span, Level, Span};
use zeroize::Zeroize;

Expand All @@ -24,7 +24,7 @@ pub struct Entropy(pub Vec<u8>);
pub struct PartyInfo {
// TODO: in the future this will probably be a mapping {party_id: [share_id, share_id, ...]}
pub party_ids: Vec<PartyId>,
pub share: KeyShare<KeyParams>,
pub share: KeyShare<ProductionParams>,
}

/// Kv manager for grpc services
Expand Down
92 changes: 90 additions & 2 deletions crypto/protocol/src/execute_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use subxt::utils::AccountId32;
use subxt_signer::sr25519;
use synedrion::{
sessions::{
make_interactive_signing_session, make_keygen_and_aux_session, FinalizeOutcome,
PrehashedMessage, ToSend,
make_interactive_signing_session, make_key_refresh_session, make_keygen_and_aux_session,
FinalizeOutcome, PrehashedMessage, ToSend,
},
signature::{
self,
Expand Down Expand Up @@ -245,3 +245,91 @@ pub async fn execute_dkg(
}
}
}

/// Execute proactive refresh.
#[instrument(skip(chans, threshold_signer))]
pub async fn execute_proactive_refresh(
mut chans: Channels,
threshold_signer: &sr25519::Keypair,
threshold_accounts: Vec<AccountId32>,
my_idx: &u8,
old_key: KeyShare<KeyParams>,
) -> Result<KeyShare<KeyParams>, ProtocolExecutionErr> {
let party_ids: Vec<PartyId> =
threshold_accounts.clone().into_iter().map(PartyId::new).collect();
let my_id = PartyId::new(threshold_accounts[*my_idx as usize].clone());
let id_to_index = party_ids
.iter()
.enumerate()
.map(|(idx, id)| (id, PartyIdx::from_usize(idx)))
.collect::<HashMap<_, _>>();

let tx = &chans.0;
let rx = &mut chans.1;

let signer = SignerWrapper(threshold_signer.clone());
// TODO (#376): while `Public::from_raw` happens to work here, it is not the correct way.
// We should have `Public` objects at this point, not `AccountId32`.
let verifiers = threshold_accounts
.into_iter()
.map(|acc| VerifierWrapper(sr25519::PublicKey(acc.0)))
.collect::<Vec<_>>();

// TODO (#375): this should come from whoever initiates the signing process,
// (or as some deterministic function, e.g. the hash of the last block mined)
// and be the same for all participants.
let shared_randomness = b"123456";

let mut sending = make_key_refresh_session(
&mut OsRng,
shared_randomness,
signer,
&verifiers,
PartyIdx::from_usize(*my_idx as usize),
)
.map_err(ProtocolExecutionErr::SessionCreationError)?;
let key_change = loop {
let (mut receiving, to_send) =
sending.start_receiving(&mut OsRng).map_err(ProtocolExecutionErr::SynedrionSession)?;

match to_send {
ToSend::Broadcast(message) => {
tx.send(ProtocolMessage::new_bcast(&my_id, message))?;
},
ToSend::Direct(msgs) =>
for (id_to, message) in msgs.into_iter() {
tx.send(ProtocolMessage::new_p2p(
&my_id,
&party_ids[id_to.as_usize()],
message,
))?;
},
};

while receiving.has_cached_messages() {
receiving.receive_cached_message().map_err(ProtocolExecutionErr::SynedrionSession)?;
}

while !receiving.can_finalize() {
let signing_message = rx.recv().await.ok_or_else(|| {
ProtocolExecutionErr::IncomingStream(format!("{:?}", receiving.current_stage()))
})?;

// TODO: we shouldn't send broadcasts to ourselves in the first place.
if signing_message.from == my_id {
continue;
}
let from_idx = id_to_index[&signing_message.from];
receiving
.receive(from_idx, signing_message.payload)
.map_err(ProtocolExecutionErr::SynedrionSession)?;
}

match receiving.finalize(&mut OsRng).map_err(ProtocolExecutionErr::SynedrionSession)? {
FinalizeOutcome::Result(res) => break res,
FinalizeOutcome::AnotherRound(new_sending) => sending = new_sending,
}
};

Ok(old_key.update(key_change))
}
Binary file modified crypto/server/entropy_metadata.scale
Binary file not shown.
8 changes: 3 additions & 5 deletions crypto/server/src/helpers/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,11 @@ pub async fn do_signing(
let info =
SignInit::new(message.clone(), sig_hash.clone(), tx_id.clone(), user_address.clone())?;
let signing_service = ThresholdSigningService::new(state, kv_manager);
let signer =
get_signer(kv_manager).await.map_err(|_| ProtocolErr::UserError("Error getting Signer"))?;
let signer = get_signer(kv_manager).await.map_err(|e| ProtocolErr::UserError(e.to_string()))?;

let x25519_secret_key = derive_static_secret(signer.signer());
let subxt_signer = get_subxt_signer(kv_manager)
.await
.map_err(|_| ProtocolErr::UserError("Error getting Signer"))?;
let subxt_signer =
get_subxt_signer(kv_manager).await.map_err(|e| ProtocolErr::UserError(e.to_string()))?;

let account_id = AccountId32(subxt_signer.public_key().0);

Expand Down
15 changes: 15 additions & 0 deletions crypto/server/src/helpers/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use entropy_protocol::{
KeyParams, ValidatorInfo,
};
use entropy_shared::{KeyVisibility, SETUP_TIMEOUT_SECONDS};
use parity_scale_codec::Encode;
use sp_core::crypto::AccountId32;
use subxt::{
ext::sp_core::{sr25519, Bytes},
Expand Down Expand Up @@ -134,3 +135,17 @@ pub async fn send_key(
}
Ok(())
}

/// Checks if a validator is in the current selected registration committee
pub fn check_in_registration_group(
validators_info: &[entropy_shared::ValidatorInfo],
validator_address: &SubxtAccountId32,
) -> Result<(), UserErr> {
let is_proper_signer = validators_info
.iter()
.any(|validator_info| validator_info.tss_account == validator_address.encode());
if !is_proper_signer {
return Err(UserErr::InvalidSigner("Invalid Signer in Signing group"));
}
Ok(())
}
5 changes: 3 additions & 2 deletions crypto/server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ async fn main() {
}
// TODO: find a proper batch size
let batch_size = 10;
let key_amount = 10_000;
let signer = get_signer(&kv_store).await.expect("Issue acquiring threshold signer key");
let has_fee_balance = check_balance_for_fees(&api, signer.account_id(), MIN_BALANCE)
.await
Expand All @@ -199,15 +200,14 @@ async fn main() {
let ip_address =
String::from_utf8(key_server_info.endpoint).expect("failed to parse IP address.");
let recip_key = x25519_dalek::PublicKey::from(key_server_info.x25519_public_key);
let all_keys = get_all_keys(&api, batch_size).await.expect("failed to get all keys.");
let all_keys = get_all_keys(&api, key_amount).await.expect("failed to get all keys.");
let _ = get_and_store_values(
all_keys, &kv_store, ip_address, batch_size, args.dev, &recip_key, &signer,
)
.await;
tell_chain_syncing_is_done(&api, &signer).await.expect("failed to finish chain sync.");
}

// TODO: unhardcode endpoint
let addr = SocketAddr::from_str(&args.threshold_url).expect("failed to parse threshold url.");
tracing::info!("listening on {}", addr);
axum::Server::bind(&addr)
Expand All @@ -221,6 +221,7 @@ pub fn app(app_state: AppState) -> Router {
.route("/user/sign_tx", post(sign_tx))
.route("/user/new", post(new_user))
.route("/user/receive_key", post(receive_key))
.route("/signer/proactive_refresh", post(proactive_refresh))
.route("/validator/sync_kvdb", post(sync_kvdb))
.route("/healthz", get(healthz))
.route("/ws", get(ws_handler));
Expand Down
Loading