Skip to main content

libcrux_chacha20poly1305/
lib.rs

1//! This crate implements the ChaCha20Poly1305 AEAD algorithm, as well as the extended nonce
2//! variant XChaCha20Poly1305.
3//!
4//! To encrypt something using ChaCha20Poly1305, use:
5//!
6//! ```rust
7//! # fn main(){
8//! # use libcrux_secrets::{Classify, ClassifyRef, Declassify, DeclassifyRef, U8};
9//! # let key_bytes = [0u8.classify(); 32];
10//! # const MSG_LEN: usize = 19;
11//! #
12//! use libcrux_chacha20poly1305::*;
13//! use libcrux_traits::aead::typed_owned::Aead as _;
14//!
15//! let msg: &[U8; MSG_LEN] = b"squeamish ossifrage".classify_ref();
16//! let mut ciphertext = [0u8; MSG_LEN];
17//! let mut tag = Tag::from([0u8.classify(); TAG_LEN]);
18//!
19//! let key = Key::from(key_bytes);
20//! let nonce = Nonce::from([123u8.classify(); NONCE_LEN]);
21//!
22//! key.encrypt(&mut ciphertext, &mut tag, &nonce, &[/* no aad */], msg)
23//!     .expect("Encryption error");
24//!
25//! // Ciphertext and tag contain encrypted data
26//! assert_eq!(
27//!     ciphertext,
28//!     [ 181, 223,  66, 115, 105, 181,  98, 178,
29//!       247, 139, 196, 238, 169, 225, 143,  94,
30//!       174, 123, 232 ]
31//! );
32//! assert_eq!(
33//!     tag.as_ref().declassify_ref(),
34//!     &[ 155, 112, 155, 212, 133, 38, 145, 115,
35//!         27, 221, 245, 237, 125, 28,  22, 101 ]
36//! );
37//! # }
38//! ```
39//!
40//! and to decrypt, do
41//!
42//! ```rust
43//! # fn main(){
44//! # use libcrux_secrets::{Classify, Declassify, DeclassifyRef};
45//! # let key_bytes  = [0u8; 32].classify();
46//! # let ciphertext = [181, 223,  66, 115, 105, 181,  98, 178, 247, 139, 196, 238, 169, 225, 143,  94, 174, 123, 232];
47//! # let tag_bytes  = [155, 112, 155, 212, 133,  38, 145, 115,  27, 221, 245, 237, 125,  28,  22, 101].classify();
48//! # const MSG_LEN: usize = 19;
49//! #
50//! use libcrux_chacha20poly1305::*;
51//! use libcrux_traits::aead::typed_owned::Aead as _;
52//!
53//! let mut plaintext = [0u8.classify(); MSG_LEN];
54//! let mut tag = Tag::from(tag_bytes);
55//!
56//! let key = Key::from(key_bytes);
57//! let nonce = Nonce::from([123u8.classify(); NONCE_LEN]);
58//!
59//! key.decrypt(&mut plaintext, &nonce, &[/* no aad */], &ciphertext, &tag)
60//!     .expect("Encryption error");
61//!
62//! assert_eq!(plaintext.declassify_ref(), b"squeamish ossifrage");
63//! # }
64//! ```
65
66#![no_std]
67
68use libcrux_traits::aead::{typed_owned, typed_refs};
69
70pub mod xchacha20_poly1305;
71
72mod hacl {
73    pub(crate) use libcrux_poly1305::hacl::mac_poly1305;
74
75    pub(crate) mod aead_chacha20poly1305;
76    pub(crate) mod chacha20;
77}
78
79mod impl_aead_trait;
80mod impl_hacl;
81
82pub use impl_aead_trait::ChaCha20Poly1305;
83pub use impl_hacl::*;
84
85/// The length of ChaCha20-Poly1305 keys.
86pub const KEY_LEN: usize = 32;
87
88/// The length of Poly1305 MAC tags.
89pub const TAG_LEN: usize = 16;
90
91/// The length of ChaCha20-Poly1305 nonces.
92pub const NONCE_LEN: usize = 12;
93
94/// An owned ChaCha20Poly1305 key.
95pub type Key = typed_owned::Key<ChaCha20Poly1305>;
96/// An owned ChaCha20Poly1305 tag.
97pub type Tag = typed_owned::Tag<ChaCha20Poly1305>;
98/// An owned ChaCha20Poly1305 nonce.
99pub type Nonce = typed_owned::Nonce<ChaCha20Poly1305>;
100
101/// A reference to a ChaCha20Poly1305 key.
102pub type KeyRef<'a> = typed_refs::KeyRef<'a, ChaCha20Poly1305>;
103/// A reference to a ChaCha20Poly1305 tag.
104pub type TagRef<'a> = typed_refs::TagRef<'a, ChaCha20Poly1305>;
105/// A mutable reference to a ChaCha20Poly1305 tag.
106pub type TagMut<'a> = typed_refs::TagMut<'a, ChaCha20Poly1305>;
107/// A reference to a ChaCha20Poly1305 nonce.
108pub type NonceRef<'a> = typed_refs::NonceRef<'a, ChaCha20Poly1305>;
109
110/// Describes the error conditions of the  ChaCha20-Poly1305 AEAD.
111#[derive(Debug)]
112pub enum AeadError {
113    /// Indicates that the plaintext argument is too large for the library to handle.
114    PlaintextTooLarge,
115    /// Indicates that the ciphertext argument is too large for the library to handle.
116    CiphertextTooLarge,
117    /// Indicates that the associated data argument is too large for the library to handle.
118    AadTooLarge,
119    /// This indicates that the provided destination ciphertext does not fit the ciphertext and tag.
120    CiphertextTooShort,
121    /// This indicates that the provided destination plaintext is shorter than `ctxt.len() - TAG_LEN`
122    /// and thus will not fit the decrypted plaintext
123    PlaintextTooShort,
124    /// Indicates that the ciphertext is not a valid encryption under the given key and nonce.
125    InvalidCiphertext,
126}
127
128impl core::fmt::Display for AeadError {
129    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
130        let msg = match self {
131            AeadError::PlaintextTooLarge => {
132                "The plaintext argument is too large for the library to handle"
133            }
134            AeadError::CiphertextTooLarge => {
135                "The ciphertext argument is too large for the library to handle"
136            }
137            AeadError::AadTooLarge => {
138                "The associated data argument is too large for the library to handle"
139            }
140            AeadError::CiphertextTooShort => {
141                "The provided destination ciphertext does not fit the ciphertext and tag"
142            }
143            AeadError::PlaintextTooShort => {
144                "The provided destination plaintext is too short to fit the decrypted plaintext"
145            }
146            AeadError::InvalidCiphertext => {
147                "The ciphertext is not a valid encryption under the given key and nonce."
148            }
149        };
150
151        f.write_str(msg)
152    }
153}
154
155/// Describes the error conditions of the Poly1305 MAC.
156#[derive(Debug)]
157pub enum MacError {
158    /// Indicates that the message argument is too large for the library to handle.
159    MessageTooLarge,
160
161    /// Indicates that the MAC tag is invalid for that key and message.
162    InvalidMacTag,
163}
164
165impl core::fmt::Display for MacError {
166    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
167        let msg = match self {
168            MacError::MessageTooLarge => {
169                "The message argument is too large for the library to handle"
170            }
171            MacError::InvalidMacTag => "The MAC tag is invalid for that key and message",
172        };
173
174        f.write_str(msg)
175    }
176}