use crate::crypto::serde as internal;
use chain_addr::{Address, Discrimination, Kind};
use chain_crypto::{
bech32::Bech32, AsymmetricKey, AsymmetricPublicKey, Ed25519, PublicKey, SecretKey,
SignatureFromStrError, SigningAlgorithm, VerificationAlgorithm,
};
use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{fmt, str::FromStr};
#[derive(Deserialize, Serialize)]
pub struct Identifier<A: AsymmetricPublicKey>(
#[serde(
deserialize_with = "internal::deserialize_public",
serialize_with = "internal::serialize_public"
)]
PublicKey<A>,
);
pub struct SigningKey<A: AsymmetricKey>(pub(crate) SecretKey<A>);
impl<A> Serialize for SigningKey<A>
where
A: AsymmetricKey,
SecretKey<A>: Bech32,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
internal::serialize_secret(&self.0, serializer)
}
}
impl<'de, A> Deserialize<'de> for SigningKey<A>
where
A: AsymmetricKey,
SecretKey<A>: Bech32,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
internal::deserialize_secret(deserializer).map(Self)
}
}
pub struct KeyPair<A: AsymmetricKey>(pub chain_crypto::KeyPair<A>);
impl<A: AsymmetricKey> KeyPair<A> {
pub fn public_key(&self) -> &PublicKey<<A as AsymmetricKey>::PubAlg> {
self.0.public_key()
}
}
#[derive(Deserialize, Serialize)]
pub struct Signature<T, A: VerificationAlgorithm>(
#[serde(
deserialize_with = "internal::deserialize_signature",
serialize_with = "internal::serialize_signature"
)]
chain_crypto::Signature<T, A>,
);
impl<A: AsymmetricKey> KeyPair<A> {
#[inline]
pub fn generate<RNG>(mut rng: RNG) -> Self
where
RNG: RngCore + CryptoRng,
{
KeyPair(chain_crypto::KeyPair::generate(&mut rng))
}
#[inline]
pub fn identifier(&self) -> Identifier<<A as AsymmetricKey>::PubAlg> {
Identifier(self.0.public_key().clone())
}
#[inline]
pub fn signing_key(&self) -> SigningKey<A> {
SigningKey(self.0.private_key().clone())
}
}
impl<A: AsymmetricPublicKey> Identifier<A> {
#[inline]
pub fn into_public_key(self) -> PublicKey<A> {
self.0
}
#[inline]
pub fn to_bech32_str(&self) -> String {
use chain_crypto::bech32::Bech32 as _;
self.0.to_bech32_str()
}
#[inline]
pub fn from_bech32_str(s: &str) -> Result<Self, chain_crypto::bech32::Error> {
use chain_crypto::bech32::Bech32 as _;
PublicKey::try_from_bech32_str(s).map(Identifier)
}
#[inline]
pub fn to_hex(&self) -> String {
self.0.to_string()
}
#[inline]
pub fn from_hex(s: &str) -> Result<Self, chain_crypto::PublicKeyFromStrError> {
s.parse().map(Identifier)
}
}
impl Identifier<Ed25519> {
#[inline]
pub fn to_single_address(&self, discrimination: Discrimination) -> Address {
Address(discrimination, Kind::Single(self.0.clone()))
}
#[inline]
pub fn to_group_address(
&self,
discrimination: Discrimination,
group: PublicKey<Ed25519>,
) -> Address {
Address(discrimination, Kind::Group(self.0.clone(), group))
}
#[inline]
pub fn to_account_address(&self, discrimination: Discrimination) -> Address {
Address(discrimination, Kind::Account(self.0.clone()))
}
}
impl<A: SigningAlgorithm> SigningKey<A>
where
<A as AsymmetricKey>::PubAlg: VerificationAlgorithm,
{
#[inline]
pub fn sign<T: AsRef<[u8]>>(&self, object: &T) -> Signature<T, <A as AsymmetricKey>::PubAlg> {
Signature(self.0.sign(object))
}
}
impl<A: AsymmetricKey> SigningKey<A> {
#[inline]
pub fn into_secret_key(self) -> SecretKey<A> {
self.0
}
#[inline]
pub fn generate<RNG>(rng: RNG) -> Self
where
RNG: RngCore + CryptoRng,
{
SigningKey(SecretKey::generate(rng))
}
#[inline]
pub fn identifier(&self) -> Identifier<<A as AsymmetricKey>::PubAlg> {
Identifier(self.0.to_public())
}
}
impl<A> SigningKey<A>
where
A: AsymmetricKey,
SecretKey<A>: Bech32,
{
#[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> {
SecretKey::try_from_bech32_str(s).map(SigningKey)
}
}
impl<T, A: VerificationAlgorithm> Signature<T, A> {
#[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> {
chain_crypto::Signature::try_from_bech32_str(s).map(Signature::from)
}
#[inline]
pub fn to_hex(&self) -> String {
self.0.to_string()
}
#[inline]
pub fn from_hex(s: &str) -> Result<Self, SignatureFromStrError> {
s.parse().map(Signature)
}
#[inline]
pub fn coerce<U>(self) -> Signature<U, A> {
Signature(self.0.coerce())
}
}
impl<A: VerificationAlgorithm, T: AsRef<[u8]>> Signature<T, A> {
#[inline]
pub fn verify(&self, identifier: &Identifier<A>, object: &T) -> chain_crypto::Verification {
self.0.verify(identifier.as_ref(), object)
}
}
impl<A: AsymmetricPublicKey> fmt::Display for Identifier<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_bech32_str().fmt(f)
}
}
impl<A: AsymmetricPublicKey> FromStr for Identifier<A> {
type Err = chain_crypto::bech32::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_bech32_str(s)
}
}
impl<A: AsymmetricPublicKey> fmt::Debug for Identifier<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Identifier").field(&self.0).finish()
}
}
impl<A: AsymmetricKey> fmt::Debug for SigningKey<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SigningKey").finish()
}
}
impl<A: AsymmetricKey> fmt::Debug for KeyPair<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("KeyPair").field("0", &self.0).finish()
}
}
impl<T, A: VerificationAlgorithm> fmt::Display for Signature<T, A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_bech32_str().fmt(f)
}
}
impl<T, A: VerificationAlgorithm> FromStr for Signature<T, A> {
type Err = chain_crypto::bech32::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_bech32_str(s)
}
}
impl<T, A: VerificationAlgorithm> fmt::Debug for Signature<T, A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Signature").field(&self.0).finish()
}
}
impl<A: AsymmetricPublicKey> AsRef<PublicKey<A>> for Identifier<A> {
fn as_ref(&self) -> &PublicKey<A> {
&self.0
}
}
impl<A: AsymmetricKey> AsRef<SecretKey<A>> for SigningKey<A> {
fn as_ref(&self) -> &SecretKey<A> {
&self.0
}
}
impl<T, A: VerificationAlgorithm> AsRef<chain_crypto::Signature<T, A>> for Signature<T, A> {
fn as_ref(&self) -> &chain_crypto::Signature<T, A> {
&self.0
}
}
impl<A: AsymmetricKey> From<SecretKey<A>> for SigningKey<A> {
fn from(key: SecretKey<A>) -> Self {
SigningKey(key)
}
}
impl<A: AsymmetricKey> From<SigningKey<A>> for SecretKey<A> {
fn from(key: SigningKey<A>) -> Self {
key.0
}
}
impl<A: AsymmetricPublicKey> From<PublicKey<A>> for Identifier<A> {
fn from(key: PublicKey<A>) -> Self {
Identifier(key)
}
}
impl<T, A: VerificationAlgorithm> From<chain_crypto::Signature<T, A>> for Signature<T, A> {
fn from(signature: chain_crypto::Signature<T, A>) -> Self {
Signature(signature)
}
}
impl<A: AsymmetricPublicKey> PartialEq<Identifier<A>> for Identifier<A> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<A: AsymmetricPublicKey> Eq for Identifier<A> {}
impl<S, T, A: VerificationAlgorithm> PartialEq<Signature<S, A>> for Signature<T, A> {
fn eq(&self, other: &Signature<S, A>) -> bool {
self.0.as_ref() == other.0.as_ref()
}
}
impl<T, A: VerificationAlgorithm> Eq for Signature<T, A> {}
impl<A: AsymmetricPublicKey> PartialOrd<Identifier<A>> for Identifier<A> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<A: AsymmetricPublicKey> Ord for Identifier<A> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl<A: AsymmetricPublicKey> std::hash::Hash for Identifier<A> {
fn hash<H>(&self, state: &mut H)
where
H: std::hash::Hasher,
{
self.0.hash(state)
}
}
impl<T, A: VerificationAlgorithm> std::hash::Hash for Signature<T, A> {
fn hash<H>(&self, state: &mut H)
where
H: std::hash::Hasher,
{
self.0.as_ref().hash(state)
}
}
impl<A: AsymmetricPublicKey> Clone for Identifier<A> {
fn clone(&self) -> Self {
Identifier(self.0.clone())
}
}
impl<A: AsymmetricKey> Clone for SigningKey<A> {
fn clone(&self) -> Self {
SigningKey(self.0.clone())
}
}
impl<A: AsymmetricKey> Clone for KeyPair<A> {
fn clone(&self) -> Self {
KeyPair(self.0.clone())
}
}
impl<T, A: VerificationAlgorithm> Clone for Signature<T, A> {
fn clone(&self) -> Self {
Signature(self.0.clone())
}
}
#[cfg(test)]
mod test {
use super::*;
use quickcheck::{Arbitrary, Gen, TestResult};
impl<A> Arbitrary for SigningKey<A>
where
<A as AsymmetricKey>::Secret: Send,
A: AsymmetricKey + 'static,
{
fn arbitrary<G>(g: &mut G) -> Self
where
G: Gen,
{
SigningKey(SecretKey::arbitrary(g))
}
}
impl<A> Arbitrary for KeyPair<A>
where
A: AsymmetricKey + 'static,
A::Secret: Send,
<A::PubAlg as AsymmetricPublicKey>::Public: Send,
{
fn arbitrary<G>(g: &mut G) -> Self
where
G: Gen,
{
KeyPair(Arbitrary::arbitrary(g))
}
}
impl<T, A> Arbitrary for Signature<T, A>
where
A: VerificationAlgorithm + 'static,
A::Signature: Send,
T: Send + 'static,
{
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Signature(Arbitrary::arbitrary(g))
}
}
#[test]
fn identifier_display() {
const EXPECTED_IDENTIFIER_STR: &str =
"ed25519_pk1yqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsqyl7vm8";
const IDENTIFIER_BYTES: [u8; 32] = [0x20; 32];
let identifier: Identifier<Ed25519> =
Identifier(PublicKey::from_binary(&IDENTIFIER_BYTES).unwrap());
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<Ed25519> =
Identifier(PublicKey::from_binary(&IDENTIFIER_BYTES).unwrap());
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 =
"---\ned25519_sk1yqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsq8j4ww6\n";
const SIGNING_KEY_BYTES: [u8; 32] = [0x20; 32];
let signing_key: SigningKey<Ed25519> =
SigningKey(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);
}
#[test]
fn signature_display() {
const EXPECTED_SIGNATURE_STR: &str =
"ed25519_sig1yqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgqzlcn38";
const SIGNATURE_BYTES: [u8; 64] = [0x20; 64];
let signature: Signature<&'static [u8], Ed25519> =
Signature(chain_crypto::Signature::from_binary(&SIGNATURE_BYTES).unwrap());
assert_eq!(signature.to_string(), EXPECTED_SIGNATURE_STR);
}
#[test]
fn signature_serde_human_readable() {
const EXPECTED_SIGNATURE_STR: &str =
"---\ned25519_sig1yqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgqzlcn38\n";
const SIGNATURE_BYTES: [u8; 64] = [0x20; 64];
let signature: Signature<&'static [u8], Ed25519> =
Signature(chain_crypto::Signature::from_binary(&SIGNATURE_BYTES).unwrap());
let signature_str = serde_yaml::to_string(&signature).unwrap();
assert_eq!(signature_str, EXPECTED_SIGNATURE_STR);
}
quickcheck! {
fn identifier_display_and_from_str(key_pair: KeyPair<Ed25519>) -> TestResult {
let identifier = key_pair.identifier();
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(key_pair: KeyPair<Ed25519>) -> TestResult {
let identifier = key_pair.identifier();
let identifier_str = serde_yaml::to_string(&identifier).unwrap();
let identifier_dec : Identifier<Ed25519> = 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<Ed25519>) -> TestResult {
let signing_key_str = serde_yaml::to_string(&signing_key).unwrap();
let signing_key_dec : SigningKey<Ed25519> = 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())
}
fn identifier_serde_binary_readable_encode_decode(key_pair: KeyPair<Ed25519>) -> TestResult {
let identifier = key_pair.identifier();
let identifier_str = bincode::serialize(&identifier).unwrap();
let identifier_dec : Identifier<Ed25519> = match bincode::deserialize(&identifier_str) {
Err(error) => return TestResult::error(error.to_string()),
Ok(identifier) => identifier,
};
TestResult::from_bool(identifier_dec == identifier)
}
fn signature_display_and_from_str(signature: Signature<&'static [u8], Ed25519>) -> TestResult {
let signature_str = signature.to_string();
let signature_dec : Signature<&'static [u8], Ed25519> = match Signature::from_str(&signature_str) {
Err(error) => return TestResult::error(error.to_string()),
Ok(signature) => signature,
};
TestResult::from_bool(signature_dec == signature)
}
fn signature_serde_human_readable_encode_decode(signature: Signature<&'static [u8], Ed25519>) -> TestResult {
let signature_str = serde_yaml::to_string(&signature).unwrap();
let signature_dec : Signature<&'static [u8], Ed25519> = match serde_yaml::from_str(&signature_str) {
Err(error) => return TestResult::error(error.to_string()),
Ok(signature) => signature,
};
TestResult::from_bool(signature_dec == signature)
}
fn signature_binary_readable_encode_decode(signature: Signature<&'static [u8], Ed25519>) -> TestResult {
let signature_str = bincode::serialize(&signature).unwrap();
let signature_dec : Signature<&'static [u8], Ed25519> = match bincode::deserialize(&signature_str) {
Err(error) => return TestResult::error(error.to_string()),
Ok(signature) => signature,
};
TestResult::from_bool(signature_dec == signature)
}
fn sign_verify(data: (Vec<u8>, KeyPair<Ed25519>)) -> TestResult {
let (data, key_pair) = data;
let identifier = key_pair.identifier();
let signing_key = key_pair.signing_key();
let signature = signing_key.sign(&data);
match signature.verify(&identifier, &data) {
chain_crypto::Verification::Success => TestResult::passed(),
chain_crypto::Verification::Failed => TestResult::error("signature verification failed"),
}
}
}
}