oqs/lib.rs
1#![warn(missing_docs)]
2#![cfg_attr(not(feature = "std"), no_std)]
3//! Friendly bindings to liboqs
4//!
5//! See the [`kem::Kem`](crate::kem::Kem) and [`sig::Sig`](crate::sig::Sig) structs for how to use this crate.
6//!
7//! # Example: Some signed KEX
8//!
9//! This protocol has no replay protection!
10//! ```
11//! use oqs::*;
12//! # #[cfg(all(feature = "ml_dsa", feature = "ml_kem"))]
13//! fn main() -> Result<()> {
14//! oqs::init(); // Important: initialize liboqs
15//! let sigalg = sig::Sig::new(sig::Algorithm::MlDsa44)?;
16//! let kemalg = kem::Kem::new(kem::Algorithm::MlKem512)?;
17//! // A's long-term secrets
18//! let (a_sig_pk, a_sig_sk) = sigalg.keypair()?;
19//! // B's long-term secrets
20//! let (b_sig_pk, b_sig_sk) = sigalg.keypair()?;
21//!
22//! // assumption: A has (a_sig_sk, a_sig_pk, b_sig_pk)
23//! // assumption: B has (b_sig_sk, b_sig_pk, a_sig_pk)
24//!
25//! // A -> B: kem_pk, signature
26//! let (kem_pk, kem_sk) = kemalg.keypair()?;
27//! let signature = sigalg.sign(kem_pk.as_ref(), &a_sig_sk)?;
28//!
29//! // B -> A: kem_ct, signature
30//! sigalg.verify(kem_pk.as_ref(), &signature, &a_sig_pk)?;
31//! let (kem_ct, b_kem_ss) = kemalg.encapsulate(&kem_pk)?;
32//! let signature = sigalg.sign(kem_ct.as_ref(), &b_sig_sk)?;
33//!
34//! // A verifies, decapsulates, now both have kem_ss
35//! sigalg.verify(kem_ct.as_ref(), &signature, &b_sig_pk)?;
36//! let a_kem_ss = kemalg.decapsulate(&kem_sk, &kem_ct)?;
37//! assert_eq!(a_kem_ss, b_kem_ss);
38//!
39//! Ok(())
40//! }
41//! # #[cfg(not(all(feature = "ml_dsa", feature = "ml_kem")))]
42//! # fn main() {}
43//! ```
44// needs to be imported to be made available
45extern crate alloc;
46
47use ffi::common::OQS_STATUS;
48
49/// Access the OQS ffi through this crate.
50pub use oqs_sys as ffi;
51
52mod macros;
53
54/// Initialize liboqs
55///
56/// Make sure to call this before you use any of the functions.
57///
58/// When the ``std`` feature is enabled, this method is thread-safe
59/// and can be called more than once.
60#[cfg(feature = "std")]
61pub fn init() {
62 use std::sync::Once;
63 static INIT: Once = Once::new();
64 INIT.call_once(|| {
65 unsafe { ffi::common::OQS_init() };
66 });
67}
68
69/// Initialize liboqs
70///
71/// Needs to be called before you use any of the functions.
72///
73/// This ``no_std`` variant is not thread-safe.
74#[cfg(not(feature = "std"))]
75pub fn init() {
76 unsafe { ffi::common::OQS_init() };
77}
78
79#[derive(Debug)]
80#[non_exhaustive]
81/// Possible errors
82pub enum Error {
83 /// Indicates an algorithm has been disabled
84 AlgorithmDisabled,
85 /// Generic error
86 Error,
87 /// Error occurred in OpenSSL functions external to liboqs
88 #[allow(clippy::upper_case_acronyms)]
89 ErrorExternalOpenSSL,
90 /// Invalid length of a public object
91 InvalidLength,
92 /// Error while trying to parse string to an algorithm
93 AlgorithmParsingError,
94}
95#[cfg(feature = "std")]
96impl std::error::Error for Error {}
97
98/// Result type for operations that may fail
99pub type Result<T> = core::result::Result<T, Error>;
100
101impl core::fmt::Display for Error {
102 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103 match self {
104 Error::AlgorithmDisabled => write!(f, "OQS Error: Algorithm has been disabled"),
105 Error::ErrorExternalOpenSSL => write!(f, "OQS error: OpenSSL call failed"),
106 _ => write!(f, "OQS Error!"),
107 }
108 }
109}
110
111/// Convert an OQS_STATUS to the Result type.
112fn status_to_result(status: OQS_STATUS) -> Result<()> {
113 match status {
114 OQS_STATUS::OQS_SUCCESS => Ok(()),
115 OQS_STATUS::OQS_ERROR => Err(Error::Error),
116 OQS_STATUS::OQS_EXTERNAL_LIB_ERROR_OPENSSL => Err(Error::ErrorExternalOpenSSL),
117 }
118}
119
120pub mod kem;
121pub mod sig;