Skip to main content

jwt_compact_preview/alg/
eddsa_compact.rs

1use ed25519_compact::{KeyPair, PublicKey, SecretKey, Seed, Signature};
2use rand_core::{CryptoRng, RngCore};
3
4use std::{borrow::Cow, fmt};
5
6use crate::{Algorithm, AlgorithmSignature, Renamed};
7
8impl AlgorithmSignature for Signature {
9    fn try_from_slice(bytes: &[u8]) -> anyhow::Result<Self> {
10        let mut signature = [0u8; Signature::BYTES];
11        if bytes.len() != signature.len() {
12            return Err(ed25519_compact::Error::SignatureMismatch.into());
13        }
14        signature.copy_from_slice(bytes);
15        Ok(Self::new(signature))
16    }
17
18    fn as_bytes(&self) -> Cow<[u8]> {
19        Cow::Borrowed(self.as_ref())
20    }
21}
22
23/// A verification key.
24#[derive(Debug, Copy, Clone, Eq, PartialEq)]
25pub struct Ed25519VerifyingKey(PublicKey);
26
27impl AsRef<PublicKey> for Ed25519VerifyingKey {
28    fn as_ref(&self) -> &PublicKey {
29        &self.0
30    }
31}
32
33impl Ed25519VerifyingKey {
34    /// Create a verification key from a slice.
35    pub fn from_slice(raw: &[u8]) -> anyhow::Result<Ed25519VerifyingKey> {
36        Ok(Ed25519VerifyingKey(PublicKey::from_slice(raw)?))
37    }
38
39    /// Return the key as raw bytes.
40    pub fn as_bytes(&self) -> Cow<[u8]> {
41        Cow::Borrowed(self.0.as_ref())
42    }
43}
44
45/// A signing key.
46pub struct Ed25519SigningKey(SecretKey);
47
48impl fmt::Debug for Ed25519SigningKey {
49    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
50        formatter
51            .debug_tuple("Ed25519SigningKey")
52            .field(&self.0.as_ref())
53            .finish()
54    }
55}
56
57impl AsRef<SecretKey> for Ed25519SigningKey {
58    fn as_ref(&self) -> &SecretKey {
59        &self.0
60    }
61}
62
63impl Ed25519SigningKey {
64    /// Create a signing key from a slice.
65    pub fn from_slice(raw: &[u8]) -> anyhow::Result<Ed25519SigningKey> {
66        Ok(Ed25519SigningKey(SecretKey::from_slice(raw)?))
67    }
68
69    /// Convert a signing key to a verification key.
70    pub fn to_verifying_key(&self) -> PublicKey {
71        self.as_ref().public_key()
72    }
73
74    /// Return the key as raw bytes.
75    pub fn as_bytes(&self) -> Cow<[u8]> {
76        Cow::Borrowed(self.0.as_ref())
77    }
78}
79
80/// Integrity algorithm using digital signatures on the Ed25519 elliptic curve.
81///
82/// The name of the algorithm is specified as `EdDSA` as per the [IANA registry].
83/// Use `with_specific_name()` to switch to non-standard `Ed25519`.
84///
85/// *This type is available if the crate is built with the `ed25519-compact` feature.*
86///
87/// [IANA registry]: https://www.iana.org/assignments/jose/jose.xhtml
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
89pub struct Ed25519;
90
91impl Ed25519 {
92    /// Creates an algorithm instance with the algorithm name specified as `Ed25519`.
93    /// This is a non-standard name, but it is used in some apps.
94    pub fn with_specific_name() -> Renamed<Self> {
95        Renamed::new(Self, "Ed25519")
96    }
97
98    /// Generate a new key pair.
99    pub fn generate<R: CryptoRng + RngCore>(
100        &self,
101        rng: &mut R,
102    ) -> (Ed25519SigningKey, Ed25519VerifyingKey) {
103        let mut seed = [0u8; Seed::BYTES];
104        rng.fill_bytes(&mut seed);
105        let keypair = KeyPair::from_seed(Seed::new(seed));
106        (
107            Ed25519SigningKey(keypair.sk),
108            Ed25519VerifyingKey(keypair.pk),
109        )
110    }
111}
112
113impl Algorithm for Ed25519 {
114    type SigningKey = Ed25519SigningKey;
115    type VerifyingKey = Ed25519VerifyingKey;
116    type Signature = Signature;
117
118    fn name(&self) -> Cow<'static, str> {
119        Cow::Borrowed("EdDSA")
120    }
121
122    fn sign(&self, signing_key: &Self::SigningKey, message: &[u8]) -> Self::Signature {
123        signing_key.as_ref().sign(message, Some(Default::default()))
124    }
125
126    fn verify_signature(
127        &self,
128        signature: &Self::Signature,
129        verifying_key: &Self::VerifyingKey,
130        message: &[u8],
131    ) -> bool {
132        verifying_key.as_ref().verify(message, signature).is_ok()
133    }
134}