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::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::X25519 => X25519Algo::derive_shared_secret(secret_key, public_key),
154        _ => Err(AlgorithmError::UnsupportedAlgorithm(alg)),
155    }
156}
157
158//
159// -----------------------------------------------------------------------------
160// POST-QUANTUM KEM
161// -----------------------------------------------------------------------------
162
163/// Returns (shared_secret, ciphertext); the shared secret zeroizes on drop.
164pub fn kem_encapsulate(
165    alg: Algorithm,
166    public_key: &[u8],
167) -> Result<(Zeroizing<Vec<u8>>, Vec<u8>), AlgorithmError> {
168    match alg {
169        Algorithm::MlKem512 => MlKem512Algo::encapsulate(public_key),
170        Algorithm::MlKem768 => MlKem768Algo::encapsulate(public_key),
171        Algorithm::MlKem1024 => MlKem1024Algo::encapsulate(public_key),
172        Algorithm::XWing768 => XWing768Algo::encapsulate(public_key),
173        Algorithm::XWing1024 => XWing1024Algo::encapsulate(public_key),
174        _ => Err(AlgorithmError::UnsupportedAlgorithm(alg)),
175    }
176}
177
178/// Decapsulate a KEM ciphertext. The returned shared secret zeroizes on drop.
179pub fn kem_decapsulate(
180    alg: Algorithm,
181    ciphertext: &[u8],
182    secret_key: &[u8],
183) -> Result<Zeroizing<Vec<u8>>, AlgorithmError> {
184    match alg {
185        Algorithm::MlKem512 => MlKem512Algo::decapsulate(ciphertext, secret_key),
186        Algorithm::MlKem768 => MlKem768Algo::decapsulate(ciphertext, secret_key),
187        Algorithm::MlKem1024 => MlKem1024Algo::decapsulate(ciphertext, secret_key),
188        Algorithm::XWing768 => XWing768Algo::decapsulate(ciphertext, secret_key),
189        Algorithm::XWing1024 => XWing1024Algo::decapsulate(ciphertext, secret_key),
190        _ => Err(AlgorithmError::UnsupportedAlgorithm(alg)),
191    }
192}
193
194//
195// -----------------------------------------------------------------------------
196// Symmetric AEAD
197// -----------------------------------------------------------------------------
198
199/// Encrypt `plaintext` with the selected AEAD. Returns
200/// `ciphertext || tag`.
201///
202/// # Examples
203///
204/// ```
205/// use crypto_core::AeadAlgorithm;
206/// use crypto_dispatch::{aead_decrypt, aead_encrypt, AeadParams};
207///
208/// # fn main() -> Result<(), crypto_dispatch::AlgorithmError> {
209/// let key = [0x42u8; 32];
210/// let nonce = [0x24u8; 12];
211/// let params = AeadParams { key: &key, nonce: &nonce, aad: b"context" };
212///
213/// let sealed = aead_encrypt(AeadAlgorithm::Aes256Gcm, &params, b"plaintext")?;
214/// let opened = aead_decrypt(AeadAlgorithm::Aes256Gcm, &params, &sealed)?;
215/// assert_eq!(opened.as_slice(), b"plaintext");
216/// # Ok(())
217/// # }
218/// ```
219pub fn aead_encrypt(
220    alg: AeadAlgorithm,
221    params: &AeadParams<'_>,
222    plaintext: &[u8],
223) -> Result<Vec<u8>, AlgorithmError> {
224    match alg {
225        AeadAlgorithm::Aes256Gcm => Aes256GcmAlgo::encrypt(params, plaintext),
226        AeadAlgorithm::Aes256GcmSiv => Aes256GcmSivAlgo::encrypt(params, plaintext),
227        AeadAlgorithm::ChaCha20Poly1305 => ChaCha20Poly1305Algo::encrypt(params, plaintext),
228        AeadAlgorithm::XChaCha20Poly1305 => XChaCha20Poly1305Algo::encrypt(params, plaintext),
229    }
230}
231
232/// Decrypt and authenticate `ciphertext || tag` with the selected AEAD.
233/// The returned plaintext is zeroized on drop.
234///
235/// Fails closed: a tampered ciphertext, tag, nonce, or AAD returns an error
236/// instead of any plaintext.
237///
238/// # Examples
239///
240/// ```
241/// use crypto_core::AeadAlgorithm;
242/// use crypto_dispatch::{aead_decrypt, aead_encrypt, AeadParams};
243///
244/// # fn main() -> Result<(), crypto_dispatch::AlgorithmError> {
245/// let key = [0x42u8; 32];
246/// let nonce = [0x24u8; 12];
247/// let params = AeadParams { key: &key, nonce: &nonce, aad: b"context" };
248///
249/// let sealed = aead_encrypt(AeadAlgorithm::Aes256GcmSiv, &params, b"plaintext")?;
250/// let opened = aead_decrypt(AeadAlgorithm::Aes256GcmSiv, &params, &sealed)?;
251/// assert_eq!(opened.as_slice(), b"plaintext");
252/// # Ok(())
253/// # }
254/// ```
255pub fn aead_decrypt(
256    alg: AeadAlgorithm,
257    params: &AeadParams<'_>,
258    ciphertext_with_tag: &[u8],
259) -> Result<Zeroizing<Vec<u8>>, AlgorithmError> {
260    match alg {
261        AeadAlgorithm::Aes256Gcm => Aes256GcmAlgo::decrypt(params, ciphertext_with_tag),
262        AeadAlgorithm::Aes256GcmSiv => Aes256GcmSivAlgo::decrypt(params, ciphertext_with_tag),
263        AeadAlgorithm::ChaCha20Poly1305 => {
264            ChaCha20Poly1305Algo::decrypt(params, ciphertext_with_tag)
265        }
266        AeadAlgorithm::XChaCha20Poly1305 => {
267            XChaCha20Poly1305Algo::decrypt(params, ciphertext_with_tag)
268        }
269    }
270}