Skip to content

Commit

Permalink
Pregenerate keyshares sets for all possible initial signer comittees (#…
Browse files Browse the repository at this point in the history
…1073)

* Pregenerate keyshares for all combinations of non-signers

* Dont add keyshare for the non-signer

* Tidy how validator names are represented in create-test-keyshares

* Tidy create test keyshares fn

* Rm comment

* Ignore absense of non-signer

* Add publish=false to create-test-keyshares crate

* Readme

* Readme

* Update crates/threshold-signature-server/src/helpers/tests.rs

Co-authored-by: Hernando Castano <[email protected]>

* Minor improvement to create test keyshare crate

---------

Co-authored-by: Hernando Castano <[email protected]>
  • Loading branch information
ameba23 and HCastano authored Oct 1, 2024
1 parent 0b8d54a commit 367fccb
Show file tree
Hide file tree
Showing 57 changed files with 112 additions and 65 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ It is however only intended for use with test networks and has no secure private

Everytime a change to the chain's interface happens, metadata needs to be pulled. You'll need to install Subxt using `cargo install subxt-cli`. Then [run a development chain](#getting-started-with-docker) and then invoke [the `./scripts/pull_entropy_metadata.sh` script](./scripts/pull_entropy_metadata.sh).

## Regenerating test keyshares

To speed up running tests, some tests use pre-generated keyshares rather than running a distributed key generation during the test. If you need to regenerate these keyshares because something has changed in either Synedrion or the identities of the test TS servers, you can run:

```sh
./scripts/create-test-keyshares.sh`
```
from the project root. For an explanation of how the test keyshare sets are structured, see [`create-test-keyshares`](./scripts/create-test-keyshares).
## Support
Need help with something not necessarily related to `entropy-core`?
Expand Down
2 changes: 2 additions & 0 deletions crates/testing-utils/keyshares/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
See [`create-test-keyshares`](../../../scripts/create-test-keyshares) for an explanation of how
these are generated and what the different keyshare sets represent.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
20 changes: 8 additions & 12 deletions crates/testing-utils/src/create_test_keyshares.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,32 @@ use std::collections::BTreeSet;
/// threshold keyshares with auxiliary info
pub async fn create_test_keyshares<Params>(
distributed_secret_key_bytes: [u8; 32],
alice: sr25519::Pair,
bob: sr25519::Pair,
charlie: sr25519::Pair,
signers: [sr25519::Pair; 3],
) -> Vec<(ThresholdKeyShare<Params, PartyId>, AuxInfo<Params, PartyId>)>
where
Params: SchemeParams,
{
let signing_key = SigningKey::from_bytes(&(distributed_secret_key_bytes).into()).unwrap();
let signers = vec![alice.clone(), bob.clone(), charlie.clone()];
let session_id = SessionId::from_seed(b"12345".as_slice());
let all_parties =
signers.iter().map(|pair| PartyId::from(pair.public())).collect::<BTreeSet<_>>();

let mut old_holders = all_parties.clone();
old_holders.remove(&PartyId::from(charlie.clone().public()));
// Remove one member as we initially create 2 of 2 keyshares, then reshare to 2 of 3
old_holders.remove(&PartyId::from(signers[2].public()));

let keyshares =
KeyShare::<Params, PartyId>::new_centralized(&mut OsRng, &old_holders, Some(&signing_key));
let aux_infos = AuxInfo::<Params, PartyId>::new_centralized(&mut OsRng, &all_parties);

let alice_id = PartyId::from(bob.public());
let new_holder = NewHolder {
verifying_key: keyshares[&alice_id].verifying_key(),
verifying_key: keyshares.values().next().unwrap().verifying_key(),
old_threshold: 2,
old_holders,
};

let mut sessions = signers
let mut sessions = signers[..2]
.iter()
.filter(|&pair| pair.public() != charlie.public())
.map(|pair| {
let inputs = KeyResharingInputs {
old_holder: Some(OldHolder {
Expand All @@ -82,7 +78,7 @@ where
})
.collect::<Vec<_>>();

let charlie_session = {
let new_holder_session = {
let inputs = KeyResharingInputs {
old_holder: None,
new_holder: Some(new_holder.clone()),
Expand All @@ -92,14 +88,14 @@ where
make_key_resharing_session(
&mut OsRng,
session_id,
PairWrapper(charlie),
PairWrapper(signers[2].clone()),
&all_parties,
inputs,
)
.unwrap()
};

sessions.push(charlie_session);
sessions.push(new_holder_session);

let new_t_key_shares = run_nodes(sessions).await;

Expand Down
6 changes: 6 additions & 0 deletions crates/threshold-signature-server/src/helpers/launch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ pub enum ValidatorName {
Eve,
}

impl std::fmt::Display for ValidatorName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", format!("{:?}", self).to_lowercase())
}
}

/// Output for --setup-only flag
#[derive(Deserialize, Debug, Clone)]
pub struct SetupOnlyOutput {
Expand Down
35 changes: 16 additions & 19 deletions crates/threshold-signature-server/src/helpers/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,23 +216,14 @@ pub async fn spawn_testing_validators(
}

/// Add the pre-generated test keyshares to a kvdb
async fn put_keyshares_in_db(_index: usize, validator_name: ValidatorName) {
// Eve's keyshares are used as the network parent key
let user_name = "eve";

let string_validator_name = match validator_name {
ValidatorName::Alice => "alice",
ValidatorName::Bob => "bob",
ValidatorName::Charlie => "charlie",
ValidatorName::Dave => "dave",
ValidatorName::Eve => "eve",
};
async fn put_keyshares_in_db(non_signer_name: ValidatorName, validator_name: ValidatorName) {
let keyshare_bytes = {
let project_root = project_root::get_project_root().expect("Error obtaining project root.");
let file_path = project_root.join(format!(
"crates/testing-utils/keyshares/production/{}-keyshare-held-by-{}.keyshare",
user_name, string_validator_name
"crates/testing-utils/keyshares/production/{}/keyshare-held-by-{}.keyshare",
non_signer_name, validator_name
));
println!("File path {:?}", file_path);
std::fs::read(file_path).unwrap()
};

Expand Down Expand Up @@ -299,8 +290,7 @@ pub async fn jump_start_network_with_signer(
let validators_names =
vec![ValidatorName::Alice, ValidatorName::Bob, ValidatorName::Charlie, ValidatorName::Dave];
let mut non_signer = None;
let mut keyshare_index = 0;
for validator_name in validators_names {
for validator_name in validators_names.clone() {
let mnemonic = development_mnemonic(&Some(validator_name));
let (tss_signer, _static_secret) =
get_signer_and_x25519_secret_from_mnemonic(&mnemonic.to_string()).unwrap();
Expand All @@ -310,14 +300,21 @@ pub async fn jump_start_network_with_signer(
// Ignore the error as one confirmation will fail
if submit_transaction(api, rpc, &tss_signer, &jump_start_confirm_request, None)
.await
.is_ok()
.is_err()
{
put_keyshares_in_db(keyshare_index, validator_name).await;
keyshare_index += 1;
} else {
non_signer = Some(validator_name);
}
}
if let Some(non_signer) = non_signer {
for validator_name in validators_names {
if non_signer != validator_name {
put_keyshares_in_db(non_signer, validator_name).await;
}
}
} else {
tracing::error!("Missing non-signer - not storing pre-generated keyshares");
}

non_signer
}

Expand Down
2 changes: 2 additions & 0 deletions scripts/create-test-keyshares/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ homepage ='https://entropy.xyz/'
license ='AGPL-3.0-or-later'
repository ='https://github.com/entropyxyz/entropy-core'
edition ='2021'
publish =false

[dependencies]
entropy-testing-utils={ version="0.2.0-rc.1", path="../../crates/testing-utils" }
tokio ={ version="1.40", features=["macros", "fs", "rt-multi-thread", "io-util", "process"] }
entropy-shared ={ version="0.2.0-rc.1", path="../../crates/shared" }
entropy-kvdb ={ version="0.2.0-rc.1", path="../../crates/kvdb", default-features=false }
sp-core ="31.0.0"

# Unreleased version of Synedrion with support for child key derivations.
synedrion={ git="https://github.com/entropyxyz/synedrion", rev="1d210d149dfeb0dca1dd41d7fac4d0bf03c686fa" }
Expand Down
17 changes: 17 additions & 0 deletions scripts/create-test-keyshares/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# `entropy-create-test-keyshares`

This is used to create sets of pre-generated keyshares. These are used in some of the `entropy-tss`
tests to speed up the test by not needing to run a distributed key generation during the test.

Since keyshares are linked to the identities of the holders, and the initial signer set is selected
randomly during the test, there is one keyshare set generated per possible combination of initial
signers.

Since we have 4 nodes, and 3 signers, we refer to each set by the name of the node who is **not** in
the signer set (which is the one who will act as the relayer node).

So set 'alice' consists of ['bob', 'charlie', 'dave'] and set 'bob' consists of ['alice', 'charlie',
dave'], etc.

There are also different keyshare sets for 'test' or 'production' parameters used by Synedrion. Test
parameters are less secure but mean that the protocols run much faster.
84 changes: 50 additions & 34 deletions scripts/create-test-keyshares/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,60 +17,76 @@
//! The base path for where to store keyshares is given as a single command line argument
//! If it is not given, the current working directory is used
use entropy_kvdb::kv_manager::helpers::serialize;
use entropy_shared::{DETERMINISTIC_KEY_SHARE_DAVE, DETERMINISTIC_KEY_SHARE_EVE};
use entropy_shared::DETERMINISTIC_KEY_SHARE_EVE;
use entropy_testing_utils::create_test_keyshares::create_test_keyshares;
use entropy_tss::helpers::{
launch::{DEFAULT_ALICE_MNEMONIC, DEFAULT_BOB_MNEMONIC, DEFAULT_DAVE_MNEMONIC},
launch::{
ValidatorName, DEFAULT_ALICE_MNEMONIC, DEFAULT_BOB_MNEMONIC, DEFAULT_CHARLIE_MNEMONIC,
DEFAULT_DAVE_MNEMONIC,
},
validator::get_signer_and_x25519_secret_from_mnemonic,
};
use std::{env::args, path::PathBuf};
use sp_core::sr25519;
use std::{env::args, iter::zip, path::PathBuf};
use synedrion::{ProductionParams, TestParams};

#[tokio::main]
async fn main() {
let base_path = PathBuf::from(args().nth(1).unwrap_or_else(|| ".".to_string()));

let (alice_pair, _) =
get_signer_and_x25519_secret_from_mnemonic(DEFAULT_ALICE_MNEMONIC).unwrap();
let (bob_pair, _) = get_signer_and_x25519_secret_from_mnemonic(DEFAULT_BOB_MNEMONIC).unwrap();
let (charlie_pair, _) =
get_signer_and_x25519_secret_from_mnemonic(DEFAULT_DAVE_MNEMONIC).unwrap();
let keypairs_and_names: Vec<_> = [
(DEFAULT_ALICE_MNEMONIC, ValidatorName::Alice),
(DEFAULT_BOB_MNEMONIC, ValidatorName::Bob),
(DEFAULT_CHARLIE_MNEMONIC, ValidatorName::Charlie),
(DEFAULT_DAVE_MNEMONIC, ValidatorName::Dave),
]
.into_iter()
.map(|(mnemonic, name)| {
let (pair, _) = get_signer_and_x25519_secret_from_mnemonic(mnemonic).unwrap();
(pair.signer().clone(), name)
})
.collect();

let names_and_secret_keys =
[("dave", *DETERMINISTIC_KEY_SHARE_DAVE), ("eve", *DETERMINISTIC_KEY_SHARE_EVE)];
let secret_key = *DETERMINISTIC_KEY_SHARE_EVE;

for (name, secret_key) in names_and_secret_keys {
let test_keyshares = create_test_keyshares::<TestParams>(
secret_key,
alice_pair.signer().clone(),
bob_pair.signer().clone(),
charlie_pair.signer().clone(),
)
.await;
let test_keyshres_serialized =
for (_keypair, name) in keypairs_and_names.iter() {
let (keypairs_this_time, names_this_time): (Vec<sr25519::Pair>, Vec<ValidatorName>) =
keypairs_and_names.iter().filter(|(_, n)| n != name).cloned().unzip();

let keypairs_this_time: [sr25519::Pair; 3] = keypairs_this_time
.try_into()
.map_err(|_| "Cannot convert keypair vector to array")
.unwrap();

// Create and write test keyshares
let test_keyshares =
create_test_keyshares::<TestParams>(secret_key, keypairs_this_time.clone()).await;
let test_keyshares_serialized: Vec<_> =
test_keyshares.iter().map(|k| serialize(k).unwrap()).collect();
write_keyshares(base_path.join("test"), name, test_keyshres_serialized).await;
let keyshares_and_names = zip(test_keyshares_serialized, names_this_time.clone()).collect();
write_keyshares(base_path.join("test"), name, keyshares_and_names).await;

let production_keyshares = create_test_keyshares::<ProductionParams>(
secret_key,
alice_pair.signer().clone(),
bob_pair.signer().clone(),
charlie_pair.signer().clone(),
)
.await;
let production_keyshres_serialized =
// Create and write production keyshares
let production_keyshares =
create_test_keyshares::<ProductionParams>(secret_key, keypairs_this_time.clone()).await;
let production_keyshres_serialized: Vec<_> =
production_keyshares.iter().map(|k| serialize(k).unwrap()).collect();
write_keyshares(base_path.join("production"), name, production_keyshres_serialized).await;
let keyshares_and_names = zip(production_keyshres_serialized, names_this_time).collect();
write_keyshares(base_path.join("production"), name, keyshares_and_names).await;
}
}

async fn write_keyshares(base_path: PathBuf, name: &str, keyshares_bytes: Vec<Vec<u8>>) {
let holder_names = ["alice", "bob", "dave"];
for (i, bytes) in keyshares_bytes.iter().enumerate() {
let filename = format!("{}-keyshare-held-by-{}.keyshare", name, holder_names[i]);
async fn write_keyshares(
base_path: PathBuf,
name_of_excluded: &ValidatorName,
keyshares_and_names: Vec<(Vec<u8>, ValidatorName)>,
) {
for (keyshare, name) in keyshares_and_names {
let mut filepath = base_path.clone();
filepath.push(name_of_excluded.to_string());
let filename = format!("keyshare-held-by-{}.keyshare", name);
filepath.push(filename);
println!("Writing keyshare file: {:?}", filepath);
std::fs::write(filepath, bytes).unwrap();
std::fs::write(filepath, keyshare).unwrap();
}
}

0 comments on commit 367fccb

Please sign in to comment.