use crate::Error;
use fuel_types::Bytes64;
use core::ops::Deref;
use core::{fmt, str};
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct Signature(Bytes64);
impl Signature {
pub const LEN: usize = Bytes64::LEN;
pub fn from_bytes(bytes: [u8; Self::LEN]) -> Self {
Self(bytes.into())
}
pub fn from_bytes_ref(bytes: &[u8; Self::LEN]) -> &Self {
#[allow(unsafe_code)]
unsafe {
&*(bytes.as_ptr() as *const Self)
}
}
#[deprecated = "Use `Signature::from_bytes` instead"]
pub fn from_bytes_unchecked(bytes: [u8; Self::LEN]) -> Self {
Self::from_bytes(bytes)
}
}
impl Deref for Signature {
type Target = [u8; Signature::LEN];
fn deref(&self) -> &[u8; Signature::LEN] {
self.0.deref()
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl AsMut<[u8]> for Signature {
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut()
}
}
impl fmt::LowerHex for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::UpperHex for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<Signature> for [u8; Signature::LEN] {
fn from(salt: Signature) -> [u8; Signature::LEN] {
salt.0.into()
}
}
impl From<Signature> for Bytes64 {
fn from(s: Signature) -> Self {
s.0
}
}
impl str::FromStr for Signature {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Bytes64::from_str(s)
.map_err(|_| Error::InvalidSignature)
.map(|s| Self::from_bytes(s.into()))
}
}
#[cfg(feature = "std")]
mod use_std {
use crate::{Error, Message, PublicKey, SecretKey, Signature};
use lazy_static::lazy_static;
use secp256k1::{
ecdsa::{RecoverableSignature as SecpRecoverableSignature, RecoveryId},
Secp256k1,
};
use std::borrow::Borrow;
lazy_static! {
static ref SIGNING_SECP: Secp256k1<secp256k1::SignOnly> = Secp256k1::signing_only();
static ref RECOVER_SECP: Secp256k1<secp256k1::All> = Secp256k1::new();
}
impl Signature {
pub(crate) fn to_secp(&mut self) -> SecpRecoverableSignature {
let v = (self.as_mut()[32] >> 7) as i32;
self.truncate_recovery_id();
let v = RecoveryId::from_i32(v)
.unwrap_or_else(|_| RecoveryId::from_i32(0).expect("0 is infallible recovery ID"));
let signature = SecpRecoverableSignature::from_compact(self.as_ref(), v).unwrap_or_else(|_| {
SecpRecoverableSignature::from_compact(&[0u8; 64], v).expect("Zeroed signature is infallible")
});
signature
}
pub(crate) fn from_secp(signature: SecpRecoverableSignature) -> Self {
let (v, mut signature) = signature.serialize_compact();
let v = v.to_i32();
signature[32] |= (v << 7) as u8;
Signature::from_bytes(signature)
}
pub(crate) fn truncate_recovery_id(&mut self) {
self.as_mut()[32] &= 0x7f;
}
pub fn sign(secret: &SecretKey, message: &Message) -> Self {
let secret = secret.borrow();
let message = message.to_secp();
let signature = SIGNING_SECP.sign_ecdsa_recoverable(&message, secret);
Signature::from_secp(signature)
}
pub fn recover(mut self, message: &Message) -> Result<PublicKey, Error> {
let signature = self.to_secp();
let message = message.to_secp();
let pk = RECOVER_SECP
.recover_ecdsa(&message, &signature)
.map(|pk| PublicKey::from_secp(&pk))?;
Ok(pk)
}
pub fn verify(self, pk: &PublicKey, message: &Message) -> Result<(), Error> {
self.recover(message)
.and_then(|pk_p| (pk == &pk_p).then_some(()).ok_or(Error::InvalidSignature))
}
}
}