signer-core 0.1.0

Signer core package.
Documentation
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)
  }
}