Skip to main content

lib_q_core/
lib.rs

1//! lib-Q Core - Common types and traits for post-quantum cryptography
2//!
3//! This crate provides the foundational types, traits, and error handling
4//! used across all lib-Q crates.
5//!
6//! ## Context factories
7//!
8//! Core does not provide factories that depend on algorithm implementation crates (no cycles).
9//! For [`AeadContext`], use [`AeadContext::new`](crate::contexts::AeadContext::new),
10//! [`AeadContext::with_aead_operations`](crate::contexts::AeadContext::with_aead_operations), or
11//! [`AeadContext::with_provider`](crate::contexts::AeadContext::with_provider). The `lib-q-aead` crate supplies
12//! `LibQAeadProvider` for [`AeadContext::with_aead_operations`](crate::contexts::AeadContext::with_aead_operations); the umbrella `lib-q` crate exposes `libq::aead::context()` wired to that provider.
13
14#![cfg_attr(not(feature = "std"), no_std)]
15#![deny(unsafe_code)]
16#![deny(unused_qualifications)]
17
18#[cfg(feature = "alloc")]
19extern crate alloc;
20
21pub mod algorithm_registry;
22pub mod api;
23pub mod error;
24pub mod traits;
25pub mod wasm_common;
26
27// New modular architecture
28#[cfg(feature = "alloc")]
29pub mod aead_semantic;
30#[cfg(feature = "alloc")]
31pub mod contexts;
32#[cfg(feature = "alloc")]
33pub mod providers;
34#[cfg(feature = "alloc")]
35pub mod security;
36
37// WASM bindings
38#[cfg(feature = "wasm")]
39pub mod wasm;
40
41// Re-exports
42#[cfg(feature = "alloc")]
43pub use aead_semantic::{
44    AeadDecryptSemantic,
45    DecryptSemanticOutcome,
46};
47pub use algorithm_registry::*;
48pub use api::*;
49#[cfg(feature = "alloc")]
50pub use contexts::{
51    AeadContext,
52    HashContext,
53    KemContext,
54    SignatureContext,
55};
56pub use error::{
57    Error,
58    HexDecodeError,
59    Result,
60};
61// Re-export new modular components
62#[cfg(feature = "alloc")]
63pub use providers::LibQCryptoProvider;
64#[cfg(feature = "alloc")]
65pub use security::SecurityValidator;
66pub use traits::*;
67#[cfg(feature = "wasm")]
68pub use wasm::*;
69
70// Constants
71pub const VERSION: &str = env!("CARGO_PKG_VERSION");
72
73/// Initialize the core library
74pub fn init() -> Result<()> {
75    Ok(())
76}
77
78/// Get library version information
79pub fn version() -> &'static str {
80    VERSION
81}
82
83/// Create a new hash context with no provider installed.
84///
85/// Call [`HashContext::set_provider`] or use [`HashContext::with_provider`] before
86/// [`HashContext::hash`] will succeed. Leaf crates (for example `lib-q-hash`) and the
87/// `libq` umbrella expose factories that install a hash implementation up front.
88#[cfg(feature = "alloc")]
89pub fn create_hash_context() -> HashContext {
90    HashContext::new()
91}
92
93/// Create a new KEM context
94#[cfg(feature = "alloc")]
95pub fn create_kem_context() -> KemContext {
96    KemContext::new()
97}
98
99/// Create a new signature context
100#[cfg(feature = "alloc")]
101pub fn create_signature_context() -> SignatureContext {
102    SignatureContext::new()
103}
104
105// Aborting `#[panic_handler]` for `no_std` builds. Required because `lib-q-core` declares a
106// `cdylib` crate-type (for `wasm-pack`), and Cargo builds that cdylib on every target — a cdylib
107// is a final artifact and so needs a panic handler even when it is merely a transitive dependency
108// of another `no_std` crate (e.g. `lib-q-intrinsics`). Providing it by default keeps standalone
109// `cargo check --profile dev-no-std` of any `no_std` consumer working.
110//
111// It is deliberately excluded when:
112//   - `std` is enabled — `std` supplies the handler;
113//   - `wasm` is enabled — the `wasm-bindgen` cdylib links `std`, which supplies the handler;
114//     defining our own would be a duplicate `panic_impl` lang item;
115//   - `no_panic_handler` is set — firmware/integrators that supply their own handler opt out.
116#[cfg(all(
117    not(feature = "std"),
118    not(feature = "wasm"),
119    not(feature = "no_panic_handler")
120))]
121mod no_std_panic_handler {
122    use core::panic::PanicInfo;
123
124    #[panic_handler]
125    #[allow(clippy::empty_loop)]
126    fn panic(_info: &PanicInfo) -> ! {
127        // `panic = "abort"` is required for `no_std` final artifacts (see the `dev-no-std`
128        // profile); spin so the divergent handler is a valid `-> !` with no `std` unwinder.
129        loop {}
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136
137    #[test]
138    fn test_init() {
139        assert!(init().is_ok());
140    }
141
142    #[test]
143    fn test_version() {
144        assert!(!version().is_empty());
145        assert_eq!(version(), VERSION);
146    }
147
148    #[test]
149    fn test_no_std_compatibility() {
150        #[cfg(not(feature = "std"))]
151        use alloc::string::ToString;
152
153        // Test that core functionality works in no_std mode
154        let error = Error::InvalidKeySize {
155            expected: 32,
156            actual: 16,
157        };
158        assert_eq!(error.to_string(), "Invalid key size: expected 32, got 16");
159
160        // Test that we can create basic structures
161        #[cfg(feature = "alloc")]
162        {
163            let public_key = KemPublicKey::new(vec![1, 2, 3, 4]);
164            assert_eq!(public_key.as_bytes(), &[1, 2, 3, 4]);
165
166            let secret_key = KemSecretKey::new(vec![5, 6, 7, 8]);
167            assert_eq!(secret_key.as_bytes(), &[5, 6, 7, 8]);
168        }
169    }
170}