Skip to main content

poly1305/backend/
autodetect.rs

1//! Autodetection support for AVX2 CPU intrinsics on x86 CPUs, with fallback
2//! to the "soft" backend when it's unavailable.
3
4use universal_hash::{UhfClosure, consts::U16};
5
6use crate::{Block, Key, Tag, backend};
7use core::mem::ManuallyDrop;
8
9cpufeatures::new!(avx2_cpuid, "avx2");
10
11pub(crate) struct State {
12    inner: Inner,
13    token: avx2_cpuid::InitToken,
14}
15
16union Inner {
17    avx2: ManuallyDrop<backend::avx2::State>,
18    soft: ManuallyDrop<backend::soft::State>,
19}
20
21impl State {
22    /// Initialize Poly1305 [`State`] with the given key
23    #[inline]
24    pub(crate) fn new(key: &Key) -> State {
25        let (token, avx2_present) = avx2_cpuid::init_get();
26
27        let inner = if avx2_present {
28            Inner {
29                avx2: ManuallyDrop::new(backend::avx2::State::new(key)),
30            }
31        } else {
32            Inner {
33                soft: ManuallyDrop::new(backend::soft::State::new(key)),
34            }
35        };
36
37        Self { inner, token }
38    }
39
40    /// Compute a Poly1305 block
41    #[inline]
42    pub(crate) fn compute_block(&mut self, block: &Block, partial: bool) {
43        if self.token.get() {
44            unsafe { (*self.inner.avx2).compute_block(block, partial) }
45        } else {
46            unsafe { (*self.inner.soft).compute_block(block, partial) }
47        }
48    }
49
50    pub(crate) fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = U16>) {
51        if self.token.get() {
52            unsafe { f.call(&mut *self.inner.avx2) }
53        } else {
54            unsafe { f.call(&mut *self.inner.soft) }
55        }
56    }
57
58    pub(crate) fn finalize(&mut self) -> Tag {
59        if self.token.get() {
60            unsafe { (*self.inner.avx2).finalize() }
61        } else {
62            unsafe { (*self.inner.soft).finalize() }
63        }
64    }
65}
66
67impl Clone for State {
68    fn clone(&self) -> Self {
69        let inner = if self.token.get() {
70            Inner {
71                avx2: ManuallyDrop::new(unsafe { (*self.inner.avx2).clone() }),
72            }
73        } else {
74            Inner {
75                soft: ManuallyDrop::new(unsafe { (*self.inner.soft).clone() }),
76            }
77        };
78
79        Self {
80            inner,
81            token: self.token,
82        }
83    }
84}