use curve25519_dalek::edwards::CompressedEdwardsY;
use super::Context;
use crate::key_algos::StaticSigningAlgo as _;
pub use ed25519_dalek::{ed25519::Signature, Digest, Sha512, SignatureError};
pub use ed25519_dalek;
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct VerifyingKey(ed25519_dalek::VerifyingKey);
impl VerifyingKey {
pub const LEN: usize = Self::key_len();
pub fn try_from_bytes(bytes: &[u8; Self::LEN]) -> Result<Self, TryFromBytesError> {
let compressed_edwards = CompressedEdwardsY(bytes.to_owned());
let Some(edwards) = compressed_edwards.decompress() else {
return Err(TryFromBytesError::NotOnCurve);
};
let key = ed25519_dalek::VerifyingKey::from(edwards);
if key.is_weak() {
return Err(TryFromBytesError::WeakKey);
}
Ok(Self(key))
}
const fn key_len() -> usize {
let len = crate::key_algos::Ed25519::VERIFYING_KEY_LEN;
assert!(len == ed25519_dalek::PUBLIC_KEY_LENGTH);
len
}
pub fn into_inner(self) -> ed25519_dalek::VerifyingKey {
self.0
}
pub fn verify(
&self,
message: impl AsRef<[u8]>,
context: Context,
signature: &Signature,
) -> Result<(), SignatureError> {
let digest = Sha512::new().chain_update(message);
self.verify_digest(digest, context, signature)
}
pub fn verify_digest(
&self,
message_digest: Sha512,
context: Context,
signature: &Signature,
) -> Result<(), SignatureError> {
self.0
.verify_prehashed_strict(message_digest, Some(context.0), signature)
}
}
impl TryFrom<ed25519_dalek::VerifyingKey> for VerifyingKey {
type Error = TryFromBytesError;
fn try_from(value: ed25519_dalek::VerifyingKey) -> Result<Self, Self::Error> {
Self::try_from_bytes(value.as_bytes())
}
}
#[derive(Debug)]
pub struct SigningKey(ed25519_dalek::SigningKey);
impl SigningKey {
pub const LEN: usize = Self::key_len();
pub fn from_bytes(bytes: &[u8; Self::LEN]) -> Self {
let signing = ed25519_dalek::SigningKey::from_bytes(bytes);
let _pub = VerifyingKey::try_from(signing.verifying_key())
.expect("this should never fail. if it does, please open an issue");
Self(signing)
}
const fn key_len() -> usize {
let len = crate::key_algos::Ed25519::SIGNING_KEY_LEN;
assert!(len == ed25519_dalek::SECRET_KEY_LENGTH);
len
}
pub fn into_inner(self) -> ed25519_dalek::SigningKey {
self.0
}
#[cfg(feature = "random")]
pub fn random() -> Self {
let mut csprng = rand_core::OsRng;
Self(ed25519_dalek::SigningKey::generate(&mut csprng))
}
#[cfg(feature = "random")]
pub fn random_from_rng<R: rand_core::CryptoRngCore + ?Sized>(rng: &mut R) -> Self {
Self(ed25519_dalek::SigningKey::generate(rng))
}
pub fn verifying_key(&self) -> VerifyingKey {
VerifyingKey::try_from(self.0.verifying_key())
.expect("this should never fail. if it does, please open an issue")
}
pub fn sign(&self, message: impl AsRef<[u8]>, context: Context) -> Signature {
let digest = Sha512::new().chain_update(message);
self.sign_digest(digest, context)
}
pub fn sign_digest(&self, message_digest: Sha512, context: Context) -> Signature {
self.0
.sign_prehashed(message_digest, Some(context.0))
.expect("this should never fail. if it does, please open an issue")
}
}
#[derive(thiserror::Error, Debug)]
pub enum TryFromBytesError {
#[error(
"the provided bytes was not the y coordinate of a valid point on the curve"
)]
NotOnCurve,
#[error("public key has a low order and is too weak, which would allow the key to generate signatures that work for almost any message. To prevent this, we reject weak keys.")]
WeakKey,
}
#[cfg(test)]
mod test {}