Skip to main content

crypto_dispatch/
registry.rs

1// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2//
3// SPDX-License-Identifier: Apache-2.0
4
5use zeroize::Zeroizing;
6
7use crate::traits::{AeadCipherAlgorithm, AeadParams, SignatureAlgorithm};
8use crate::AlgorithmError;
9use crypto_core::{AeadAlgorithm, Algorithm};
10
11// --- Signature algorithm adapters ---
12use crate::algorithms::ed25519::Ed25519Algo;
13use crate::algorithms::ml_dsa_44::MlDsa44Algo;
14use crate::algorithms::ml_dsa_65::MlDsa65Algo;
15use crate::algorithms::ml_dsa_87::MlDsa87Algo;
16use crate::algorithms::p256::P256Algo;
17use crate::algorithms::p384::P384Algo;
18use crate::algorithms::p521::P521Algo;
19use crate::algorithms::secp256k1::Secp256k1Algo;
20
21// --- Key agreement / KEM adapters ---
22use crate::algorithms::ml_kem_1024::MlKem1024Algo;
23use crate::algorithms::ml_kem_512::MlKem512Algo;
24use crate::algorithms::ml_kem_768::MlKem768Algo;
25use crate::algorithms::x25519::X25519Algo;
26use crate::algorithms::x_wing::{XWing1024Algo, XWing768Algo};
27
28// --- Symmetric adapters ---
29use crate::algorithms::aes256_gcm::{Aes128GcmAlgo, Aes192GcmAlgo, Aes256GcmAlgo};
30use crate::algorithms::aes256_gcm_siv::Aes256GcmSivAlgo;
31use crate::algorithms::chacha20_poly1305::{ChaCha20Poly1305Algo, XChaCha20Poly1305Algo};
32
33//
34// -----------------------------------------------------------------------------
35// Keypair generation (ALL ALGORITHMS)
36// -----------------------------------------------------------------------------
37
38/// Generate a raw keypair for the given algorithm.
39///
40/// This is supported for:
41/// - signature algorithms
42/// - key agreement algorithms
43/// - KEM algorithms
44///
45/// Returns (public_key, secret_key); the secret half zeroizes on drop.
46pub fn generate_keypair(alg: Algorithm) -> Result<(Vec<u8>, Zeroizing<Vec<u8>>), AlgorithmError> {
47    match alg {
48        Algorithm::Ed25519 => Ed25519Algo::generate_keypair(),
49        Algorithm::P256 => P256Algo::generate_keypair(),
50        Algorithm::P384 => P384Algo::generate_keypair(),
51        Algorithm::P521 => P521Algo::generate_keypair(),
52        Algorithm::Secp256k1 => Secp256k1Algo::generate_keypair(),
53        Algorithm::MlDsa44 => MlDsa44Algo::generate_keypair(),
54        Algorithm::MlDsa65 => MlDsa65Algo::generate_keypair(),
55        Algorithm::MlDsa87 => MlDsa87Algo::generate_keypair(),
56
57        Algorithm::X25519 => X25519Algo::generate_keypair(),
58        Algorithm::MlKem512 => MlKem512Algo::generate_keypair(),
59        Algorithm::MlKem768 => MlKem768Algo::generate_keypair(),
60        Algorithm::MlKem1024 => MlKem1024Algo::generate_keypair(),
61        Algorithm::XWing768 => XWing768Algo::generate_keypair(),
62        Algorithm::XWing1024 => XWing1024Algo::generate_keypair(),
63    }
64}
65
66//
67// -----------------------------------------------------------------------------
68// Signature algorithms ONLY
69// -----------------------------------------------------------------------------
70
71/// Sign `msg` with `secret` under the selected signature algorithm,
72/// returning the detached signature bytes.
73///
74/// # Examples
75///
76/// ```
77/// use crypto_core::Algorithm;
78/// use crypto_dispatch::{generate_keypair, sign, verify};
79///
80/// # fn main() -> Result<(), crypto_dispatch::AlgorithmError> {
81/// let (public, secret) = generate_keypair(Algorithm::Ed25519)?;
82/// let signature = sign(Algorithm::Ed25519, &secret, b"message")?;
83/// verify(Algorithm::Ed25519, &public, b"message", &signature)?;
84/// # Ok(())
85/// # }
86/// ```
87pub fn sign(alg: Algorithm, secret: &[u8], msg: &[u8]) -> Result<Vec<u8>, AlgorithmError> {
88    match alg {
89        Algorithm::Ed25519 => Ed25519Algo::sign(secret, msg),
90        Algorithm::P256 => P256Algo::sign(secret, msg),
91        Algorithm::P384 => P384Algo::sign(secret, msg),
92        Algorithm::P521 => P521Algo::sign(secret, msg),
93        Algorithm::Secp256k1 => Secp256k1Algo::sign(secret, msg),
94        Algorithm::MlDsa44 => MlDsa44Algo::sign(secret, msg),
95        Algorithm::MlDsa65 => MlDsa65Algo::sign(secret, msg),
96        Algorithm::MlDsa87 => MlDsa87Algo::sign(secret, msg),
97        _ => Err(AlgorithmError::UnsupportedAlgorithm(alg)),
98    }
99}
100
101/// Verify a detached signature.
102///
103/// Fails closed: a signature that does not verify is an
104/// [`AlgorithmError::SignatureInvalid`] error, never a boolean, so a
105/// forgotten result check cannot be mistaken for success.
106///
107/// # Examples
108///
109/// ```
110/// use crypto_core::Algorithm;
111/// use crypto_dispatch::{generate_keypair, sign, verify};
112///
113/// # fn main() -> Result<(), crypto_dispatch::AlgorithmError> {
114/// let (public, secret) = generate_keypair(Algorithm::Ed25519)?;
115/// let signature = sign(Algorithm::Ed25519, &secret, b"message")?;
116///
117/// // The signed message verifies.
118/// verify(Algorithm::Ed25519, &public, b"message", &signature)?;
119///
120/// // A different message returns Err, never `Ok(false)`.
121/// assert!(verify(Algorithm::Ed25519, &public, b"tampered", &signature).is_err());
122/// # Ok(())
123/// # }
124/// ```
125pub fn verify(alg: Algorithm, public: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), AlgorithmError> {
126    match alg {
127        Algorithm::Ed25519 => Ed25519Algo::verify(public, msg, sig),
128        Algorithm::P256 => P256Algo::verify(public, msg, sig),
129        Algorithm::P384 => P384Algo::verify(public, msg, sig),
130        Algorithm::P521 => P521Algo::verify(public, msg, sig),
131        Algorithm::Secp256k1 => Secp256k1Algo::verify(public, msg, sig),
132        Algorithm::MlDsa44 => MlDsa44Algo::verify(public, msg, sig),
133        Algorithm::MlDsa65 => MlDsa65Algo::verify(public, msg, sig),
134        Algorithm::MlDsa87 => MlDsa87Algo::verify(public, msg, sig),
135        _ => Err(AlgorithmError::UnsupportedAlgorithm(alg)),
136    }
137}
138
139//
140// -----------------------------------------------------------------------------
141// ECDH / DH key agreement
142// -----------------------------------------------------------------------------
143
144/// Derive a Diffie–Hellman shared secret. The returned secret zeroizes on
145/// drop.
146pub fn derive_shared_secret(
147    alg: Algorithm,
148    secret_key: &[u8],
149    public_key: &[u8],
150) -> Result<Zeroizing<Vec<u8>>, AlgorithmError> {
151    match alg {
152        Algorithm::P256 => P256Algo::derive_shared_secret(secret_key, public_key),
153        Algorithm::P384 => P384Algo::derive_shared_secret(secret_key, public_key),
154        Algorithm::P521 => P521Algo::derive_shared_secret(secret_key, public_key),
155        Algorithm::X25519 => X25519Algo::derive_shared_secret(secret_key, public_key),
156        _ => Err(AlgorithmError::UnsupportedAlgorithm(alg)),
157    }
158}
159
160//
161// -----------------------------------------------------------------------------
162// POST-QUANTUM KEM
163// -----------------------------------------------------------------------------
164
165/// Returns (shared_secret, ciphertext); the shared secret zeroizes on drop.
166pub fn kem_encapsulate(
167    alg: Algorithm,
168    public_key: &[u8],
169) -> Result<(Zeroizing<Vec<u8>>, Vec<u8>), AlgorithmError> {
170    match alg {
171        Algorithm::MlKem512 => MlKem512Algo::encapsulate(public_key),
172        Algorithm::MlKem768 => MlKem768Algo::encapsulate(public_key),
173        Algorithm::MlKem1024 => MlKem1024Algo::encapsulate(public_key),
174        Algorithm::XWing768 => XWing768Algo::encapsulate(public_key),
175        Algorithm::XWing1024 => XWing1024Algo::encapsulate(public_key),
176        _ => Err(AlgorithmError::UnsupportedAlgorithm(alg)),
177    }
178}
179
180/// Decapsulate a KEM ciphertext. The returned shared secret zeroizes on drop.
181pub fn kem_decapsulate(
182    alg: Algorithm,
183    ciphertext: &[u8],
184    secret_key: &[u8],
185) -> Result<Zeroizing<Vec<u8>>, AlgorithmError> {
186    match alg {
187        Algorithm::MlKem512 => MlKem512Algo::decapsulate(ciphertext, secret_key),
188        Algorithm::MlKem768 => MlKem768Algo::decapsulate(ciphertext, secret_key),
189        Algorithm::MlKem1024 => MlKem1024Algo::decapsulate(ciphertext, secret_key),
190        Algorithm::XWing768 => XWing768Algo::decapsulate(ciphertext, secret_key),
191        Algorithm::XWing1024 => XWing1024Algo::decapsulate(ciphertext, secret_key),
192        _ => Err(AlgorithmError::UnsupportedAlgorithm(alg)),
193    }
194}
195
196//
197// -----------------------------------------------------------------------------
198// Symmetric AEAD
199// -----------------------------------------------------------------------------
200
201/// Encrypt `plaintext` with the selected AEAD. Returns
202/// `ciphertext || tag`.
203///
204/// # Examples
205///
206/// ```
207/// use crypto_core::AeadAlgorithm;
208/// use crypto_dispatch::{aead_decrypt, aead_encrypt, AeadParams};
209///
210/// # fn main() -> Result<(), crypto_dispatch::AlgorithmError> {
211/// let key = [0x42u8; 32];
212/// let nonce = [0x24u8; 12];
213/// let params = AeadParams { key: &key, nonce: &nonce, aad: b"context" };
214///
215/// let sealed = aead_encrypt(AeadAlgorithm::Aes256Gcm, &params, b"plaintext")?;
216/// let opened = aead_decrypt(AeadAlgorithm::Aes256Gcm, &params, &sealed)?;
217/// assert_eq!(opened.as_slice(), b"plaintext");
218/// # Ok(())
219/// # }
220/// ```
221pub fn aead_encrypt(
222    alg: AeadAlgorithm,
223    params: &AeadParams<'_>,
224    plaintext: &[u8],
225) -> Result<Vec<u8>, AlgorithmError> {
226    match alg {
227        AeadAlgorithm::Aes128Gcm => Aes128GcmAlgo::encrypt(params, plaintext),
228        AeadAlgorithm::Aes192Gcm => Aes192GcmAlgo::encrypt(params, plaintext),
229        AeadAlgorithm::Aes256Gcm => Aes256GcmAlgo::encrypt(params, plaintext),
230        AeadAlgorithm::Aes256GcmSiv => Aes256GcmSivAlgo::encrypt(params, plaintext),
231        AeadAlgorithm::ChaCha20Poly1305 => ChaCha20Poly1305Algo::encrypt(params, plaintext),
232        AeadAlgorithm::XChaCha20Poly1305 => XChaCha20Poly1305Algo::encrypt(params, plaintext),
233    }
234}
235
236/// Decrypt and authenticate `ciphertext || tag` with the selected AEAD.
237/// The returned plaintext is zeroized on drop.
238///
239/// Fails closed: a tampered ciphertext, tag, nonce, or AAD returns an error
240/// instead of any plaintext.
241///
242/// # Examples
243///
244/// ```
245/// use crypto_core::AeadAlgorithm;
246/// use crypto_dispatch::{aead_decrypt, aead_encrypt, AeadParams};
247///
248/// # fn main() -> Result<(), crypto_dispatch::AlgorithmError> {
249/// let key = [0x42u8; 32];
250/// let nonce = [0x24u8; 12];
251/// let params = AeadParams { key: &key, nonce: &nonce, aad: b"context" };
252///
253/// let sealed = aead_encrypt(AeadAlgorithm::Aes256GcmSiv, &params, b"plaintext")?;
254/// let opened = aead_decrypt(AeadAlgorithm::Aes256GcmSiv, &params, &sealed)?;
255/// assert_eq!(opened.as_slice(), b"plaintext");
256/// # Ok(())
257/// # }
258/// ```
259pub fn aead_decrypt(
260    alg: AeadAlgorithm,
261    params: &AeadParams<'_>,
262    ciphertext_with_tag: &[u8],
263) -> Result<Zeroizing<Vec<u8>>, AlgorithmError> {
264    match alg {
265        AeadAlgorithm::Aes128Gcm => Aes128GcmAlgo::decrypt(params, ciphertext_with_tag),
266        AeadAlgorithm::Aes192Gcm => Aes192GcmAlgo::decrypt(params, ciphertext_with_tag),
267        AeadAlgorithm::Aes256Gcm => Aes256GcmAlgo::decrypt(params, ciphertext_with_tag),
268        AeadAlgorithm::Aes256GcmSiv => Aes256GcmSivAlgo::decrypt(params, ciphertext_with_tag),
269        AeadAlgorithm::ChaCha20Poly1305 => {
270            ChaCha20Poly1305Algo::decrypt(params, ciphertext_with_tag)
271        }
272        AeadAlgorithm::XChaCha20Poly1305 => {
273            XChaCha20Poly1305Algo::decrypt(params, ciphertext_with_tag)
274        }
275    }
276}