pkgconfig: Fix libgcrypt.pc.
[libgcrypt.git] / cipher / cipher-gcm-armv7-neon.S
1 /* cipher-gcm-armv7-neon.S - ARM/NEON accelerated GHASH
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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) && \
23     defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) && \
24     defined(HAVE_GCC_INLINE_ASM_NEON)
25
26 .syntax unified
27 .fpu neon
28 .arm
29
30 .text
31
32 #ifdef __PIC__
33 #  define GET_DATA_POINTER(reg, name, rtmp) \
34                 ldr reg, 1f; \
35                 ldr rtmp, 2f; \
36                 b 3f; \
37         1:      .word _GLOBAL_OFFSET_TABLE_-(3f+8); \
38         2:      .word name(GOT); \
39         3:      add reg, pc, reg; \
40                 ldr reg, [reg, rtmp];
41 #else
42 #  define GET_DATA_POINTER(reg, name, rtmp) ldr reg, =name
43 #endif
44
45
46 /* Constants */
47
48 .align 4
49 gcry_gcm_reduction_constant:
50 .Lrconst64:
51   .quad 0xc200000000000000
52
53 /* Register macros */
54
55 #define rhash q0
56 #define rhash_l d0
57 #define rhash_h d1
58
59 #define rh1 q1
60 #define rh1_l d2
61 #define rh1_h d3
62
63 #define rbuf q2
64 #define rbuf_l d4
65 #define rbuf_h d5
66
67 #define rbuf1 q3
68 #define rbuf1_l d6
69 #define rbuf1_h d7
70
71 #define t0q q4
72 #define t0l d8
73 #define t0h d9
74
75 #define t1q q5
76 #define t1l d10
77 #define t1h d11
78
79 #define t2q q6
80 #define t2l d12
81 #define t2h d13
82
83 #define t3q q7
84 #define t3l d14
85 #define t3h d15
86
87 /* q8 */
88 #define k16 d16
89 #define k32 d17
90
91 /* q9 */
92 #define k48 d18
93
94 #define k0 q10
95
96 #define rr0 q11
97 #define rr0_l d22
98 #define rr0_h d23
99
100 #define rr1 q12
101 #define rr1_l d24
102 #define rr1_h d25
103
104 #define rt0 q13
105 #define rt0_l d26
106 #define rt0_h d27
107
108 #define rt1 q14
109 #define rt1_l d28
110 #define rt1_h d29
111
112 #define rrconst q15
113 #define rrconst_l d30
114 #define rrconst_h d31
115
116 /* Macro for 64x64=>128 carry-less multiplication using vmull.p8 instruction.
117  *
118  * From "Câmara, D.; Gouvêa, C. P. L.; López, J. & Dahab, R. Fast Software
119  * Polynomial Multiplication on ARM Processors using the NEON Engine. The
120  * Second International Workshop on Modern Cryptography and Security
121  * Engineering — MoCrySEn, 2013". */
122
123 #define vmull_p64(rq, rl, rh, ad, bd) \
124         vext.8 t0l, ad, ad, $1; \
125         vmull.p8 t0q, t0l, bd; \
126         vext.8 rl, bd, bd, $1; \
127         vmull.p8 rq, ad, rl; \
128         vext.8 t1l, ad, ad, $2; \
129         vmull.p8 t1q, t1l, bd; \
130         vext.8 t3l, bd, bd, $2; \
131         vmull.p8 t3q, ad, t3l; \
132         vext.8 t2l, ad, ad, $3; \
133         vmull.p8 t2q, t2l, bd; \
134         veor t0q, t0q, rq; \
135         vext.8 rl, bd, bd, $3; \
136         vmull.p8 rq, ad, rl; \
137         veor t1q, t1q, t3q; \
138         vext.8 t3l, bd, bd, $4; \
139         vmull.p8 t3q, ad, t3l; \
140         veor t0l, t0l, t0h; \
141         vand t0h, t0h, k48; \
142         veor t1l, t1l, t1h; \
143         vand t1h, t1h, k32; \
144         veor t2q, t2q, rq; \
145         veor t0l, t0l, t0h; \
146         veor t1l, t1l, t1h; \
147         veor t2l, t2l, t2h; \
148         vand t2h, t2h, k16; \
149         veor t3l, t3l, t3h; \
150         vmov.i64 t3h, $0; \
151         vext.8 t0q, t0q, t0q, $15; \
152         veor t2l, t2l, t2h; \
153         vext.8 t1q, t1q, t1q, $14; \
154         vmull.p8 rq, ad, bd; \
155         vext.8 t2q, t2q, t2q, $13; \
156         vext.8 t3q, t3q, t3q, $12; \
157         veor t0q, t0q, t1q; \
158         veor t2q, t2q, t3q; \
159         veor rq, rq, t0q; \
160         veor rq, rq, t2q;
161
162 /* GHASH macros.
163  *
164  * See "Gouvêa, C. P. L. & López, J. Implementing GCM on ARMv8. Topics in
165  * Cryptology — CT-RSA 2015" for details.
166  */
167
168 /* Input: 'a' and 'b', Output: 'r0:r1' (low 128-bits in r0, high in r1)
169  *  Note: 'r1' may be 'a' or 'b', 'r0' must not be either 'a' or 'b'.
170  */
171 #define PMUL_128x128(r0, r1, a, b, t1, t2, interleave_op) \
172         veor t1##_h, b##_l, b##_h; \
173         veor t1##_l, a##_l, a##_h; \
174         vmull_p64( r0, r0##_l, r0##_h, a##_l, b##_l ); \
175         vmull_p64( r1, r1##_l, r1##_h, a##_h, b##_h ); \
176         vmull_p64( t2, t2##_h, t2##_l, t1##_h, t1##_l ); \
177         interleave_op; \
178         veor t2, r0; \
179         veor t2, r1; \
180         veor r0##_h, t2##_l; \
181         veor r1##_l, t2##_h;
182
183 /* Reduction using Xor and Shift.
184  * Input: 'r0:r1', Output: 'a'
185  *
186  * See "Shay Gueron, Michael E. Kounavis. Intel Carry-Less Multiplication
187  * Instruction and its Usage for Computing the GCM Mode" for details.
188  */
189 #define REDUCTION(a, r0, r1, t, interleave_op) \
190         vshl.u32 t0q, r0, #31; \
191         vshl.u32 t1q, r0, #30; \
192         vshl.u32 t2q, r0, #25; \
193         veor t0q, t0q, t1q; \
194         veor t0q, t0q, t2q; \
195         vext.8 t, t0q, k0, #4; \
196         vext.8 t0q, k0, t0q, #(16-12); \
197         veor r0, r0, t0q; \
198         interleave_op; \
199         vshr.u32 t0q, r0, #1; \
200         vshr.u32 t1q, r0, #2; \
201         vshr.u32 t2q, r0, #7; \
202         veor t0q, t0q, t1q; \
203         veor t0q, t0q, t2q; \
204         veor t0q, t0q, t; \
205         veor r0, r0, t0q; \
206         veor a, r0, r1;
207
208 #define _(...) __VA_ARGS__
209 #define __ _()
210
211 /* Other functional macros */
212
213 #define CLEAR_REG(reg) veor reg, reg;
214
215
216 /*
217  * unsigned int _gcry_ghash_armv7_neon (void *gcm_key, byte *result,
218  *                                      const byte *buf, size_t nblocks);
219  */
220 .align 3
221 .globl _gcry_ghash_armv7_neon
222 .type  _gcry_ghash_armv7_neon,%function;
223 _gcry_ghash_armv7_neon:
224   /* input:
225    *    r0: gcm_key
226    *    r1: result/hash
227    *    r2: buf
228    *    r3: nblocks
229    */
230   push {r4-r6, lr}
231
232   cmp r3, #0
233   beq .Ldo_nothing
234
235   vpush {q4-q7}
236
237   vld1.64 {rhash}, [r1]
238   vld1.64 {rh1}, [r0]
239
240   vrev64.8 rhash, rhash /* byte-swap */
241
242   vmov.i64 k0, #0x0
243   vmov.i64 k16, #0xffff
244   vmov.i64 k32, #0xffffffff
245   vmov.i64 k48, #0xffffffffffff
246
247   vext.8 rhash, rhash, rhash, #8
248
249   /* Handle remaining blocks. */
250
251   vld1.64 {rbuf}, [r2]!
252   subs r3, r3, #1
253
254   vrev64.8 rbuf, rbuf /* byte-swap */
255   vext.8 rbuf, rbuf, rbuf, #8
256
257   veor rhash, rhash, rbuf
258
259   beq .Lend
260
261 .Loop:
262   vld1.64 {rbuf}, [r2]!
263   PMUL_128x128(rr0, rr1, rhash, rh1, rt0, rt1, _(vrev64.8 rbuf, rbuf))
264   REDUCTION(rhash, rr0, rr1, rt0, _(vext.8 rbuf, rbuf, rbuf, #8))
265   subs r3, r3, #1
266   veor rhash, rhash, rbuf
267
268   bne .Loop
269
270 .Lend:
271   PMUL_128x128(rr0, rr1, rhash, rh1, rt0, rt1, _(CLEAR_REG(rbuf)))
272   REDUCTION(rhash, rr0, rr1, rt0, _(CLEAR_REG(rh1)))
273
274 .Ldone:
275   CLEAR_REG(rr1)
276   vrev64.8 rhash, rhash /* byte-swap */
277   CLEAR_REG(rt0)
278   CLEAR_REG(rr0)
279   vext.8 rhash, rhash, rhash, #8
280   CLEAR_REG(rt1)
281   CLEAR_REG(t0q)
282   CLEAR_REG(t1q)
283   CLEAR_REG(t2q)
284   CLEAR_REG(t3q)
285   vst1.64 {rhash}, [r1]
286   CLEAR_REG(rhash)
287
288   vpop {q4-q7}
289
290 .Ldo_nothing:
291   mov r0, #0
292   pop {r4-r6, pc}
293 .size _gcry_ghash_armv7_neon,.-_gcry_ghash_armv7_neon;
294
295
296 /*
297  * void _gcry_ghash_armv7_neon (void *gcm_key);
298  */
299 .align 3
300 .globl _gcry_ghash_setup_armv7_neon
301 .type  _gcry_ghash_setup_armv7_neon,%function;
302 _gcry_ghash_setup_armv7_neon:
303   /* input:
304    *    r0: gcm_key
305    */
306
307   vpush {q4-q7}
308
309   GET_DATA_POINTER(r2, .Lrconst64, r3)
310
311   vld1.64 {rrconst_h}, [r2]
312
313 #define GCM_LSH_1(r_out, ia, ib, const_d, oa, ob, ma) \
314         /* H <<< 1 */ \
315         vshr.s64 ma, ib, #63; \
316         vshr.u64 oa, ib, #63; \
317         vshr.u64 ob, ia, #63; \
318         vand ma, const_d; \
319         vshl.u64 ib, ib, #1; \
320         vshl.u64 ia, ia, #1; \
321         vorr ob, ib; \
322         vorr oa, ia; \
323         veor ob, ma; \
324         vst1.64 {oa, ob}, [r_out]
325
326   vld1.64 {rhash}, [r0]
327   vrev64.8 rhash, rhash /* byte-swap */
328   vext.8 rhash, rhash, rhash, #8
329
330   vmov rbuf1, rhash
331   GCM_LSH_1(r0, rhash_l, rhash_h, rrconst_h, rh1_l, rh1_h, rt1_l) /* H<<<1 */
332
333   CLEAR_REG(rh1)
334   CLEAR_REG(rhash)
335   CLEAR_REG(rbuf1)
336   CLEAR_REG(rrconst)
337   vpop {q4-q7}
338   bx lr
339 .size _gcry_ghash_setup_armv7_neon,.-_gcry_ghash_setup_armv7_neon;
340
341 #endif