poly1305/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
5    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
6)]
7#![warn(missing_docs)]
8
9pub use universal_hash;
10
11use core::fmt::{self, Debug};
12use universal_hash::{
13    KeyInit, UhfClosure, UniversalHash,
14    consts::{U16, U32},
15    crypto_common::{BlockSizeUser, KeySizeUser},
16};
17
18mod backend;
19
20#[cfg(all(
21    any(target_arch = "x86", target_arch = "x86_64"),
22    not(poly1305_force_soft),
23    target_feature = "avx2", // Fuzz tests bypass AVX2 autodetection code
24    any(fuzzing, test)
25))]
26mod fuzz;
27
28#[cfg(all(
29    any(target_arch = "x86", target_arch = "x86_64"),
30    not(poly1305_force_soft)
31))]
32use crate::backend::autodetect::State;
33
34#[cfg(not(all(
35    any(target_arch = "x86", target_arch = "x86_64"),
36    not(poly1305_force_soft)
37)))]
38use crate::backend::soft::State;
39
40/// Size of a Poly1305 key
41pub const KEY_SIZE: usize = 32;
42
43/// Size of the blocks Poly1305 acts upon
44pub const BLOCK_SIZE: usize = 16;
45
46/// Poly1305 keys (32-bytes)
47pub type Key = universal_hash::Key<Poly1305>;
48
49/// Poly1305 blocks (16-bytes)
50pub type Block = universal_hash::Block<Poly1305>;
51
52/// Poly1305 tags (16-bytes)
53pub type Tag = universal_hash::Block<Poly1305>;
54
55/// The Poly1305 universal hash function.
56///
57/// Note that Poly1305 is not a traditional MAC and is single-use only
58/// (a.k.a. "one-time authenticator").
59///
60/// For this reason it doesn't impl the `crypto_mac::Mac` trait.
61#[derive(Clone)]
62pub struct Poly1305 {
63    state: State,
64}
65
66impl KeySizeUser for Poly1305 {
67    type KeySize = U32;
68}
69
70impl KeyInit for Poly1305 {
71    /// Initialize Poly1305 with the given key
72    fn new(key: &Key) -> Poly1305 {
73        Poly1305 {
74            state: State::new(key),
75        }
76    }
77}
78
79impl BlockSizeUser for Poly1305 {
80    type BlockSize = U16;
81}
82
83impl UniversalHash for Poly1305 {
84    fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>) {
85        self.state.update_with_backend(f);
86    }
87
88    /// Get the hashed output
89    fn finalize(self) -> Tag {
90        self.state.finalize()
91    }
92}
93
94impl Poly1305 {
95    /// Compute unpadded Poly1305 for the given input data.
96    ///
97    /// The main use case for this is XSalsa20Poly1305.
98    pub fn compute_unpadded(mut self, data: &[u8]) -> Tag {
99        let (blocks, remaining) = Block::slice_as_chunks(data);
100
101        for block in blocks {
102            self.state.compute_block(block, false);
103        }
104
105        if !remaining.is_empty() {
106            let mut block = Block::default();
107            block[..remaining.len()].copy_from_slice(remaining);
108            block[remaining.len()] = 1;
109            self.state.compute_block(&block, true);
110        }
111
112        self.state.finalize()
113    }
114}
115
116impl Debug for Poly1305 {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        f.debug_struct("Poly1305").finish_non_exhaustive()
119    }
120}
121
122#[cfg(all(
123    any(target_arch = "x86", target_arch = "x86_64"),
124    not(poly1305_force_soft),
125    target_feature = "avx2", // Fuzz tests bypass AVX2 autodetection code
126    any(fuzzing, test)
127))]
128pub use crate::fuzz::fuzz_avx2;