pkgconfig: Fix libgcrypt.pc.
[libgcrypt.git] / cipher / crc-armv8-ce.c
1 /* crc-armv8-ce.c - ARMv8-CE PMULL accelerated CRC implementation
2  * Copyright (C) 2019 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  *
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "g10lib.h"
28
29 #include "bithelp.h"
30 #include "bufhelp.h"
31
32
33 #if defined(ENABLE_ARM_CRYPTO_SUPPORT) && defined(__AARCH64EL__) && \
34     defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) && \
35     defined(HAVE_GCC_INLINE_ASM_AARCH64_CRYPTO)
36
37
38 #define ALIGNED_16 __attribute__ ((aligned (16)))
39
40
41 struct u16_unaligned_s
42 {
43   u16 a;
44 } __attribute__((packed, aligned (1), may_alias));
45
46 struct u32_unaligned_s
47 {
48   u32 a;
49 } __attribute__((packed, aligned (1), may_alias));
50
51
52 /* Constants structure for generic reflected/non-reflected CRC32 PMULL
53  * functions. */
54 struct crc32_consts_s
55 {
56   /* k: { x^(32*17), x^(32*15), x^(32*5), x^(32*3), x^(32*2), 0 } mod P(x) */
57   u64 k[6];
58   /* my_p: { floor(x^64 / P(x)), P(x) } */
59   u64 my_p[2];
60 };
61
62 /* PMULL constants for CRC32 and CRC32RFC1510. */
63 static const struct crc32_consts_s crc32_consts ALIGNED_16 =
64 {
65   { /* k[6] = reverse_33bits( x^(32*y) mod P(x) ) */
66     U64_C(0x154442bd4), U64_C(0x1c6e41596), /* y = { 17, 15 } */
67     U64_C(0x1751997d0), U64_C(0x0ccaa009e), /* y = { 5, 3 } */
68     U64_C(0x163cd6124), 0                   /* y = 2 */
69   },
70   { /* my_p[2] = reverse_33bits ( { floor(x^64 / P(x)), P(x) } ) */
71     U64_C(0x1f7011641), U64_C(0x1db710641)
72   }
73 };
74
75 /* PMULL constants for CRC24RFC2440 (polynomial multiplied with x⁸). */
76 static const struct crc32_consts_s crc24rfc2440_consts ALIGNED_16 =
77 {
78   { /* k[6] = x^(32*y) mod P(x) << 32*/
79     U64_C(0x08289a00) << 32, U64_C(0x74b44a00) << 32, /* y = { 17, 15 } */
80     U64_C(0xc4b14d00) << 32, U64_C(0xfd7e0c00) << 32, /* y = { 5, 3 } */
81     U64_C(0xd9fe8c00) << 32, 0                        /* y = 2 */
82   },
83   { /* my_p[2] = { floor(x^64 / P(x)), P(x) } */
84     U64_C(0x1f845fe24), U64_C(0x1864cfb00)
85   }
86 };
87
88
89 u32 _gcry_crc32r_armv8_ce_reduction_4 (u32 data, u32 crc,
90                                        const struct crc32_consts_s *consts);
91 void _gcry_crc32r_armv8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
92                                  const struct crc32_consts_s *consts);
93
94 u32 _gcry_crc32_armv8_ce_reduction_4 (u32 data, u32 crc,
95                                       const struct crc32_consts_s *consts);
96 void _gcry_crc32_armv8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
97                                 const struct crc32_consts_s *consts);
98
99
100 static inline void
101 crc32r_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen,
102                      const struct crc32_consts_s *consts)
103 {
104   u32 crc = *pcrc;
105   u32 data;
106
107   while (inlen >= 4)
108     {
109       data = ((const struct u32_unaligned_s *)inbuf)->a;
110       data ^= crc;
111
112       inlen -= 4;
113       inbuf += 4;
114
115       crc = _gcry_crc32r_armv8_ce_reduction_4 (data, 0, consts);
116     }
117
118   switch (inlen)
119     {
120     case 0:
121       break;
122     case 1:
123       data = inbuf[0];
124       data ^= crc;
125       data <<= 24;
126       crc >>= 8;
127       crc = _gcry_crc32r_armv8_ce_reduction_4 (data, crc, consts);
128       break;
129     case 2:
130       data = ((const struct u16_unaligned_s *)inbuf)->a;
131       data ^= crc;
132       data <<= 16;
133       crc >>= 16;
134       crc = _gcry_crc32r_armv8_ce_reduction_4 (data, crc, consts);
135       break;
136     case 3:
137       data = ((const struct u16_unaligned_s *)inbuf)->a;
138       data |= inbuf[2] << 16;
139       data ^= crc;
140       data <<= 8;
141       crc >>= 24;
142       crc = _gcry_crc32r_armv8_ce_reduction_4 (data, crc, consts);
143       break;
144     }
145
146   *pcrc = crc;
147 }
148
149 static inline void
150 crc32_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen,
151                     const struct crc32_consts_s *consts)
152 {
153   u32 crc = *pcrc;
154   u32 data;
155
156   while (inlen >= 4)
157     {
158       data = ((const struct u32_unaligned_s *)inbuf)->a;
159       data ^= crc;
160       data = _gcry_bswap32(data);
161
162       inlen -= 4;
163       inbuf += 4;
164
165       crc = _gcry_crc32_armv8_ce_reduction_4 (data, 0, consts);
166     }
167
168   switch (inlen)
169     {
170     case 0:
171       break;
172     case 1:
173       data = inbuf[0];
174       data ^= crc;
175       data = data & 0xffU;
176       crc = _gcry_bswap32(crc >> 8);
177       crc = _gcry_crc32_armv8_ce_reduction_4 (data, crc, consts);
178       break;
179     case 2:
180       data = ((const struct u16_unaligned_s *)inbuf)->a;
181       data ^= crc;
182       data = _gcry_bswap32(data << 16);
183       crc = _gcry_bswap32(crc >> 16);
184       crc = _gcry_crc32_armv8_ce_reduction_4 (data, crc, consts);
185       break;
186     case 3:
187       data = ((const struct u16_unaligned_s *)inbuf)->a;
188       data |= inbuf[2] << 16;
189       data ^= crc;
190       data = _gcry_bswap32(data << 8);
191       crc = crc & 0xff000000U;
192       crc = _gcry_crc32_armv8_ce_reduction_4 (data, crc, consts);
193       break;
194     }
195
196   *pcrc = crc;
197 }
198
199 void
200 _gcry_crc32_armv8_ce_pmull (u32 *pcrc, const byte *inbuf, size_t inlen)
201 {
202   const struct crc32_consts_s *consts = &crc32_consts;
203
204   if (!inlen)
205     return;
206
207   if (inlen >= 16)
208     _gcry_crc32r_armv8_ce_bulk (pcrc, inbuf, inlen, consts);
209   else
210     crc32r_less_than_16 (pcrc, inbuf, inlen, consts);
211 }
212
213 void
214 _gcry_crc24rfc2440_armv8_ce_pmull (u32 *pcrc, const byte *inbuf, size_t inlen)
215 {
216   const struct crc32_consts_s *consts = &crc24rfc2440_consts;
217
218   if (!inlen)
219     return;
220
221   /* Note: *pcrc in input endian. */
222
223   if (inlen >= 16)
224     _gcry_crc32_armv8_ce_bulk (pcrc, inbuf, inlen, consts);
225   else
226     crc32_less_than_16 (pcrc, inbuf, inlen, consts);
227 }
228
229 #endif /* USE_INTEL_PCLMUL */