use anyhow::anyhow;
use base64::{prelude::BASE64_URL_SAFE, Engine};
use schnorrkel::MiniSecretKey;
use serde::{Deserialize, Serialize};
use crate::{signer_signature::SignerSignature, utils};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SignerUser {
pub public: SignerUserPublic,
pub prv_key: String,
}
impl SignerUser {
pub fn generete(username: &str) -> anyhow::Result<Self> {
let mini_secret = schnorrkel::MiniSecretKey::generate();
let mut u = Self::from_mini_secret_key(mini_secret)?;
u.public.username = username.to_string();
Ok(u)
}
pub fn from_secret(secret: &str) -> anyhow::Result<Self> {
let mini_secret =
schnorrkel::MiniSecretKey::from_bytes(&BASE64_URL_SAFE.decode(secret)?)
.map_err(|e| anyhow!("decode secret failed: {:?}", e))?;
Self::from_mini_secret_key(mini_secret)
}
pub(crate) fn from_mini_secret_key(
mini_secret: MiniSecretKey,
) -> anyhow::Result<Self> {
let keypair = mini_secret.expand_to_keypair(MiniSecretKey::UNIFORM_MODE);
let pub_key = BASE64_URL_SAFE.encode(keypair.public.as_ref());
let prv_key = BASE64_URL_SAFE.encode(mini_secret.as_bytes());
Ok(SignerUser {
public: SignerUserPublic {
username: String::new(),
pub_key,
},
prv_key,
})
}
pub(crate) fn to_keypair(&self) -> anyhow::Result<schnorrkel::Keypair> {
let keypair = schnorrkel::MiniSecretKey::from_bytes(
&base64::prelude::BASE64_URL_SAFE.decode(&self.prv_key)?,
)
.map_err(|e| anyhow!("parse schnorrkel secret key failed {}", e))?
.expand_to_keypair(MiniSecretKey::UNIFORM_MODE);
Ok(keypair)
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SignerUserPublic {
pub pub_key: String,
pub username: String,
}
impl SignerUserPublic {
pub fn create_signature(&self, user: &SignerUser) -> anyhow::Result<Vec<u8>> {
let h = utils::jsonhash::json_hash(&serde_json::to_value(self)?)?;
let sig = SignerSignature::create(user, &h)?;
Ok(BASE64_URL_SAFE.decode(sig.bytes)?)
}
pub fn verify_signature(&self, sig_byets: &[u8]) -> anyhow::Result<()> {
let h = utils::jsonhash::json_hash(&serde_json::to_value(self)?)?;
let sig = SignerSignature {
bytes: BASE64_URL_SAFE.encode(sig_byets),
pub_key: self.pub_key.clone(),
};
sig.verify(&h)
}
}