use rlua::{prelude::*, UserDataMethods, UserData, MetaMethod, Lua};
use sodiumoxide::crypto::sign;
use base64;
use crate::error::Error;
pub struct LuaSecretKey (sign::SecretKey);
pub struct LuaPublicKey (sign::PublicKey);
pub fn sign(_: &Lua, this: &LuaSecretKey, msg: String) -> Result<String, LuaError> {
let signed_data = sign::sign(msg.as_bytes(), &this.0);
Ok(base64::encode(&signed_data))
}
pub fn verify(_: &Lua, this: &LuaPublicKey, base64_msg: String) -> Result<String, LuaError> {
let signed_msg = base64::decode(&base64_msg).map_err(LuaError::external)?;
sign::verify(&signed_msg, &this.0)
.and_then(|v| String::from_utf8(v).map_err(|_| ()) )
.map_err(|_| LuaError::external(Error::VerifyError))
}
pub fn sign_detached(_: &Lua, this: &LuaSecretKey, msg: String) -> Result<String, LuaError> {
let signature = sign::sign_detached(msg.as_bytes(), &this.0);
Ok(base64::encode(signature.0.as_ref()))
}
pub fn verify_detached(_: &Lua, this: &LuaPublicKey, (msg, base64_signature): (String, String)) -> Result<bool, LuaError> {
let signature_bytes = base64::decode(&base64_signature).map_err(LuaError::external)?;
let signature = sign::Signature::from_slice(&signature_bytes).ok_or(LuaError::external(Error::InvalidSignature))?;
Ok(sign::verify_detached(&signature, msg.as_bytes(), &this.0))
}
impl UserData for LuaSecretKey {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("sign", sign);
methods.add_method("sign_detached", sign_detached);
methods.add_meta_method(MetaMethod::ToString, |_, this, _: ()| {
Ok(base64::encode((this.0).0.as_ref()))
});
}
}
impl UserData for LuaPublicKey {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("verify", verify);
methods.add_method("verify_detached", verify_detached);
methods.add_meta_method(MetaMethod::ToString, |_, this, _: ()| {
Ok(base64::encode((this.0).0.as_ref()))
});
}
}
pub fn new_keypair(_lua: &Lua, _: ()) -> LuaResult<(LuaSecretKey, LuaPublicKey)> {
let (pk, sk) = sign::gen_keypair();
Ok((LuaSecretKey(sk), LuaPublicKey(pk)))
}
pub fn load_secret(_: &Lua, base64_key: String) -> Result<LuaSecretKey, LuaError> {
base64::decode(&base64_key).map_err(Error::from)
.and_then(|vec| sign::SecretKey::from_slice(&vec).ok_or(Error::InvalidKeys).map(LuaSecretKey))
.map_err(LuaError::external)
}
pub fn load_public(_: &Lua, base64_key: String) -> Result<LuaPublicKey, LuaError> {
base64::decode(&base64_key).map_err(Error::from)
.and_then(|vec| sign::PublicKey::from_slice(&vec).ok_or(Error::InvalidKeys).map(LuaPublicKey))
.map_err(LuaError::external)
}