signer-core 0.1.0

Signer core package.
Documentation
use anyhow::anyhow;
use base64::{prelude::BASE64_URL_SAFE, Engine};
use chacha20poly1305::{
  aead::{Aead, OsRng},
  AeadCore, KeyInit,
};
use schnorrkel::context::SigningContext;
use serde::{Deserialize, Serialize};
use sha3::digest::generic_array::GenericArray;

use crate::signer_user::SignerUser;

#[derive(Debug, Serialize, Deserialize)]
pub struct SignerMessage {
  pub sender: String,
  pub cipher_text: String,
  pub nonce: String,
}

impl SignerMessage {
  pub fn create(
    sender: &SignerUser,
    receiver: &str,
    message: &[u8],
  ) -> anyhow::Result<Self> {
    let key = key_agreement(sender, &receiver)?;

    let cipher =
      chacha20poly1305::ChaCha20Poly1305::new(GenericArray::from_slice(&key));
    let nonce = chacha20poly1305::ChaCha20Poly1305::generate_nonce(&mut OsRng);

    let cipher_text = cipher
      .encrypt(&nonce, message)
      .map_err(|e| anyhow!("encrypt signer message failed: {}", e))?;

    Ok(Self {
      sender: sender.public.pub_key.clone(),
      cipher_text: BASE64_URL_SAFE.encode(cipher_text),
      nonce: BASE64_URL_SAFE.encode(nonce),
    })
  }

  pub fn decrypt(&self, receiver: &SignerUser) -> anyhow::Result<Vec<u8>> {
    let key = key_agreement(receiver, &self.sender)?;

    let cipher =
      chacha20poly1305::ChaCha20Poly1305::new(GenericArray::from_slice(&key));
    let nonce = BASE64_URL_SAFE.decode(&self.nonce)?;

    let plain_text = cipher
      .decrypt(
        GenericArray::from_slice(&nonce),
        &*BASE64_URL_SAFE.decode(&self.cipher_text)?,
      )
      .map_err(|e| anyhow!("decrypt signer message failed: {}", e))?;

    Ok(plain_text)
  }
}

fn key_agreement(
  sender: &SignerUser,
  receiver: &str,
) -> anyhow::Result<[u8; 32]> {
  let keypair = sender.to_keypair()?;
  let public =
    schnorrkel::PublicKey::from_bytes(&BASE64_URL_SAFE.decode(&receiver)?)
      .map_err(|e| anyhow!("parse receiver public key failed: {}", e))?;

  let mut trans = SigningContext::new(b"").bytes(b"");
  keypair.commit_key_exchange(&mut trans, b"", &public);
  let mut key: [u8; 32] = [0; 32];
  trans.challenge_bytes(b"", key.as_mut_slice());

  Ok(key)
}