From 6de581ac08f84f35471d5e9482510c3e4d3a26f7 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Wed, 17 May 2023 17:42:35 +0900 Subject: [PATCH] [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` --- clap-v3-utils/src/keypair.rs | 7 ++- sdk/src/signer/keypair.rs | 4 +- sdk/src/signer/mod.rs | 5 ++ .../src/encryption/auth_encryption.rs | 6 +- zk-token-sdk/src/encryption/elgamal.rs | 59 ++++++++++++++++++- 5 files changed, 74 insertions(+), 7 deletions(-) diff --git a/clap-v3-utils/src/keypair.rs b/clap-v3-utils/src/keypair.rs index bd1ea2a966..a229dbc7ac 100644 --- a/clap-v3-utils/src/keypair.rs +++ b/clap-v3-utils/src/keypair.rs @@ -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( +fn encodable_key_from_path( 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( +fn encodable_key_from_seed_phrase( key_name: &str, skip_validation: bool, derivation_path: Option, diff --git a/sdk/src/signer/keypair.rs b/sdk/src/signer/keypair.rs index c6a911fdde..812be2897f 100644 --- a/sdk/src/signer/keypair.rs +++ b/sdk/src/signer/keypair.rs @@ -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(&self, writer: &mut W) -> Result> { write_keypair(self, writer) } +} +impl SeedDerivable for Keypair { fn from_seed(seed: &[u8]) -> Result> { keypair_from_seed(seed) } diff --git a/sdk/src/signer/mod.rs b/sdk/src/signer/mod.rs index 94add04f41..edbb2e4c18 100644 --- a/sdk/src/signer/mod.rs +++ b/sdk/src/signer/mod.rs @@ -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>; fn from_seed_and_derivation_path( seed: &[u8], diff --git a/zk-token-sdk/src/encryption/auth_encryption.rs b/zk-token-sdk/src/encryption/auth_encryption.rs index f85abe8430..f89dc4201c 100644 --- a/zk-token-sdk/src/encryption/auth_encryption.rs +++ b/zk-token-sdk/src/encryption/auth_encryption.rs @@ -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> { const MINIMUM_SEED_LEN: usize = 16; diff --git a/zk-token-sdk/src/encryption/elgamal.rs b/zk-token-sdk/src/encryption/elgamal.rs index d77051301a..b1f05b50a1 100644 --- a/zk-token-sdk/src/encryption/elgamal.rs +++ b/zk-token-sdk/src/encryption/elgamal.rs @@ -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(&self, writer: &mut W) -> Result> { self.write_json(writer) } +} +impl SeedDerivable for ElGamalKeypair { fn from_seed(seed: &[u8]) -> Result> { let secret = ElGamalSecretKey::from_seed(seed)?; let public = ElGamalPubkey::new(&secret); @@ -336,6 +338,22 @@ impl ElGamalPubkey { } } +impl EncodableKey for ElGamalPubkey { + fn read(reader: &mut R) -> Result> { + let bytes: Vec = 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(&self, writer: &mut W) -> Result> { + 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(reader: &mut R) -> Result> { + let bytes: Vec = 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(&self, writer: &mut W) -> Result> { + 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::from_seed(seed) + } + + fn from_seed_and_derivation_path( + _seed: &[u8], + _derivation_path: Option, + ) -> Result> { + Err(ElGamalError::DerivationMethodNotSupported.into()) + } + + fn from_seed_phrase_and_passphrase( + seed_phrase: &str, + passphrase: &str, + ) -> Result> { + Self::from_seed(&generate_seed_from_seed_phrase_and_passphrase( + seed_phrase, + passphrase, + )) + } +} + impl From for ElGamalSecretKey { fn from(scalar: Scalar) -> ElGamalSecretKey { ElGamalSecretKey(scalar)