use core::cell::UnsafeCell;
use crate::error::{check, len_as_u32, WolfCryptError};
use wolfcrypt_rs::{
wc_ed25519_export_public, wc_ed25519_free,
wc_ed25519_import_private_key, wc_ed25519_import_private_only,
wc_ed25519_import_public, wc_ed25519_init,
wc_ed25519_make_key, wc_ed25519_make_public, wc_ed25519_sign_msg,
wc_ed25519_verify_msg, wc_ed25519_key, wc_FreeRng, wc_InitRng, WC_RNG,
};
const ED25519_KEY_SIZE: usize = 32;
const ED25519_SIG_SIZE: usize = 64;
pub struct Ed25519SigningKey {
key: UnsafeCell<wc_ed25519_key>,
rng: UnsafeCell<WC_RNG>,
}
unsafe impl Send for Ed25519SigningKey {}
impl Ed25519SigningKey {
pub fn from_seed(seed: &[u8; ED25519_KEY_SIZE]) -> Result<Self, WolfCryptError> {
let mut key = wc_ed25519_key::zeroed();
let rc = unsafe { wc_ed25519_init(&mut key) };
check(rc, "wc_ed25519_init")?;
let rc = unsafe {
wc_ed25519_import_private_only(seed.as_ptr(), ED25519_KEY_SIZE as u32, &mut key)
};
check(rc, "wc_ed25519_import_private_only")?;
let mut pub_buf = [0u8; ED25519_KEY_SIZE];
let rc = unsafe {
wc_ed25519_make_public(&mut key, pub_buf.as_mut_ptr(), ED25519_KEY_SIZE as u32)
};
check(rc, "wc_ed25519_make_public")?;
let rc = unsafe {
wc_ed25519_import_private_key(
seed.as_ptr(),
ED25519_KEY_SIZE as u32,
pub_buf.as_ptr(),
ED25519_KEY_SIZE as u32,
&mut key,
)
};
check(rc, "wc_ed25519_import_private_key")?;
let mut rng = WC_RNG::zeroed();
let rc = unsafe { wc_InitRng(&mut rng) };
check(rc, "wc_InitRng")?;
Ok(Self {
key: UnsafeCell::new(key),
rng: UnsafeCell::new(rng),
})
}
pub fn generate(rng: &mut crate::rand::WolfRng) -> Result<Self, WolfCryptError> {
let mut key = wc_ed25519_key::zeroed();
let rc = unsafe { wc_ed25519_init(&mut key) };
check(rc, "wc_ed25519_init")?;
let rc = unsafe {
wc_ed25519_make_key(&mut rng.rng, ED25519_KEY_SIZE as i32, &mut key)
};
check(rc, "wc_ed25519_make_key")?;
let mut own_rng = WC_RNG::zeroed();
let rc = unsafe { wc_InitRng(&mut own_rng) };
check(rc, "wc_InitRng")?;
Ok(Self {
key: UnsafeCell::new(key),
rng: UnsafeCell::new(own_rng),
})
}
pub fn verifying_key(&self) -> Ed25519VerifyingKey {
let mut pub_buf = [0u8; ED25519_KEY_SIZE];
let mut pub_len: u32 = ED25519_KEY_SIZE as u32;
let rc = unsafe {
wc_ed25519_export_public(
self.key.get() as *const _,
pub_buf.as_mut_ptr(),
&mut pub_len,
)
};
assert_eq!(rc, 0, "wc_ed25519_export_public failed (key not initialized)");
Ed25519VerifyingKey::from_bytes(&pub_buf)
.expect("exported public key must be valid")
}
}
impl Drop for Ed25519SigningKey {
fn drop(&mut self) {
unsafe {
wc_ed25519_free(self.key.get_mut());
wc_FreeRng(self.rng.get_mut());
}
}
}
impl signature_trait::Signer<ed25519_trait::Signature> for Ed25519SigningKey {
fn try_sign(&self, msg: &[u8]) -> Result<ed25519_trait::Signature, signature_trait::Error> {
let mut sig_buf = [0u8; ED25519_SIG_SIZE];
let mut sig_len: u32 = ED25519_SIG_SIZE as u32;
let rc = unsafe {
wc_ed25519_sign_msg(
msg.as_ptr(),
len_as_u32(msg.len()),
sig_buf.as_mut_ptr(),
&mut sig_len,
self.key.get(),
)
};
if rc != 0 {
return Err(signature_trait::Error::new());
}
Ok(ed25519_trait::Signature::from_bytes(&sig_buf))
}
}
pub struct Ed25519VerifyingKey {
key: UnsafeCell<wc_ed25519_key>,
pub_bytes: [u8; ED25519_KEY_SIZE],
}
unsafe impl Send for Ed25519VerifyingKey {}
impl Ed25519VerifyingKey {
pub fn from_bytes(bytes: &[u8; ED25519_KEY_SIZE]) -> Result<Self, WolfCryptError> {
let mut key = wc_ed25519_key::zeroed();
let rc = unsafe { wc_ed25519_init(&mut key) };
check(rc, "wc_ed25519_init")?;
let rc = unsafe {
wc_ed25519_import_public(bytes.as_ptr(), ED25519_KEY_SIZE as u32, &mut key)
};
check(rc, "wc_ed25519_import_public")?;
Ok(Self {
key: UnsafeCell::new(key),
pub_bytes: *bytes,
})
}
pub fn as_bytes(&self) -> &[u8; ED25519_KEY_SIZE] {
&self.pub_bytes
}
}
impl Drop for Ed25519VerifyingKey {
fn drop(&mut self) {
unsafe {
wc_ed25519_free(self.key.get_mut());
}
}
}
impl signature_trait::Verifier<ed25519_trait::Signature> for Ed25519VerifyingKey {
fn verify(
&self,
msg: &[u8],
signature: &ed25519_trait::Signature,
) -> Result<(), signature_trait::Error> {
let sig_bytes = signature.to_bytes();
let mut result: i32 = 0;
let rc = unsafe {
wc_ed25519_verify_msg(
sig_bytes.as_ptr(),
len_as_u32(sig_bytes.len()),
msg.as_ptr(),
len_as_u32(msg.len()),
&mut result,
self.key.get(),
)
};
if rc != 0 || result != 1 {
return Err(signature_trait::Error::new());
}
Ok(())
}
}
pub fn ed25519_sign_raw(
seed: &[u8],
pub_key: &[u8],
message: &[u8],
) -> Result<[u8; 64], WolfCryptError> {
let mut key = wc_ed25519_key::zeroed();
let rc = unsafe { wc_ed25519_init(&mut key) };
check(rc, "wc_ed25519_init")?;
let rc = unsafe {
wc_ed25519_import_private_key(
seed.as_ptr(), len_as_u32(seed.len()),
pub_key.as_ptr(), len_as_u32(pub_key.len()),
&mut key,
)
};
if rc != 0 {
unsafe { wc_ed25519_free(&mut key) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ed25519_import_private_key" });
}
let mut sig = [0u8; 64];
let mut sig_len: u32 = 64;
let rc = unsafe {
wc_ed25519_sign_msg(
message.as_ptr(), len_as_u32(message.len()),
sig.as_mut_ptr(), &mut sig_len,
&mut key,
)
};
unsafe { wc_ed25519_free(&mut key) };
check(rc, "wc_ed25519_sign_msg")?;
Ok(sig)
}
pub fn ed25519_verify_raw(
pub_key: &[u8],
message: &[u8],
sig: &[u8],
) -> Result<(), WolfCryptError> {
let mut key = wc_ed25519_key::zeroed();
let rc = unsafe { wc_ed25519_init(&mut key) };
check(rc, "wc_ed25519_init")?;
let rc = unsafe {
wc_ed25519_import_public(
pub_key.as_ptr(), len_as_u32(pub_key.len()),
&mut key,
)
};
if rc != 0 {
unsafe { wc_ed25519_free(&mut key) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_ed25519_import_public" });
}
let mut result: core::ffi::c_int = 0;
let rc = unsafe {
wc_ed25519_verify_msg(
sig.as_ptr(), len_as_u32(sig.len()),
message.as_ptr(), len_as_u32(message.len()),
&mut result,
&mut key,
)
};
unsafe { wc_ed25519_free(&mut key) };
check(rc, "wc_ed25519_verify_msg")?;
if result == 1 { Ok(()) } else { Err(WolfCryptError::InvalidInput) }
}