polyval/backend/
autodetect.rs

1//! Autodetection for CPU intrinsics, with fallback to the "soft" backend when
2//! they are unavailable.
3
4use crate::{backend::soft, Key, Tag};
5use core::mem::ManuallyDrop;
6use universal_hash::{
7    consts::U16,
8    crypto_common::{BlockSizeUser, KeySizeUser},
9    KeyInit, Reset, UniversalHash,
10};
11
12#[cfg(all(target_arch = "aarch64", polyval_armv8))]
13use super::pmull as intrinsics;
14
15#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
16use super::clmul as intrinsics;
17
18#[cfg(all(target_arch = "aarch64", polyval_armv8))]
19cpufeatures::new!(mul_intrinsics, "aes"); // `aes` implies PMULL
20
21#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
22cpufeatures::new!(mul_intrinsics, "pclmulqdq");
23
24/// **POLYVAL**: GHASH-like universal hash over GF(2^128).
25pub struct Polyval {
26    inner: Inner,
27    token: mul_intrinsics::InitToken,
28}
29
30union Inner {
31    intrinsics: ManuallyDrop<intrinsics::Polyval>,
32    soft: ManuallyDrop<soft::Polyval>,
33}
34
35impl KeySizeUser for Polyval {
36    type KeySize = U16;
37}
38
39impl KeyInit for Polyval {
40    /// Initialize POLYVAL with the given `H` field element
41    fn new(h: &Key) -> Self {
42        let (token, has_intrinsics) = mul_intrinsics::init_get();
43
44        let inner = if has_intrinsics {
45            Inner {
46                intrinsics: ManuallyDrop::new(intrinsics::Polyval::new(h)),
47            }
48        } else {
49            Inner {
50                soft: ManuallyDrop::new(soft::Polyval::new(h)),
51            }
52        };
53
54        Self { inner, token }
55    }
56}
57
58impl BlockSizeUser for Polyval {
59    type BlockSize = U16;
60}
61
62impl UniversalHash for Polyval {
63    fn update_with_backend(
64        &mut self,
65        f: impl universal_hash::UhfClosure<BlockSize = Self::BlockSize>,
66    ) {
67        unsafe {
68            if self.token.get() {
69                f.call(&mut *self.inner.intrinsics)
70            } else {
71                f.call(&mut *self.inner.soft)
72            }
73        }
74    }
75
76    /// Get POLYVAL result (i.e. computed `S` field element)
77    fn finalize(self) -> Tag {
78        unsafe {
79            if self.token.get() {
80                ManuallyDrop::into_inner(self.inner.intrinsics).finalize()
81            } else {
82                ManuallyDrop::into_inner(self.inner.soft).finalize()
83            }
84        }
85    }
86}
87
88impl Clone for Polyval {
89    fn clone(&self) -> Self {
90        let inner = if self.token.get() {
91            Inner {
92                intrinsics: ManuallyDrop::new(unsafe { (*self.inner.intrinsics).clone() }),
93            }
94        } else {
95            Inner {
96                soft: ManuallyDrop::new(unsafe { (*self.inner.soft).clone() }),
97            }
98        };
99
100        Self {
101            inner,
102            token: self.token,
103        }
104    }
105}
106
107impl Reset for Polyval {
108    fn reset(&mut self) {
109        if self.token.get() {
110            unsafe { (*self.inner.intrinsics).reset() }
111        } else {
112            unsafe { (*self.inner.soft).reset() }
113        }
114    }
115}