Added deterministic keypair generation.

- The Account Manager has a new subcommand, allowing generation of deterministic keys given a particular validator index.
 - Split functionality in generate_deterministic_keypair function
 - Fixed up READMEs to reflect new functionality & correct naming.
This commit is contained in:
Luke Anderson 2019-04-08 15:02:11 +10:00
parent a46f676f89
commit 177a351462
No known key found for this signature in database
GPG Key ID: 44408169EC61E228
8 changed files with 69 additions and 15 deletions

View File

@ -11,3 +11,4 @@ slog = "^2.2.3"
slog-term = "^2.4.0" slog-term = "^2.4.0"
slog-async = "^2.3.0" slog-async = "^2.3.0"
validator_client = { path = "../validator_client" } validator_client = { path = "../validator_client" }
types = { path = "../eth2/types" }

View File

@ -1,6 +1,6 @@
# Lighthouse Accounts Manager # Lighthouse Account Manager
The accounts manager (AM) is a stand-alone binary which allows The account manager (AM) is a stand-alone binary which allows
users to generate and manage the cryptographic keys necessary to users to generate and manage the cryptographic keys necessary to
interact with Ethereum Serenity. interact with Ethereum Serenity.
@ -21,4 +21,14 @@ staking on Ethereum 1.x (TPD)
The AM is not a service, and does not run continuously, nor does it The AM is not a service, and does not run continuously, nor does it
interact with any running services. interact with any running services.
It is intended to be executed separately from other Lighthouse binaries It is intended to be executed separately from other Lighthouse binaries
and produce files which can be consumed by them. and produce files which can be consumed by them.&
## Usage
Simply run `./account_manager generate` to generate a new random private key,
which will be automatically saved to the correct directory.
If you prefer to use our "deterministic" keys for testing purposes, simply
run `./accounts_manager generate_deterministic -i <index>`, where `index` is
the validator index for the key. This will reliably produce the same key each time
and save it to the directory.

View File

@ -3,6 +3,7 @@ use clap::{App, Arg, SubCommand};
use slog::{debug, info, o, Drain}; use slog::{debug, info, o, Drain};
use std::path::PathBuf; use std::path::PathBuf;
use validator_client::Config as ValidatorClientConfig; use validator_client::Config as ValidatorClientConfig;
use types::test_utils::generate_deterministic_keypair;
fn main() { fn main() {
// Logging // Logging
@ -29,6 +30,21 @@ fn main() {
.version("0.0.1") .version("0.0.1")
.author("Sigma Prime <contact@sigmaprime.io>"), .author("Sigma Prime <contact@sigmaprime.io>"),
) )
.subcommand(
SubCommand::with_name("generate_deterministic")
.about("Generates a deterministic validator private key FOR TESTING")
.version("0.0.1")
.author("Sigma Prime <contact@sigmaprime.io>")
.arg(
Arg::with_name("validator index")
.long("index")
.short("i")
.value_name("index")
.help("The index of the validator, for which the test key is generated")
.takes_value(true)
.required(true)
)
)
.get_matches(); .get_matches();
let config = ValidatorClientConfig::parse_args(&matches, &log) let config = ValidatorClientConfig::parse_args(&matches, &log)
@ -50,7 +66,24 @@ fn main() {
keypair.identifier(), keypair.identifier(),
key_path.to_string_lossy() key_path.to_string_lossy()
); );
} },
("generate_deterministic", Some(gen_d_matches)) => {
let validator_index = gen_d_matches
.value_of("validator index")
.expect("Validator index required.")
.parse::<u64>()
.expect("Invalid validator index.") as usize;
let keypair = generate_deterministic_keypair(validator_index);
let key_path: PathBuf = config
.save_key(&keypair)
.expect("Unable to save newly generated deterministic private key.");
debug!(
log,
"Deterministic Keypair generated {:?}, saved to: {:?}",
keypair.identifier(),
key_path.to_string_lossy()
);
},
_ => panic!( _ => panic!(
"The account manager must be run with a subcommand. See help for more information." "The account manager must be run with a subcommand. See help for more information."
), ),

View File

@ -18,13 +18,17 @@ pub fn generate_deterministic_keypairs(validator_count: usize) -> Vec<Keypair> {
let keypairs: Vec<Keypair> = (0..validator_count) let keypairs: Vec<Keypair> = (0..validator_count)
.collect::<Vec<usize>>() .collect::<Vec<usize>>()
.par_iter() .par_iter()
.map(|&i| { .map(|&i| generate_deterministic_keypair(i))
let secret = int_to_bytes48(i as u64 + 1000); .collect();
keypairs
}
/// Generates a single deterministic keypair, where the secret key is `validator_index`.
///
/// This is used for testing only, and not to be used in production!
pub fn generate_deterministic_keypair(validator_index: usize) -> Keypair {
let secret = int_to_bytes48(validator_index as u64 + 1000);
let sk = SecretKey::from_bytes(&secret).unwrap(); let sk = SecretKey::from_bytes(&secret).unwrap();
let pk = PublicKey::from_secret_key(&sk); let pk = PublicKey::from_secret_key(&sk);
Keypair { sk, pk } Keypair { sk, pk }
})
.collect();
keypairs
} }

View File

@ -16,6 +16,7 @@ mod testing_transfer_builder;
mod testing_voluntary_exit_builder; mod testing_voluntary_exit_builder;
pub use generate_deterministic_keypairs::generate_deterministic_keypairs; pub use generate_deterministic_keypairs::generate_deterministic_keypairs;
pub use generate_deterministic_keypairs::generate_deterministic_keypair;
pub use keypairs_file::KeypairsFile; pub use keypairs_file::KeypairsFile;
pub use rand::{prng::XorShiftRng, SeedableRng}; pub use rand::{prng::XorShiftRng, SeedableRng};
pub use serde_utils::{fork_from_hex_str, u8_from_hex_str}; pub use serde_utils::{fork_from_hex_str, u8_from_hex_str};

View File

@ -75,8 +75,9 @@ The configuration directory structure looks like:
Where the hex value of the directory is a portion of the validator public key. Where the hex value of the directory is a portion of the validator public key.
Validator keys must be generated using the separate `accounts_manager` binary, which will Validator keys must be generated using the separate `account_manager` binary, which will
place the keys into this directory structure in a format compatible with the validator client. place the keys into this directory structure in a format compatible with the validator client.
Be sure to check the readme for `account_manager`.
The chain specification (slot length, BLS domain, etc.) defaults to foundation The chain specification (slot length, BLS domain, etc.) defaults to foundation
parameters, however is temporary and an upgrade will allow these parameters to be parameters, however is temporary and an upgrade will allow these parameters to be

View File

@ -9,7 +9,7 @@ mod signer;
use crate::config::Config as ValidatorClientConfig; use crate::config::Config as ValidatorClientConfig;
use clap::{App, Arg}; use clap::{App, Arg};
use protos::services_grpc::ValidatorServiceClient; use protos::services_grpc::ValidatorServiceClient;
use service::Service as ValidatorService; use crate::service::Service as ValidatorService;
use slog::{error, info, o, Drain}; use slog::{error, info, o, Drain};
use types::Keypair; use types::Keypair;

View File

@ -166,11 +166,15 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
/* Generate the duties manager */ /* Generate the duties manager */
// generate keypairs // Load generated keypairs
let keypairs = match config.fetch_keys(&log) {
Some(kps) => Arc::new(kps),
None => panic!("No key pairs found, cannot start validator client without at least one. Try running `./account_manager generate` first.")
};
// TODO: keypairs are randomly generated; they should be loaded from a file or generated. // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
// https://github.com/sigp/lighthouse/issues/160 // https://github.com/sigp/lighthouse/issues/160
let keypairs = Arc::new(generate_deterministic_keypairs(8)); //let keypairs = Arc::new(generate_deterministic_keypairs(8));
// Builds a mapping of Epoch -> Map(PublicKey, EpochDuty) // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
// where EpochDuty contains slot numbers and attestation data that each validator needs to // where EpochDuty contains slot numbers and attestation data that each validator needs to