poly1305/backend/
autodetect.rs1use universal_hash::{UhfClosure, UniversalHash, common::BlockSizeUser, 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 BlockSizeUser for State {
22 type BlockSize = U16;
23}
24
25impl State {
26 #[inline]
28 pub(crate) fn new(key: &Key) -> State {
29 let (token, avx2_present) = avx2_cpuid::init_get();
30
31 let inner = if avx2_present {
32 Inner {
33 avx2: ManuallyDrop::new(backend::avx2::State::new(key)),
34 }
35 } else {
36 Inner {
37 soft: ManuallyDrop::new(backend::soft::State::new(key)),
38 }
39 };
40
41 Self { inner, token }
42 }
43
44 #[inline]
46 pub(crate) fn compute_block(&mut self, block: &Block, partial: bool) {
47 if self.token.get() {
48 unsafe { (*self.inner.avx2).compute_block(block, partial) }
49 } else {
50 unsafe { (*self.inner.soft).compute_block(block, partial) }
51 }
52 }
53}
54
55impl UniversalHash for State {
56 fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>) {
57 if self.token.get() {
58 unsafe { f.call(&mut *self.inner.avx2) }
59 } else {
60 unsafe { f.call(&mut *self.inner.soft) }
61 }
62 }
63
64 #[inline]
66 fn finalize(mut self) -> Tag {
67 if self.token.get() {
68 unsafe { (*self.inner.avx2).finalize() }
69 } else {
70 unsafe { (*self.inner.soft).finalize_mut() }
71 }
72 }
73}
74
75impl Clone for State {
76 fn clone(&self) -> Self {
77 let inner = if self.token.get() {
78 Inner {
79 avx2: ManuallyDrop::new(unsafe { (*self.inner.avx2).clone() }),
80 }
81 } else {
82 Inner {
83 soft: ManuallyDrop::new(unsafe { (*self.inner.soft).clone() }),
84 }
85 };
86
87 Self {
88 inner,
89 token: self.token,
90 }
91 }
92}
93
94#[cfg(feature = "zeroize")]
95impl Drop for State {
96 fn drop(&mut self) {
97 use zeroize::Zeroize;
98 const SIZE: usize = size_of::<State>();
99 let state = unsafe { &mut *core::ptr::from_mut::<State>(self).cast::<[u8; SIZE]>() };
100 state.zeroize();
101 }
102}