use anyhow::{anyhow, Result}; use secp256k1::{Message, PublicKey, ecdsa::Signature, Secp256k1, SecretKey}; use sha2::{Digest, Sha256}; /// Helper for authentication operations pub struct AuthHelper { secret_key: SecretKey, public_key: PublicKey, secp: Secp256k1, } impl AuthHelper { /// Create a new auth helper from a private key hex string pub fn new(private_key_hex: &str) -> Result { let secp = Secp256k1::new(); let secret_key_bytes = hex::decode(private_key_hex) .map_err(|_| anyhow!("Invalid private key hex format"))?; let secret_key = SecretKey::from_slice(&secret_key_bytes) .map_err(|_| anyhow!("Invalid private key"))?; let public_key = PublicKey::from_secret_key(&secp, &secret_key); Ok(Self { secret_key, public_key, secp, }) } /// Generate a new random private key pub fn generate() -> Result { let secp = Secp256k1::new(); let (secret_key, public_key) = secp.generate_keypair(&mut rand::thread_rng()); Ok(Self { secret_key, public_key, secp, }) } /// Get the public key as a hex string pub fn public_key_hex(&self) -> String { hex::encode(self.public_key.serialize()) } /// Get the private key as a hex string pub fn private_key_hex(&self) -> String { hex::encode(self.secret_key.secret_bytes()) } /// Sign a message and return the signature as hex pub fn sign_message(&self, message: &str) -> Result { let message_hash = Sha256::digest(message.as_bytes()); let message = Message::from_slice(&message_hash) .map_err(|_| anyhow!("Failed to create message from hash"))?; let signature = self.secp.sign_ecdsa(&message, &self.secret_key); Ok(hex::encode(signature.serialize_compact())) } /// Verify a signature against a message pub fn verify_signature(&self, message: &str, signature_hex: &str) -> Result { let message_hash = Sha256::digest(message.as_bytes()); let message = Message::from_slice(&message_hash) .map_err(|_| anyhow!("Failed to create message from hash"))?; let signature_bytes = hex::decode(signature_hex) .map_err(|_| anyhow!("Invalid signature hex format"))?; let signature = Signature::from_compact(&signature_bytes) .map_err(|_| anyhow!("Invalid signature format"))?; match self.secp.verify_ecdsa(&message, &signature, &self.public_key) { Ok(_) => Ok(true), Err(_) => Ok(false), } } }