xref: /linux/arch/arm/crypto/chacha-neon-core.S (revision a4eb44a6435d6d8f9e642407a4a06f65eb90ca04)
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 */
20
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  */
48
49#include <linux/linkage.h>
50#include <asm/cache.h>
51
52	.text
53	.fpu		neon
54	.align		5
55
56/*
57 * chacha_permute - permute one block
58 *
59 * Permute one 64-byte block where the state matrix is stored in the four NEON
60 * registers q0-q3.  It performs matrix operations on four words in parallel,
61 * but requires shuffling to rearrange the words after each round.
62 *
63 * The round count is given in r3.
64 *
65 * Clobbers: r3, ip, q4-q5
66 */
67chacha_permute:
68
69	adr		ip, .Lrol8_table
70	vld1.8		{d10}, [ip, :64]
71
72.Ldoubleround:
73	// x0 += x1, x3 = rotl32(x3 ^ x0, 16)
74	vadd.i32	q0, q0, q1
75	veor		q3, q3, q0
76	vrev32.16	q3, q3
77
78	// x2 += x3, x1 = rotl32(x1 ^ x2, 12)
79	vadd.i32	q2, q2, q3
80	veor		q4, q1, q2
81	vshl.u32	q1, q4, #12
82	vsri.u32	q1, q4, #20
83
84	// x0 += x1, x3 = rotl32(x3 ^ x0, 8)
85	vadd.i32	q0, q0, q1
86	veor		q3, q3, q0
87	vtbl.8		d6, {d6}, d10
88	vtbl.8		d7, {d7}, d10
89
90	// x2 += x3, x1 = rotl32(x1 ^ x2, 7)
91	vadd.i32	q2, q2, q3
92	veor		q4, q1, q2
93	vshl.u32	q1, q4, #7
94	vsri.u32	q1, q4, #25
95
96	// x1 = shuffle32(x1, MASK(0, 3, 2, 1))
97	vext.8		q1, q1, q1, #4
98	// x2 = shuffle32(x2, MASK(1, 0, 3, 2))
99	vext.8		q2, q2, q2, #8
100	// x3 = shuffle32(x3, MASK(2, 1, 0, 3))
101	vext.8		q3, q3, q3, #12
102
103	// x0 += x1, x3 = rotl32(x3 ^ x0, 16)
104	vadd.i32	q0, q0, q1
105	veor		q3, q3, q0
106	vrev32.16	q3, q3
107
108	// x2 += x3, x1 = rotl32(x1 ^ x2, 12)
109	vadd.i32	q2, q2, q3
110	veor		q4, q1, q2
111	vshl.u32	q1, q4, #12
112	vsri.u32	q1, q4, #20
113
114	// x0 += x1, x3 = rotl32(x3 ^ x0, 8)
115	vadd.i32	q0, q0, q1
116	veor		q3, q3, q0
117	vtbl.8		d6, {d6}, d10
118	vtbl.8		d7, {d7}, d10
119
120	// x2 += x3, x1 = rotl32(x1 ^ x2, 7)
121	vadd.i32	q2, q2, q3
122	veor		q4, q1, q2
123	vshl.u32	q1, q4, #7
124	vsri.u32	q1, q4, #25
125
126	// x1 = shuffle32(x1, MASK(2, 1, 0, 3))
127	vext.8		q1, q1, q1, #12
128	// x2 = shuffle32(x2, MASK(1, 0, 3, 2))
129	vext.8		q2, q2, q2, #8
130	// x3 = shuffle32(x3, MASK(0, 3, 2, 1))
131	vext.8		q3, q3, q3, #4
132
133	subs		r3, r3, #2
134	bne		.Ldoubleround
135
136	bx		lr
137ENDPROC(chacha_permute)
138
139ENTRY(chacha_block_xor_neon)
140	// r0: Input state matrix, s
141	// r1: 1 data block output, o
142	// r2: 1 data block input, i
143	// r3: nrounds
144	push		{lr}
145
146	// x0..3 = s0..3
147	add		ip, r0, #0x20
148	vld1.32		{q0-q1}, [r0]
149	vld1.32		{q2-q3}, [ip]
150
151	vmov		q8, q0
152	vmov		q9, q1
153	vmov		q10, q2
154	vmov		q11, q3
155
156	bl		chacha_permute
157
158	add		ip, r2, #0x20
159	vld1.8		{q4-q5}, [r2]
160	vld1.8		{q6-q7}, [ip]
161
162	// o0 = i0 ^ (x0 + s0)
163	vadd.i32	q0, q0, q8
164	veor		q0, q0, q4
165
166	// o1 = i1 ^ (x1 + s1)
167	vadd.i32	q1, q1, q9
168	veor		q1, q1, q5
169
170	// o2 = i2 ^ (x2 + s2)
171	vadd.i32	q2, q2, q10
172	veor		q2, q2, q6
173
174	// o3 = i3 ^ (x3 + s3)
175	vadd.i32	q3, q3, q11
176	veor		q3, q3, q7
177
178	add		ip, r1, #0x20
179	vst1.8		{q0-q1}, [r1]
180	vst1.8		{q2-q3}, [ip]
181
182	pop		{pc}
183ENDPROC(chacha_block_xor_neon)
184
185ENTRY(hchacha_block_neon)
186	// r0: Input state matrix, s
187	// r1: output (8 32-bit words)
188	// r2: nrounds
189	push		{lr}
190
191	vld1.32		{q0-q1}, [r0]!
192	vld1.32		{q2-q3}, [r0]
193
194	mov		r3, r2
195	bl		chacha_permute
196
197	vst1.32		{q0}, [r1]!
198	vst1.32		{q3}, [r1]
199
200	pop		{pc}
201ENDPROC(hchacha_block_neon)
202
203	.align		4
204.Lctrinc:	.word	0, 1, 2, 3
205.Lrol8_table:	.byte	3, 0, 1, 2, 7, 4, 5, 6
206
207	.align		5
208ENTRY(chacha_4block_xor_neon)
209	push		{r4, lr}
210	mov		r4, sp			// preserve the stack pointer
211	sub		ip, sp, #0x20		// allocate a 32 byte buffer
212	bic		ip, ip, #0x1f		// aligned to 32 bytes
213	mov		sp, ip
214
215	// r0: Input state matrix, s
216	// r1: 4 data blocks output, o
217	// r2: 4 data blocks input, i
218	// r3: nrounds
219
220	//
221	// This function encrypts four consecutive ChaCha blocks by loading
222	// the state matrix in NEON registers four times. The algorithm performs
223	// each operation on the corresponding word of each state matrix, hence
224	// requires no word shuffling. The words are re-interleaved before the
225	// final addition of the original state and the XORing step.
226	//
227
228	// x0..15[0-3] = s0..15[0-3]
229	add		ip, r0, #0x20
230	vld1.32		{q0-q1}, [r0]
231	vld1.32		{q2-q3}, [ip]
232
233	adr		lr, .Lctrinc
234	vdup.32		q15, d7[1]
235	vdup.32		q14, d7[0]
236	vld1.32		{q4}, [lr, :128]
237	vdup.32		q13, d6[1]
238	vdup.32		q12, d6[0]
239	vdup.32		q11, d5[1]
240	vdup.32		q10, d5[0]
241	vadd.u32	q12, q12, q4		// x12 += counter values 0-3
242	vdup.32		q9, d4[1]
243	vdup.32		q8, d4[0]
244	vdup.32		q7, d3[1]
245	vdup.32		q6, d3[0]
246	vdup.32		q5, d2[1]
247	vdup.32		q4, d2[0]
248	vdup.32		q3, d1[1]
249	vdup.32		q2, d1[0]
250	vdup.32		q1, d0[1]
251	vdup.32		q0, d0[0]
252
253	adr		ip, .Lrol8_table
254	b		1f
255
256.Ldoubleround4:
257	vld1.32		{q8-q9}, [sp, :256]
2581:
259	// x0 += x4, x12 = rotl32(x12 ^ x0, 16)
260	// x1 += x5, x13 = rotl32(x13 ^ x1, 16)
261	// x2 += x6, x14 = rotl32(x14 ^ x2, 16)
262	// x3 += x7, x15 = rotl32(x15 ^ x3, 16)
263	vadd.i32	q0, q0, q4
264	vadd.i32	q1, q1, q5
265	vadd.i32	q2, q2, q6
266	vadd.i32	q3, q3, q7
267
268	veor		q12, q12, q0
269	veor		q13, q13, q1
270	veor		q14, q14, q2
271	veor		q15, q15, q3
272
273	vrev32.16	q12, q12
274	vrev32.16	q13, q13
275	vrev32.16	q14, q14
276	vrev32.16	q15, q15
277
278	// x8 += x12, x4 = rotl32(x4 ^ x8, 12)
279	// x9 += x13, x5 = rotl32(x5 ^ x9, 12)
280	// x10 += x14, x6 = rotl32(x6 ^ x10, 12)
281	// x11 += x15, x7 = rotl32(x7 ^ x11, 12)
282	vadd.i32	q8, q8, q12
283	vadd.i32	q9, q9, q13
284	vadd.i32	q10, q10, q14
285	vadd.i32	q11, q11, q15
286
287	vst1.32		{q8-q9}, [sp, :256]
288
289	veor		q8, q4, q8
290	veor		q9, q5, q9
291	vshl.u32	q4, q8, #12
292	vshl.u32	q5, q9, #12
293	vsri.u32	q4, q8, #20
294	vsri.u32	q5, q9, #20
295
296	veor		q8, q6, q10
297	veor		q9, q7, q11
298	vshl.u32	q6, q8, #12
299	vshl.u32	q7, q9, #12
300	vsri.u32	q6, q8, #20
301	vsri.u32	q7, q9, #20
302
303	// x0 += x4, x12 = rotl32(x12 ^ x0, 8)
304	// x1 += x5, x13 = rotl32(x13 ^ x1, 8)
305	// x2 += x6, x14 = rotl32(x14 ^ x2, 8)
306	// x3 += x7, x15 = rotl32(x15 ^ x3, 8)
307	vld1.8		{d16}, [ip, :64]
308	vadd.i32	q0, q0, q4
309	vadd.i32	q1, q1, q5
310	vadd.i32	q2, q2, q6
311	vadd.i32	q3, q3, q7
312
313	veor		q12, q12, q0
314	veor		q13, q13, q1
315	veor		q14, q14, q2
316	veor		q15, q15, q3
317
318	vtbl.8		d24, {d24}, d16
319	vtbl.8		d25, {d25}, d16
320	vtbl.8		d26, {d26}, d16
321	vtbl.8		d27, {d27}, d16
322	vtbl.8		d28, {d28}, d16
323	vtbl.8		d29, {d29}, d16
324	vtbl.8		d30, {d30}, d16
325	vtbl.8		d31, {d31}, d16
326
327	vld1.32		{q8-q9}, [sp, :256]
328
329	// x8 += x12, x4 = rotl32(x4 ^ x8, 7)
330	// x9 += x13, x5 = rotl32(x5 ^ x9, 7)
331	// x10 += x14, x6 = rotl32(x6 ^ x10, 7)
332	// x11 += x15, x7 = rotl32(x7 ^ x11, 7)
333	vadd.i32	q8, q8, q12
334	vadd.i32	q9, q9, q13
335	vadd.i32	q10, q10, q14
336	vadd.i32	q11, q11, q15
337
338	vst1.32		{q8-q9}, [sp, :256]
339
340	veor		q8, q4, q8
341	veor		q9, q5, q9
342	vshl.u32	q4, q8, #7
343	vshl.u32	q5, q9, #7
344	vsri.u32	q4, q8, #25
345	vsri.u32	q5, q9, #25
346
347	veor		q8, q6, q10
348	veor		q9, q7, q11
349	vshl.u32	q6, q8, #7
350	vshl.u32	q7, q9, #7
351	vsri.u32	q6, q8, #25
352	vsri.u32	q7, q9, #25
353
354	vld1.32		{q8-q9}, [sp, :256]
355
356	// x0 += x5, x15 = rotl32(x15 ^ x0, 16)
357	// x1 += x6, x12 = rotl32(x12 ^ x1, 16)
358	// x2 += x7, x13 = rotl32(x13 ^ x2, 16)
359	// x3 += x4, x14 = rotl32(x14 ^ x3, 16)
360	vadd.i32	q0, q0, q5
361	vadd.i32	q1, q1, q6
362	vadd.i32	q2, q2, q7
363	vadd.i32	q3, q3, q4
364
365	veor		q15, q15, q0
366	veor		q12, q12, q1
367	veor		q13, q13, q2
368	veor		q14, q14, q3
369
370	vrev32.16	q15, q15
371	vrev32.16	q12, q12
372	vrev32.16	q13, q13
373	vrev32.16	q14, q14
374
375	// x10 += x15, x5 = rotl32(x5 ^ x10, 12)
376	// x11 += x12, x6 = rotl32(x6 ^ x11, 12)
377	// x8 += x13, x7 = rotl32(x7 ^ x8, 12)
378	// x9 += x14, x4 = rotl32(x4 ^ x9, 12)
379	vadd.i32	q10, q10, q15
380	vadd.i32	q11, q11, q12
381	vadd.i32	q8, q8, q13
382	vadd.i32	q9, q9, q14
383
384	vst1.32		{q8-q9}, [sp, :256]
385
386	veor		q8, q7, q8
387	veor		q9, q4, q9
388	vshl.u32	q7, q8, #12
389	vshl.u32	q4, q9, #12
390	vsri.u32	q7, q8, #20
391	vsri.u32	q4, q9, #20
392
393	veor		q8, q5, q10
394	veor		q9, q6, q11
395	vshl.u32	q5, q8, #12
396	vshl.u32	q6, q9, #12
397	vsri.u32	q5, q8, #20
398	vsri.u32	q6, q9, #20
399
400	// x0 += x5, x15 = rotl32(x15 ^ x0, 8)
401	// x1 += x6, x12 = rotl32(x12 ^ x1, 8)
402	// x2 += x7, x13 = rotl32(x13 ^ x2, 8)
403	// x3 += x4, x14 = rotl32(x14 ^ x3, 8)
404	vld1.8		{d16}, [ip, :64]
405	vadd.i32	q0, q0, q5
406	vadd.i32	q1, q1, q6
407	vadd.i32	q2, q2, q7
408	vadd.i32	q3, q3, q4
409
410	veor		q15, q15, q0
411	veor		q12, q12, q1
412	veor		q13, q13, q2
413	veor		q14, q14, q3
414
415	vtbl.8		d30, {d30}, d16
416	vtbl.8		d31, {d31}, d16
417	vtbl.8		d24, {d24}, d16
418	vtbl.8		d25, {d25}, d16
419	vtbl.8		d26, {d26}, d16
420	vtbl.8		d27, {d27}, d16
421	vtbl.8		d28, {d28}, d16
422	vtbl.8		d29, {d29}, d16
423
424	vld1.32		{q8-q9}, [sp, :256]
425
426	// x10 += x15, x5 = rotl32(x5 ^ x10, 7)
427	// x11 += x12, x6 = rotl32(x6 ^ x11, 7)
428	// x8 += x13, x7 = rotl32(x7 ^ x8, 7)
429	// x9 += x14, x4 = rotl32(x4 ^ x9, 7)
430	vadd.i32	q10, q10, q15
431	vadd.i32	q11, q11, q12
432	vadd.i32	q8, q8, q13
433	vadd.i32	q9, q9, q14
434
435	vst1.32		{q8-q9}, [sp, :256]
436
437	veor		q8, q7, q8
438	veor		q9, q4, q9
439	vshl.u32	q7, q8, #7
440	vshl.u32	q4, q9, #7
441	vsri.u32	q7, q8, #25
442	vsri.u32	q4, q9, #25
443
444	veor		q8, q5, q10
445	veor		q9, q6, q11
446	vshl.u32	q5, q8, #7
447	vshl.u32	q6, q9, #7
448	vsri.u32	q5, q8, #25
449	vsri.u32	q6, q9, #25
450
451	subs		r3, r3, #2
452	bne		.Ldoubleround4
453
454	// x0..7[0-3] are in q0-q7, x10..15[0-3] are in q10-q15.
455	// x8..9[0-3] are on the stack.
456
457	// Re-interleave the words in the first two rows of each block (x0..7).
458	// Also add the counter values 0-3 to x12[0-3].
459	  vld1.32	{q8}, [lr, :128]	// load counter values 0-3
460	vzip.32		q0, q1			// => (0 1 0 1) (0 1 0 1)
461	vzip.32		q2, q3			// => (2 3 2 3) (2 3 2 3)
462	vzip.32		q4, q5			// => (4 5 4 5) (4 5 4 5)
463	vzip.32		q6, q7			// => (6 7 6 7) (6 7 6 7)
464	  vadd.u32	q12, q8			// x12 += counter values 0-3
465	vswp		d1, d4
466	vswp		d3, d6
467	  vld1.32	{q8-q9}, [r0]!		// load s0..7
468	vswp		d9, d12
469	vswp		d11, d14
470
471	// Swap q1 and q4 so that we'll free up consecutive registers (q0-q1)
472	// after XORing the first 32 bytes.
473	vswp		q1, q4
474
475	// First two rows of each block are (q0 q1) (q2 q6) (q4 q5) (q3 q7)
476
477	// x0..3[0-3] += s0..3[0-3]	(add orig state to 1st row of each block)
478	vadd.u32	q0, q0, q8
479	vadd.u32	q2, q2, q8
480	vadd.u32	q4, q4, q8
481	vadd.u32	q3, q3, q8
482
483	// x4..7[0-3] += s4..7[0-3]	(add orig state to 2nd row of each block)
484	vadd.u32	q1, q1, q9
485	vadd.u32	q6, q6, q9
486	vadd.u32	q5, q5, q9
487	vadd.u32	q7, q7, q9
488
489	// XOR first 32 bytes using keystream from first two rows of first block
490	vld1.8		{q8-q9}, [r2]!
491	veor		q8, q8, q0
492	veor		q9, q9, q1
493	vst1.8		{q8-q9}, [r1]!
494
495	// Re-interleave the words in the last two rows of each block (x8..15).
496	vld1.32		{q8-q9}, [sp, :256]
497	  mov		sp, r4		// restore original stack pointer
498	  ldr		r4, [r4, #8]	// load number of bytes
499	vzip.32		q12, q13	// => (12 13 12 13) (12 13 12 13)
500	vzip.32		q14, q15	// => (14 15 14 15) (14 15 14 15)
501	vzip.32		q8, q9		// => (8 9 8 9) (8 9 8 9)
502	vzip.32		q10, q11	// => (10 11 10 11) (10 11 10 11)
503	  vld1.32	{q0-q1}, [r0]	// load s8..15
504	vswp		d25, d28
505	vswp		d27, d30
506	vswp		d17, d20
507	vswp		d19, d22
508
509	// Last two rows of each block are (q8 q12) (q10 q14) (q9 q13) (q11 q15)
510
511	// x8..11[0-3] += s8..11[0-3]	(add orig state to 3rd row of each block)
512	vadd.u32	q8,  q8,  q0
513	vadd.u32	q10, q10, q0
514	vadd.u32	q9,  q9,  q0
515	vadd.u32	q11, q11, q0
516
517	// x12..15[0-3] += s12..15[0-3] (add orig state to 4th row of each block)
518	vadd.u32	q12, q12, q1
519	vadd.u32	q14, q14, q1
520	vadd.u32	q13, q13, q1
521	vadd.u32	q15, q15, q1
522
523	// XOR the rest of the data with the keystream
524
525	vld1.8		{q0-q1}, [r2]!
526	subs		r4, r4, #96
527	veor		q0, q0, q8
528	veor		q1, q1, q12
529	ble		.Lle96
530	vst1.8		{q0-q1}, [r1]!
531
532	vld1.8		{q0-q1}, [r2]!
533	subs		r4, r4, #32
534	veor		q0, q0, q2
535	veor		q1, q1, q6
536	ble		.Lle128
537	vst1.8		{q0-q1}, [r1]!
538
539	vld1.8		{q0-q1}, [r2]!
540	subs		r4, r4, #32
541	veor		q0, q0, q10
542	veor		q1, q1, q14
543	ble		.Lle160
544	vst1.8		{q0-q1}, [r1]!
545
546	vld1.8		{q0-q1}, [r2]!
547	subs		r4, r4, #32
548	veor		q0, q0, q4
549	veor		q1, q1, q5
550	ble		.Lle192
551	vst1.8		{q0-q1}, [r1]!
552
553	vld1.8		{q0-q1}, [r2]!
554	subs		r4, r4, #32
555	veor		q0, q0, q9
556	veor		q1, q1, q13
557	ble		.Lle224
558	vst1.8		{q0-q1}, [r1]!
559
560	vld1.8		{q0-q1}, [r2]!
561	subs		r4, r4, #32
562	veor		q0, q0, q3
563	veor		q1, q1, q7
564	blt		.Llt256
565.Lout:
566	vst1.8		{q0-q1}, [r1]!
567
568	vld1.8		{q0-q1}, [r2]
569	veor		q0, q0, q11
570	veor		q1, q1, q15
571	vst1.8		{q0-q1}, [r1]
572
573	pop		{r4, pc}
574
575.Lle192:
576	vmov		q4, q9
577	vmov		q5, q13
578
579.Lle160:
580	// nothing to do
581
582.Lfinalblock:
583	// Process the final block if processing less than 4 full blocks.
584	// Entered with 32 bytes of ChaCha cipher stream in q4-q5, and the
585	// previous 32 byte output block that still needs to be written at
586	// [r1] in q0-q1.
587	beq		.Lfullblock
588
589.Lpartialblock:
590	adr		lr, .Lpermute + 32
591	add		r2, r2, r4
592	add		lr, lr, r4
593	add		r4, r4, r1
594
595	vld1.8		{q2-q3}, [lr]
596	vld1.8		{q6-q7}, [r2]
597
598	add		r4, r4, #32
599
600	vtbl.8		d4, {q4-q5}, d4
601	vtbl.8		d5, {q4-q5}, d5
602	vtbl.8		d6, {q4-q5}, d6
603	vtbl.8		d7, {q4-q5}, d7
604
605	veor		q6, q6, q2
606	veor		q7, q7, q3
607
608	vst1.8		{q6-q7}, [r4]	// overlapping stores
609	vst1.8		{q0-q1}, [r1]
610	pop		{r4, pc}
611
612.Lfullblock:
613	vmov		q11, q4
614	vmov		q15, q5
615	b		.Lout
616.Lle96:
617	vmov		q4, q2
618	vmov		q5, q6
619	b		.Lfinalblock
620.Lle128:
621	vmov		q4, q10
622	vmov		q5, q14
623	b		.Lfinalblock
624.Lle224:
625	vmov		q4, q3
626	vmov		q5, q7
627	b		.Lfinalblock
628.Llt256:
629	vmov		q4, q11
630	vmov		q5, q15
631	b		.Lpartialblock
632ENDPROC(chacha_4block_xor_neon)
633
634	.align		L1_CACHE_SHIFT
635.Lpermute:
636	.byte		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
637	.byte		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
638	.byte		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
639	.byte		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
640	.byte		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
641	.byte		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
642	.byte		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
643	.byte		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
644