ts_crypto/
edwards.rs

1//! Edwards curve keys
2
3use ed25519_dalek::Signer;
4use sha2::{Digest, Sha256};
5use signature::SignatureEncoding;
6
7/// An edwards curve verifying key.
8pub enum EdwardsVerifyingKey {
9    /// Using Curve25519.
10    Ed25519(ed25519_dalek::VerifyingKey),
11    /// Using Curve448.
12    Ed448(ed448_goldilocks::VerifyingKey),
13}
14
15/// An edwards curve signing key.
16#[expect(clippy::large_enum_variant)]
17pub enum EdwardsSigningKey {
18    /// Using Curve25519
19    Ed25519(ed25519_dalek::SigningKey),
20    /// Using Curve448
21    Ed448(ed448_goldilocks::SigningKey),
22}
23
24impl EdwardsVerifyingKey {
25    /// Get the raw verifying key.
26    pub fn raw_key(&self) -> Vec<u8> {
27        match &self {
28            Self::Ed25519(key) => key.as_bytes().to_vec(),
29            Self::Ed448(key) => key.as_bytes().to_vec(),
30        }
31    }
32
33    /// Returns if this key verifies the signature to match the message.
34    pub fn verifies(&self, signature: &[u8], message: &[u8]) -> bool {
35        match &self {
36            Self::Ed25519(key) => {
37                let Ok(signature) = ed25519_dalek::Signature::from_slice(signature) else {
38                    return false;
39                };
40                key.verify_strict(message, &signature).is_ok()
41            }
42
43            Self::Ed448(key) => {
44                let Ok(signature) = ed448_goldilocks::Signature::from_slice(signature) else {
45                    return false;
46                };
47                key.verify_raw(&signature, message).is_ok()
48            }
49        }
50    }
51
52    /// Create an edwards key from a raw key.
53    pub fn from_raw_key(raw_key: &[u8]) -> Option<Self> {
54        match raw_key.len() {
55            ed25519_dalek::PUBLIC_KEY_LENGTH => {
56                #[allow(clippy::missing_panics_doc)]
57                let raw_key: &[u8; ed25519_dalek::PUBLIC_KEY_LENGTH] = raw_key
58                    .try_into()
59                    .expect("<&[u8;T]>::try_from(&[u8]) should succeed if <&[u8]>::len() == T");
60                let key = ed25519_dalek::VerifyingKey::from_bytes(raw_key).ok()?;
61                Some(Self::Ed25519(key))
62            }
63            ed448_goldilocks::PUBLIC_KEY_LENGTH => {
64                #[allow(clippy::missing_panics_doc)]
65                let raw_key: &[u8; ed448_goldilocks::PUBLIC_KEY_LENGTH] = raw_key
66                    .try_into()
67                    .expect("<&[u8;T]>::try_from(&[u8]) should succeed if <&[u8]>::len() == T");
68                let key = ed448_goldilocks::VerifyingKey::from_bytes(raw_key).ok()?;
69                Some(Self::Ed448(key))
70            }
71            _ => None,
72        }
73    }
74
75    /// Returns the ID for this key.
76    pub fn key_id(&self) -> Vec<u8> {
77        let key = self.raw_key();
78        let digest = Sha256::digest(key);
79        digest.to_vec()
80    }
81}
82
83impl EdwardsSigningKey {
84    /// Sign the message using this key.
85    pub fn sign(&self, message: &[u8]) -> Vec<u8> {
86        match &self {
87            Self::Ed25519(key) => key.sign(message).to_vec(),
88            Self::Ed448(key) => key.sign_raw(message).to_bytes().to_vec(),
89        }
90    }
91
92    /// Get the verifying key for this signing key
93    pub fn verifying_key(&self) -> EdwardsVerifyingKey {
94        match &self {
95            Self::Ed25519(key) => EdwardsVerifyingKey::Ed25519(key.verifying_key()),
96            Self::Ed448(key) => EdwardsVerifyingKey::Ed448(key.verifying_key()),
97        }
98    }
99}