use crate::utils::as_array_32;
use core::fmt;
use core::mem::size_of;
#[cfg(feature = "dalek")]
use rand::{CryptoRng, RngCore};
use zerocopy::{AsBytes, FromBytes};
use zeroize::Zeroize;
#[cfg(all(feature = "dalek", not(feature = "force_sodium")))]
use crate::dalek::sign;
#[cfg(all(
feature = "sodium",
any(feature = "force_sodium", not(feature = "dalek"))
))]
use crate::sodium::sign;
#[derive(Clone, Debug, AsBytes, FromBytes)]
#[repr(C)]
pub struct Keypair {
pub secret: SecretKey,
pub public: PublicKey,
}
impl Keypair {
pub const SIZE: usize = size_of::<Self>();
pub fn from_slice(s: &[u8]) -> Option<Self> {
if s.len() == Self::SIZE {
Some(Keypair {
secret: SecretKey(as_array_32(&s[..32])),
public: PublicKey(as_array_32(&s[32..])),
})
} else {
None
}
}
#[cfg(feature = "b64")]
pub fn from_base64(s: &str) -> Option<Self> {
let mut buf = [0; 64];
if crate::b64::decode(s, &mut buf, Some(".ed25519")) {
Self::from_slice(&buf)
} else {
None
}
}
#[cfg(feature = "alloc")]
pub fn as_base64(&self) -> alloc::string::String {
let mut buf = [0; 64];
let (s, p) = buf.split_at_mut(32);
s.copy_from_slice(&self.secret.0);
p.copy_from_slice(&self.public.0);
base64::encode_config(&buf[..], base64::STANDARD)
}
#[cfg(any(feature = "sodium", all(feature = "dalek", feature = "getrandom")))]
pub fn generate() -> Keypair {
sign::generate_keypair()
}
#[cfg(any(feature = "sodium", feature = "dalek"))]
pub fn from_seed(seed: &[u8]) -> Option<Keypair> {
sign::keypair_from_seed(seed)
}
#[cfg(feature = "dalek")]
pub fn generate_with_rng<R>(r: &mut R) -> Keypair
where
R: CryptoRng + RngCore,
{
crate::dalek::sign::generate_keypair_with_rng(r)
}
#[cfg(any(feature = "sodium", feature = "dalek"))]
pub fn sign(&self, b: &[u8]) -> Signature {
sign::sign(self, b)
}
}
#[derive(Clone, Debug, AsBytes, FromBytes, Zeroize)]
#[zeroize(drop)]
#[repr(C)]
pub struct SecretKey(pub [u8; 32]);
impl SecretKey {
pub const SIZE: usize = size_of::<Self>();
}
#[derive(AsBytes, FromBytes, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(C)]
pub struct PublicKey(pub [u8; 32]);
impl PublicKey {
pub const SIZE: usize = size_of::<Self>();
pub fn from_slice(s: &[u8]) -> Option<Self> {
if s.len() == Self::SIZE {
let mut out = Self([0; Self::SIZE]);
out.0.copy_from_slice(s);
Some(out)
} else {
None
}
}
#[cfg(feature = "b64")]
pub fn from_base64(mut s: &str) -> Option<Self> {
if s.starts_with('@') {
s = &s[1..];
}
let mut buf = [0; Self::SIZE];
if crate::b64::decode(s, &mut buf, Some(".ed25519")) {
Some(Self(buf))
} else {
None
}
}
#[cfg(feature = "alloc")]
pub fn as_base64(&self) -> alloc::string::String {
base64::encode_config(&self.0, base64::STANDARD)
}
#[cfg(any(feature = "sodium", feature = "dalek"))]
pub fn verify(&self, sig: &Signature, b: &[u8]) -> bool {
sign::verify(self, sig, b)
}
}
#[derive(AsBytes, FromBytes, Copy, Clone)]
#[repr(C)]
pub struct Signature(pub [u8; 64]);
impl Signature {
pub const SIZE: usize = size_of::<Self>();
pub fn from_slice(s: &[u8]) -> Option<Self> {
if s.len() == Self::SIZE {
let mut out = Self([0; Self::SIZE]);
out.0.copy_from_slice(s);
Some(out)
} else {
None
}
}
#[cfg(feature = "b64")]
pub fn from_base64(s: &str) -> Option<Self> {
let mut buf = [0; Self::SIZE];
if crate::b64::decode(s, &mut buf, Some(".sig.ed25519")) {
Some(Self(buf))
} else {
None
}
}
#[cfg(feature = "alloc")]
pub fn as_base64(&self) -> alloc::string::String {
base64::encode_config(&self.0[..], base64::STANDARD)
}
}
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Signature({:?})", &self.0[..])
}
}
impl Eq for Signature {}
impl PartialEq for Signature {
fn eq(&self, other: &Self) -> bool {
self.0.as_ref().eq(other.0.as_ref())
}
}