1#![cfg_attr(not(feature = "std"), no_std)]
9
10#[cfg(feature = "alloc")]
11extern crate alloc;
12
13#[cfg(feature = "alloc")]
14use alloc::vec::Vec;
15
16mod bytes;
17
18pub mod aes;
19#[cfg(feature = "alloc")]
20pub mod argon2;
21pub mod ascon;
22pub mod blake2;
23pub mod blake3;
24pub mod chacha;
25pub mod curve25519;
26pub mod hkdf;
27pub mod hmac;
28pub mod mldsa;
29pub mod mlkem;
30pub mod poly1305;
31#[cfg(feature = "random")]
32pub mod random;
33pub mod sha2;
34pub mod sha3;
35pub mod xwing;
36
37#[cfg(feature = "alloc")]
38pub mod encoding;
39mod p_curves;
40pub mod pbkdf2;
41pub mod rsa;
42pub(crate) use bytes::Bytes;
43pub use bytes::Hash;
44pub use p_curves::{p224, p256, p384, p521};
45
46const MAX_HASH_BLOCK_SIZE: usize = 136;
47
48pub const MAX_HASH_OUTPUT_SIZE: usize = 64;
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub enum HashError {
77 TooLong,
78}
79
80impl core::fmt::Display for HashError {
81 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82 match self {
83 HashError::TooLong => write!(f, "hash is too long"),
84 }
85 }
86}
87
88impl core::error::Error for HashError {}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub enum AeadError {
92 InvalidKey,
93 InvalidNonce,
94 InvalidCiphertext,
95 Unsupported,
96}
97
98impl core::fmt::Display for AeadError {
99 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
100 match self {
101 AeadError::InvalidKey => write!(f, "key is not valid"),
102 AeadError::InvalidNonce => write!(f, "nonce is not valid"),
103 AeadError::InvalidCiphertext => write!(f, "ciphertext is not valid"),
104 AeadError::Unsupported => write!(f, "operation is not supported"),
105 }
106 }
107}
108
109impl core::error::Error for AeadError {}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
112pub enum EllipticCurveError {
113 InvalidKey,
114 Unspecified,
115 InvalidSignature,
116 InvalidSharedSecret,
117 Random(RandomError),
118}
119
120impl core::fmt::Display for EllipticCurveError {
121 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
122 match self {
123 EllipticCurveError::InvalidKey => write!(f, "key is not valid"),
124 EllipticCurveError::Unspecified => write!(f, "unknown error"),
125 EllipticCurveError::InvalidSignature => write!(f, "signature is not valid"),
126 EllipticCurveError::InvalidSharedSecret => write!(f, "shared secret is not valid"),
127 EllipticCurveError::Random(err) => write!(f, "{err}"),
128 }
129 }
130}
131
132impl core::error::Error for EllipticCurveError {}
133
134impl From<RandomError> for EllipticCurveError {
135 fn from(err: RandomError) -> Self {
136 EllipticCurveError::Random(err)
137 }
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
141pub enum RsaError {
142 InvalidKey,
143 InvalidSignature,
144 NotSupported,
145 Unspecified,
146}
147
148impl core::fmt::Display for RsaError {
149 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
150 match self {
151 RsaError::InvalidKey => write!(f, "key is not valid"),
152 RsaError::InvalidSignature => write!(f, "signature is not valid"),
153 RsaError::NotSupported => write!(f, "key size not supported"),
154 RsaError::Unspecified => write!(f, "unknown error"),
155 }
156 }
157}
158
159impl core::error::Error for RsaError {}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub enum HkdfError {
163 PrkIsTooShort(usize),
164 OutputIsTooLong,
165}
166
167impl core::fmt::Display for HkdfError {
168 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
169 match self {
170 HkdfError::PrkIsTooShort(_) => write!(f, "PRK is too short"),
171 HkdfError::OutputIsTooLong => {
172 write!(f, "HKDF output length exceeds RFC 5869 limit (255 * Hash's output size)")
173 }
174 }
175 }
176}
177
178impl core::error::Error for HkdfError {}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub enum RandomError {
183 Unsupported,
185 OsError(i64),
188 Unspecified,
190}
191
192impl core::fmt::Display for RandomError {
193 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194 match self {
195 RandomError::Unsupported => write!(f, "random number generation is not supported on this platform"),
196 RandomError::OsError(code) => write!(f, "random number generation failed with OS error {code}"),
197 RandomError::Unspecified => write!(f, "random number generation failed"),
198 }
199 }
200}
201
202impl core::error::Error for RandomError {}
203
204#[cfg(feature = "random")]
205impl From<getrandom::Error> for RandomError {
206 fn from(err: getrandom::Error) -> Self {
207 if err == getrandom::Error::UNSUPPORTED {
208 RandomError::Unsupported
209 } else if let Some(code) = err.raw_os_error() {
210 RandomError::OsError(code as i64)
211 } else {
212 RandomError::Unspecified
213 }
214 }
215}
216
217pub trait StreamCipher {
222 fn xor_keystream(&mut self, in_out: &mut [u8]);
223}
224
225pub trait Aead {
226 const KEY_SIZE: usize;
227 const TAG_SIZE: usize;
228 const NONCE_SIZE: usize;
229
230 fn encrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8]) -> Hash;
231
232 fn decrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8], tag: &[u8]) -> Result<(), AeadError>;
233
234 #[cfg(feature = "alloc")]
235 fn encrypt(&self, plaintext: &[u8], nonce: &[u8], aad: &[u8]) -> Vec<u8> {
236 let mut ciphertext = Vec::with_capacity(plaintext.len() + Self::TAG_SIZE);
237 ciphertext.extend_from_slice(plaintext);
238
239 let tag = self.encrypt_in_place(&mut ciphertext, nonce, aad);
240 ciphertext.extend_from_slice(tag.as_ref());
241
242 return ciphertext;
243 }
244
245 #[cfg(feature = "alloc")]
246 fn decrypt(&self, ciphertext: &[u8], nonce: &[u8], aad: &[u8]) -> Result<Vec<u8>, AeadError> {
247 if ciphertext.len() < Self::TAG_SIZE {
248 return Err(AeadError::InvalidCiphertext);
249 }
250
251 let plaintext_length = ciphertext.len() - Self::TAG_SIZE;
252 let mut plaintext = Vec::with_capacity(plaintext_length);
253 plaintext.extend_from_slice(&ciphertext[..plaintext_length]);
254
255 self.decrypt_in_place(&mut plaintext, nonce, aad, &ciphertext[plaintext_length..])?;
256
257 return Ok(plaintext);
258 }
259}
260
261#[cfg(feature = "zeroize")]
262pub trait Zeroize: zeroize::Zeroize {}
263#[cfg(feature = "zeroize")]
264impl<T: zeroize::Zeroize> Zeroize for T {}
265
266#[cfg(not(feature = "zeroize"))]
267pub trait Zeroize {}
268#[cfg(not(feature = "zeroize"))]
269impl<T> Zeroize for T {}
270
271pub trait Hasher: Clone + Zeroize {
273 const BLOCK_SIZE: usize;
275 const OUTPUT_SIZE: usize;
281
282 fn new() -> Self;
283 fn update(&mut self, data: &[u8]);
284 fn sum(self) -> Hash;
285
286 #[inline]
287 fn hash(data: &[u8]) -> Hash {
288 let mut hasher = Self::new();
289 hasher.update(data);
290 return hasher.sum();
291 }
292}
293
294pub trait Xof: Send + Sync {
295 fn absorb(&mut self, data: &[u8]);
296 fn squeeze(&mut self, out: &mut [u8]);
297}