[clap-v3-utils, sdk, zk-token-sdk] Split `EncodableKey` into `EncodableKey` + `SeedDerivable` (#31668)

* add `SeedDerivable` trait

* implement `SeedDerivable` for `Keypair`

* implement `SeedDerivable` for `ElGamalKeypair`

* update clap-v3-utils to use `EncodableKey + SeedDerivable`

* implement `SeedDerivable` trait for `AeKey`

* implement `EncodableKey` and `SeedDerivable` for `ElGamalSecretKey`

* implement `SeedDerivable` trait for `ElGamalPubkey`
This commit is contained in:
samkim-crypto 2023-05-17 17:42:35 +09:00 committed by GitHub
parent 2cdb43ff1b
commit 6de581ac08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 7 deletions

View File

@ -30,7 +30,8 @@ use {
pubkey::Pubkey,
signature::{
generate_seed_from_seed_phrase_and_passphrase, read_keypair, read_keypair_file,
EncodableKey, EncodableKeypair, Keypair, NullSigner, Presigner, Signature, Signer,
EncodableKey, EncodableKeypair, Keypair, NullSigner, Presigner, SeedDerivable,
Signature, Signer,
},
},
solana_zk_token_sdk::encryption::{auth_encryption::AeKey, elgamal::ElGamalKeypair},
@ -1106,7 +1107,7 @@ pub fn ae_key_from_path(
encodable_key_from_path(matches, path, key_name)
}
fn encodable_key_from_path<K: EncodableKey>(
fn encodable_key_from_path<K: EncodableKey + SeedDerivable>(
matches: &ArgMatches,
path: &str,
keypair_name: &str,
@ -1202,7 +1203,7 @@ pub fn ae_key_from_seed_phrase(
encodable_key_from_seed_phrase(keypair_name, skip_validation, derivation_path, legacy)
}
fn encodable_key_from_seed_phrase<K: EncodableKey>(
fn encodable_key_from_seed_phrase<K: EncodableKey + SeedDerivable>(
key_name: &str,
skip_validation: bool,
derivation_path: Option<DerivationPath>,

View File

@ -5,7 +5,7 @@ use {
derivation_path::DerivationPath,
pubkey::Pubkey,
signature::Signature,
signer::{EncodableKey, EncodableKeypair, Signer, SignerError},
signer::{EncodableKey, EncodableKeypair, SeedDerivable, Signer, SignerError},
},
ed25519_dalek::Signer as DalekSigner,
ed25519_dalek_bip32::Error as Bip32Error,
@ -120,7 +120,9 @@ impl EncodableKey for Keypair {
fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>> {
write_keypair(self, writer)
}
}
impl SeedDerivable for Keypair {
fn from_seed(seed: &[u8]) -> Result<Self, Box<dyn error::Error>> {
keypair_from_seed(seed)
}

View File

@ -144,6 +144,11 @@ pub trait EncodableKey: Sized {
self.write(&mut f)
}
}
/// The `SeedDerivable` trait defines the interface by which cryptographic keys/keypairs are
/// derived from byte seeds, derivation paths, and passphrases.
pub trait SeedDerivable: Sized {
fn from_seed(seed: &[u8]) -> Result<Self, Box<dyn error::Error>>;
fn from_seed_and_derivation_path(
seed: &[u8],

View File

@ -21,8 +21,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, SeedDerivable,
Signer, SignerError,
},
},
std::{
@ -126,7 +126,9 @@ impl EncodableKey for AeKey {
writer.write_all(&json.clone().into_bytes())?;
Ok(json)
}
}
impl SeedDerivable for AeKey {
fn from_seed(seed: &[u8]) -> Result<Self, Box<dyn error::Error>> {
const MINIMUM_SEED_LEN: usize = 16;

View File

@ -34,7 +34,7 @@ use {
signature::Signature,
signer::{
keypair::generate_seed_from_seed_phrase_and_passphrase, EncodableKey, EncodableKeypair,
Signer, SignerError,
SeedDerivable, Signer, SignerError,
},
},
std::convert::TryInto,
@ -248,7 +248,9 @@ impl EncodableKey for ElGamalKeypair {
fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>> {
self.write_json(writer)
}
}
impl SeedDerivable for ElGamalKeypair {
fn from_seed(seed: &[u8]) -> Result<Self, Box<dyn error::Error>> {
let secret = ElGamalSecretKey::from_seed(seed)?;
let public = ElGamalPubkey::new(&secret);
@ -336,6 +338,22 @@ impl ElGamalPubkey {
}
}
impl EncodableKey for ElGamalPubkey {
fn read<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>> {
let bytes: Vec<u8> = serde_json::from_reader(reader)?;
Self::from_bytes(&bytes).ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::Other, "Invalid ElGamalPubkey").into()
})
}
fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>> {
let bytes = self.to_bytes();
let json = serde_json::to_string(&bytes.to_vec())?;
writer.write_all(&json.clone().into_bytes())?;
Ok(json)
}
}
impl fmt::Display for ElGamalPubkey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", BASE64_STANDARD.encode(self.to_bytes()))
@ -425,6 +443,45 @@ impl ElGamalSecretKey {
}
}
impl EncodableKey for ElGamalSecretKey {
fn read<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>> {
let bytes: Vec<u8> = serde_json::from_reader(reader)?;
Self::from_bytes(&bytes).ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::Other, "Invalid ElGamalSecretKey").into()
})
}
fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>> {
let bytes = self.to_bytes();
let json = serde_json::to_string(&bytes.to_vec())?;
writer.write_all(&json.clone().into_bytes())?;
Ok(json)
}
}
impl SeedDerivable for ElGamalSecretKey {
fn from_seed(seed: &[u8]) -> Result<Self, Box<dyn error::Error>> {
Self::from_seed(seed)
}
fn from_seed_and_derivation_path(
_seed: &[u8],
_derivation_path: Option<DerivationPath>,
) -> Result<Self, Box<dyn error::Error>> {
Err(ElGamalError::DerivationMethodNotSupported.into())
}
fn from_seed_phrase_and_passphrase(
seed_phrase: &str,
passphrase: &str,
) -> Result<Self, Box<dyn error::Error>> {
Self::from_seed(&generate_seed_from_seed_phrase_and_passphrase(
seed_phrase,
passphrase,
))
}
}
impl From<Scalar> for ElGamalSecretKey {
fn from(scalar: Scalar) -> ElGamalSecretKey {
ElGamalSecretKey(scalar)