1use rand_core::{CryptoRng, RngCore};
2use serde::{Serialize, de::DeserializeOwned};
3
4use crate::record::{Key, PubRecord};
5use relay_core::{
6 info::{EncryptionInfo, SignatureInfo},
7 prelude::{Payload, Signature},
8};
9
10#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
11pub enum AlgorithmError {
12 #[error("Algorithm mismatch: expected {0}, got {1}")]
13 AlgorithmMismatch(String, String),
14 #[error("Invalid secrets: {0}")]
15 InvalidSecrets(String),
16 #[error("Invalid meta: {0}")]
17 InvalidMeta(String),
18 #[error("Signature is missing")]
19 SignatureMissing,
20 #[error("Key derivation failed: {0}")]
21 KeyDerivation(String),
22 #[error("Invalid nonce")]
23 Nonce,
24 #[error("Invalid ephemeral")]
25 Ephemeral,
26 #[error("Encryption failed: {0}")]
27 Encrypt(String),
28 #[error("Decryption failed: {0}")]
29 Decrypt(String),
30 #[error("Failed: {0}")]
31 Error(String),
32}
33
34pub trait EncryptionContext {
35 fn decrypt<T>(&self, payload: &Payload<T>, aad: &[u8]) -> Result<Vec<u8>, AlgorithmError>;
36}
37
38pub trait EncryptionAlgorithm {
39 type Meta: Serialize + DeserializeOwned;
40 type Secrets: Serialize + DeserializeOwned;
41 type Context: EncryptionContext;
42
43 fn alg() -> &'static str;
44 fn info() -> Vec<u8> {
45 format!("relay-{}", Self::alg()).into_bytes()
46 }
47
48 fn generate(
49 &self,
50 rng: impl RngCore + CryptoRng,
51 ) -> Result<(Key, Self::Secrets), AlgorithmError>;
52
53 fn open_inner(
54 &self,
55 meta: &Self::Meta,
56 secrets: &Self::Secrets,
57 ) -> Result<Self::Context, AlgorithmError>;
58
59 fn encrypt_inner(
60 &self,
61 rng: impl RngCore + CryptoRng,
62 recipient: &PubRecord,
63 payload: &[u8],
64 aad: &[u8],
65 ) -> Result<(Self::Meta, Vec<u8>), AlgorithmError>;
66
67 fn open(&self, info: &EncryptionInfo, secrets: &[u8]) -> Result<Self::Context, AlgorithmError> {
68 if info.alg != Self::alg() {
69 return Err(AlgorithmError::AlgorithmMismatch(
70 info.alg.clone(),
71 Self::alg().to_string(),
72 ));
73 }
74
75 let meta: Self::Meta = serde_json::from_slice(&info.data)
76 .map_err(|e| AlgorithmError::InvalidMeta(format!("Failed to parse meta: {e}")))?;
77 let secrets: Self::Secrets = serde_json::from_slice(secrets)
78 .map_err(|e| AlgorithmError::InvalidSecrets(format!("Failed to parse secrets: {e}")))?;
79 self.open_inner(&meta, &secrets)
80 }
81
82 fn encrypt<T>(
83 &self,
84 rng: impl RngCore + CryptoRng,
85 recipient: &PubRecord,
86 payload: &[u8],
87 aad: &[u8],
88 ) -> Result<Payload<T>, AlgorithmError> {
89 self.encrypt_inner(rng, recipient, payload, aad)
90 .map(|(meta, ciphertext)| {
91 let meta_bytes = serde_json::to_vec(&meta).map_err(|e| {
92 AlgorithmError::InvalidMeta(format!("Failed to serialize meta: {e}"))
93 })?;
94 Ok(Payload::new(
95 EncryptionInfo {
96 alg: Self::alg().to_string(),
97 data: meta_bytes,
98 },
99 None,
100 ciphertext,
101 ))
102 })?
103 }
104}
105
106pub trait SigningAlgorithm: Send + Sync {
107 type Meta: Serialize + DeserializeOwned;
108 type Secrets: Serialize + DeserializeOwned;
109
110 fn alg() -> &'static str;
111
112 fn sign_inner(
113 &self,
114 payload: &[u8],
115 secrets: &Self::Secrets,
116 ) -> Result<(Self::Meta, Vec<u8>), AlgorithmError>;
117
118 fn verify_inner(
119 &self,
120 meta: &Self::Meta,
121 signature: &[u8],
122 payload: &[u8],
123 ) -> Result<(), AlgorithmError>;
124
125 fn sign<T>(
126 &self,
127 payload: Payload<T>,
128 raw_secrets: &[u8],
129 ) -> Result<Payload<T>, AlgorithmError> {
130 let secrets: Self::Secrets = serde_json::from_slice(raw_secrets)
131 .map_err(|e| AlgorithmError::InvalidSecrets(format!("{e}")))?;
132
133 let (meta, sig_bytes) = self.sign_inner(&payload.signing_bytes(), &secrets)?;
134
135 let meta_bytes =
136 serde_json::to_vec(&meta).map_err(|e| AlgorithmError::InvalidMeta(format!("{e}")))?;
137
138 let mut signed_payload = payload;
139 signed_payload.signature = Some(Signature {
140 info: SignatureInfo {
141 alg: Self::alg().to_string(),
142 data: meta_bytes,
143 },
144 sig: sig_bytes,
145 });
146
147 Ok(signed_payload)
148 }
149
150 fn verify<T>(&self, payload: &Payload<T>) -> Result<(), AlgorithmError> {
151 let signature = payload
152 .signature
153 .as_ref()
154 .ok_or(AlgorithmError::SignatureMissing)?;
155
156 if signature.info.alg != Self::alg() {
157 return Err(AlgorithmError::AlgorithmMismatch(
158 signature.info.alg.clone(),
159 Self::alg().to_string(),
160 ));
161 }
162
163 let meta: Self::Meta = serde_json::from_slice(&signature.info.data)
164 .map_err(|e| AlgorithmError::InvalidMeta(format!("{e}")))?;
165
166 self.verify_inner(&meta, &signature.sig, &payload.signing_bytes())
167 }
168}