poly1305/backend/
autodetect.rs1use 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 #[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 #[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}