From 6d9bc302ff20871faca849ed9131e2daeda8e1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 24 Jan 2024 10:34:42 +0000 Subject: [PATCH] more completed key finalization --- nym-api/src/coconut/dkg/controller/error.rs | 3 +- nym-api/src/coconut/dkg/controller/mod.rs | 2 +- nym-api/src/coconut/dkg/key_derivation.rs | 327 +------------------ nym-api/src/coconut/dkg/key_finalization.rs | 45 ++- nym-api/src/coconut/dkg/mod.rs | 333 +++++++++++++++++++- nym-api/src/coconut/dkg/state/mod.rs | 25 +- nym-api/src/coconut/keys/mod.rs | 2 +- nym-api/src/coconut/tests/helpers.rs | 4 +- 8 files changed, 391 insertions(+), 350 deletions(-) diff --git a/nym-api/src/coconut/dkg/controller/error.rs b/nym-api/src/coconut/dkg/controller/error.rs index 0a6816698f..97a24fa325 100644 --- a/nym-api/src/coconut/dkg/controller/error.rs +++ b/nym-api/src/coconut/dkg/controller/error.rs @@ -1,6 +1,7 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only +use crate::coconut::dkg::key_finalization::KeyFinalizationError; use crate::coconut::error::CoconutError; use std::path::PathBuf; use thiserror::Error; @@ -56,7 +57,7 @@ pub enum DkgError { #[error("failed to finalize verification keys in the DKG contract: {source}")] VerificationKeyFinalizationFailure { #[source] - source: CoconutError, + source: KeyFinalizationError, }, #[error("failed to advance the DKG state: {source}")] diff --git a/nym-api/src/coconut/dkg/controller/mod.rs b/nym-api/src/coconut/dkg/controller/mod.rs index fc739243f3..9cd9bf7ca5 100644 --- a/nym-api/src/coconut/dkg/controller/mod.rs +++ b/nym-api/src/coconut/dkg/controller/mod.rs @@ -172,7 +172,7 @@ impl DkgController { ) -> Result<(), DkgError> { debug!("DKG: verification key finalization (resharing: {resharing})"); - self.verification_key_finalization(epoch_id, resharing) + self.verification_key_finalization(epoch_id) .await .map_err(|source| DkgError::VerificationKeyFinalizationFailure { source }) } diff --git a/nym-api/src/coconut/dkg/key_derivation.rs b/nym-api/src/coconut/dkg/key_derivation.rs index e2da91fd3d..94dacd54e4 100644 --- a/nym-api/src/coconut/dkg/key_derivation.rs +++ b/nym-api/src/coconut/dkg/key_derivation.rs @@ -484,6 +484,7 @@ impl DkgController { // check if we have already generated the new keys and submitted verification proposal if key_generation_state.completed() { // TODO: ASSERT: we have a VALID key + // TODO: ASSERT we have a valid proposal id // the only way this could be a false positive is if the chain forked and blocks got reverted, // but I don't think we have to worry about that @@ -505,6 +506,7 @@ impl DkgController { .await?; if maybe_share.is_some() { todo!("finalize, we're done") + // TODO: recover proposal id with some weird queries } // ASSUMPTION: @@ -527,7 +529,8 @@ impl DkgController { todo!() } - let proposal_id = self.submit_partial_verification_key(coconut_keypair.keys.verification_key(), resharing) + let proposal_id = self + .submit_partial_verification_key(coconut_keypair.keys.verification_key(), resharing) .await?; self.state.set_coconut_keypair(coconut_keypair).await; @@ -1009,326 +1012,4 @@ pub(crate) mod tests { Ok(()) } - - #[tokio::test] - #[ignore] // expensive test - async fn reshare_preserves_keys() { - todo!() - // let db = MockContractDb::new(); - // let mut clients_and_states = prepare_clients_and_states_with_finalization(&db).await; - // for controller in clients_and_states.iter_mut() { - // controller.state.set_was_in_progress(); - // } - // - // let mut vks = vec![]; - // let mut indices = vec![]; - // for controller in clients_and_states.iter() { - // let vk = controller - // .state - // .coconut_keypair() - // .await - // .as_ref() - // .unwrap() - // .keys - // .verification_key() - // .clone(); - // let index = controller.state.node_index().unwrap(); - // vks.push(vk); - // indices.push(index); - // } - // let initial_master_vk = aggregate_verification_keys(&vks, Some(&indices)).unwrap(); - // - // let new_dkg_client = DkgClient::new( - // DummyClient::new( - // AccountId::from_str("n1sqkxzh7nl6kgndr4ew9795t2nkwmd8tpql67q7").unwrap(), - // ) - // .with_dealer_details(&db.dealer_details_db) - // .with_dealings(&db.dealings_db) - // .with_proposal_db(&db.proposal_db) - // .with_verification_share(&db.verification_share_db) - // .with_threshold(&db.threshold_db) - // .with_initial_dealers_db(&db.initial_dealers_db), - // ); - // let keypair = DkgKeyPair::new(dkg::params(), OsRng); - // let identity_keypair = identity::KeyPair::new(&mut thread_rng()); - // let state = State::new( - // PathBuf::default(), - // PersistentState::default(), - // Url::parse("localhost:8000").unwrap(), - // keypair, - // *identity_keypair.public_key(), - // KeyPair::new(), - // ); - // - // for (_, active) in db.dealer_details_db.write().unwrap().values_mut() { - // *active = false; - // } - // - // *db.dealings_db.write().unwrap() = Default::default(); - // *db.verification_share_db.write().unwrap() = Default::default(); - // let mut initial_dealers = vec![]; - // for controller in clients_and_states.iter() { - // let client_address = - // Addr::unchecked(controller.dkg_client.get_address().await.as_ref()); - // initial_dealers.push(client_address); - // } - // *db.initial_dealers_db.write().unwrap() = Some(InitialReplacementData { - // initial_dealers, - // initial_height: 1, - // }); - // *clients_and_states.first_mut().unwrap() = DkgController::test_mock(new_dkg_client, state); - // - // for controller in clients_and_states.iter_mut() { - // controller.public_key_submission(0, true).await.unwrap(); - // controller.dealing_exchange(0, true).await.unwrap(); - // } - // - // for controller in clients_and_states.iter_mut() { - // let random_file: usize = OsRng.gen(); - // let keypath = temp_dir().join(format!("coconut{}.pem", random_file)); - // verification_key_submission( - // &controller.dkg_client, - // &mut controller.state, - // 0, - // &keypath, - // true, - // ) - // .await - // .unwrap(); - // std::fs::remove_file(keypath).unwrap(); - // } - // for controller in clients_and_states.iter_mut() { - // verification_key_validation(&controller.dkg_client, &mut controller.state, true) - // .await - // .unwrap(); - // } - // for controller in clients_and_states.iter_mut() { - // verification_key_finalization(&controller.dkg_client, &mut controller.state, true) - // .await - // .unwrap(); - // } - // assert!(db - // .proposal_db - // .read() - // .unwrap() - // .values() - // .all(|proposal| { proposal.status == Status::Executed })); - // - // let mut vks = vec![]; - // let mut indices = vec![]; - // for controller in clients_and_states.iter() { - // let vk = controller - // .state - // .coconut_keypair() - // .await - // .as_ref() - // .unwrap() - // .keys - // .verification_key() - // .clone(); - // let index = controller.state.node_index().unwrap(); - // vks.push(vk); - // indices.push(index); - // } - // let reshared_master_vk = aggregate_verification_keys(&vks, Some(&indices)).unwrap(); - // assert_eq!(initial_master_vk, reshared_master_vk); - } - - #[tokio::test] - #[ignore] // expensive test - async fn reshare_after_reset() { - todo!() - // let db = MockContractDb::new(); - // let mut clients_and_states = prepare_clients_and_states_with_finalization(&db).await; - // for controller in clients_and_states.iter_mut() { - // controller.state.set_was_in_progress(); - // } - // - // let new_dkg_client = DkgClient::new( - // DummyClient::new( - // AccountId::from_str("n1vxkywf9g4cg0k2dehanzwzz64jw782qm0kuynf").unwrap(), - // ) - // .with_dealer_details(&db.dealer_details_db) - // .with_dealings(&db.dealings_db) - // .with_proposal_db(&db.proposal_db) - // .with_verification_share(&db.verification_share_db) - // .with_threshold(&db.threshold_db) - // .with_initial_dealers_db(&db.initial_dealers_db), - // ); - // let keypair = DkgKeyPair::new(dkg::params(), OsRng); - // let identity_keypair = identity::KeyPair::new(&mut thread_rng()); - // let state = State::new( - // PathBuf::default(), - // PersistentState::default(), - // Url::parse("localhost:8000").unwrap(), - // keypair, - // *identity_keypair.public_key(), - // KeyPair::new(), - // ); - // let new_dkg_client2 = DkgClient::new( - // DummyClient::new( - // AccountId::from_str("n1sqkxzh7nl6kgndr4ew9795t2nkwmd8tpql67q7").unwrap(), - // ) - // .with_dealer_details(&db.dealer_details_db) - // .with_dealings(&db.dealings_db) - // .with_proposal_db(&db.proposal_db) - // .with_verification_share(&db.verification_share_db) - // .with_threshold(&db.threshold_db) - // .with_initial_dealers_db(&db.initial_dealers_db), - // ); - // let keypair = DkgKeyPair::new(dkg::params(), OsRng); - // let identity_keypair = identity::KeyPair::new(&mut thread_rng()); - // let state2 = State::new( - // PathBuf::default(), - // PersistentState::default(), - // Url::parse("localhost:8000").unwrap(), - // keypair, - // *identity_keypair.public_key(), - // KeyPair::new(), - // ); - // - // for (_, active) in db.dealer_details_db.write().unwrap().values_mut() { - // *active = false; - // } - // - // *db.dealings_db.write().unwrap() = Default::default(); - // *db.verification_share_db.write().unwrap() = Default::default(); - // clients_and_states.pop().unwrap(); - // let controller2 = clients_and_states.pop().unwrap(); - // clients_and_states.push(DkgController::test_mock(new_dkg_client, state)); - // clients_and_states.push(DkgController::test_mock(new_dkg_client2, state2)); - // - // // DKG in reset mode - // for controller in clients_and_states.iter_mut() { - // controller.public_key_submission(0, false).await.unwrap(); - // } - // for controller in clients_and_states.iter_mut() { - // controller.dealing_exchange(0, false).await.unwrap(); - // } - // for controller in clients_and_states.iter_mut() { - // let random_file: usize = OsRng.gen(); - // let keypath = temp_dir().join(format!("coconut{}.pem", random_file)); - // verification_key_submission( - // &controller.dkg_client, - // &mut controller.state, - // 0, - // &keypath, - // false, - // ) - // .await - // .unwrap(); - // std::fs::remove_file(keypath).unwrap(); - // } - // for controller in clients_and_states.iter_mut() { - // verification_key_validation(&controller.dkg_client, &mut controller.state, false) - // .await - // .unwrap(); - // } - // for controller in clients_and_states.iter_mut() { - // verification_key_finalization(&controller.dkg_client, &mut controller.state, false) - // .await - // .unwrap(); - // } - // assert!(db - // .proposal_db - // .read() - // .unwrap() - // .values() - // .all(|proposal| { proposal.status == Status::Executed })); - // for controller in clients_and_states.iter_mut() { - // controller.state.set_was_in_progress(); - // } - // - // // DKG in reshare mode - // let mut vks = vec![]; - // let mut indices = vec![]; - // for controller in clients_and_states.iter() { - // let vk = controller - // .state - // .coconut_keypair() - // .await - // .as_ref() - // .unwrap() - // .keys - // .verification_key() - // .clone(); - // let index = controller.state.node_index().unwrap(); - // vks.push(vk); - // indices.push(index); - // } - // let initial_master_vk = aggregate_verification_keys(&vks, Some(&indices)).unwrap(); - // - // for (_, active) in db.dealer_details_db.write().unwrap().values_mut() { - // *active = false; - // } - // *db.dealings_db.write().unwrap() = Default::default(); - // *db.verification_share_db.write().unwrap() = Default::default(); - // let mut initial_dealers = vec![]; - // for controller in clients_and_states.iter() { - // let client_address = - // Addr::unchecked(controller.dkg_client.get_address().await.as_ref()); - // initial_dealers.push(client_address); - // } - // *db.initial_dealers_db.write().unwrap() = Some(InitialReplacementData { - // initial_dealers, - // initial_height: 1, - // }); - // *clients_and_states.last_mut().unwrap() = controller2; - // - // for controller in clients_and_states.iter_mut() { - // controller.public_key_submission(0, true).await.unwrap(); - // controller.dealing_exchange(0, true).await.unwrap(); - // } - // - // for controller in clients_and_states.iter_mut() { - // let random_file: usize = OsRng.gen(); - // let keypath = temp_dir().join(format!("coconut{}.pem", random_file)); - // verification_key_submission( - // &controller.dkg_client, - // &mut controller.state, - // 0, - // &keypath, - // true, - // ) - // .await - // .unwrap(); - // std::fs::remove_file(keypath).unwrap(); - // } - // - // for controller in clients_and_states.iter_mut() { - // verification_key_validation(&controller.dkg_client, &mut controller.state, true) - // .await - // .unwrap(); - // } - // for controller in clients_and_states.iter_mut() { - // verification_key_finalization(&controller.dkg_client, &mut controller.state, true) - // .await - // .unwrap(); - // } - // // assert!(db - // // .proposal_db - // // .read() - // // .unwrap() - // // .values() - // // .all(|proposal| { proposal.status == Status::Executed })); - // - // let mut vks = vec![]; - // let mut indices = vec![]; - // for controller in clients_and_states.iter() { - // let vk = controller - // .state - // .coconut_keypair() - // .await - // .as_ref() - // .unwrap() - // .keys - // .verification_key() - // .clone(); - // let index = controller.state.node_index().unwrap(); - // vks.push(vk); - // indices.push(index); - // } - // let reshared_master_vk = aggregate_verification_keys(&vks, Some(&indices)).unwrap(); - // assert_eq!(initial_master_vk, reshared_master_vk); - } } diff --git a/nym-api/src/coconut/dkg/key_finalization.rs b/nym-api/src/coconut/dkg/key_finalization.rs index 9135d01939..65f4e39425 100644 --- a/nym-api/src/coconut/dkg/key_finalization.rs +++ b/nym-api/src/coconut/dkg/key_finalization.rs @@ -1,20 +1,33 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use crate::coconut::dkg::client::DkgClient; use crate::coconut::dkg::controller::DkgController; -use crate::coconut::dkg::state::{ConsistentState, State}; use crate::coconut::error::CoconutError; use cw3::Status; use nym_coconut_dkg_common::types::EpochId; use rand::{CryptoRng, RngCore}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum KeyFinalizationError { + #[error(transparent)] + CoconutError(#[from] CoconutError), + + #[error("our proposal for key verification is still open (or is pending) (proposal id: {proposal_id}) ")] + UnresolvedProposal { proposal_id: u64 }, + + #[error("our proposal for key verification has been rejected (proposal id: {proposal_id})")] + RejectedProposal { proposal_id: u64 }, + + #[error("can't complete key finalization without key validation")] + IncompleteKeyValidation, +} impl DkgController { pub(crate) async fn verification_key_finalization( &mut self, epoch_id: EpochId, - _resharing: bool, - ) -> Result<(), CoconutError> { + ) -> Result<(), KeyFinalizationError> { let key_finalization_state = self.state.key_finalization_state(epoch_id)?; // check if we have already executed our own proposal @@ -25,6 +38,10 @@ impl DkgController { return Ok(()); } + if !self.state.key_validation_state(epoch_id)?.completed { + return Err(KeyFinalizationError::IncompleteKeyValidation); + } + let proposal_id = self.state.proposal_id(epoch_id)?; // check whether our key has already been verified with executed proposal, @@ -32,34 +49,42 @@ impl DkgController { // or by another party let status = self.dkg_client.get_proposal_status(proposal_id).await?; match status { + // if the proposal hasn't been resolved, there's not much we can do but wait and pray Status::Pending | Status::Open => { + // 'theoretically' it's possible that more votes are going to come in, but it's very unlikely warn!("our proposal ({proposal_id}) still hasn't received enough votes to get accepted"); - todo!(); + return Err(KeyFinalizationError::UnresolvedProposal { proposal_id }); } + // if the proposal has been rejected, there's nothing we can do, we failed the DKG Status::Rejected => { - // TODO: technically there's nothing enforcing this... + // technically there's nothing enforcing this, so as long as our keys have been properly generated + // (even though they've been rejected by other parties), they could still issue [cryptographically] valid credentials error!("our key verification proposal ({proposal_id}) has been rejected - we can't use our derived keys!"); - todo!() + self.state.key_finalization_state_mut(epoch_id)?.completed = true; + return Err(KeyFinalizationError::RejectedProposal { proposal_id }); } + // if the proposal has passed, execute it to finalize our key Status::Passed => { self.dkg_client .execute_verification_key_share(proposal_id) .await?; } + // if they proposal has already been executed, we're done! Status::Executed => { + // generally each dealer is responsible for executing its own proposals, + // but technically there's nothing preventing other dealers from executing them debug!("our dkg proposal has already been executed"); } } self.state.key_finalization_state_mut(epoch_id)?.completed = true; + self.state.validate_coconut_keypair(); info!("DKG: Finalized own verification key on chain"); Ok(()) } } -// each dealer is responsible for executing its own proposals - #[cfg(test)] mod tests { use super::*; @@ -84,7 +109,7 @@ mod tests { validate_keys(&mut controllers, false).await; for controller in controllers.iter_mut() { - let res = controller.verification_key_finalization(epoch, false).await; + let res = controller.verification_key_finalization(epoch).await; assert!(res.is_ok()); assert!(controller.state.key_finalization_state(epoch)?.completed); diff --git a/nym-api/src/coconut/dkg/mod.rs b/nym-api/src/coconut/dkg/mod.rs index ad4ab16290..2b36d467a6 100644 --- a/nym-api/src/coconut/dkg/mod.rs +++ b/nym-api/src/coconut/dkg/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2022 - Nym Technologies SA +// Copyright 2022-2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only use std::sync::OnceLock; @@ -13,7 +13,334 @@ pub(crate) mod complaints; pub(crate) mod controller; pub(crate) mod dealing; pub(crate) mod key_derivation; -mod key_finalization; -mod key_validation; +pub(crate) mod key_finalization; +pub(crate) mod key_validation; pub(crate) mod public_key; pub(crate) mod state; + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + #[ignore] // expensive test + async fn reshare_preserves_keys() { + todo!() + // let db = MockContractDb::new(); + // let mut clients_and_states = prepare_clients_and_states_with_finalization(&db).await; + // for controller in clients_and_states.iter_mut() { + // controller.state.set_was_in_progress(); + // } + // + // let mut vks = vec![]; + // let mut indices = vec![]; + // for controller in clients_and_states.iter() { + // let vk = controller + // .state + // .coconut_keypair() + // .await + // .as_ref() + // .unwrap() + // .keys + // .verification_key() + // .clone(); + // let index = controller.state.node_index().unwrap(); + // vks.push(vk); + // indices.push(index); + // } + // let initial_master_vk = aggregate_verification_keys(&vks, Some(&indices)).unwrap(); + // + // let new_dkg_client = DkgClient::new( + // DummyClient::new( + // AccountId::from_str("n1sqkxzh7nl6kgndr4ew9795t2nkwmd8tpql67q7").unwrap(), + // ) + // .with_dealer_details(&db.dealer_details_db) + // .with_dealings(&db.dealings_db) + // .with_proposal_db(&db.proposal_db) + // .with_verification_share(&db.verification_share_db) + // .with_threshold(&db.threshold_db) + // .with_initial_dealers_db(&db.initial_dealers_db), + // ); + // let keypair = DkgKeyPair::new(dkg::params(), OsRng); + // let identity_keypair = identity::KeyPair::new(&mut thread_rng()); + // let state = State::new( + // PathBuf::default(), + // PersistentState::default(), + // Url::parse("localhost:8000").unwrap(), + // keypair, + // *identity_keypair.public_key(), + // KeyPair::new(), + // ); + // + // for (_, active) in db.dealer_details_db.write().unwrap().values_mut() { + // *active = false; + // } + // + // *db.dealings_db.write().unwrap() = Default::default(); + // *db.verification_share_db.write().unwrap() = Default::default(); + // let mut initial_dealers = vec![]; + // for controller in clients_and_states.iter() { + // let client_address = + // Addr::unchecked(controller.dkg_client.get_address().await.as_ref()); + // initial_dealers.push(client_address); + // } + // *db.initial_dealers_db.write().unwrap() = Some(InitialReplacementData { + // initial_dealers, + // initial_height: 1, + // }); + // *clients_and_states.first_mut().unwrap() = DkgController::test_mock(new_dkg_client, state); + // + // for controller in clients_and_states.iter_mut() { + // controller.public_key_submission(0, true).await.unwrap(); + // controller.dealing_exchange(0, true).await.unwrap(); + // } + // + // for controller in clients_and_states.iter_mut() { + // let random_file: usize = OsRng.gen(); + // let keypath = temp_dir().join(format!("coconut{}.pem", random_file)); + // verification_key_submission( + // &controller.dkg_client, + // &mut controller.state, + // 0, + // &keypath, + // true, + // ) + // .await + // .unwrap(); + // std::fs::remove_file(keypath).unwrap(); + // } + // for controller in clients_and_states.iter_mut() { + // verification_key_validation(&controller.dkg_client, &mut controller.state, true) + // .await + // .unwrap(); + // } + // for controller in clients_and_states.iter_mut() { + // verification_key_finalization(&controller.dkg_client, &mut controller.state, true) + // .await + // .unwrap(); + // } + // assert!(db + // .proposal_db + // .read() + // .unwrap() + // .values() + // .all(|proposal| { proposal.status == Status::Executed })); + // + // let mut vks = vec![]; + // let mut indices = vec![]; + // for controller in clients_and_states.iter() { + // let vk = controller + // .state + // .coconut_keypair() + // .await + // .as_ref() + // .unwrap() + // .keys + // .verification_key() + // .clone(); + // let index = controller.state.node_index().unwrap(); + // vks.push(vk); + // indices.push(index); + // } + // let reshared_master_vk = aggregate_verification_keys(&vks, Some(&indices)).unwrap(); + // assert_eq!(initial_master_vk, reshared_master_vk); + } + + #[tokio::test] + #[ignore] // expensive test + async fn reshare_after_reset() { + todo!() + // let db = MockContractDb::new(); + // let mut clients_and_states = prepare_clients_and_states_with_finalization(&db).await; + // for controller in clients_and_states.iter_mut() { + // controller.state.set_was_in_progress(); + // } + // + // let new_dkg_client = DkgClient::new( + // DummyClient::new( + // AccountId::from_str("n1vxkywf9g4cg0k2dehanzwzz64jw782qm0kuynf").unwrap(), + // ) + // .with_dealer_details(&db.dealer_details_db) + // .with_dealings(&db.dealings_db) + // .with_proposal_db(&db.proposal_db) + // .with_verification_share(&db.verification_share_db) + // .with_threshold(&db.threshold_db) + // .with_initial_dealers_db(&db.initial_dealers_db), + // ); + // let keypair = DkgKeyPair::new(dkg::params(), OsRng); + // let identity_keypair = identity::KeyPair::new(&mut thread_rng()); + // let state = State::new( + // PathBuf::default(), + // PersistentState::default(), + // Url::parse("localhost:8000").unwrap(), + // keypair, + // *identity_keypair.public_key(), + // KeyPair::new(), + // ); + // let new_dkg_client2 = DkgClient::new( + // DummyClient::new( + // AccountId::from_str("n1sqkxzh7nl6kgndr4ew9795t2nkwmd8tpql67q7").unwrap(), + // ) + // .with_dealer_details(&db.dealer_details_db) + // .with_dealings(&db.dealings_db) + // .with_proposal_db(&db.proposal_db) + // .with_verification_share(&db.verification_share_db) + // .with_threshold(&db.threshold_db) + // .with_initial_dealers_db(&db.initial_dealers_db), + // ); + // let keypair = DkgKeyPair::new(dkg::params(), OsRng); + // let identity_keypair = identity::KeyPair::new(&mut thread_rng()); + // let state2 = State::new( + // PathBuf::default(), + // PersistentState::default(), + // Url::parse("localhost:8000").unwrap(), + // keypair, + // *identity_keypair.public_key(), + // KeyPair::new(), + // ); + // + // for (_, active) in db.dealer_details_db.write().unwrap().values_mut() { + // *active = false; + // } + // + // *db.dealings_db.write().unwrap() = Default::default(); + // *db.verification_share_db.write().unwrap() = Default::default(); + // clients_and_states.pop().unwrap(); + // let controller2 = clients_and_states.pop().unwrap(); + // clients_and_states.push(DkgController::test_mock(new_dkg_client, state)); + // clients_and_states.push(DkgController::test_mock(new_dkg_client2, state2)); + // + // // DKG in reset mode + // for controller in clients_and_states.iter_mut() { + // controller.public_key_submission(0, false).await.unwrap(); + // } + // for controller in clients_and_states.iter_mut() { + // controller.dealing_exchange(0, false).await.unwrap(); + // } + // for controller in clients_and_states.iter_mut() { + // let random_file: usize = OsRng.gen(); + // let keypath = temp_dir().join(format!("coconut{}.pem", random_file)); + // verification_key_submission( + // &controller.dkg_client, + // &mut controller.state, + // 0, + // &keypath, + // false, + // ) + // .await + // .unwrap(); + // std::fs::remove_file(keypath).unwrap(); + // } + // for controller in clients_and_states.iter_mut() { + // verification_key_validation(&controller.dkg_client, &mut controller.state, false) + // .await + // .unwrap(); + // } + // for controller in clients_and_states.iter_mut() { + // verification_key_finalization(&controller.dkg_client, &mut controller.state, false) + // .await + // .unwrap(); + // } + // assert!(db + // .proposal_db + // .read() + // .unwrap() + // .values() + // .all(|proposal| { proposal.status == Status::Executed })); + // for controller in clients_and_states.iter_mut() { + // controller.state.set_was_in_progress(); + // } + // + // // DKG in reshare mode + // let mut vks = vec![]; + // let mut indices = vec![]; + // for controller in clients_and_states.iter() { + // let vk = controller + // .state + // .coconut_keypair() + // .await + // .as_ref() + // .unwrap() + // .keys + // .verification_key() + // .clone(); + // let index = controller.state.node_index().unwrap(); + // vks.push(vk); + // indices.push(index); + // } + // let initial_master_vk = aggregate_verification_keys(&vks, Some(&indices)).unwrap(); + // + // for (_, active) in db.dealer_details_db.write().unwrap().values_mut() { + // *active = false; + // } + // *db.dealings_db.write().unwrap() = Default::default(); + // *db.verification_share_db.write().unwrap() = Default::default(); + // let mut initial_dealers = vec![]; + // for controller in clients_and_states.iter() { + // let client_address = + // Addr::unchecked(controller.dkg_client.get_address().await.as_ref()); + // initial_dealers.push(client_address); + // } + // *db.initial_dealers_db.write().unwrap() = Some(InitialReplacementData { + // initial_dealers, + // initial_height: 1, + // }); + // *clients_and_states.last_mut().unwrap() = controller2; + // + // for controller in clients_and_states.iter_mut() { + // controller.public_key_submission(0, true).await.unwrap(); + // controller.dealing_exchange(0, true).await.unwrap(); + // } + // + // for controller in clients_and_states.iter_mut() { + // let random_file: usize = OsRng.gen(); + // let keypath = temp_dir().join(format!("coconut{}.pem", random_file)); + // verification_key_submission( + // &controller.dkg_client, + // &mut controller.state, + // 0, + // &keypath, + // true, + // ) + // .await + // .unwrap(); + // std::fs::remove_file(keypath).unwrap(); + // } + // + // for controller in clients_and_states.iter_mut() { + // verification_key_validation(&controller.dkg_client, &mut controller.state, true) + // .await + // .unwrap(); + // } + // for controller in clients_and_states.iter_mut() { + // verification_key_finalization(&controller.dkg_client, &mut controller.state, true) + // .await + // .unwrap(); + // } + // // assert!(db + // // .proposal_db + // // .read() + // // .unwrap() + // // .values() + // // .all(|proposal| { proposal.status == Status::Executed })); + // + // let mut vks = vec![]; + // let mut indices = vec![]; + // for controller in clients_and_states.iter() { + // let vk = controller + // .state + // .coconut_keypair() + // .await + // .as_ref() + // .unwrap() + // .keys + // .verification_key() + // .clone(); + // let index = controller.state.node_index().unwrap(); + // vks.push(vk); + // indices.push(index); + // } + // let reshared_master_vk = aggregate_verification_keys(&vks, Some(&indices)).unwrap(); + // assert_eq!(initial_master_vk, reshared_master_vk); + } +} diff --git a/nym-api/src/coconut/dkg/state/mod.rs b/nym-api/src/coconut/dkg/state/mod.rs index ecd41024ae..e8c0f9326f 100644 --- a/nym-api/src/coconut/dkg/state/mod.rs +++ b/nym-api/src/coconut/dkg/state/mod.rs @@ -5,6 +5,8 @@ use crate::coconut::dkg::complaints::ComplaintReason; use crate::coconut::dkg::controller::keys::archive_coconut_keypair; use crate::coconut::dkg::state::dealing_exchange::DealingExchangeState; use crate::coconut::dkg::state::key_derivation::KeyDerivationState; +use crate::coconut::dkg::state::key_finalization::FinalizationState; +use crate::coconut::dkg::state::key_validation::ValidationState; use crate::coconut::dkg::state::registration::RegistrationState; use crate::coconut::error::CoconutError; use crate::coconut::keys::{KeyPair as CoconutKeyPair, KeyPairWithEpoch}; @@ -26,8 +28,6 @@ use std::path::{Path, PathBuf}; use time::OffsetDateTime; use tokio::sync::RwLockReadGuard; use url::Url; -use crate::coconut::dkg::state::key_finalization::FinalizationState; -use crate::coconut::dkg::state::key_validation::ValidationState; mod dealing_exchange; mod key_derivation; @@ -246,13 +246,13 @@ impl PersistentState { #[derive(Default)] pub(crate) struct DkgState { pub(crate) registration: RegistrationState, - + pub(crate) dealing_exchange: DealingExchangeState, pub(crate) key_generation: KeyDerivationState, - + pub(crate) key_validation: ValidationState, - + pub(crate) key_finalization: FinalizationState, } @@ -267,7 +267,8 @@ impl DkgState { dkg_participant.address ) } - self.dealing_exchange.dealers + self.dealing_exchange + .dealers .insert(dkg_participant.assigned_index, dkg_participant); } } @@ -524,9 +525,11 @@ impl State { .receiver_index .ok_or(CoconutError::UnavailableReceiverIndex { epoch_id }) } - - pub fn proposal_id(&self, epoch_id: EpochId) -> Result { - self.key_derivation_state(epoch_id)?.proposal_id.ok_or(CoconutError::UnavailableProposalId {epoch_id}) + + pub fn proposal_id(&self, epoch_id: EpochId) -> Result { + self.key_derivation_state(epoch_id)? + .proposal_id + .ok_or(CoconutError::UnavailableProposalId { epoch_id }) } pub fn persistent_state_path(&self) -> &Path { @@ -557,6 +560,10 @@ impl State { self.coconut_keypair.invalidate() } + pub fn validate_coconut_keypair(&self) { + self.coconut_keypair.validate() + } + pub fn get_dealing(&self, epoch_id: EpochId, dealing_index: DealingIndex) -> Option<&Dealing> { self.generated_dealings .get(&epoch_id) diff --git a/nym-api/src/coconut/keys/mod.rs b/nym-api/src/coconut/keys/mod.rs index 605cc1e68a..fa380d4a67 100644 --- a/nym-api/src/coconut/keys/mod.rs +++ b/nym-api/src/coconut/keys/mod.rs @@ -67,7 +67,7 @@ impl KeyPair { self.valid.load(Ordering::SeqCst) } - pub fn enable(&self) { + pub fn validate(&self) { self.valid.store(true, Ordering::SeqCst); } diff --git a/nym-api/src/coconut/tests/helpers.rs b/nym-api/src/coconut/tests/helpers.rs index 165ac46e2b..574577de89 100644 --- a/nym-api/src/coconut/tests/helpers.rs +++ b/nym-api/src/coconut/tests/helpers.rs @@ -125,7 +125,7 @@ pub(crate) async fn validate_keys(controllers: &mut [TestingDkgController], resh guard.dkg_epoch.state = EpochState::VerificationKeyFinalization { resharing } } -pub(crate) async fn finalize(controllers: &mut [TestingDkgController], resharing: bool) { +pub(crate) async fn finalize(controllers: &mut [TestingDkgController]) { let epoch = controllers[0] .chain_state .lock() @@ -135,7 +135,7 @@ pub(crate) async fn finalize(controllers: &mut [TestingDkgController], resharing for controller in controllers.iter_mut() { controller - .verification_key_finalization(epoch, resharing) + .verification_key_finalization(epoch) .await .unwrap(); }