#[cfg(test)]
#[path = "tests/crypto.rs"]
mod tests;
use crate::std::{ByteSized, ByteSizedError, ByteSizedFull, ByteSizedMut, ForceFrom};
use base64::{DecodeError, engine::{Engine as _, general_purpose::STANDARD as BASE64}};
use core::{
cmp::Ordering,
convert::TryFrom,
fmt::{Debug, Display, self},
hash::{Hash, Hasher},
ops::Deref,
str::FromStr,
};
use digest::Digest;
use sha2::{Sha256, Sha512};
use ed25519_dalek::{SigningKey as RealSigningKey, VerifyingKey as RealVerifyingKey};
use generic_array::{
ArrayLength,
GenericArray,
typenum::{U32, U64, Unsigned},
};
use hex::{FromHexError, self};
use rand_core::CryptoRngCore;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _};
use std::borrow::Cow;
#[derive(Copy, Clone, Default, Eq, Hash, PartialEq)]
pub struct Sha256Hash {
hash: [u8; 32],
}
impl Sha256Hash {
pub fn new<T: Into<Self>>(data: T) -> Self {
data.into()
}
}
impl Hashed for Sha256Hash {
type Algorithm = Sha256;
type OutputSize = U32;
fn from_digest(output: GenericArray<u8, Self::OutputSize>) -> Self {
let mut hash = [0_u8; 32];
hash.copy_from_slice(output.as_slice());
Self::from_bytes(hash)
}
}
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
pub struct Sha512Hash {
hash: [u8; 64],
}
impl Sha512Hash {
pub fn new<T: Into<Self>>(data: T) -> Self {
data.into()
}
}
impl Default for Sha512Hash {
fn default() -> Self {
Self { hash: [0; 64] }
}
}
impl Hashed for Sha512Hash {
type Algorithm = Sha512;
type OutputSize = U64;
fn from_digest(output: GenericArray<u8, Self::OutputSize>) -> Self {
let mut hash = [0_u8; 64];
hash.copy_from_slice(output.as_slice());
Self::from_bytes(hash)
}
}
macro_rules! impl_traits_for_hashed_type { ($t:ty, $o:ty, $s:expr) => {
impl ByteSized<$s> for $t {
fn as_bytes(&self) -> &[u8; $s] {
&self.hash
}
fn to_bytes(&self) -> [u8; $s] {
self.hash
}
fn from_bytes(bytes: [u8; $s]) -> Self {
Self { hash: bytes }
}
fn to_base64(&self) -> String {
BASE64.encode(self.hash)
}
fn from_base64(encoded: &str) -> Result<Self, DecodeError> {
Ok(Self::force_from(BASE64.decode(encoded)?))
}
fn to_hex(&self) -> String {
hex::encode(self.hash)
}
fn from_hex(encoded: &str) -> Result<Self, FromHexError> {
Ok(Self::force_from(hex::decode(encoded)?))
}
fn to_vec(&self) -> Vec<u8> {
self.hash.to_vec()
}
}
impl ByteSizedMut<$s> for $t {
fn as_mut_bytes(&mut self) -> &mut [u8; $s] {
&mut self.hash
}
fn into_bytes(self) -> [u8; $s] {
self.hash
}
fn into_vec(self) -> Vec<u8> {
self.hash.into_iter().collect()
}
}
impl AsMut<[u8; $s]> for $t {
fn as_mut(&mut self) -> &mut [u8; $s] {
self.as_mut_bytes()
}
}
impl AsRef<[u8; $s]> for $t {
fn as_ref(&self) -> &[u8; $s] {
self.as_bytes()
}
}
impl Debug for $t {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl Display for $t {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl From<[u8; $s]> for $t {
fn from(b: [u8; $s]) -> Self {
Self::from_bytes(b)
}
}
impl From<&[u8; $s]> for $t {
fn from(b: &[u8; $s]) -> Self {
Self::from_bytes(*b)
}
}
impl From<GenericArray<u8, $o>> for $t {
fn from(a: GenericArray<u8, $o>) -> Self {
Self::from(&a)
}
}
impl From<&GenericArray<u8, $o>> for $t {
fn from(a: &GenericArray<u8, $o>) -> Self {
let mut hash = [0_u8; $s];
hash.copy_from_slice(a.as_slice());
Self::from_bytes(hash)
}
}
impl FromStr for $t {
type Err = ByteSizedError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(s)
}
}
impl ForceFrom<&[u8]> for $t {
fn force_from(b: &[u8]) -> Self {
let mut array = [0_u8; $s];
let len = b.len().min($s);
#[expect(clippy::indexing_slicing, reason = "Infallible")]
array[..len].copy_from_slice(&b[..len]);
Self::from(array)
}
}
impl<const N: usize> ForceFrom<&[u8; N]> for $t {
fn force_from(b: &[u8; N]) -> Self {
Self::force_from(&b[..])
}
}
impl ForceFrom<Vec<u8>> for $t {
fn force_from(v: Vec<u8>) -> Self {
Self::force_from(&*v)
}
}
impl ForceFrom<&Vec<u8>> for $t {
fn force_from(v: &Vec<u8>) -> Self {
Self::force_from(&**v)
}
}
impl PartialEq<[u8; $s]> for $t {
fn eq(&self, other: &[u8; $s]) -> bool {
&self.hash == other
}
}
impl PartialEq<&[u8; $s]> for $t {
fn eq(&self, other: &&[u8; $s]) -> bool {
&&self.hash == other
}
}
impl Serialize for $t {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for $t {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let string = String::deserialize(deserializer)?;
Self::from_hex(&string).map_err(D::Error::custom)
}
}
impl TryFrom<&[u8]> for $t {
type Error = ByteSizedError;
fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
match b.len().cmp(&$s) {
Ordering::Greater => return Err(ByteSizedError::DataTooLong($s)),
Ordering::Less => return Err(ByteSizedError::DataTooShort($s)),
Ordering::Equal => {},
}
Ok(Self::force_from(b))
}
}
impl TryFrom<&str> for $t {
type Error = ByteSizedError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Self::try_from(hex::decode(s).map_err(|_err| ByteSizedError::InvalidHexString)?)
}
}
impl TryFrom<String> for $t {
type Error = ByteSizedError;
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl TryFrom<&String> for $t {
type Error = ByteSizedError;
fn try_from(s: &String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl TryFrom<Box<str>> for $t {
type Error = ByteSizedError;
fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
Self::try_from(&*s)
}
}
impl<'a> TryFrom<Cow<'a, str>> for $t {
type Error = ByteSizedError;
fn try_from(s: Cow<'a, str>) -> Result<Self, Self::Error> {
Self::try_from(s.as_ref())
}
}
impl TryFrom<Vec<u8>> for $t {
type Error = ByteSizedError;
fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(&*v)
}
}
impl TryFrom<&Vec<u8>> for $t {
type Error = ByteSizedError;
fn try_from(v: &Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(v.as_slice())
}
}
};}
impl_traits_for_hashed_type!(Sha256Hash, U32, 32);
impl_traits_for_hashed_type!(Sha512Hash, U64, 64);
#[derive(Clone, Eq, PartialEq)]
pub struct SigningKey {
key: RealSigningKey,
}
impl SigningKey {
#[must_use]
pub fn generate<R: CryptoRngCore + ?Sized>(csprng: &mut R) -> Self {
Self::from(RealSigningKey::generate(csprng))
}
#[must_use]
pub fn into_inner(self) -> RealSigningKey {
self.key
}
#[must_use]
pub fn verifying_key(&self) -> VerifyingKey {
VerifyingKey::from(&self.key.verifying_key())
}
}
impl ByteSized<32> for SigningKey {
fn as_bytes(&self) -> &[u8; 32] {
self.key.as_bytes()
}
fn to_bytes(&self) -> [u8; 32] {
self.key.to_bytes()
}
fn from_bytes(bytes: [u8; 32]) -> Self {
Self { key: RealSigningKey::from_bytes(&bytes) }
}
fn to_base64(&self) -> String {
self.key.to_base64()
}
fn from_base64(encoded: &str) -> Result<Self, DecodeError> {
RealSigningKey::from_base64(encoded).map(|key| Self { key })
}
fn to_hex(&self) -> String {
self.key.to_hex()
}
fn from_hex(encoded: &str) -> Result<Self, FromHexError> {
RealSigningKey::from_hex(encoded).map(|key| Self { key })
}
fn to_vec(&self) -> Vec<u8> {
self.key.to_vec()
}
}
impl ByteSizedFull<32> for SigningKey {}
impl AsRef<[u8; 32]> for SigningKey {
fn as_ref(&self) -> &[u8; 32] {
self.as_bytes()
}
}
impl Debug for SigningKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl Default for SigningKey {
fn default() -> Self {
Self { key: RealSigningKey::from_bytes(&[0; 32]) }
}
}
impl Deref for SigningKey {
type Target = RealSigningKey;
fn deref(&self) -> &Self::Target {
&self.key
}
}
impl Display for SigningKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl From<RealSigningKey> for SigningKey {
fn from(key: RealSigningKey) -> Self {
Self { key }
}
}
impl From<&RealSigningKey> for SigningKey {
fn from(key: &RealSigningKey) -> Self {
Self { key: key.clone() }
}
}
impl From<[u8; 32]> for SigningKey {
fn from(b: [u8; 32]) -> Self {
Self::from_bytes(b)
}
}
impl From<&[u8; 32]> for SigningKey {
fn from(b: &[u8; 32]) -> Self {
Self::from_bytes(*b)
}
}
impl FromStr for SigningKey {
type Err = ByteSizedError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(s)
}
}
impl ForceFrom<&[u8]> for SigningKey {
fn force_from(value: &[u8]) -> Self {
Self { key: RealSigningKey::force_from(value) }
}
}
impl<const N: usize> ForceFrom<&[u8; N]> for SigningKey {
fn force_from(value: &[u8; N]) -> Self {
Self::force_from(&value[..])
}
}
impl ForceFrom<Vec<u8>> for SigningKey {
fn force_from(value: Vec<u8>) -> Self {
Self::force_from(&*value)
}
}
impl ForceFrom<&Vec<u8>> for SigningKey {
fn force_from(value: &Vec<u8>) -> Self {
Self::force_from(&**value)
}
}
impl Hash for SigningKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.key.as_bytes().hash(state);
}
}
impl Serialize for SigningKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for SigningKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let string = String::deserialize(deserializer)?;
Self::from_hex(&string).map_err(D::Error::custom)
}
}
impl TryFrom<&[u8]> for SigningKey {
type Error = ByteSizedError;
fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
match b.len().cmp(&32) {
Ordering::Greater => return Err(ByteSizedError::DataTooLong(32)),
Ordering::Less => return Err(ByteSizedError::DataTooShort(32)),
Ordering::Equal => {},
}
Ok(Self::force_from(b))
}
}
impl TryFrom<&str> for SigningKey {
type Error = ByteSizedError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Self::try_from(hex::decode(s).map_err(|_err| ByteSizedError::InvalidHexString)?)
}
}
impl TryFrom<String> for SigningKey {
type Error = ByteSizedError;
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl TryFrom<&String> for SigningKey {
type Error = ByteSizedError;
fn try_from(s: &String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl TryFrom<Box<str>> for SigningKey {
type Error = ByteSizedError;
fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
Self::try_from(&*s)
}
}
impl<'a> TryFrom<Cow<'a, str>> for SigningKey {
type Error = ByteSizedError;
fn try_from(s: Cow<'a, str>) -> Result<Self, Self::Error> {
Self::try_from(s.as_ref())
}
}
impl TryFrom<Vec<u8>> for SigningKey {
type Error = ByteSizedError;
fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(&*v)
}
}
impl TryFrom<&Vec<u8>> for SigningKey {
type Error = ByteSizedError;
fn try_from(v: &Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(v.as_slice())
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct VerifyingKey {
key: RealVerifyingKey,
}
impl VerifyingKey {
#[must_use]
pub const fn into_inner(self) -> RealVerifyingKey {
self.key
}
}
impl ByteSized<32> for VerifyingKey {
fn as_bytes(&self) -> &[u8; 32] {
self.key.as_bytes()
}
fn to_bytes(&self) -> [u8; 32] {
self.key.to_bytes()
}
fn from_bytes(bytes: [u8; 32]) -> Self {
#[expect(clippy::option_if_let_else, reason = "Using map_or_else() here would not be as clear, and no more concise")]
match RealVerifyingKey::from_bytes(&bytes) {
Ok(key) => Self { key },
Err(_) => Self::default(),
}
}
fn to_base64(&self) -> String {
self.key.to_base64()
}
fn from_base64(encoded: &str) -> Result<Self, DecodeError> {
RealVerifyingKey::from_base64(encoded).map(|key| Self { key })
}
fn to_hex(&self) -> String {
self.key.to_hex()
}
fn from_hex(encoded: &str) -> Result<Self, FromHexError> {
RealVerifyingKey::from_hex(encoded).map(|key| Self { key })
}
fn to_vec(&self) -> Vec<u8> {
self.key.to_vec()
}
}
impl ByteSizedFull<32> for VerifyingKey {}
impl AsRef<[u8; 32]> for VerifyingKey {
fn as_ref(&self) -> &[u8; 32] {
self.as_bytes()
}
}
impl Debug for VerifyingKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl Default for VerifyingKey {
fn default() -> Self {
#[expect(clippy::unwrap_used, reason = "Infallible")]
Self { key: RealVerifyingKey::from_bytes(&[0; 32]).unwrap() }
}
}
impl Deref for VerifyingKey {
type Target = RealVerifyingKey;
fn deref(&self) -> &Self::Target {
&self.key
}
}
impl Display for VerifyingKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl From<RealVerifyingKey> for VerifyingKey {
fn from(key: RealVerifyingKey) -> Self {
Self { key }
}
}
impl From<&RealVerifyingKey> for VerifyingKey {
fn from(key: &RealVerifyingKey) -> Self {
Self { key: *key }
}
}
impl From<[u8; 32]> for VerifyingKey {
fn from(b: [u8; 32]) -> Self {
Self::from_bytes(b)
}
}
impl From<&[u8; 32]> for VerifyingKey {
fn from(b: &[u8; 32]) -> Self {
Self::from_bytes(*b)
}
}
impl FromStr for VerifyingKey {
type Err = ByteSizedError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(s)
}
}
impl ForceFrom<&[u8]> for VerifyingKey {
fn force_from(value: &[u8]) -> Self {
Self { key: RealVerifyingKey::force_from(value) }
}
}
impl<const N: usize> ForceFrom<&[u8; N]> for VerifyingKey {
fn force_from(value: &[u8; N]) -> Self {
Self::force_from(&value[..])
}
}
impl ForceFrom<Vec<u8>> for VerifyingKey {
fn force_from(value: Vec<u8>) -> Self {
Self::force_from(&*value)
}
}
impl ForceFrom<&Vec<u8>> for VerifyingKey {
fn force_from(value: &Vec<u8>) -> Self {
Self::force_from(&**value)
}
}
impl Hash for VerifyingKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.key.as_bytes().hash(state);
}
}
impl Serialize for VerifyingKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for VerifyingKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let string = String::deserialize(deserializer)?;
Self::from_hex(&string).map_err(D::Error::custom)
}
}
impl TryFrom<&[u8]> for VerifyingKey {
type Error = ByteSizedError;
fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
match b.len().cmp(&32) {
Ordering::Greater => return Err(ByteSizedError::DataTooLong(32)),
Ordering::Less => return Err(ByteSizedError::DataTooShort(32)),
Ordering::Equal => {},
}
Ok(Self::force_from(b))
}
}
impl TryFrom<&str> for VerifyingKey {
type Error = ByteSizedError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Self::try_from(hex::decode(s).map_err(|_err| ByteSizedError::InvalidHexString)?)
}
}
impl TryFrom<String> for VerifyingKey {
type Error = ByteSizedError;
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl TryFrom<&String> for VerifyingKey {
type Error = ByteSizedError;
fn try_from(s: &String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl TryFrom<Box<str>> for VerifyingKey {
type Error = ByteSizedError;
fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
Self::try_from(&*s)
}
}
impl<'a> TryFrom<Cow<'a, str>> for VerifyingKey {
type Error = ByteSizedError;
fn try_from(s: Cow<'a, str>) -> Result<Self, Self::Error> {
Self::try_from(s.as_ref())
}
}
impl TryFrom<Vec<u8>> for VerifyingKey {
type Error = ByteSizedError;
fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(&*v)
}
}
impl TryFrom<&Vec<u8>> for VerifyingKey {
type Error = ByteSizedError;
fn try_from(v: &Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(v.as_slice())
}
}
pub trait Hashed: Sized {
type Algorithm: Digest<OutputSize = Self::OutputSize> + Send;
type OutputSize: ArrayLength<u8> + Unsigned;
fn from_digest(output: GenericArray<u8, Self::OutputSize>) -> Self;
}
pub trait SigningKeyExt: ByteSized<32> {}
impl SigningKeyExt for RealSigningKey {}
impl ByteSized<32> for RealSigningKey {
fn as_bytes(&self) -> &[u8; 32] {
self.as_bytes()
}
fn to_bytes(&self) -> [u8; 32] {
self.to_bytes()
}
fn from_bytes(bytes: [u8; 32]) -> Self {
Self::from_bytes(&bytes)
}
fn to_base64(&self) -> String {
BASE64.encode(self.as_bytes())
}
fn from_base64(encoded: &str) -> Result<Self, DecodeError> {
Ok(Self::force_from(BASE64.decode(encoded)?))
}
fn to_hex(&self) -> String {
hex::encode(self.as_bytes())
}
fn from_hex(encoded: &str) -> Result<Self, FromHexError> {
Ok(Self::force_from(hex::decode(encoded)?))
}
fn to_vec(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
}
impl ForceFrom<&[u8]> for RealSigningKey {
fn force_from(value: &[u8]) -> Self {
let mut array = [0_u8; 32];
let len = value.len().min(32);
#[expect(clippy::indexing_slicing, reason = "Infallible")]
array[..len].copy_from_slice(&value[..len]);
Self::from(array)
}
}
impl<const N: usize> ForceFrom<&[u8; N]> for RealSigningKey {
fn force_from(value: &[u8; N]) -> Self {
Self::force_from(&value[..])
}
}
impl ForceFrom<Vec<u8>> for RealSigningKey {
fn force_from(value: Vec<u8>) -> Self {
Self::force_from(&*value)
}
}
impl ForceFrom<&Vec<u8>> for RealSigningKey {
fn force_from(value: &Vec<u8>) -> Self {
Self::force_from(&**value)
}
}
pub trait VerifyingKeyExt: ByteSized<32> {}
impl VerifyingKeyExt for RealVerifyingKey {}
impl ByteSized<32> for RealVerifyingKey {
fn as_bytes(&self) -> &[u8; 32] {
self.as_bytes()
}
fn to_bytes(&self) -> [u8; 32] {
self.to_bytes()
}
fn from_bytes(bytes: [u8; 32]) -> Self {
#[expect(clippy::unwrap_used, reason = "Infallible")]
Self::from_bytes(&bytes).unwrap_or_else(|_| Self::from_bytes(&[0_u8; 32]).unwrap())
}
fn to_base64(&self) -> String {
BASE64.encode(self.as_bytes())
}
fn from_base64(encoded: &str) -> Result<Self, DecodeError> {
Ok(Self::force_from(BASE64.decode(encoded)?))
}
fn to_hex(&self) -> String {
hex::encode(self.as_bytes())
}
fn from_hex(encoded: &str) -> Result<Self, FromHexError> {
Ok(Self::force_from(hex::decode(encoded)?))
}
fn to_vec(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
}
impl ForceFrom<&[u8]> for RealVerifyingKey {
fn force_from(value: &[u8]) -> Self {
let mut array = [0_u8; 32];
let len = value.len().min(32);
#[expect(clippy::indexing_slicing, reason = "Infallible")]
array[..len].copy_from_slice(&value[..len]);
#[expect(clippy::unwrap_used, reason = "Infallible")]
Self::from_bytes(&array).unwrap_or_else(|_| Self::from_bytes(&[0_u8; 32]).unwrap())
}
}
impl<const N: usize> ForceFrom<&[u8; N]> for RealVerifyingKey {
fn force_from(value: &[u8; N]) -> Self {
Self::force_from(&value[..])
}
}
impl ForceFrom<Vec<u8>> for RealVerifyingKey {
fn force_from(value: Vec<u8>) -> Self {
Self::force_from(&*value)
}
}
impl ForceFrom<&Vec<u8>> for RealVerifyingKey {
fn force_from(value: &Vec<u8>) -> Self {
Self::force_from(&**value)
}
}