use secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey, XOnlyPublicKey};
use std::fmt;
use super::auth::{AuthResponse, auth_challenge_digest};
use super::encoding::{decode_secret, encode_npub};
use super::{FipsAddress, IdentityError, NodeAddr, sha256};
pub struct Identity {
keypair: Keypair,
node_addr: NodeAddr,
address: FipsAddress,
}
impl Identity {
pub fn generate() -> Self {
let mut secret_bytes = [0u8; 32];
rand::Rng::fill_bytes(&mut rand::rng(), &mut secret_bytes);
let secret_key =
SecretKey::from_slice(&secret_bytes).expect("32 random bytes is a valid secret key");
Self::from_secret_key(secret_key)
}
pub fn from_keypair(keypair: Keypair) -> Self {
let (pubkey, _parity) = keypair.x_only_public_key();
let node_addr = NodeAddr::from_pubkey(&pubkey);
let address = FipsAddress::from_node_addr(&node_addr);
Self {
keypair,
node_addr,
address,
}
}
pub fn from_secret_key(secret_key: SecretKey) -> Self {
let secp = Secp256k1::new();
let keypair = Keypair::from_secret_key(&secp, &secret_key);
Self::from_keypair(keypair)
}
pub fn from_secret_bytes(bytes: &[u8; 32]) -> Result<Self, IdentityError> {
let secret_key = SecretKey::from_slice(bytes)?;
Ok(Self::from_secret_key(secret_key))
}
pub fn from_secret_str(s: &str) -> Result<Self, IdentityError> {
let secret_key = decode_secret(s)?;
Ok(Self::from_secret_key(secret_key))
}
pub fn keypair(&self) -> Keypair {
self.keypair
}
pub fn pubkey(&self) -> XOnlyPublicKey {
self.keypair.x_only_public_key().0
}
pub fn pubkey_full(&self) -> PublicKey {
self.keypair.public_key()
}
pub fn npub(&self) -> String {
encode_npub(&self.pubkey())
}
pub fn node_addr(&self) -> &NodeAddr {
&self.node_addr
}
pub fn address(&self) -> &FipsAddress {
&self.address
}
pub fn sign(&self, data: &[u8]) -> secp256k1::schnorr::Signature {
let secp = Secp256k1::new();
let digest = sha256(data);
secp.sign_schnorr(&digest, &self.keypair)
}
pub fn sign_challenge(&self, challenge: &[u8; 32], timestamp: u64) -> AuthResponse {
let digest = auth_challenge_digest(challenge, timestamp);
let secp = Secp256k1::new();
let signature = secp.sign_schnorr(&digest, &self.keypair);
AuthResponse {
pubkey: self.pubkey(),
timestamp,
signature,
}
}
}
impl fmt::Debug for Identity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Identity")
.field("node_addr", &self.node_addr)
.field("address", &self.address)
.finish_non_exhaustive()
}
}