baobab/interfaces/openrpc/client/src/auth.rs
2025-08-07 11:56:49 +02:00

82 lines
2.7 KiB
Rust

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<secp256k1::All>,
}
impl AuthHelper {
/// Create a new auth helper from a private key hex string
pub fn new(private_key_hex: &str) -> Result<Self> {
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<Self> {
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<String> {
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<bool> {
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),
}
}
}