use core::alloc::Layout;
#[cfg(feature = "software-crypto-ed25519")]
pub use software::*;
use wasefire_error::Error;
use crate::Support;
pub trait Api: Support<bool> + Send {
const PRIVATE: Layout;
const PUBLIC: Layout;
const WRAPPED: usize;
fn generate(private: &mut [u8]) -> Result<(), Error>;
fn public(private: &[u8], public: &mut [u8]) -> Result<(), Error>;
fn sign(
private: &[u8], message: &[u8], r: &mut [u8; 32], s: &mut [u8; 32],
) -> Result<(), Error>;
fn verify(public: &[u8], message: &[u8], r: &[u8; 32], s: &[u8; 32]) -> Result<bool, Error>;
fn drop_private(private: &mut [u8]) -> Result<(), Error>;
fn export_private(private: &[u8], wrapped: &mut [u8]) -> Result<(), Error>;
fn import_private(wrapped: &[u8], private: &mut [u8]) -> Result<(), Error>;
fn export_public(public: &[u8], a: &mut [u8; 32]) -> Result<(), Error>;
fn import_public(a: &[u8; 32], public: &mut [u8]) -> Result<(), Error>;
}
#[cfg(feature = "software-crypto-ed25519")]
mod software {
use core::marker::PhantomData;
use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
use signature::rand_core::CryptoRngCore;
use wasefire_error::Code;
use zeroize::Zeroize;
use super::*;
use crate::Supported;
use crate::crypto::WithError;
pub struct Software<R> {
rng: PhantomData<R>,
}
impl<R> Supported for Software<R> {}
impl<R: Default + CryptoRngCore + WithError + Send> Api for Software<R> {
const PRIVATE: Layout = unsafe { Layout::from_size_align_unchecked(32, 1) };
const PUBLIC: Layout = unsafe { Layout::from_size_align_unchecked(32, 1) };
const WRAPPED: usize = 32;
fn generate(private: &mut [u8]) -> Result<(), Error> {
if private.len() != 32 {
return Err(Error::user(Code::InvalidLength));
}
let mut rng = R::default();
let key = R::with_error(|| SigningKey::generate(&mut rng))?;
private.copy_from_slice(&key.to_bytes());
Ok(())
}
fn public(private: &[u8], public: &mut [u8]) -> Result<(), Error> {
if private.len() != 32 || public.len() != 32 {
return Err(Error::user(Code::InvalidLength));
}
let key = SigningKey::from_bytes(private.try_into().unwrap());
public.copy_from_slice(key.verifying_key().as_bytes());
Ok(())
}
fn sign(
private: &[u8], message: &[u8], r: &mut [u8; 32], s: &mut [u8; 32],
) -> Result<(), Error> {
if private.len() != 32 {
return Err(Error::user(Code::InvalidLength));
}
let key = SigningKey::from_bytes(private.try_into().unwrap());
let sig = key.try_sign(message).map_err(|_| Error::world(0))?;
r.copy_from_slice(sig.r_bytes());
s.copy_from_slice(sig.s_bytes());
Ok(())
}
fn verify(
public: &[u8], message: &[u8], r: &[u8; 32], s: &[u8; 32],
) -> Result<bool, Error> {
if public.len() != 32 {
return Err(Error::user(Code::InvalidLength));
}
let key =
VerifyingKey::from_bytes(public.try_into().unwrap()).map_err(|_| Error::user(0))?;
let sig = Signature::from_components(*r, *s);
Ok(key.verify_strict(message, &sig).is_ok())
}
fn drop_private(private: &mut [u8]) -> Result<(), Error> {
if private.len() != 32 {
return Err(Error::user(Code::InvalidLength));
}
private.zeroize();
Ok(())
}
fn export_private(private: &[u8], wrapped: &mut [u8]) -> Result<(), Error> {
if private.len() != 32 || wrapped.len() != 32 {
return Err(Error::user(Code::InvalidLength));
}
wrapped.copy_from_slice(private);
Ok(())
}
fn import_private(wrapped: &[u8], private: &mut [u8]) -> Result<(), Error> {
if wrapped.len() != 32 || private.len() != 32 {
return Err(Error::user(Code::InvalidLength));
}
private.copy_from_slice(wrapped);
Ok(())
}
fn export_public(public: &[u8], a: &mut [u8; 32]) -> Result<(), Error> {
if public.len() != 32 {
return Err(Error::user(Code::InvalidLength));
}
a.copy_from_slice(public);
Ok(())
}
fn import_public(a: &[u8; 32], public: &mut [u8]) -> Result<(), Error> {
if public.len() != 32 {
return Err(Error::user(Code::InvalidLength));
}
public.copy_from_slice(a);
Ok(())
}
}
}