use alloc::vec::Vec;
use anyhow::anyhow;
use codec::{Decode, DecodeWithMemTracking, Encode};
#[derive(
Debug, Clone, Encode, Decode, DecodeWithMemTracking, scale_info::TypeInfo, PartialEq, Eq,
)]
pub enum Signature {
Evm { address: Vec<u8>, signature: Vec<u8> },
Sr25519 { public_key: Vec<u8>, signature: Vec<u8> },
Ed25519 { public_key: Vec<u8>, signature: Vec<u8> },
}
impl Signature {
pub fn verify(
&self,
msg: &[u8; 32],
public_key_op: Option<Vec<u8>>,
) -> Result<Vec<u8>, anyhow::Error> {
match self {
Signature::Evm { signature, .. } => {
if signature.len() != 65 {
Err(anyhow!("Invalid Signature"))?
}
let mut sig = [0u8; 65];
sig.copy_from_slice(&signature);
let pub_key = sp_io::crypto::secp256k1_ecdsa_recover(&sig, msg)
.map_err(|_| anyhow!("Signature Verification failed"))?;
let signer = sp_io::hashing::keccak_256(&pub_key[..])[12..].to_vec();
Ok(signer)
},
Signature::Sr25519 { signature, public_key } => {
Self::verify_sr25519(signature, public_key, msg, &public_key_op)?;
Ok(public_key_op.unwrap_or(public_key.clone()))
},
Signature::Ed25519 { signature, public_key, .. } => {
let signature =
signature.as_slice().try_into().map_err(|_| anyhow!("Invalid Signature"))?;
let pub_key = public_key_op
.clone()
.unwrap_or(public_key.clone())
.as_slice()
.try_into()
.map_err(|_| anyhow!("Invalid Public Key"))?;
if !sp_io::crypto::ed25519_verify(&signature, msg, &pub_key) {
Err(anyhow!("Signature Verification failed"))?
}
Ok(public_key_op.unwrap_or(public_key.clone()))
},
}
}
fn verify_sr25519(
signature: &Vec<u8>,
public_key: &Vec<u8>,
msg: &[u8; 32],
public_key_op: &Option<Vec<u8>>,
) -> Result<[u8; 32], anyhow::Error> {
let signature =
signature.as_slice().try_into().map_err(|_| anyhow!("Invalid Signature"))?;
let pub_key = public_key_op
.clone()
.unwrap_or(public_key.clone())
.as_slice()
.try_into()
.map_err(|_| anyhow!("Invalid Public Key"))?;
if !sp_io::crypto::sr25519_verify(&signature, msg, &pub_key) {
return Err(anyhow!("Sr25519 signature verification failed"));
}
Ok(pub_key.into())
}
pub fn verify_and_get_sr25519_pubkey(
&self,
msg: &[u8; 32],
public_key_op: Option<Vec<u8>>,
) -> Result<[u8; 32], anyhow::Error> {
match self {
Signature::Sr25519 { public_key, signature } =>
Self::verify_sr25519(signature, public_key, msg, &public_key_op),
_ => Err(anyhow!("Signature is not of type Sr25519")),
}
}
pub fn signer(&self) -> Vec<u8> {
match self {
Signature::Evm { address, .. } => address.clone(),
Signature::Sr25519 { public_key, .. } => public_key.clone(),
Signature::Ed25519 { public_key, .. } => public_key.clone(),
}
}
}