poly1305/
lib.rs

1//! The Poly1305 universal hash function and message authentication code.
2//!
3//! # About
4//!
5//! Poly1305 is a universal hash function suitable for use as a one-time
6//! authenticator and, when combined with a cipher, a message authentication
7//! code (MAC).
8//!
9//! It takes a 32-byte one-time key and a message and produces a 16-byte tag,
10//! which can be used to authenticate the message.
11//!
12//! Poly1305 is primarily notable for its use in the [`ChaCha20Poly1305`] and
13//! [`XSalsa20Poly1305`] authenticated encryption algorithms.
14//!
15//! # Minimum Supported Rust Version
16//!
17//! Rust **1.56** or higher.
18//!
19//! Minimum supported Rust version may be changed in the future, but such
20//! changes will be accompanied with a minor version bump.
21//!
22//! # Security Notes
23//!
24//! This crate has received one [security audit by NCC Group][audit], with no
25//! significant findings. We would like to thank [MobileCoin] for funding the
26//! audit.
27//!
28//! NOTE: the audit predates the AVX2 backend, which has not yet been audited.
29//!
30//! All implementations contained in the crate are designed to execute in constant
31//! time, either by relying on hardware intrinsics (e.g. AVX2 on x86/x86_64), or
32//! using a portable implementation which is only constant time on processors which
33//! implement constant-time multiplication.
34//!
35//! It is not suitable for use on processors with a variable-time multiplication
36//! operation (e.g. short circuit on multiply-by-zero / multiply-by-one, such as
37//! certain 32-bit PowerPC CPUs and some non-ARM microcontrollers).
38//!
39//! [`ChaCha20Poly1305`]: https://docs.rs/chacha20poly1305
40//! [`XSalsa20Poly1305`]: https://docs.rs/xsalsa20poly1305
41//! [audit]: https://research.nccgroup.com/2020/02/26/public-report-rustcrypto-aes-gcm-and-chacha20poly1305-implementation-review/
42//! [MobileCoin]: https://mobilecoin.com
43
44#![no_std]
45#![doc(
46    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
47    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
48)]
49#![warn(missing_docs, rust_2018_idioms)]
50
51#[cfg(feature = "std")]
52extern crate std;
53
54pub use universal_hash;
55
56use universal_hash::{
57    consts::{U16, U32},
58    crypto_common::{BlockSizeUser, KeySizeUser},
59    generic_array::GenericArray,
60    KeyInit, UniversalHash,
61};
62
63mod backend;
64
65#[cfg(all(
66    any(target_arch = "x86", target_arch = "x86_64"),
67    not(poly1305_force_soft),
68    target_feature = "avx2", // Fuzz tests bypass AVX2 autodetection code
69    any(fuzzing, test)
70))]
71mod fuzz;
72
73#[cfg(all(
74    any(target_arch = "x86", target_arch = "x86_64"),
75    not(poly1305_force_soft)
76))]
77use crate::backend::autodetect::State;
78
79#[cfg(not(all(
80    any(target_arch = "x86", target_arch = "x86_64"),
81    not(poly1305_force_soft)
82)))]
83use crate::backend::soft::State;
84
85/// Size of a Poly1305 key
86pub const KEY_SIZE: usize = 32;
87
88/// Size of the blocks Poly1305 acts upon
89pub const BLOCK_SIZE: usize = 16;
90
91/// Poly1305 keys (32-bytes)
92pub type Key = universal_hash::Key<Poly1305>;
93
94/// Poly1305 blocks (16-bytes)
95pub type Block = universal_hash::Block<Poly1305>;
96
97/// Poly1305 tags (16-bytes)
98pub type Tag = universal_hash::Block<Poly1305>;
99
100/// The Poly1305 universal hash function.
101///
102/// Note that Poly1305 is not a traditional MAC and is single-use only
103/// (a.k.a. "one-time authenticator").
104///
105/// For this reason it doesn't impl the `crypto_mac::Mac` trait.
106#[derive(Clone)]
107pub struct Poly1305 {
108    state: State,
109}
110
111impl KeySizeUser for Poly1305 {
112    type KeySize = U32;
113}
114
115impl KeyInit for Poly1305 {
116    /// Initialize Poly1305 with the given key
117    fn new(key: &Key) -> Poly1305 {
118        Poly1305 {
119            state: State::new(key),
120        }
121    }
122}
123
124impl BlockSizeUser for Poly1305 {
125    type BlockSize = U16;
126}
127
128impl UniversalHash for Poly1305 {
129    fn update_with_backend(
130        &mut self,
131        f: impl universal_hash::UhfClosure<BlockSize = Self::BlockSize>,
132    ) {
133        self.state.update_with_backend(f);
134    }
135
136    /// Get the hashed output
137    fn finalize(self) -> Tag {
138        self.state.finalize()
139    }
140}
141
142impl Poly1305 {
143    /// Compute unpadded Poly1305 for the given input data.
144    ///
145    /// The main use case for this is XSalsa20Poly1305.
146    pub fn compute_unpadded(mut self, data: &[u8]) -> Tag {
147        for chunk in data.chunks(BLOCK_SIZE) {
148            if chunk.len() == BLOCK_SIZE {
149                let block = GenericArray::from_slice(chunk);
150                self.state.compute_block(block, false);
151            } else {
152                let mut block = Block::default();
153                block[..chunk.len()].copy_from_slice(chunk);
154                block[chunk.len()] = 1;
155                self.state.compute_block(&block, true)
156            }
157        }
158
159        self.state.finalize()
160    }
161}
162
163opaque_debug::implement!(Poly1305);
164
165#[cfg(all(
166    any(target_arch = "x86", target_arch = "x86_64"),
167    not(poly1305_force_soft),
168    target_feature = "avx2", // Fuzz tests bypass AVX2 autodetection code
169    any(fuzzing, test)
170))]
171pub use crate::fuzz::fuzz_avx2;