[clap-v3-utils] Add `EncodableKeypair` trait and make `confirm_keypair_pubkey` generic (#31642)

* add `EncodableKeypair` trait

* implement `EncodableKeypair` for `Keypair`

* implement `EncodableKeypair` for `ElGamalKeypair

* make confirm pubkey functions generic

* fix a typo

* Update sdk/src/signer/keypair.rs

Co-authored-by: Trent Nelson <trent.a.b.nelson@gmail.com>

* Update clap-v3-utils/src/keypair.rs

Co-authored-by: Tyera <teulberg@gmail.com>

* fix a typo

---------

Co-authored-by: Trent Nelson <trent.a.b.nelson@gmail.com>
Co-authored-by: Tyera <teulberg@gmail.com>
This commit is contained in:
samkim-crypto 2023-05-17 05:37:59 +09:00 committed by GitHub
parent ad67fd5be5
commit e14384d8ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 23 deletions

View File

@ -30,7 +30,7 @@ use {
pubkey::Pubkey,
signature::{
generate_seed_from_seed_phrase_and_passphrase, read_keypair, read_keypair_file,
EncodableKey, Keypair, NullSigner, Presigner, Signature, Signer,
EncodableKey, EncodableKeypair, Keypair, NullSigner, Presigner, Signature, Signer,
},
},
solana_zk_token_sdk::encryption::{auth_encryption::AeKey, elgamal::ElGamalKeypair},
@ -1004,23 +1004,11 @@ pub fn keypair_from_path(
) -> Result<Keypair, Box<dyn error::Error>> {
let keypair = encodable_key_from_path(matches, path, keypair_name)?;
if confirm_pubkey {
confirm_keypair_pubkey(&keypair);
confirm_encodable_keypair_pubkey(&keypair, "pubkey");
}
Ok(keypair)
}
fn confirm_keypair_pubkey(keypair: &Keypair) {
let pubkey = keypair.pubkey();
print!("Recovered pubkey `{pubkey:?}`. Continue? (y/n): ");
let _ignored = stdout().flush();
let mut input = String::new();
stdin().read_line(&mut input).expect("Unexpected input");
if input.to_lowercase().trim() != "y" {
println!("Exiting");
exit(1);
}
}
/// Loads an [ElGamalKeypair] from one of several possible sources.
///
/// If `confirm_pubkey` is `true` then after deriving the keypair, the user will
@ -1063,14 +1051,14 @@ pub fn elgamal_keypair_from_path(
) -> Result<ElGamalKeypair, Box<dyn error::Error>> {
let elgamal_keypair = encodable_key_from_path(matches, path, elgamal_keypair_name)?;
if confirm_pubkey {
confirm_elgamal_keypair_pubkey(&elgamal_keypair);
confirm_encodable_keypair_pubkey(&elgamal_keypair, "ElGamal pubkey");
}
Ok(elgamal_keypair)
}
fn confirm_elgamal_keypair_pubkey(keypair: &ElGamalKeypair) {
let elgamal_pubkey = keypair.public;
print!("Recovered ElGamal pubkey `{elgamal_pubkey:?}`. Continue? (y/n): ");
fn confirm_encodable_keypair_pubkey<K: EncodableKeypair>(keypair: &K, pubkey_label: &str) {
let pubkey = keypair.encodable_pubkey().to_string();
println!("Recovered {pubkey_label} `{pubkey:?}`. Continue? (y/n): ");
let _ignored = stdout().flush();
let mut input = String::new();
stdin().read_line(&mut input).expect("Unexpected input");
@ -1175,7 +1163,7 @@ pub fn keypair_from_seed_phrase(
let keypair: Keypair =
encodable_key_from_seed_phrase(keypair_name, skip_validation, derivation_path, legacy)?;
if confirm_pubkey {
confirm_keypair_pubkey(&keypair);
confirm_encodable_keypair_pubkey(&keypair, "pubkey");
}
Ok(keypair)
}
@ -1198,7 +1186,7 @@ pub fn elgamal_keypair_from_seed_phrase(
legacy,
)?;
if confirm_pubkey {
confirm_elgamal_keypair_pubkey(&elgamal_keypair);
confirm_encodable_keypair_pubkey(&elgamal_keypair, "ElGamal pubkey");
}
Ok(elgamal_keypair)
}

View File

@ -5,7 +5,7 @@ use {
derivation_path::DerivationPath,
pubkey::Pubkey,
signature::Signature,
signer::{EncodableKey, Signer, SignerError},
signer::{EncodableKey, EncodableKeypair, Signer, SignerError},
},
ed25519_dalek::Signer as DalekSigner,
ed25519_dalek_bip32::Error as Bip32Error,
@ -140,6 +140,16 @@ impl EncodableKey for Keypair {
}
}
impl EncodableKeypair for Keypair {
type Pubkey = Pubkey;
/// Returns the associated pubkey. Use this function specifically for settings that involve
/// reading or writing pubkeys. For other settings, use `Signer::pubkey()` instead.
fn encodable_pubkey(&self) -> Self::Pubkey {
self.pubkey()
}
}
/// Reads a JSON-encoded `Keypair` from a `Reader` implementor
pub fn read_keypair<R: Read>(reader: &mut R) -> Result<Keypair, Box<dyn error::Error>> {
let bytes: Vec<u8> = serde_json::from_reader(reader)?;

View File

@ -155,6 +155,15 @@ pub trait EncodableKey: Sized {
) -> Result<Self, Box<dyn error::Error>>;
}
/// The `EncodableKeypair` trait extends `EncodableKey` for asymmetric keypairs, i.e. have
/// associated public keys.
pub trait EncodableKeypair: EncodableKey {
type Pubkey: ToString;
/// Returns an encodable representation of the associated public key.
fn encodable_pubkey(&self) -> Self::Pubkey;
}
#[cfg(test)]
mod tests {
use {super::*, crate::signer::keypair::Keypair};

View File

@ -33,8 +33,8 @@ use {
pubkey::Pubkey,
signature::Signature,
signer::{
keypair::generate_seed_from_seed_phrase_and_passphrase, EncodableKey, Signer,
SignerError,
keypair::generate_seed_from_seed_phrase_and_passphrase, EncodableKey, EncodableKeypair,
Signer, SignerError,
},
},
std::convert::TryInto,
@ -273,6 +273,14 @@ impl EncodableKey for ElGamalKeypair {
}
}
impl EncodableKeypair for ElGamalKeypair {
type Pubkey = ElGamalPubkey;
fn encodable_pubkey(&self) -> Self::Pubkey {
self.public
}
}
/// Public key for the ElGamal encryption scheme.
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, Zeroize)]
pub struct ElGamalPubkey(RistrettoPoint);