use anyhow::{Result, anyhow};
use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey, Keypair, XOnlyPublicKey};
use bitcoin::secp256k1::rand::rngs::OsRng;
use sha2::{Sha256, Digest};
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum KeyType {
Ecdsa,
Schnorr,
}
#[derive(Debug, Clone)]
pub struct ManagedKey {
pub secret_key: SecretKey,
pub public_key: PublicKey,
pub x_only_pubkey: XOnlyPublicKey,
pub keypair: Keypair,
}
impl ManagedKey {
pub fn generate() -> Result<Self> {
let secp = Secp256k1::new();
let (secret_key, public_key) = secp.generate_keypair(&mut OsRng);
let keypair = Keypair::from_secret_key(&secp, &secret_key);
let (x_only_pubkey, _parity) = keypair.x_only_public_key();
Ok(Self {
secret_key,
public_key,
x_only_pubkey,
keypair,
})
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
let secp = Secp256k1::new();
let secret_key = SecretKey::from_slice(bytes)
.map_err(|e| anyhow!("Invalid secret key: {}", e))?;
let public_key = PublicKey::from_secret_key(&secp, &secret_key);
let keypair = Keypair::from_secret_key(&secp, &secret_key);
let (x_only_pubkey, _parity) = keypair.x_only_public_key();
Ok(Self {
secret_key,
public_key,
x_only_pubkey,
keypair,
})
}
pub fn to_did(&self) -> String {
format!("did:btcr:{}", hex::encode(self.public_key.serialize()))
}
pub fn pubkey_hex(&self) -> String {
hex::encode(self.public_key.serialize())
}
pub fn x_only_pubkey_hex(&self) -> String {
hex::encode(self.x_only_pubkey.serialize())
}
pub fn sign_ecdsa(&self, message: &[u8]) -> Result<String> {
let secp = Secp256k1::new();
let mut hasher = Sha256::new();
hasher.update(message);
let hash = hasher.finalize();
let msg = bitcoin::secp256k1::Message::from_digest_slice(&hash)
.map_err(|e| anyhow!("Invalid message: {}", e))?;
let sig = secp.sign_ecdsa(&msg, &self.secret_key);
Ok(hex::encode(sig.serialize_der()))
}
pub fn sign_schnorr(&self, message: &[u8]) -> Result<String> {
let secp = Secp256k1::new();
let mut hasher = Sha256::new();
hasher.update(message);
let hash = hasher.finalize();
let msg = bitcoin::secp256k1::Message::from_digest_slice(&hash)
.map_err(|e| anyhow!("Invalid message: {}", e))?;
let sig = secp.sign_schnorr_no_aux_rand(&msg, &self.keypair);
Ok(hex::encode(sig.serialize()))
}
pub fn verify_schnorr(&self, message: &[u8], sig_hex: &str) -> Result<bool> {
let secp = Secp256k1::new();
let sig_bytes = hex::decode(sig_hex)
.map_err(|e| anyhow!("Invalid signature hex: {}", e))?;
let sig = bitcoin::secp256k1::schnorr::Signature::from_slice(&sig_bytes)
.map_err(|e| anyhow!("Invalid signature: {}", e))?;
let mut hasher = Sha256::new();
hasher.update(message);
let hash = hasher.finalize();
let msg = bitcoin::secp256k1::Message::from_digest_slice(&hash)
.map_err(|e| anyhow!("Invalid message: {}", e))?;
Ok(secp.verify_schnorr(&sig, &msg, &self.x_only_pubkey).is_ok())
}
}
pub fn derive_taproot_internal_key(did_key: &ManagedKey) -> XOnlyPublicKey {
did_key.x_only_pubkey
}
#[derive(Serialize, Deserialize)]
pub struct KeyManagerExport {
pub did: String,
pub pubkey_hex: String,
pub x_only_pubkey_hex: String,
pub key_type: String,
}
impl From<&ManagedKey> for KeyManagerExport {
fn from(key: &ManagedKey) -> Self {
Self {
did: key.to_did(),
pubkey_hex: key.pubkey_hex(),
x_only_pubkey_hex: key.x_only_pubkey_hex(),
key_type: "secp256k1".to_string(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_generation() {
let key = ManagedKey::generate().unwrap();
assert_eq!(key.pubkey_hex().len(), 66); assert_eq!(key.x_only_pubkey_hex().len(), 64); }
#[test]
fn test_schnorr_sign_verify() {
let key = ManagedKey::generate().unwrap();
let message = b"test message";
let sig = key.sign_schnorr(message).unwrap();
assert!(key.verify_schnorr(message, &sig).unwrap());
}
}