Skip to content

Commit

Permalink
pcli: add init threshold dkg command
Browse files Browse the repository at this point in the history
This allows initializing threshold custody with a dkg.

This means the functionality we need for threshold custody is complete,
modulo polish.
  • Loading branch information
cronokirby committed Dec 6, 2023
1 parent b459cd0 commit 96547e3
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 35 deletions.
82 changes: 48 additions & 34 deletions crates/bin/pcli/src/command/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ use std::{io::Read, str::FromStr};

use anyhow::Result;
use camino::Utf8PathBuf;
use penumbra_custody::threshold;
use penumbra_keys::keys::{Bip44Path, SeedPhrase, SpendKey};
use rand_core::OsRng;
use url::Url;

use crate::config::{CustodyConfig, PcliConfig};
use crate::{
config::{CustodyConfig, PcliConfig},
terminal::ActualTerminal,
};

#[derive(Debug, clap::Parser)]
pub struct InitCmd {
Expand Down Expand Up @@ -128,44 +132,45 @@ pub enum ThresholdInitCmd {
#[clap(long, value_delimiter = ' ', multiple_values = true)]
home: Vec<Utf8PathBuf>,
},
/// Generate a config file without using a trusted dealer.
Dkg {
/// The minimum number of signers required to make a signature (>= 2).
#[clap(short, long)]
threshold: u16,
/// The maximum number of signers that can make a signature
#[clap(short, long)]
num_participants: u16,
},
}

impl ThresholdInitCmd {
fn exec(&self, grpc_url: Url) -> Result<()> {
use penumbra_custody::threshold;

match self {
ThresholdInitCmd::Deal { threshold: t, home } => {
if *t < 2 {
anyhow::bail!("threshold must be >= 2");
}
let n = home.len() as u16;
println!("Generating {}-of-{} threshold config.", t, n);
let configs = threshold::Config::deal(&mut OsRng, *t, n)?;
println!("Writing dealt config files...");
for (i, (config, path)) in configs.into_iter().zip(home.iter()).enumerate() {
let full_viewing_key = config.fvk().clone();
let config = PcliConfig {
custody: CustodyConfig::Threshold(config),
full_viewing_key,
grpc_url: grpc_url.clone(),
view_url: None,
disable_warning: false,
};
println!(" Writing signer {} config to {}", i, path);
std::fs::create_dir_all(path)?;
config.save(path.join(crate::CONFIG_FILE_NAME))?;
}
Ok(())
}
}
fn exec_deal(threshold: u16, home: Vec<Utf8PathBuf>, grpc_url: Url) -> Result<()> {
if threshold < 2 {
anyhow::bail!("threshold must be >= 2");
}
let n = home.len() as u16;
println!("Generating {}-of-{} threshold config.", threshold, n);
let configs = threshold::Config::deal(&mut OsRng, threshold, n)?;
println!("Writing dealt config files...");
for (i, (config, path)) in configs.into_iter().zip(home.iter()).enumerate() {
let full_viewing_key = config.fvk().clone();
let config = PcliConfig {
custody: CustodyConfig::Threshold(config),
full_viewing_key,
grpc_url: grpc_url.clone(),
view_url: None,
disable_warning: false,
};
println!(" Writing signer {} config to {}", i, path);
std::fs::create_dir_all(path)?;
config.save(path.join(crate::CONFIG_FILE_NAME))?;
}
Ok(())
}

impl InitCmd {
pub fn exec(&self, home_dir: impl AsRef<camino::Utf8Path>) -> Result<()> {
if let InitSubCmd::Threshold(cmd) = &self.subcmd {
cmd.exec(self.grpc_url.clone())?;
pub async fn exec(&self, home_dir: impl AsRef<camino::Utf8Path>) -> Result<()> {
if let InitSubCmd::Threshold(ThresholdInitCmd::Deal { threshold, home }) = &self.subcmd {
exec_deal(threshold.clone(), home.clone(), self.grpc_url.clone())?;
return Ok(());
}
let home_dir = home_dir.as_ref();
Expand Down Expand Up @@ -196,7 +201,16 @@ impl InitCmd {
CustodyConfig::SoftKms(spend_key.into()),
)
}
InitSubCmd::Threshold(_) => panic!("this should already have been handled above"),
InitSubCmd::Threshold(ThresholdInitCmd::Dkg {
threshold,
num_participants,
}) => {
let config = threshold::dkg(*threshold, *num_participants, &ActualTerminal).await?;
(config.fvk().clone(), CustodyConfig::Threshold(config))
}
InitSubCmd::Threshold(ThresholdInitCmd::Deal { .. }) => {
panic!("this should already have been handled above")
}
InitSubCmd::ViewOnly { full_viewing_key } => {
let full_viewing_key = full_viewing_key.parse()?;
(full_viewing_key, CustodyConfig::ViewOnly)
Expand Down
2 changes: 1 addition & 1 deletion crates/bin/pcli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ async fn main() -> Result<()> {
// create the client state, so handle it specially here so that we can have
// common code for the other subcommands.
if let Command::Init(init_cmd) = &opt.cmd {
init_cmd.exec(opt.home.as_path())?;
init_cmd.exec(opt.home.as_path()).await?;
return Ok(());
}

Expand Down

0 comments on commit 96547e3

Please sign in to comment.