use crate::crypto::key;
use chain_addr::{Address, Discrimination};
use chain_crypto::{AsymmetricKey, Ed25519, Ed25519Extended, SecretKey};
use chain_impl_mockchain::{
account,
key::{AccountPublicKey, EitherEd25519SecretKey},
};
use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use std::{fmt, str::FromStr};
use thiserror::Error;
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
pub struct Identifier(key::Identifier<account::AccountAlg>);
#[derive(Clone)]
pub struct SigningKey(EitherEd25519SecretKey);
#[derive(Debug, Error)]
pub enum SigningKeyParseError {
#[error("Invalid bech32: {0}")]
InvalidBech32Encoding(#[from] bech32::Error),
#[error("Invalid secret key: {0}")]
InvalidSecretKey(#[from] chain_crypto::bech32::Error),
#[error("Unexpected key '{hrp}'. Expected either ed25519 or ed25519extended")]
UnexpectedHrp { hrp: String },
}
impl Identifier {
#[inline]
pub fn to_address(&self, discrimination: Discrimination) -> Address {
self.0.to_account_address(discrimination)
}
#[inline]
pub fn to_inner(&self) -> account::Identifier {
account::Identifier::from(self.as_ref().clone())
}
#[inline]
pub fn to_bech32_str(&self) -> String {
self.0.to_bech32_str()
}
#[inline]
pub fn from_bech32_str(s: &str) -> Result<Self, chain_crypto::bech32::Error> {
key::Identifier::from_bech32_str(s).map(Identifier)
}
#[inline]
pub fn to_hex(&self) -> String {
self.0.to_hex()
}
#[inline]
pub fn from_hex(s: &str) -> Result<Self, chain_crypto::PublicKeyFromStrError> {
key::Identifier::from_hex(s).map(Identifier)
}
}
impl SigningKey {
#[inline]
pub fn identifier(&self) -> Identifier {
Identifier(self.0.to_public().into())
}
#[inline]
pub fn generate<RNG>(rng: RNG) -> Self
where
RNG: RngCore + CryptoRng,
{
SigningKey(EitherEd25519SecretKey::Normal(SecretKey::generate(rng)))
}
#[inline]
pub fn generate_extended<RNG>(rng: RNG) -> Self
where
RNG: RngCore + CryptoRng,
{
SigningKey(EitherEd25519SecretKey::Extended(SecretKey::generate(rng)))
}
#[inline]
pub fn to_bech32_str(&self) -> String {
use chain_crypto::bech32::Bech32 as _;
match &self.0 {
EitherEd25519SecretKey::Normal(ed25519_key) => ed25519_key.to_bech32_str(),
EitherEd25519SecretKey::Extended(ed25519e_key) => ed25519e_key.to_bech32_str(),
}
}
#[inline]
pub fn to_hex(&self) -> String {
match &self.0 {
EitherEd25519SecretKey::Normal(ed25519_key) => {
hex::encode(ed25519_key.clone().leak_secret().as_ref())
}
EitherEd25519SecretKey::Extended(ed25519e_key) => {
hex::encode(ed25519e_key.clone().leak_secret().as_ref())
}
}
}
#[inline]
pub fn from_bech32_str(s: &str) -> Result<Self, SigningKeyParseError> {
use chain_crypto::bech32::Bech32 as _;
let (hrp, _, _variant) = bech32::decode(s)?;
let key = match hrp.as_ref() {
Ed25519::SECRET_BECH32_HRP => SigningKey(EitherEd25519SecretKey::Normal(
SecretKey::try_from_bech32_str(s)?,
)),
Ed25519Extended::SECRET_BECH32_HRP => SigningKey(EitherEd25519SecretKey::Extended(
SecretKey::try_from_bech32_str(s)?,
)),
_ => return Err(SigningKeyParseError::UnexpectedHrp { hrp }),
};
Ok(key)
}
}
impl fmt::Debug for SigningKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("SigningKey").finish()
}
}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_bech32_str().fmt(f)
}
}
impl FromStr for Identifier {
type Err = chain_crypto::bech32::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_bech32_str(s)
}
}
impl AsRef<AccountPublicKey> for Identifier {
fn as_ref(&self) -> &AccountPublicKey {
self.0.as_ref()
}
}
impl AsRef<EitherEd25519SecretKey> for SigningKey {
fn as_ref(&self) -> &EitherEd25519SecretKey {
&self.0
}
}
impl From<SecretKey<Ed25519>> for SigningKey {
fn from(key: SecretKey<Ed25519>) -> Self {
SigningKey(EitherEd25519SecretKey::Normal(key))
}
}
impl From<SecretKey<Ed25519Extended>> for SigningKey {
fn from(key: SecretKey<Ed25519Extended>) -> Self {
SigningKey(EitherEd25519SecretKey::Extended(key))
}
}
impl From<AccountPublicKey> for Identifier {
fn from(key: AccountPublicKey) -> Self {
Identifier(key::Identifier::from(key))
}
}
impl From<account::Identifier> for Identifier {
fn from(identifier: account::Identifier) -> Self {
Identifier(key::Identifier::from(identifier.as_ref().clone()))
}
}
impl From<key::Identifier<account::AccountAlg>> for Identifier {
fn from(identifier: key::Identifier<account::AccountAlg>) -> Self {
Identifier(identifier)
}
}
impl Serialize for SigningKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
if serializer.is_human_readable() {
self.to_bech32_str().serialize(serializer)
} else {
unimplemented!()
}
}
}
impl<'de> Deserialize<'de> for SigningKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
if deserializer.is_human_readable() {
let s = String::deserialize(deserializer)?;
SigningKey::from_bech32_str(&s).map_err(<D::Error as serde::de::Error>::custom)
} else {
unimplemented!()
}
}
}
#[cfg(test)]
mod test {
use super::*;
use quickcheck::{Arbitrary, Gen, TestResult};
impl Arbitrary for SigningKey {
fn arbitrary<G>(g: &mut G) -> Self
where
G: Gen,
{
if bool::arbitrary(g) {
let key: key::SigningKey<Ed25519> = key::SigningKey::arbitrary(g);
SigningKey(EitherEd25519SecretKey::Normal(key.0))
} else {
let key: key::SigningKey<Ed25519Extended> = key::SigningKey::arbitrary(g);
SigningKey(EitherEd25519SecretKey::Extended(key.0))
}
}
}
impl Arbitrary for Identifier {
fn arbitrary<G>(g: &mut G) -> Self
where
G: Gen,
{
SigningKey::arbitrary(g).identifier()
}
}
#[test]
fn identifier_display() {
const EXPECTED_IDENTIFIER_STR: &str =
"ed25519_pk1yqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsqyl7vm8";
const IDENTIFIER_BYTES: [u8; 32] = [0x20; 32];
let identifier = Identifier(
AccountPublicKey::from_binary(&IDENTIFIER_BYTES)
.unwrap()
.into(),
);
assert_eq!(identifier.to_string(), EXPECTED_IDENTIFIER_STR);
}
#[test]
fn identifier_serde_human_readable() {
const EXPECTED_IDENTIFIER_STR: &str =
"---\ned25519_pk1yqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsqyl7vm8\n";
const IDENTIFIER_BYTES: [u8; 32] = [0x20; 32];
let identifier = Identifier(
AccountPublicKey::from_binary(&IDENTIFIER_BYTES)
.unwrap()
.into(),
);
let identifier_str = serde_yaml::to_string(&identifier).unwrap();
assert_eq!(identifier_str, EXPECTED_IDENTIFIER_STR);
}
#[test]
fn signing_key_serde_human_readable() {
const EXPECTED_SIGNING_KEY_STR: &str =
"---\ned25519e_sk1yqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgq4hu79f\n";
const SIGNING_KEY_BYTES: [u8; 64] = [0x20; 64];
let signing_key = SigningKey(EitherEd25519SecretKey::Extended(
SecretKey::from_binary(&SIGNING_KEY_BYTES).unwrap(),
));
let signing_key_str = serde_yaml::to_string(&signing_key).unwrap();
assert_eq!(signing_key_str, EXPECTED_SIGNING_KEY_STR);
}
quickcheck! {
fn identifier_display_and_from_str(identifier: Identifier) -> TestResult {
let identifier_str = identifier.to_string();
let identifier_dec = match Identifier::from_str(&identifier_str) {
Err(error) => return TestResult::error(error.to_string()),
Ok(identifier) => identifier,
};
TestResult::from_bool(identifier_dec == identifier)
}
fn identifier_serde_human_readable_encode_decode(identifier: Identifier) -> TestResult {
let identifier_str = serde_yaml::to_string(&identifier).unwrap();
let identifier_dec : Identifier = match serde_yaml::from_str(&identifier_str) {
Err(error) => return TestResult::error(error.to_string()),
Ok(identifier) => identifier,
};
TestResult::from_bool(identifier_dec == identifier)
}
fn signing_key_serde_human_readable_encode_decode(signing_key: SigningKey) -> TestResult {
let signing_key_str = serde_yaml::to_string(&signing_key).unwrap();
let signing_key_dec : SigningKey = match serde_yaml::from_str(&signing_key_str) {
Err(error) => return TestResult::error(error.to_string()),
Ok(signing_key) => signing_key,
};
TestResult::from_bool(signing_key_dec.identifier() == signing_key.identifier())
}
}
}