use crate::account_address::AccountAddress;
use anyhow::{ensure, Error, Result};
use diem_crypto::{
bls::{
BLSPublicKey, BLSPublicKeyUnchecked, BLSSignature,
BLSSignatureUnchecked,
},
ed25519::{Ed25519PublicKey, Ed25519Signature},
hash::CryptoHash,
multi_bls::MultiBLSSignature,
multi_ed25519::{MultiEd25519PublicKey, MultiEd25519Signature},
traits::Signature,
CryptoMaterialError, HashValue, ValidCryptoMaterial,
ValidCryptoMaterialStringExt,
};
use diem_crypto_derive::{CryptoHasher, DeserializeKey, SerializeKey};
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use rand::{rngs::OsRng, Rng};
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, fmt, str::FromStr};
#[derive(Debug)]
#[repr(u8)]
pub enum Scheme {
Ed25519 = 0,
MultiEd25519 = 1,
BLS = 2,
MultiBLS = 3,
}
impl fmt::Display for Scheme {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let display = match self {
Scheme::Ed25519 => "Ed25519",
Scheme::MultiEd25519 => "MultiEd25519",
Scheme::BLS => "bls",
Scheme::MultiBLS => "multi_bls",
};
write!(f, "Scheme::{}", display)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum TransactionAuthenticator {
Ed25519 {
public_key: Ed25519PublicKey,
signature: Ed25519Signature,
},
MultiEd25519 {
public_key: MultiEd25519PublicKey,
signature: MultiEd25519Signature,
},
BLS {
public_key: BLSPublicKey,
signature: BLSSignature,
},
MultiBLS {
signature: MultiBLSSignature,
}, }
#[derive(Deserialize)]
pub enum TransactionAuthenticatorUnchecked {
Ed25519 {
public_key: Ed25519PublicKey,
signature: Ed25519Signature,
},
MultiEd25519 {
public_key: MultiEd25519PublicKey,
signature: MultiEd25519Signature,
},
BLS {
public_key: BLSPublicKeyUnchecked,
signature: BLSSignatureUnchecked,
},
MultiBLS {
signature: MultiBLSSignature,
},
}
impl From<TransactionAuthenticatorUnchecked> for TransactionAuthenticator {
fn from(t: TransactionAuthenticatorUnchecked) -> Self {
match t {
TransactionAuthenticatorUnchecked::BLS {
public_key,
signature,
} => Self::BLS {
public_key: public_key.into(),
signature: signature.into(),
},
TransactionAuthenticatorUnchecked::MultiBLS { signature } => {
Self::MultiBLS { signature }
}
TransactionAuthenticatorUnchecked::Ed25519 {
public_key,
signature,
} => Self::Ed25519 {
public_key,
signature,
},
TransactionAuthenticatorUnchecked::MultiEd25519 {
public_key,
signature,
} => Self::MultiEd25519 {
public_key,
signature,
},
}
}
}
impl TransactionAuthenticator {
pub fn scheme(&self) -> Scheme {
match self {
Self::Ed25519 { .. } => Scheme::Ed25519,
Self::MultiEd25519 { .. } => Scheme::MultiEd25519,
Self::BLS { .. } => Scheme::BLS,
Self::MultiBLS { .. } => Scheme::MultiBLS,
}
}
pub fn ed25519(
public_key: Ed25519PublicKey, signature: Ed25519Signature,
) -> Self {
Self::Ed25519 {
public_key,
signature,
}
}
pub fn multi_ed25519(
public_key: MultiEd25519PublicKey, signature: MultiEd25519Signature,
) -> Self {
Self::MultiEd25519 {
public_key,
signature,
}
}
pub fn bls(public_key: BLSPublicKey, signature: BLSSignature) -> Self {
Self::BLS {
public_key,
signature,
}
}
pub fn multi_bls(signature: MultiBLSSignature) -> Self {
Self::MultiBLS { signature }
}
pub fn verify<T: Serialize + CryptoHash>(&self, message: &T) -> Result<()> {
match self {
Self::Ed25519 {
public_key,
signature,
} => signature.verify(message, public_key),
Self::MultiEd25519 {
public_key,
signature,
} => signature.verify(message, public_key),
Self::BLS {
public_key,
signature,
} => signature.verify(message, public_key),
Self::MultiBLS { .. } => {
Ok(())
}
}
}
pub fn public_key_bytes(&self) -> Vec<u8> {
match self {
Self::Ed25519 { public_key, .. } => public_key.to_bytes().to_vec(),
Self::MultiEd25519 { public_key, .. } => {
public_key.to_bytes().to_vec()
}
Self::BLS { public_key, .. } => public_key.to_bytes().to_vec(),
Self::MultiBLS { .. } => todo!(),
}
}
pub fn signature_bytes(&self) -> Vec<u8> {
match self {
Self::Ed25519 { signature, .. } => signature.to_bytes().to_vec(),
Self::MultiEd25519 { signature, .. } => {
signature.to_bytes().to_vec()
}
Self::BLS { signature, .. } => signature.to_bytes().to_vec(),
Self::MultiBLS { .. } => todo!(),
}
}
pub fn authentication_key_preimage(&self) -> AuthenticationKeyPreimage {
AuthenticationKeyPreimage::new(self.public_key_bytes(), self.scheme())
}
pub fn authentication_key(&self) -> AuthenticationKey {
AuthenticationKey::from_preimage(&self.authentication_key_preimage())
}
}
#[derive(
Clone,
Copy,
CryptoHasher,
Debug,
DeserializeKey,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
SerializeKey,
)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct AuthenticationKey([u8; AuthenticationKey::LENGTH]);
impl AuthenticationKey {
pub const LENGTH: usize = 32;
pub const fn new(bytes: [u8; Self::LENGTH]) -> Self { Self(bytes) }
pub fn from_preimage(
preimage: &AuthenticationKeyPreimage,
) -> AuthenticationKey {
AuthenticationKey::new(*HashValue::sha3_256_of(&preimage.0).as_ref())
}
pub fn ed25519(public_key: &Ed25519PublicKey) -> AuthenticationKey {
Self::from_preimage(&AuthenticationKeyPreimage::ed25519(public_key))
}
pub fn multi_ed25519(public_key: &MultiEd25519PublicKey) -> Self {
Self::from_preimage(&AuthenticationKeyPreimage::multi_ed25519(
public_key,
))
}
pub fn derived_address(&self) -> AccountAddress {
let mut array = [0u8; AccountAddress::LENGTH];
array.copy_from_slice(&self.0[Self::LENGTH - AccountAddress::LENGTH..]);
AccountAddress::new(array)
}
pub fn prefix(&self) -> [u8; AccountAddress::LENGTH] {
let mut array = [0u8; AccountAddress::LENGTH];
array.copy_from_slice(&self.0[..AccountAddress::LENGTH]);
array
}
pub fn to_vec(&self) -> Vec<u8> { self.0.to_vec() }
pub fn random() -> Self {
let mut rng = OsRng;
let buf: [u8; Self::LENGTH] = rng.gen();
AuthenticationKey::new(buf)
}
}
impl ValidCryptoMaterial for AuthenticationKey {
fn to_bytes(&self) -> Vec<u8> { self.to_vec() }
}
pub struct AuthenticationKeyPreimage(Vec<u8>);
impl AuthenticationKeyPreimage {
fn new(mut public_key_bytes: Vec<u8>, scheme: Scheme) -> Self {
public_key_bytes.push(scheme as u8);
Self(public_key_bytes)
}
pub fn ed25519(public_key: &Ed25519PublicKey) -> AuthenticationKeyPreimage {
Self::new(public_key.to_bytes().to_vec(), Scheme::Ed25519)
}
pub fn multi_ed25519(
public_key: &MultiEd25519PublicKey,
) -> AuthenticationKeyPreimage {
Self::new(public_key.to_bytes(), Scheme::MultiEd25519)
}
pub fn into_vec(self) -> Vec<u8> { self.0 }
}
impl fmt::Display for TransactionAuthenticator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"TransactionAuthenticator[scheme id: {:?}, public key: {}, signature: {}]",
self.scheme(),
hex::encode(&self.public_key_bytes()),
hex::encode(&self.signature_bytes())
)
}
}
impl TryFrom<&[u8]> for AuthenticationKey {
type Error = CryptoMaterialError;
fn try_from(
bytes: &[u8],
) -> std::result::Result<AuthenticationKey, CryptoMaterialError> {
if bytes.len() != Self::LENGTH {
return Err(CryptoMaterialError::WrongLengthError);
}
let mut addr = [0u8; Self::LENGTH];
addr.copy_from_slice(bytes);
Ok(AuthenticationKey(addr))
}
}
impl TryFrom<Vec<u8>> for AuthenticationKey {
type Error = CryptoMaterialError;
fn try_from(
bytes: Vec<u8>,
) -> std::result::Result<AuthenticationKey, CryptoMaterialError> {
AuthenticationKey::try_from(&bytes[..])
}
}
impl FromStr for AuthenticationKey {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
ensure!(
!s.is_empty(),
"authentication key string should not be empty.",
);
let bytes_out = ::hex::decode(s)?;
let key = AuthenticationKey::try_from(bytes_out.as_slice())?;
Ok(key)
}
}
impl AsRef<[u8]> for AuthenticationKey {
fn as_ref(&self) -> &[u8] { &self.0 }
}
impl fmt::LowerHex for AuthenticationKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", hex::encode(&self.0))
}
}
impl fmt::Display for AuthenticationKey {
fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
write!(f, "{:#x}", self)
}
}
#[cfg(test)]
mod tests {
use crate::transaction::authenticator::AuthenticationKey;
use std::str::FromStr;
#[test]
fn test_from_str_should_not_panic_by_given_empty_string() {
assert!(AuthenticationKey::from_str("").is_err());
}
}