ring/aead/gcm/
ffi.rs

1// Copyright 2018 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15use crate::{
16    bb,
17    polyfill::{slice::AsChunks, ArraySplitMap},
18};
19
20pub(in super::super) const BLOCK_LEN: usize = 16;
21pub(in super::super) type Block = [u8; BLOCK_LEN];
22pub(super) const ZERO_BLOCK: Block = [0u8; BLOCK_LEN];
23
24#[cfg(any(
25    all(target_arch = "aarch64", target_endian = "little"),
26    all(target_arch = "arm", target_endian = "little"),
27    target_arch = "x86",
28    target_arch = "x86_64"
29))]
30macro_rules! htable_new {
31    ( $name:ident, $value:expr $(,)? ) => {{
32        use crate::aead::gcm::ffi::HTable;
33        prefixed_extern! {
34            fn $name(HTable: &mut HTable, h: &[u64; 2]);
35        }
36        HTable::new($name, $value)
37    }};
38}
39
40/// SAFETY:
41///  * The function `$name` must meet the contract of the `f` paramweter of
42///    `ghash()`.
43#[cfg(any(
44    all(target_arch = "aarch64", target_endian = "little"),
45    all(target_arch = "arm", target_endian = "little"),
46    target_arch = "x86",
47    target_arch = "x86_64"
48))]
49macro_rules! ghash {
50    ( $name:ident, $xi:expr, $h_table:expr, $input:expr $(,)? ) => {{
51        use crate::aead::gcm::ffi::{HTable, Xi};
52        prefixed_extern! {
53            fn $name(
54                xi: &mut Xi,
55                Htable: &HTable,
56                inp: *const u8,
57                len: crate::c::NonZero_size_t,
58            );
59        }
60        $h_table.ghash($name, $xi, $input)
61    }};
62}
63
64pub(in super::super) struct KeyValue([u64; 2]);
65
66impl KeyValue {
67    pub(in super::super) fn new(value: Block) -> Self {
68        Self(value.array_split_map(u64::from_be_bytes))
69    }
70
71    pub(super) fn into_inner(self) -> [u64; 2] {
72        self.0
73    }
74}
75
76/// SAFETY:
77///   * `f` must read `len` bytes from `inp`; it may assume
78///     that `len` is a (non-zero) multiple of `BLOCK_LEN`.
79///   * `f` may inspect CPU features.
80#[cfg(any(
81    all(target_arch = "aarch64", target_endian = "little"),
82    all(target_arch = "arm", target_endian = "little"),
83    target_arch = "x86",
84    target_arch = "x86_64"
85))]
86impl HTable {
87    pub(super) unsafe fn new(
88        init: unsafe extern "C" fn(HTable: &mut HTable, &[u64; 2]),
89        value: KeyValue,
90    ) -> Self {
91        let mut r = Self {
92            Htable: [U128 { hi: 0, lo: 0 }; HTABLE_LEN],
93        };
94        unsafe { init(&mut r, &value.0) };
95        r
96    }
97
98    #[cfg(any(
99        all(target_arch = "aarch64", target_endian = "little"),
100        all(target_arch = "arm", target_endian = "little")
101    ))]
102    pub(super) unsafe fn gmult(
103        &self,
104        f: unsafe extern "C" fn(xi: &mut Xi, h_table: &HTable),
105        xi: &mut Xi,
106    ) {
107        unsafe { f(xi, self) }
108    }
109
110    pub(super) unsafe fn ghash(
111        &self,
112        f: unsafe extern "C" fn(
113            xi: &mut Xi,
114            Htable: &HTable,
115            inp: *const u8,
116            len: crate::c::NonZero_size_t,
117        ),
118        xi: &mut Xi,
119        input: AsChunks<u8, BLOCK_LEN>,
120    ) {
121        use core::num::NonZeroUsize;
122
123        let input = input.as_flattened();
124
125        let input_len = match NonZeroUsize::new(input.len()) {
126            Some(len) => len,
127            None => {
128                return;
129            }
130        };
131
132        // SAFETY:
133        //  * There are `input_len: NonZeroUsize` bytes available at `input` for
134        //    `f` to read.
135        unsafe {
136            f(xi, self, input.as_ptr(), input_len);
137        }
138    }
139}
140
141// The alignment is required by some assembly code, such as `ghash-ssse3-*`.
142#[derive(Clone)]
143#[repr(C, align(16))]
144pub(in super::super) struct HTable {
145    Htable: [U128; HTABLE_LEN],
146}
147
148#[derive(Clone, Copy)]
149#[repr(C)]
150pub(super) struct U128 {
151    pub(super) hi: u64,
152    pub(super) lo: u64,
153}
154
155const HTABLE_LEN: usize = 16;
156
157#[repr(transparent)]
158pub(in super::super) struct Xi(pub(super) Block);
159
160impl Xi {
161    #[inline]
162    pub(super) fn bitxor_assign(&mut self, a: Block) {
163        self.0 = bb::xor_16(self.0, a)
164    }
165}