Skip to main content

rnp/
algorithm.rs

1//! Domain primitives: public-key algorithms, curves, hashes, ciphers,
2//! compression, key usage.
3//!
4//! These types were previously in `keygen.rs` but they're used across the
5//! crate — encryption, signing, verification, security queries, key
6//! inspection. Centralizing them in `algorithm` makes the dependency graph
7//! honest: `keygen` depends on `algorithm`, not vice versa.
8//!
9//! [`keygen`](crate::keygen) re-exports every type here for backward
10//! compatibility. New code should prefer the `algorithm::` path.
11
12// ---------------------------------------------------------------------------
13// Public-key algorithms
14// ---------------------------------------------------------------------------
15
16/// Public-key algorithm. Maps to the `RNP_ALGNAME_*` string constants in
17/// `rnp.h`.
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19#[non_exhaustive]
20pub enum Algorithm {
21    /// `"RSA"`. Used for primary or subkey; supports sign + encrypt (legacy).
22    Rsa,
23    /// `"ELGAMAL"`. Subkey only, encryption.
24    ElGamal,
25    /// `"DSA"`. Primary only, signing.
26    Dsa,
27    /// `"ECDH"`. Subkey only, encryption.
28    Ecdh,
29    /// `"ECDSA"`. Primary or subkey, signing.
30    Ecdsa,
31    /// `"EDDSA"`. Primary or subkey, signing (Ed25519 curve).
32    Eddsa,
33    /// `"SM2"`. Primary or subkey, sign + encrypt.
34    Sm2,
35}
36
37impl Algorithm {
38    pub fn as_str(self) -> &'static str {
39        match self {
40            Algorithm::Rsa => "RSA",
41            Algorithm::ElGamal => "ELGAMAL",
42            Algorithm::Dsa => "DSA",
43            Algorithm::Ecdh => "ECDH",
44            Algorithm::Ecdsa => "ECDSA",
45            Algorithm::Eddsa => "EDDSA",
46            Algorithm::Sm2 => "SM2",
47        }
48    }
49
50    /// Whether this algorithm can produce signatures. Maps to OpenPGP's
51    /// "signing-capable" public-key algorithms (DSA, ECDSA, EdDSA, SM2,
52    /// RSA). Useful for builder-time validation.
53    pub fn is_signature(self) -> bool {
54        matches!(
55            self,
56            Algorithm::Rsa | Algorithm::Dsa | Algorithm::Ecdsa | Algorithm::Eddsa | Algorithm::Sm2
57        )
58    }
59
60    /// Whether this algorithm can perform public-key encryption / key
61    /// encapsulation. Maps to OpenPGP's encryption-capable algorithms
62    /// (RSA, ECDH, ElGamal, SM2).
63    pub fn is_encryption(self) -> bool {
64        matches!(
65            self,
66            Algorithm::Rsa | Algorithm::Ecdh | Algorithm::ElGamal | Algorithm::Sm2
67        )
68    }
69}
70
71/// PQC composite algorithms. Available only when the crate is built with
72/// `--features pqc` and the linked librnp was built with `ENABLE_PQC=ON`.
73///
74/// These wrap the `RNP_ALGNAME_KYBER*` / `RNP_ALGNAME_DILITHIUM*` /
75/// `RNP_ALGNAME_SPHINCSPLUS_*` string constants in `rnp.h`.
76#[cfg(feature = "pqc")]
77#[derive(Clone, Copy, Debug, PartialEq, Eq)]
78pub enum PqcAlgorithm {
79    // Key-encapsulation (encryption) composites.
80    MlKem768X25519,
81    MlKem1024X448,
82    MlKem768P384,
83    MlKem1024P521,
84    MlKem768Bp384,
85    MlKem1024Bp512,
86    // Signature composites.
87    MlDsa65Ed25519,
88    MlDsa87Ed448,
89    MlDsa65P384,
90    MlDsa87P521,
91    MlDsa65Bp384,
92    MlDsa87Bp512,
93    // Standalone SLH-DSA variants.
94    SlhDsaShake128f,
95    SlhDsaShake128s,
96    SlhDsaShake256s,
97}
98
99#[cfg(feature = "pqc")]
100impl PqcAlgorithm {
101    pub fn as_str(self) -> &'static str {
102        match self {
103            PqcAlgorithm::MlKem768X25519 => "ML-KEM-768+X25519",
104            PqcAlgorithm::MlKem1024X448 => "ML-KEM-1024+X448",
105            PqcAlgorithm::MlKem768P384 => "ML-KEM-768+ECDH-P384",
106            PqcAlgorithm::MlKem1024P521 => "ML-KEM-1024+ECDH-P521",
107            PqcAlgorithm::MlKem768Bp384 => "ML-KEM-768+ECDH-BP384",
108            PqcAlgorithm::MlKem1024Bp512 => "ML-KEM-1024+ECDH-BP512",
109            PqcAlgorithm::MlDsa65Ed25519 => "ML-DSA-65+ED25519",
110            PqcAlgorithm::MlDsa87Ed448 => "ML-DSA-87+ED448",
111            PqcAlgorithm::MlDsa65P384 => "ML-DSA-65+ECDSA-P384",
112            PqcAlgorithm::MlDsa87P521 => "ML-DSA-87+ECDSA-P521",
113            PqcAlgorithm::MlDsa65Bp384 => "ML-DSA-65+ECDSA-BP384",
114            PqcAlgorithm::MlDsa87Bp512 => "ML-DSA-87+ECDSA-BP512",
115            PqcAlgorithm::SlhDsaShake128f => "SLH-DSA-SHAKE-128f",
116            PqcAlgorithm::SlhDsaShake128s => "SLH-DSA-SHAKE-128s",
117            PqcAlgorithm::SlhDsaShake256s => "SLH-DSA-SHAKE-256s",
118        }
119    }
120}
121
122/// Runtime probe: confirm that the linked librnp actually supports PQC.
123/// Build-time `--features pqc` only makes the symbols visible to bindgen —
124/// the binary must also have been compiled with `ENABLE_PQC=ON`. Call this
125/// before any PQC operation.
126#[cfg(feature = "pqc")]
127pub fn librnp_supports_pqc() -> bool {
128    crate::security::supports_feature(
129        crate::security::FeatureType::PublicKeyAlgorithm,
130        "ML-KEM-768+X25519",
131    )
132    .unwrap_or(false)
133}
134
135// ---------------------------------------------------------------------------
136// Curves
137// ---------------------------------------------------------------------------
138
139/// Elliptic curve name. Pass to [`crate::KeyBuilder::curve`] /
140/// [`crate::SubkeyBuilder::curve`].
141#[derive(Clone, Copy, Debug, PartialEq, Eq)]
142#[non_exhaustive]
143pub enum Curve {
144    /// `"NIST P-256"` (secp256r1).
145    P256,
146    /// `"NIST P-384"` (secp384r1).
147    P384,
148    /// `"NIST P-521"` (secp521r1).
149    P521,
150    /// `"Ed25519"` — used with `Algorithm::Eddsa`.
151    Ed25519,
152    /// `"Curve25519"` — used with `Algorithm::Ecdh`.
153    Curve25519,
154    /// `"brainpoolP256r1"`.
155    Bp256,
156    /// `"brainpoolP384r1"`.
157    Bp384,
158    /// `"brainpoolP512r1"`.
159    Bp512,
160    /// `"secp256k1"` — Bitcoin curve.
161    Secp256k1,
162    /// `"SM2 P-256"`.
163    Sm2P256,
164}
165
166impl Curve {
167    pub fn as_str(self) -> &'static str {
168        match self {
169            Curve::P256 => "NIST P-256",
170            Curve::P384 => "NIST P-384",
171            Curve::P521 => "NIST P-521",
172            Curve::Ed25519 => "Ed25519",
173            Curve::Curve25519 => "Curve25519",
174            Curve::Bp256 => "brainpoolP256r1",
175            Curve::Bp384 => "brainpoolP384r1",
176            Curve::Bp512 => "brainpoolP512r1",
177            Curve::Secp256k1 => "secp256k1",
178            Curve::Sm2P256 => "SM2 P-256",
179        }
180    }
181}
182
183// ---------------------------------------------------------------------------
184// Hashes
185// ---------------------------------------------------------------------------
186
187/// Hash algorithm. Pass to [`crate::KeyBuilder::hash`] and signature
188/// operations.
189#[derive(Clone, Copy, Debug, PartialEq, Eq)]
190#[non_exhaustive]
191pub enum Hash {
192    Sha1,
193    Sha224,
194    Sha256,
195    Sha384,
196    Sha512,
197    Sha3_256,
198    Sha3_512,
199    Md5,
200    Ripemd160,
201    Sm3,
202}
203
204impl Hash {
205    pub fn as_str(self) -> &'static str {
206        match self {
207            Hash::Sha1 => "SHA1",
208            Hash::Sha224 => "SHA224",
209            Hash::Sha256 => "SHA256",
210            Hash::Sha384 => "SHA384",
211            Hash::Sha512 => "SHA512",
212            Hash::Sha3_256 => "SHA3-256",
213            Hash::Sha3_512 => "SHA3-512",
214            Hash::Md5 => "MD5",
215            Hash::Ripemd160 => "RIPEMD160",
216            Hash::Sm3 => "SM3",
217        }
218    }
219
220    /// Digest size in bytes (e.g. SHA-256 → 32). Used for S2K iteration
221    /// sizing and signature-digest allocation.
222    pub fn digest_size(self) -> usize {
223        match self {
224            Hash::Sha1 | Hash::Ripemd160 => 20,
225            Hash::Sha224 => 28,
226            Hash::Sha256 | Hash::Sha3_256 | Hash::Sm3 => 32,
227            Hash::Sha384 => 48,
228            Hash::Sha512 | Hash::Sha3_512 => 64,
229            Hash::Md5 => 16,
230        }
231    }
232}
233
234// ---------------------------------------------------------------------------
235// Symmetric ciphers
236// ---------------------------------------------------------------------------
237
238/// Symmetric cipher. Used in protection, encryption, AEAD.
239#[derive(Clone, Copy, Debug, PartialEq, Eq)]
240#[non_exhaustive]
241pub enum Cipher {
242    Idea,
243    Tripledes,
244    Cast5,
245    Blowfish,
246    Aes128,
247    Aes192,
248    Aes256,
249    Twofish,
250    Camellia128,
251    Camellia192,
252    Camellia256,
253    Sm4,
254}
255
256impl Cipher {
257    pub fn as_str(self) -> &'static str {
258        match self {
259            Cipher::Idea => "IDEA",
260            Cipher::Tripledes => "TRIPLEDES",
261            Cipher::Cast5 => "CAST5",
262            Cipher::Blowfish => "BLOWFISH",
263            Cipher::Aes128 => "AES128",
264            Cipher::Aes192 => "AES192",
265            Cipher::Aes256 => "AES256",
266            Cipher::Twofish => "TWOFISH",
267            Cipher::Camellia128 => "CAMELLIA128",
268            Cipher::Camellia192 => "CAMELLIA192",
269            Cipher::Camellia256 => "CAMELLIA256",
270            Cipher::Sm4 => "SM4",
271        }
272    }
273
274    /// Symmetric key size in bytes (e.g. AES-256 → 32).
275    pub fn key_size(self) -> usize {
276        match self {
277            Cipher::Idea | Cipher::Cast5 | Cipher::Blowfish => 16,
278            Cipher::Tripledes => 24,
279            Cipher::Aes128 | Cipher::Camellia128 => 16,
280            Cipher::Aes192 | Cipher::Camellia192 => 24,
281            Cipher::Aes256 | Cipher::Camellia256 | Cipher::Twofish | Cipher::Sm4 => 32,
282        }
283    }
284
285    /// Block size in bytes (e.g. AES → 16).
286    pub fn block_size(self) -> usize {
287        match self {
288            // 64-bit block ciphers.
289            Cipher::Blowfish | Cipher::Cast5 | Cipher::Tripledes | Cipher::Idea => 8,
290            // 128-bit block ciphers (the AES family + Camellia + Twofish + SM4).
291            Cipher::Aes128
292            | Cipher::Aes192
293            | Cipher::Aes256
294            | Cipher::Camellia128
295            | Cipher::Camellia192
296            | Cipher::Camellia256
297            | Cipher::Twofish
298            | Cipher::Sm4 => 16,
299        }
300    }
301}
302
303// ---------------------------------------------------------------------------
304// Compression
305// ---------------------------------------------------------------------------
306
307/// Compression algorithm.
308#[derive(Clone, Copy, Debug, PartialEq, Eq)]
309#[non_exhaustive]
310pub enum Compression {
311    Zip,
312    Zlib,
313    Bzip2,
314}
315
316impl Compression {
317    pub fn as_str(self) -> &'static str {
318        match self {
319            Compression::Zip => "ZIP",
320            Compression::Zlib => "ZLIB",
321            Compression::Bzip2 => "BZIP2",
322        }
323    }
324}
325
326// ---------------------------------------------------------------------------
327// Key usage flags
328// ---------------------------------------------------------------------------
329
330/// Key usage flag.
331#[derive(Clone, Copy, Debug, PartialEq, Eq)]
332#[non_exhaustive]
333pub enum KeyUsage {
334    Certify,
335    Sign,
336    EncryptComms,
337    EncryptStorage,
338}
339
340impl KeyUsage {
341    pub fn as_str(self) -> &'static str {
342        match self {
343            KeyUsage::Certify => "certify",
344            KeyUsage::Sign => "sign",
345            KeyUsage::EncryptComms => "encrypt",
346            KeyUsage::EncryptStorage => "encrypt",
347        }
348    }
349}