use k256::ecdsa;
use k256::ecdsa::signature::DigestVerifier;
use k256::ecdsa::{RecoveryId, SigningKey, VerifyingKey};
use sha3::{Digest, Keccak256};
use crate::error::{Error, Result};
use crate::{PrivateKey, PublicKey};
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Signature {
sig: [u8; 64],
id: u8,
}
impl Signature {
pub fn new() -> Self {
Self {
sig: [0u8; 64],
id: 0,
}
}
pub fn from_bytes(bytes: [u8; 65]) -> Self {
let mut res = Self::new();
res.sig.copy_from_slice(&bytes[..64]);
res.id = bytes[64];
res
}
pub fn from_slice(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 64 {
return Err(Error::InvalidSignature);
}
let mut res = Self::new();
res.sig.copy_from_slice(bytes);
if bytes.len() == 65 {
res.id = bytes[64];
}
Ok(res)
}
pub fn from_hex(hex: &str) -> Result<Self> {
let bytes = hex::decode(hex)?;
Self::from_slice(&bytes)
}
pub fn as_bytes(&self) -> [u8; 65] {
let mut res = [0u8; 65];
res[..64].copy_from_slice(&self.sig);
res[64] = self.id;
res
}
pub fn as_slice(&self) -> &[u8] {
let bytes = self.as_bytes();
Box::leak(Box::new(bytes))
}
pub fn as_hex(&self) -> String {
let bytes = self.as_bytes();
hex::encode(bytes)
}
}
impl From<ecdsa::Signature> for Signature {
fn from(sig: ecdsa::Signature) -> Self {
let mut res = Self::new();
res.sig.copy_from_slice(sig.to_bytes().as_slice());
res
}
}
impl From<&Signature> for ecdsa::Signature {
fn from(value: &Signature) -> Self {
Self::from_slice(&value.sig).unwrap()
}
}
impl From<&Signature> for RecoveryId {
fn from(value: &Signature) -> Self {
Self::from_byte(value.id).unwrap()
}
}
pub trait K256Sign {
fn sign(&self, msg: &str) -> Signature;
}
pub trait K256Verify {
fn verify(&self, msg: &str, signature: &Signature) -> bool;
}
pub trait K256Recover {
fn recover(msg: &str, signature: &Signature) -> Result<PublicKey>;
}
impl From<&PrivateKey> for SigningKey {
fn from(value: &PrivateKey) -> Self {
Self::from_slice(value.as_slice()).unwrap()
}
}
impl From<SigningKey> for PrivateKey {
fn from(value: SigningKey) -> Self {
let bytes = value.to_bytes();
Self::from_slice(bytes.as_slice()).unwrap()
}
}
impl From<&PublicKey> for VerifyingKey {
fn from(value: &PublicKey) -> Self {
Self::from_sec1_bytes(value.as_slice()).unwrap()
}
}
impl From<VerifyingKey> for PublicKey {
fn from(value: VerifyingKey) -> Self {
let bytes = value.to_encoded_point(false);
Self::from_slice(bytes.as_bytes()).unwrap()
}
}
impl K256Sign for PrivateKey {
fn sign(&self, msg: &str) -> Signature {
let digest = Keccak256::new_with_prefix(msg.as_bytes());
let key: SigningKey = self.into();
let (sig, id) = key.sign_digest_recoverable(digest).unwrap();
let mut signature: Signature = sig.into();
signature.id = id.to_byte();
signature
}
}
impl K256Verify for PublicKey {
fn verify(&self, msg: &str, signature: &Signature) -> bool {
let digest = Keccak256::new_with_prefix(msg.as_bytes());
let key: VerifyingKey = self.into();
let sig: ecdsa::Signature = signature.into();
key.verify_digest(digest, &sig).is_ok()
}
}
impl K256Recover for PrivateKey {
fn recover(msg: &str, signature: &Signature) -> Result<PublicKey> {
let digest = Keccak256::new_with_prefix(msg.as_bytes());
let sig: ecdsa::Signature = signature.into();
let id: RecoveryId = signature.into();
let recovered = VerifyingKey::recover_from_digest(digest, &sig, id)
.map_err(|e| Error::RecoveryError(e.to_string()))?;
let recovered_bytes = recovered.to_encoded_point(false);
PublicKey::from_slice(recovered_bytes.as_bytes())
}
}
impl K256Recover for PublicKey {
fn recover(msg: &str, signature: &Signature) -> Result<PublicKey> {
PrivateKey::recover(msg, signature)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_k256() {
let sk = PrivateKey::new();
let pk = sk.public_key();
let msg = "hello world";
let signature = sk.sign(msg);
assert!(pk.verify(msg, &signature));
let recovered = PublicKey::recover(msg, &signature).unwrap();
assert_eq!(pk, recovered);
}
}