Skip to main content

relay_ciphers/
ed25519.rs

1use ed25519_dalek::{Signature, Signer as _, SigningKey, VerifyingKey};
2use serde::{Deserialize, Serialize};
3
4use relay_crypto::{
5    alg::{AlgorithmError, SigningAlgorithm},
6    hex,
7    kid::kid_from_key,
8    rand_core::{CryptoRng, RngCore},
9    record::Key,
10};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct Meta {
14    #[serde(with = "hex::serde")]
15    pub public_key: [u8; 32],
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct Secrets {
20    #[serde(with = "hex::serde")]
21    pub secret: [u8; 32],
22}
23
24pub struct Ed25519;
25
26impl Ed25519 {
27    pub fn generate(
28        &self,
29        mut rng: impl RngCore + CryptoRng,
30    ) -> Result<(Key, Secrets), AlgorithmError> {
31        let mut secret = [0u8; 32];
32        rng.fill_bytes(&mut secret);
33
34        let signing = SigningKey::from_bytes(&secret);
35        let verifying = signing.verifying_key();
36        let public = verifying.to_bytes();
37        let kid = kid_from_key(public.to_vec());
38
39        Ok((
40            Key {
41                alg: Self::alg().to_string(),
42                kid,
43                data: public.to_vec(),
44            },
45            Secrets { secret },
46        ))
47    }
48}
49
50impl SigningAlgorithm for Ed25519 {
51    type Meta = Meta;
52    type Secrets = Secrets;
53
54    fn alg() -> &'static str {
55        "ed25519"
56    }
57
58    fn sign_inner(
59        &self,
60        payload: &[u8],
61        secrets: &Self::Secrets,
62    ) -> Result<(Self::Meta, Vec<u8>), AlgorithmError> {
63        let signing = SigningKey::from_bytes(&secrets.secret);
64        let public = signing.verifying_key().to_bytes();
65        let signature = signing.sign(payload);
66
67        Ok((Meta { public_key: public }, signature.to_bytes().to_vec()))
68    }
69
70    fn verify_inner(
71        &self,
72        meta: &Self::Meta,
73        signature: &[u8],
74        payload: &[u8],
75    ) -> Result<(), AlgorithmError> {
76        let signature = Signature::from_slice(signature)
77            .map_err(|e| AlgorithmError::Error(format!("invalid signature: {e}")))?;
78        let verifying = VerifyingKey::from_bytes(&meta.public_key)
79            .map_err(|e| AlgorithmError::InvalidMeta(format!("invalid public key: {e}")))?;
80
81        verifying
82            .verify_strict(payload, &signature)
83            .map_err(|e| AlgorithmError::Error(format!("signature verification failed: {e}")))
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use crate::x25519_xchacha20poly1305::X25519XChaCha20Poly1305;
91    use relay_core::{chrono::Utc, prelude::Payload};
92    use relay_crypto::{
93        alg::{EncryptionAlgorithm, EncryptionContext, SigningAlgorithm},
94        record::{Key, PubRecord},
95        rng::os_rng_hkdf,
96    };
97
98    #[test]
99    fn sign_verify() {
100        let mut rng = os_rng_hkdf(None, b"test").unwrap();
101
102        let (_key, secrets) = Ed25519.generate(&mut rng).expect("key generation failed");
103
104        let payload = Payload::<()>::new(
105            relay_core::info::EncryptionInfo {
106                alg: "none".into(),
107                data: vec![],
108            },
109            None,
110            b"hello world".to_vec(),
111        );
112
113        let signed = Ed25519
114            .sign(payload, &serde_json::to_vec(&secrets).unwrap())
115            .expect("sign failed");
116
117        assert!(signed.is_signed());
118
119        Ed25519.verify(&signed).expect("verify failed");
120    }
121
122    #[test]
123    fn encrypt_sign_verify_decrypt() {
124        let mut rng = os_rng_hkdf(None, b"test").unwrap();
125
126        let (enc_key, enc_secrets) = X25519XChaCha20Poly1305
127            .generate(&mut rng)
128            .expect("enc generation failed");
129
130        let (_sign_key, sign_secrets) = Ed25519.generate(&mut rng).expect("sign generation failed");
131
132        let record = PubRecord {
133            id: "recipient".to_string(),
134            created_at: Utc::now(),
135            expires_at: None,
136            encryption: enc_key,
137            signing: Key {
138                alg: String::new(),
139                kid: String::new(),
140                data: vec![],
141            },
142        };
143
144        let message = b"Hello, world!";
145        let aad = b"aad";
146
147        let payload: Payload<()> = X25519XChaCha20Poly1305
148            .encrypt(&mut rng, &record, message, aad)
149            .expect("encryption failed");
150
151        let signed = Ed25519
152            .sign(payload, &serde_json::to_vec(&sign_secrets).unwrap())
153            .expect("sign failed");
154
155        Ed25519.verify(&signed).expect("verify failed");
156
157        let context = X25519XChaCha20Poly1305
158            .open(&signed.info, &serde_json::to_vec(&enc_secrets).unwrap())
159            .unwrap();
160
161        let decrypted = context.decrypt(&signed, aad).unwrap();
162
163        assert_eq!(decrypted, message);
164    }
165}