Linux 5.7.7
[linux/fpc-iii.git] / arch / arm / crypto / chacha-neon-core.S
blobeb22926d49127e894a060afc003871d743dfe36d
1 /*
2  * ChaCha/XChaCha NEON helper functions
3  *
4  * Copyright (C) 2016 Linaro, Ltd. <ard.biesheuvel@linaro.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Based on:
11  * ChaCha20 256-bit cipher algorithm, RFC7539, x64 SSE3 functions
12  *
13  * Copyright (C) 2015 Martin Willi
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  */
21  /*
22   * NEON doesn't have a rotate instruction.  The alternatives are, more or less:
23   *
24   * (a)  vshl.u32 + vsri.u32            (needs temporary register)
25   * (b)  vshl.u32 + vshr.u32 + vorr     (needs temporary register)
26   * (c)  vrev32.16                      (16-bit rotations only)
27   * (d)  vtbl.8 + vtbl.8                (multiple of 8 bits rotations only,
28   *                                      needs index vector)
29   *
30   * ChaCha has 16, 12, 8, and 7-bit rotations.  For the 12 and 7-bit rotations,
31   * the only choices are (a) and (b).  We use (a) since it takes two-thirds the
32   * cycles of (b) on both Cortex-A7 and Cortex-A53.
33   *
34   * For the 16-bit rotation, we use vrev32.16 since it's consistently fastest
35   * and doesn't need a temporary register.
36   *
37   * For the 8-bit rotation, we use vtbl.8 + vtbl.8.  On Cortex-A7, this sequence
38   * is twice as fast as (a), even when doing (a) on multiple registers
39   * simultaneously to eliminate the stall between vshl and vsri.  Also, it
40   * parallelizes better when temporary registers are scarce.
41   *
42   * A disadvantage is that on Cortex-A53, the vtbl sequence is the same speed as
43   * (a), so the need to load the rotation table actually makes the vtbl method
44   * slightly slower overall on that CPU (~1.3% slower ChaCha20).  Still, it
45   * seems to be a good compromise to get a more significant speed boost on some
46   * CPUs, e.g. ~4.8% faster ChaCha20 on Cortex-A7.
47   */
49 #include <linux/linkage.h>
51         .text
52         .fpu            neon
53         .align          5
56  * chacha_permute - permute one block
57  *
58  * Permute one 64-byte block where the state matrix is stored in the four NEON
59  * registers q0-q3.  It performs matrix operations on four words in parallel,
60  * but requires shuffling to rearrange the words after each round.
61  *
62  * The round count is given in r3.
63  *
64  * Clobbers: r3, ip, q4-q5
65  */
66 chacha_permute:
68         adr             ip, .Lrol8_table
69         vld1.8          {d10}, [ip, :64]
71 .Ldoubleround:
72         // x0 += x1, x3 = rotl32(x3 ^ x0, 16)
73         vadd.i32        q0, q0, q1
74         veor            q3, q3, q0
75         vrev32.16       q3, q3
77         // x2 += x3, x1 = rotl32(x1 ^ x2, 12)
78         vadd.i32        q2, q2, q3
79         veor            q4, q1, q2
80         vshl.u32        q1, q4, #12
81         vsri.u32        q1, q4, #20
83         // x0 += x1, x3 = rotl32(x3 ^ x0, 8)
84         vadd.i32        q0, q0, q1
85         veor            q3, q3, q0
86         vtbl.8          d6, {d6}, d10
87         vtbl.8          d7, {d7}, d10
89         // x2 += x3, x1 = rotl32(x1 ^ x2, 7)
90         vadd.i32        q2, q2, q3
91         veor            q4, q1, q2
92         vshl.u32        q1, q4, #7
93         vsri.u32        q1, q4, #25
95         // x1 = shuffle32(x1, MASK(0, 3, 2, 1))
96         vext.8          q1, q1, q1, #4
97         // x2 = shuffle32(x2, MASK(1, 0, 3, 2))
98         vext.8          q2, q2, q2, #8
99         // x3 = shuffle32(x3, MASK(2, 1, 0, 3))
100         vext.8          q3, q3, q3, #12
102         // x0 += x1, x3 = rotl32(x3 ^ x0, 16)
103         vadd.i32        q0, q0, q1
104         veor            q3, q3, q0
105         vrev32.16       q3, q3
107         // x2 += x3, x1 = rotl32(x1 ^ x2, 12)
108         vadd.i32        q2, q2, q3
109         veor            q4, q1, q2
110         vshl.u32        q1, q4, #12
111         vsri.u32        q1, q4, #20
113         // x0 += x1, x3 = rotl32(x3 ^ x0, 8)
114         vadd.i32        q0, q0, q1
115         veor            q3, q3, q0
116         vtbl.8          d6, {d6}, d10
117         vtbl.8          d7, {d7}, d10
119         // x2 += x3, x1 = rotl32(x1 ^ x2, 7)
120         vadd.i32        q2, q2, q3
121         veor            q4, q1, q2
122         vshl.u32        q1, q4, #7
123         vsri.u32        q1, q4, #25
125         // x1 = shuffle32(x1, MASK(2, 1, 0, 3))
126         vext.8          q1, q1, q1, #12
127         // x2 = shuffle32(x2, MASK(1, 0, 3, 2))
128         vext.8          q2, q2, q2, #8
129         // x3 = shuffle32(x3, MASK(0, 3, 2, 1))
130         vext.8          q3, q3, q3, #4
132         subs            r3, r3, #2
133         bne             .Ldoubleround
135         bx              lr
136 ENDPROC(chacha_permute)
138 ENTRY(chacha_block_xor_neon)
139         // r0: Input state matrix, s
140         // r1: 1 data block output, o
141         // r2: 1 data block input, i
142         // r3: nrounds
143         push            {lr}
145         // x0..3 = s0..3
146         add             ip, r0, #0x20
147         vld1.32         {q0-q1}, [r0]
148         vld1.32         {q2-q3}, [ip]
150         vmov            q8, q0
151         vmov            q9, q1
152         vmov            q10, q2
153         vmov            q11, q3
155         bl              chacha_permute
157         add             ip, r2, #0x20
158         vld1.8          {q4-q5}, [r2]
159         vld1.8          {q6-q7}, [ip]
161         // o0 = i0 ^ (x0 + s0)
162         vadd.i32        q0, q0, q8
163         veor            q0, q0, q4
165         // o1 = i1 ^ (x1 + s1)
166         vadd.i32        q1, q1, q9
167         veor            q1, q1, q5
169         // o2 = i2 ^ (x2 + s2)
170         vadd.i32        q2, q2, q10
171         veor            q2, q2, q6
173         // o3 = i3 ^ (x3 + s3)
174         vadd.i32        q3, q3, q11
175         veor            q3, q3, q7
177         add             ip, r1, #0x20
178         vst1.8          {q0-q1}, [r1]
179         vst1.8          {q2-q3}, [ip]
181         pop             {pc}
182 ENDPROC(chacha_block_xor_neon)
184 ENTRY(hchacha_block_neon)
185         // r0: Input state matrix, s
186         // r1: output (8 32-bit words)
187         // r2: nrounds
188         push            {lr}
190         vld1.32         {q0-q1}, [r0]!
191         vld1.32         {q2-q3}, [r0]
193         mov             r3, r2
194         bl              chacha_permute
196         vst1.32         {q0}, [r1]!
197         vst1.32         {q3}, [r1]
199         pop             {pc}
200 ENDPROC(hchacha_block_neon)
202         .align          4
203 .Lctrinc:       .word   0, 1, 2, 3
204 .Lrol8_table:   .byte   3, 0, 1, 2, 7, 4, 5, 6
206         .align          5
207 ENTRY(chacha_4block_xor_neon)
208         push            {r4-r5}
209         mov             r4, sp                  // preserve the stack pointer
210         sub             ip, sp, #0x20           // allocate a 32 byte buffer
211         bic             ip, ip, #0x1f           // aligned to 32 bytes
212         mov             sp, ip
214         // r0: Input state matrix, s
215         // r1: 4 data blocks output, o
216         // r2: 4 data blocks input, i
217         // r3: nrounds
219         //
220         // This function encrypts four consecutive ChaCha blocks by loading
221         // the state matrix in NEON registers four times. The algorithm performs
222         // each operation on the corresponding word of each state matrix, hence
223         // requires no word shuffling. The words are re-interleaved before the
224         // final addition of the original state and the XORing step.
225         //
227         // x0..15[0-3] = s0..15[0-3]
228         add             ip, r0, #0x20
229         vld1.32         {q0-q1}, [r0]
230         vld1.32         {q2-q3}, [ip]
232         adr             r5, .Lctrinc
233         vdup.32         q15, d7[1]
234         vdup.32         q14, d7[0]
235         vld1.32         {q4}, [r5, :128]
236         vdup.32         q13, d6[1]
237         vdup.32         q12, d6[0]
238         vdup.32         q11, d5[1]
239         vdup.32         q10, d5[0]
240         vadd.u32        q12, q12, q4            // x12 += counter values 0-3
241         vdup.32         q9, d4[1]
242         vdup.32         q8, d4[0]
243         vdup.32         q7, d3[1]
244         vdup.32         q6, d3[0]
245         vdup.32         q5, d2[1]
246         vdup.32         q4, d2[0]
247         vdup.32         q3, d1[1]
248         vdup.32         q2, d1[0]
249         vdup.32         q1, d0[1]
250         vdup.32         q0, d0[0]
252         adr             ip, .Lrol8_table
253         b               1f
255 .Ldoubleround4:
256         vld1.32         {q8-q9}, [sp, :256]
258         // x0 += x4, x12 = rotl32(x12 ^ x0, 16)
259         // x1 += x5, x13 = rotl32(x13 ^ x1, 16)
260         // x2 += x6, x14 = rotl32(x14 ^ x2, 16)
261         // x3 += x7, x15 = rotl32(x15 ^ x3, 16)
262         vadd.i32        q0, q0, q4
263         vadd.i32        q1, q1, q5
264         vadd.i32        q2, q2, q6
265         vadd.i32        q3, q3, q7
267         veor            q12, q12, q0
268         veor            q13, q13, q1
269         veor            q14, q14, q2
270         veor            q15, q15, q3
272         vrev32.16       q12, q12
273         vrev32.16       q13, q13
274         vrev32.16       q14, q14
275         vrev32.16       q15, q15
277         // x8 += x12, x4 = rotl32(x4 ^ x8, 12)
278         // x9 += x13, x5 = rotl32(x5 ^ x9, 12)
279         // x10 += x14, x6 = rotl32(x6 ^ x10, 12)
280         // x11 += x15, x7 = rotl32(x7 ^ x11, 12)
281         vadd.i32        q8, q8, q12
282         vadd.i32        q9, q9, q13
283         vadd.i32        q10, q10, q14
284         vadd.i32        q11, q11, q15
286         vst1.32         {q8-q9}, [sp, :256]
288         veor            q8, q4, q8
289         veor            q9, q5, q9
290         vshl.u32        q4, q8, #12
291         vshl.u32        q5, q9, #12
292         vsri.u32        q4, q8, #20
293         vsri.u32        q5, q9, #20
295         veor            q8, q6, q10
296         veor            q9, q7, q11
297         vshl.u32        q6, q8, #12
298         vshl.u32        q7, q9, #12
299         vsri.u32        q6, q8, #20
300         vsri.u32        q7, q9, #20
302         // x0 += x4, x12 = rotl32(x12 ^ x0, 8)
303         // x1 += x5, x13 = rotl32(x13 ^ x1, 8)
304         // x2 += x6, x14 = rotl32(x14 ^ x2, 8)
305         // x3 += x7, x15 = rotl32(x15 ^ x3, 8)
306         vld1.8          {d16}, [ip, :64]
307         vadd.i32        q0, q0, q4
308         vadd.i32        q1, q1, q5
309         vadd.i32        q2, q2, q6
310         vadd.i32        q3, q3, q7
312         veor            q12, q12, q0
313         veor            q13, q13, q1
314         veor            q14, q14, q2
315         veor            q15, q15, q3
317         vtbl.8          d24, {d24}, d16
318         vtbl.8          d25, {d25}, d16
319         vtbl.8          d26, {d26}, d16
320         vtbl.8          d27, {d27}, d16
321         vtbl.8          d28, {d28}, d16
322         vtbl.8          d29, {d29}, d16
323         vtbl.8          d30, {d30}, d16
324         vtbl.8          d31, {d31}, d16
326         vld1.32         {q8-q9}, [sp, :256]
328         // x8 += x12, x4 = rotl32(x4 ^ x8, 7)
329         // x9 += x13, x5 = rotl32(x5 ^ x9, 7)
330         // x10 += x14, x6 = rotl32(x6 ^ x10, 7)
331         // x11 += x15, x7 = rotl32(x7 ^ x11, 7)
332         vadd.i32        q8, q8, q12
333         vadd.i32        q9, q9, q13
334         vadd.i32        q10, q10, q14
335         vadd.i32        q11, q11, q15
337         vst1.32         {q8-q9}, [sp, :256]
339         veor            q8, q4, q8
340         veor            q9, q5, q9
341         vshl.u32        q4, q8, #7
342         vshl.u32        q5, q9, #7
343         vsri.u32        q4, q8, #25
344         vsri.u32        q5, q9, #25
346         veor            q8, q6, q10
347         veor            q9, q7, q11
348         vshl.u32        q6, q8, #7
349         vshl.u32        q7, q9, #7
350         vsri.u32        q6, q8, #25
351         vsri.u32        q7, q9, #25
353         vld1.32         {q8-q9}, [sp, :256]
355         // x0 += x5, x15 = rotl32(x15 ^ x0, 16)
356         // x1 += x6, x12 = rotl32(x12 ^ x1, 16)
357         // x2 += x7, x13 = rotl32(x13 ^ x2, 16)
358         // x3 += x4, x14 = rotl32(x14 ^ x3, 16)
359         vadd.i32        q0, q0, q5
360         vadd.i32        q1, q1, q6
361         vadd.i32        q2, q2, q7
362         vadd.i32        q3, q3, q4
364         veor            q15, q15, q0
365         veor            q12, q12, q1
366         veor            q13, q13, q2
367         veor            q14, q14, q3
369         vrev32.16       q15, q15
370         vrev32.16       q12, q12
371         vrev32.16       q13, q13
372         vrev32.16       q14, q14
374         // x10 += x15, x5 = rotl32(x5 ^ x10, 12)
375         // x11 += x12, x6 = rotl32(x6 ^ x11, 12)
376         // x8 += x13, x7 = rotl32(x7 ^ x8, 12)
377         // x9 += x14, x4 = rotl32(x4 ^ x9, 12)
378         vadd.i32        q10, q10, q15
379         vadd.i32        q11, q11, q12
380         vadd.i32        q8, q8, q13
381         vadd.i32        q9, q9, q14
383         vst1.32         {q8-q9}, [sp, :256]
385         veor            q8, q7, q8
386         veor            q9, q4, q9
387         vshl.u32        q7, q8, #12
388         vshl.u32        q4, q9, #12
389         vsri.u32        q7, q8, #20
390         vsri.u32        q4, q9, #20
392         veor            q8, q5, q10
393         veor            q9, q6, q11
394         vshl.u32        q5, q8, #12
395         vshl.u32        q6, q9, #12
396         vsri.u32        q5, q8, #20
397         vsri.u32        q6, q9, #20
399         // x0 += x5, x15 = rotl32(x15 ^ x0, 8)
400         // x1 += x6, x12 = rotl32(x12 ^ x1, 8)
401         // x2 += x7, x13 = rotl32(x13 ^ x2, 8)
402         // x3 += x4, x14 = rotl32(x14 ^ x3, 8)
403         vld1.8          {d16}, [ip, :64]
404         vadd.i32        q0, q0, q5
405         vadd.i32        q1, q1, q6
406         vadd.i32        q2, q2, q7
407         vadd.i32        q3, q3, q4
409         veor            q15, q15, q0
410         veor            q12, q12, q1
411         veor            q13, q13, q2
412         veor            q14, q14, q3
414         vtbl.8          d30, {d30}, d16
415         vtbl.8          d31, {d31}, d16
416         vtbl.8          d24, {d24}, d16
417         vtbl.8          d25, {d25}, d16
418         vtbl.8          d26, {d26}, d16
419         vtbl.8          d27, {d27}, d16
420         vtbl.8          d28, {d28}, d16
421         vtbl.8          d29, {d29}, d16
423         vld1.32         {q8-q9}, [sp, :256]
425         // x10 += x15, x5 = rotl32(x5 ^ x10, 7)
426         // x11 += x12, x6 = rotl32(x6 ^ x11, 7)
427         // x8 += x13, x7 = rotl32(x7 ^ x8, 7)
428         // x9 += x14, x4 = rotl32(x4 ^ x9, 7)
429         vadd.i32        q10, q10, q15
430         vadd.i32        q11, q11, q12
431         vadd.i32        q8, q8, q13
432         vadd.i32        q9, q9, q14
434         vst1.32         {q8-q9}, [sp, :256]
436         veor            q8, q7, q8
437         veor            q9, q4, q9
438         vshl.u32        q7, q8, #7
439         vshl.u32        q4, q9, #7
440         vsri.u32        q7, q8, #25
441         vsri.u32        q4, q9, #25
443         veor            q8, q5, q10
444         veor            q9, q6, q11
445         vshl.u32        q5, q8, #7
446         vshl.u32        q6, q9, #7
447         vsri.u32        q5, q8, #25
448         vsri.u32        q6, q9, #25
450         subs            r3, r3, #2
451         bne             .Ldoubleround4
453         // x0..7[0-3] are in q0-q7, x10..15[0-3] are in q10-q15.
454         // x8..9[0-3] are on the stack.
456         // Re-interleave the words in the first two rows of each block (x0..7).
457         // Also add the counter values 0-3 to x12[0-3].
458           vld1.32       {q8}, [r5, :128]        // load counter values 0-3
459         vzip.32         q0, q1                  // => (0 1 0 1) (0 1 0 1)
460         vzip.32         q2, q3                  // => (2 3 2 3) (2 3 2 3)
461         vzip.32         q4, q5                  // => (4 5 4 5) (4 5 4 5)
462         vzip.32         q6, q7                  // => (6 7 6 7) (6 7 6 7)
463           vadd.u32      q12, q8                 // x12 += counter values 0-3
464         vswp            d1, d4
465         vswp            d3, d6
466           vld1.32       {q8-q9}, [r0]!          // load s0..7
467         vswp            d9, d12
468         vswp            d11, d14
470         // Swap q1 and q4 so that we'll free up consecutive registers (q0-q1)
471         // after XORing the first 32 bytes.
472         vswp            q1, q4
474         // First two rows of each block are (q0 q1) (q2 q6) (q4 q5) (q3 q7)
476         // x0..3[0-3] += s0..3[0-3]     (add orig state to 1st row of each block)
477         vadd.u32        q0, q0, q8
478         vadd.u32        q2, q2, q8
479         vadd.u32        q4, q4, q8
480         vadd.u32        q3, q3, q8
482         // x4..7[0-3] += s4..7[0-3]     (add orig state to 2nd row of each block)
483         vadd.u32        q1, q1, q9
484         vadd.u32        q6, q6, q9
485         vadd.u32        q5, q5, q9
486         vadd.u32        q7, q7, q9
488         // XOR first 32 bytes using keystream from first two rows of first block
489         vld1.8          {q8-q9}, [r2]!
490         veor            q8, q8, q0
491         veor            q9, q9, q1
492         vst1.8          {q8-q9}, [r1]!
494         // Re-interleave the words in the last two rows of each block (x8..15).
495         vld1.32         {q8-q9}, [sp, :256]
496         vzip.32         q12, q13        // => (12 13 12 13) (12 13 12 13)
497         vzip.32         q14, q15        // => (14 15 14 15) (14 15 14 15)
498         vzip.32         q8, q9          // => (8 9 8 9) (8 9 8 9)
499         vzip.32         q10, q11        // => (10 11 10 11) (10 11 10 11)
500           vld1.32       {q0-q1}, [r0]   // load s8..15
501         vswp            d25, d28
502         vswp            d27, d30
503         vswp            d17, d20
504         vswp            d19, d22
506         // Last two rows of each block are (q8 q12) (q10 q14) (q9 q13) (q11 q15)
508         // x8..11[0-3] += s8..11[0-3]   (add orig state to 3rd row of each block)
509         vadd.u32        q8,  q8,  q0
510         vadd.u32        q10, q10, q0
511         vadd.u32        q9,  q9,  q0
512         vadd.u32        q11, q11, q0
514         // x12..15[0-3] += s12..15[0-3] (add orig state to 4th row of each block)
515         vadd.u32        q12, q12, q1
516         vadd.u32        q14, q14, q1
517         vadd.u32        q13, q13, q1
518         vadd.u32        q15, q15, q1
520         // XOR the rest of the data with the keystream
522         vld1.8          {q0-q1}, [r2]!
523         veor            q0, q0, q8
524         veor            q1, q1, q12
525         vst1.8          {q0-q1}, [r1]!
527         vld1.8          {q0-q1}, [r2]!
528         veor            q0, q0, q2
529         veor            q1, q1, q6
530         vst1.8          {q0-q1}, [r1]!
532         vld1.8          {q0-q1}, [r2]!
533         veor            q0, q0, q10
534         veor            q1, q1, q14
535         vst1.8          {q0-q1}, [r1]!
537         vld1.8          {q0-q1}, [r2]!
538         veor            q0, q0, q4
539         veor            q1, q1, q5
540         vst1.8          {q0-q1}, [r1]!
542         vld1.8          {q0-q1}, [r2]!
543         veor            q0, q0, q9
544         veor            q1, q1, q13
545         vst1.8          {q0-q1}, [r1]!
547         vld1.8          {q0-q1}, [r2]!
548         veor            q0, q0, q3
549         veor            q1, q1, q7
550         vst1.8          {q0-q1}, [r1]!
552         vld1.8          {q0-q1}, [r2]
553           mov           sp, r4          // restore original stack pointer
554         veor            q0, q0, q11
555         veor            q1, q1, q15
556         vst1.8          {q0-q1}, [r1]
558         pop             {r4-r5}
559         bx              lr
560 ENDPROC(chacha_4block_xor_neon)