1/*	$NetBSD: chacha_neon_32.S,v 1.4 2020/08/23 16:39:06 riastradh Exp $	*/
2
3/*-
4 * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <machine/asm.h>
30
31RCSID("$NetBSD: chacha_neon_32.S,v 1.4 2020/08/23 16:39:06 riastradh Exp $")
32
33	.fpu	neon
34
35/*
36 * ChaCha round, split up so we can interleave the quarterrounds on
37 * independent rows/diagonals to maximize pipeline efficiency, with
38 * spills to deal with the scarcity of registers.  Reference:
39 *
40 *	Daniel J. Bernstein, `ChaCha, a variant of Salsa20', Workshop
41 *	Record of the State of the Art in Stream Ciphers -- SASC 2008.
42 *	https://cr.yp.to/papers.html#chacha
43 *
44 *	a += b; d ^= a; d <<<= 16;
45 *	c += d; b ^= c; b <<<= 12;
46 *	a += b; d ^= a; d <<<= 8;
47 *	c += d; b ^= c; b <<<= 7;
48 *
49 * The rotations are implemented with:
50 *	<<< 16		VREV32.16 for 16,
51 *	<<< 12		VSHL/VSRI/VORR (shift left, shift right and insert, OR)
52 *	<<< 8		TBL (general permutation; rot8 below stored in r)
53 *	<<< 7		VSHL/VSRI/VORR
54 */
55
56.macro	ROUNDLD	a0,a1,a2,a3, b0,b1,b2,b3, c0,c1,c2,c3, d0,d1,d2,d3
57	vld1.8		{\c2-\c3}, [sp, :256]
58.endm
59
60.macro	ROUND	a0,a1,a2,a3, b0,b1,b2,b3, c0,c1,c2,c3, d0,d1,d2,d3, c0l, d0l,d0h,d1l,d1h,d2l,d2h,d3l,d3h
61	/* a += b; d ^= a; d <<<= 16 */
62	vadd.u32	\a0, \a0, \b0
63	vadd.u32	\a1, \a1, \b1
64	vadd.u32	\a2, \a2, \b2
65	vadd.u32	\a3, \a3, \b3
66
67	veor		\d0, \d0, \a0
68	veor		\d1, \d1, \a1
69	veor		\d2, \d2, \a2
70	veor		\d3, \d3, \a3
71
72	vrev32.16	\d0, \d0
73	vrev32.16	\d1, \d1
74	vrev32.16	\d2, \d2
75	vrev32.16	\d3, \d3
76
77	/* c += d; b ^= c; b <<<= 12 */
78	vadd.u32	\c0, \c0, \d0
79	vadd.u32	\c1, \c1, \d1
80	vadd.u32	\c2, \c2, \d2
81	vadd.u32	\c3, \c3, \d3
82
83	vst1.8		{\c0-\c1}, [sp, :256]	/* free c0 and c1 as temps */
84
85	veor		\c0, \b0, \c0
86	veor		\c1, \b1, \c1
87	vshl.u32	\b0, \c0, #12
88	vshl.u32	\b1, \c1, #12
89	vsri.u32	\b0, \c0, #(32 - 12)
90	vsri.u32	\b1, \c1, #(32 - 12)
91
92	veor		\c0, \b2, \c2
93	veor		\c1, \b3, \c3
94	vshl.u32	\b2, \c0, #12
95	vshl.u32	\b3, \c1, #12
96	vsri.u32	\b2, \c0, #(32 - 12)
97	vsri.u32	\b3, \c1, #(32 - 12)
98
99	vld1.8		{\c0l}, [r7, :64]	/* load rot8 table */
100
101	/* a += b; d ^= a; d <<<= 8 */
102	vadd.u32	\a0, \a0, \b0
103	vadd.u32	\a1, \a1, \b1
104	vadd.u32	\a2, \a2, \b2
105	vadd.u32	\a3, \a3, \b3
106
107	veor		\d0, \d0, \a0
108	veor		\d1, \d1, \a1
109	veor		\d2, \d2, \a2
110	veor		\d3, \d3, \a3
111
112	vtbl.8		\d0l, {\d0l}, \c0l	/* <<< 8 */
113	vtbl.8		\d0h, {\d0h}, \c0l
114	vtbl.8		\d1l, {\d1l}, \c0l
115	vtbl.8		\d1h, {\d1h}, \c0l
116	vtbl.8		\d2l, {\d2l}, \c0l
117	vtbl.8		\d2h, {\d2h}, \c0l
118	vtbl.8		\d3l, {\d3l}, \c0l
119	vtbl.8		\d3h, {\d3h}, \c0l
120
121	vld1.8		{\c0-\c1}, [sp, :256]	/* restore c0 and c1 */
122
123	/* c += d; b ^= c; b <<<= 7 */
124	vadd.u32	\c2, \c2, \d2
125	vadd.u32	\c3, \c3, \d3
126	vadd.u32	\c0, \c0, \d0
127	vadd.u32	\c1, \c1, \d1
128
129	vst1.8		{\c2-\c3}, [sp, :256]	/* free c2 and c3 as temps */
130
131	veor		\c2, \b2, \c2
132	veor		\c3, \b3, \c3
133	vshl.u32	\b2, \c2, #7
134	vshl.u32	\b3, \c3, #7
135	vsri.u32	\b2, \c2, #(32 - 7)
136	vsri.u32	\b3, \c3, #(32 - 7)
137
138	veor		\c2, \b0, \c0
139	veor		\c3, \b1, \c1
140	vshl.u32	\b0, \c2, #7
141	vshl.u32	\b1, \c3, #7
142	vsri.u32	\b0, \c2, #(32 - 7)
143	vsri.u32	\b1, \c3, #(32 - 7)
144.endm
145
146	.text
147	.p2align 2
148.Lconstants_addr:
149	.long	.Lconstants - .
150
151/*
152 * chacha_stream256_neon(uint8_t s[256]@r0,
153 *     uint32_t blkno@r1,
154 *     const uint8_t nonce[12]@r2,
155 *     const uint8_t key[32]@r3,
156 *     const uint8_t const[16]@sp[0],
157 *     unsigned nr@sp[4])
158 */
159ENTRY(chacha_stream256_neon)
160	/* save callee-saves registers */
161	push	{r4, r5, r6, r7, r8, r10, fp, lr}
162	vpush	{d8-d15}
163	mov	fp, sp
164
165	/* r7 := .Lconstants - .Lconstants_addr, r6 := .Lconstants_addr */
166	ldr	r7, .Lconstants_addr
167	adr	r6, .Lconstants_addr
168
169	/* reserve space for two 128-bit/16-byte q registers */
170	sub	sp, sp, #0x20
171	bic	sp, sp, #0x1f	/* align */
172
173	/* get parameters */
174	add	ip, fp, #96
175	add	r7, r7, r6	/* r7 := .Lconstants (= v0123) */
176	ldm	ip, {r4, r5}	/* r4 := const, r5 := nr */
177	ldm	r2, {r6, r8, r10}	/* (r6, r8, r10) := nonce[0:12) */
178
179	vld1.8	{q12}, [r4]	/* q12 := constant */
180	vld1.8	{q13-q14}, [r3]	/* q13-q14 := key */
181	vld1.32	{q15}, [r7, :128]! /* q15 := (0, 1, 2, 3) (128-bit aligned) */
182
183#ifdef __ARM_BIG_ENDIAN
184	rev	r6, r6
185	rev	r8, r8
186	rev	r10, r10
187#endif
188
189	vdup.32	q0, d24[0]	/* q0-q3 := constant */
190	vdup.32	q1, d24[1]
191	vdup.32	q2, d25[0]
192	vdup.32	q3, d25[1]
193	vdup.32	q12, r1		/* q12 := (blkno, blkno, blkno, blkno) */
194	vdup.32	q4, d26[0]	/* q4-q11 := (key, key, key, key) */
195	vdup.32	q5, d26[1]
196	vdup.32	q6, d27[0]
197	vdup.32	q7, d27[1]
198	vdup.32	q8, d28[0]
199	vdup.32	q9, d28[1]
200	vdup.32	q10, d29[0]
201	vdup.32	q11, d29[1]
202	vadd.u32 q12, q12, q15	/* q12 := (blkno,blkno+1,blkno+2,blkno+3) */
203	vdup.32	q13, r6		/* q13-q15 := nonce */
204	vdup.32	q14, r8
205	vdup.32	q15, r10
206
207	b	2f
208
209	_ALIGN_TEXT
2101:	ROUNDLD	q0,q1,q2,q3, q5,q6,q7,q4, q10,q11,q8,q9, q15,q12,q13,q14
2112:	subs	r5, r5, #2
212	ROUND	q0,q1,q2,q3, q4,q5,q6,q7, q8,q9,q10,q11, q12,q13,q14,q15, \
213			d16, d24,d25, d26,d27, d28,d29, d30,d31
214	ROUNDLD	q0,q1,q2,q3, q4,q5,q6,q7, q8,q9,q10,q11, q12,q13,q14,q15
215	ROUND	q0,q1,q2,q3, q5,q6,q7,q4, q10,q11,q8,q9, q15,q12,q13,q14, \
216			d20, d30,d31, d24,d25, d26,d27, d28,d29
217	bne	1b
218
219	/*
220	 * q8-q9 are free / saved on the stack.  We have:
221	 *
222	 *	q0 = (x0[0], x1[0]; x2[0], x3[0])
223	 *	q1 = (x0[1], x1[1]; x2[1], x3[1])
224	 *	q2 = (x0[2], x1[2]; x2[2], x3[2])
225	 *	q3 = (x0[3], x1[3]; x2[3], x3[3])
226	 *	...
227	 *	q15 = (x0[15], x1[15]; x2[15], x3[15])
228	 *
229	 * where xi[j] is the jth word of the ith 16-word block.  Zip
230	 * consecutive pairs with vzip.32, and you get:
231	 *
232	 *	q0 = (x0[0], x0[1]; x1[0], x1[1])
233	 *	q1 = (x2[0], x2[1]; x3[0], x3[1])
234	 *	q2 = (x0[2], x0[3]; x1[2], x1[3])
235	 *	q3 = (x2[2], x2[3]; x3[2], x3[3])
236	 *	...
237	 *	q15 = (x2[14], x2[15]; x3[14], x3[15])
238	 *
239	 * As 64-bit d registers, this is:
240	 *
241	 *	d0 = (x0[0], x0[1])	d1 = (x1[0], x1[1])
242	 *	d2 = (x2[0], x2[1])	d3 = (x3[0], x3[1])
243	 *	d4 = (x0[2], x0[3])	d5 = (x1[2], x1[3])
244	 *	d6 = (x2[2], x2[3])	d7 = (x3[2], x3[3])
245	 *	...
246	 *	d30 = (x2[14], x2[15])	d31 = (x3[14], x3[15])
247	 *
248	 * Swap d1<->d4, d3<->d6, ..., and you get:
249	 *
250	 *	q0 = (x0[0], x0[1]; x0[2], x0[3])
251	 *	q1 = (x2[0], x2[1]; x2[2], x2[3])
252	 *	q2 = (x1[0], x1[1]; x1[2], x1[3])
253	 *	q3 = (x3[0], x3[1]; x3[2], x3[3])
254	 *	...
255	 *	q15 = (x15[0], x15[1]; x15[2], x15[3])
256	 */
257
258	sub	r7, r7, #0x10
259	vdup.32	q8, r1		/* q8 := (blkno, blkno, blkno, blkno) */
260	vld1.32	{q9}, [r7, :128] /* q9 := (0, 1, 2, 3) */
261
262	vzip.32	q0, q1
263	vzip.32	q2, q3
264	vzip.32	q4, q5
265	vzip.32	q6, q7
266
267	vadd.u32 q8, q8, q9	/* q8 := (blkno,blkno+1,blkno+2,blkno+3) */
268	vld1.8	{q9}, [r4]	/* q9 := constant */
269	vadd.u32 q12, q12, q8	/* q12 += (blkno,blkno+1,blkno+2,blkno+3) */
270	vld1.8	{q8}, [r3]!	/* q8 := key[0:16) */
271
272	vswp	d1, d4
273	vswp	d9, d12
274	vswp	d3, d6
275	vswp	d11, d14
276
277	/*
278	 * At this point, the blocks are:
279	 *
280	 *	q0 = (x0[0], x0[1]; x0[2], x0[3])
281	 *	q1 = (x2[0], x2[1]; x2[2], x2[3])
282	 *	q2 = (x1[0], x1[1]; x1[2], x1[3])
283	 *	q3 = (x3[0], x3[1]; x3[2], x3[3])
284	 *	q4 = (x0[4], x0[5]; x0[6], x0[7])
285	 *	q5 = (x2[4], x2[5]; x2[6], x2[7])
286	 *	q6 = (x1[4], x1[5]; x1[6], x1[7])
287	 *	q7 = (x3[4], x3[5]; x3[6], x3[7])
288	 *
289	 * The first two rows to write out are q0 = x0[0:4) and q4 =
290	 * x0[4:8).  Swapping q1<->q4, q3<->q6, q9<->q12, and q11<->q14
291	 * enables us to issue all stores in consecutive pairs:
292	 *	x0 in q0-q1
293	 *	x1 in q8-q9
294	 *	x2 in q2-q3
295	 *	x3 in q10-q11
296	 *	x4 in q4-q5
297	 *	x5 in q12-q3
298	 *	x6 in q6-q7
299	 *	x7 in q14-q15
300	 */
301
302	vswp	q1, q4
303	vswp	q3, q6
304
305	vadd.u32 q0, q0, q9
306	vadd.u32 q4, q4, q9
307	vadd.u32 q2, q2, q9
308	vadd.u32 q6, q6, q9
309
310	vadd.u32 q1, q1, q8
311	vadd.u32 q5, q5, q8
312	vadd.u32 q3, q3, q8
313	vadd.u32 q7, q7, q8
314
315	vld1.8	{q8-q9}, [sp, :256]	/* restore q8-q9 */
316
317	vst1.8	{q0-q1}, [r0]!
318	vld1.8	{q0}, [r3]	/* q0 := key[16:32) */
319	mov	r3, #0		/* q1 = (0, nonce[0:4), ..., nonce[8:12)) */
320	vmov	d2, r3, r6
321	vmov	d3, r8, r10
322
323	vzip.32	q8, q9
324	vzip.32	q10, q11
325	vzip.32	q12, q13
326	vzip.32	q14, q15
327
328	vswp	d17, d20
329	vswp	d25, d28
330	vswp	d19, d22
331	vswp	d27, d30
332
333	vswp	q9, q12
334	vswp	q11, q14
335
336	vadd.u32 q8, q8, q0
337	vadd.u32 q12, q12, q0
338	vadd.u32 q10, q10, q0
339	vadd.u32 q14, q14, q0
340
341	vadd.u32 q9, q9, q1
342	vadd.u32 q13, q13, q1
343	vadd.u32 q11, q11, q1
344	vadd.u32 q15, q15, q1
345
346	/* vst1.8	{q0-q1}, [r0]! */
347	vst1.8	{q8-q9}, [r0]!
348	vst1.8	{q2-q3}, [r0]!
349	vst1.8	{q10-q11}, [r0]!
350	vst1.8	{q4-q5}, [r0]!
351	vst1.8	{q12-q13}, [r0]!
352	vst1.8	{q6-q7}, [r0]!
353	vst1.8	{q14-q15}, [r0]
354
355	/* zero temporary space on the stack */
356	vmov.i32 q0, #0
357	vmov.i32 q1, #0
358	vst1.8	{q0-q1}, [sp, :256]
359
360	/* restore callee-saves registers and stack */
361	mov	sp, fp
362	vpop	{d8-d15}
363	pop	{r4, r5, r6, r7, r8, r10, fp, lr}
364	bx	lr
365END(chacha_stream256_neon)
366
367/*
368 * chacha_stream_xor256_neon(uint8_t s[256]@r0, const uint8_t p[256]@r1,
369 *     uint32_t blkno@r2,
370 *     const uint8_t nonce[12]@r3,
371 *     const uint8_t key[32]@sp[0],
372 *     const uint8_t const[16]@sp[4],
373 *     unsigned nr@sp[8])
374 */
375ENTRY(chacha_stream_xor256_neon)
376	/* save callee-saves registers */
377	push	{r4, r5, r6, r7, r8, r10, fp, lr}
378	vpush	{d8-d15}
379	mov	fp, sp
380
381	/* r7 := .Lconstants - .Lconstants_addr, r6 := .Lconstants_addr */
382	ldr	r7, .Lconstants_addr
383	adr	r6, .Lconstants_addr
384
385	/* reserve space for two 128-bit/16-byte q registers */
386	sub	sp, sp, #0x20
387	bic	sp, sp, #0x1f	/* align */
388
389	/* get parameters */
390	add	ip, fp, #96
391	add	r7, r7, r6	/* r7 := .Lconstants (= v0123) */
392	ldm	ip, {r4, r5, ip}	/* r4 := key, r5 := const, ip := nr */
393	ldm	r3, {r6, r8, r10}	/* (r6, r8, r10) := nonce[0:12) */
394
395	vld1.8	{q12}, [r5]	/* q12 := constant */
396	vld1.8	{q13-q14}, [r4]	/* q13-q14 := key */
397	vld1.32	{q15}, [r7, :128]! /* q15 := (0, 1, 2, 3) (128-bit aligned) */
398
399#ifdef __ARM_BIG_ENDIAN
400	rev	r6, r6
401	rev	r8, r8
402	rev	r10, r10
403#endif
404
405	vdup.32	q0, d24[0]	/* q0-q3 := constant */
406	vdup.32	q1, d24[1]
407	vdup.32	q2, d25[0]
408	vdup.32	q3, d25[1]
409	vdup.32	q12, r2		/* q12 := (blkno, blkno, blkno, blkno) */
410	vdup.32	q4, d26[0]	/* q4-q11 := (key, key, key, key) */
411	vdup.32	q5, d26[1]
412	vdup.32	q6, d27[0]
413	vdup.32	q7, d27[1]
414	vdup.32	q8, d28[0]
415	vdup.32	q9, d28[1]
416	vdup.32	q10, d29[0]
417	vdup.32	q11, d29[1]
418	vadd.u32 q12, q12, q15	/* q12 := (blkno,blkno+1,blkno+2,blkno+3) */
419	vdup.32	q13, r6		/* q13-q15 := nonce */
420	vdup.32	q14, r8
421	vdup.32	q15, r10
422
423	b	2f
424
425	_ALIGN_TEXT
4261:	ROUNDLD	q0,q1,q2,q3, q5,q6,q7,q4, q10,q11,q8,q9, q15,q12,q13,q14
4272:	subs	ip, ip, #2
428	ROUND	q0,q1,q2,q3, q4,q5,q6,q7, q8,q9,q10,q11, q12,q13,q14,q15, \
429			d16, d24,d25, d26,d27, d28,d29, d30,d31
430	ROUNDLD	q0,q1,q2,q3, q4,q5,q6,q7, q8,q9,q10,q11, q12,q13,q14,q15
431	ROUND	q0,q1,q2,q3, q5,q6,q7,q4, q10,q11,q8,q9, q15,q12,q13,q14, \
432			d20, d30,d31, d24,d25, d26,d27, d28,d29
433	bne	1b
434
435	/*
436	 * q8-q9 are free / saved on the stack.  Now for the real fun:
437	 * in only 16 registers, compute p[i] ^ (y[i] + x[i]) for i in
438	 * {0,1,2,...,15}.  The twist is that the p[i] and the y[i] are
439	 * transposed from one another, and the x[i] are in general
440	 * registers and memory.  See comments in chacha_stream256_neon
441	 * for the layout with swaps.
442	 */
443
444	sub	r7, r7, #0x10
445	vdup.32	q8, r2		/* q8 := (blkno, blkno, blkno, blkno) */
446	vld1.32	{q9}, [r7, :128] /* q9 := (0, 1, 2, 3) */
447
448	vzip.32	q0, q1
449	vzip.32	q2, q3
450	vzip.32	q4, q5
451	vzip.32	q6, q7
452
453	vadd.u32 q8, q8, q9	/* q8 := (blkno,blkno+1,blkno+2,blkno+3) */
454	vld1.8	{q9}, [r5]	/* q9 := constant */
455	vadd.u32 q12, q12, q8	/* q12 += (blkno,blkno+1,blkno+2,blkno+3) */
456	vld1.8	{q8}, [r4]!	/* q8 := key[0:16) */
457
458	vswp	d3, d6
459	vswp	d9, d12
460	vswp	d1, d4
461	vswp	d11, d14
462
463	vswp	q1, q4
464	vswp	q3, q6
465
466	vadd.u32 q0, q0, q9
467	vadd.u32 q4, q4, q9
468	vadd.u32 q2, q2, q9
469	vadd.u32 q6, q6, q9
470
471	vadd.u32 q1, q1, q8
472	vadd.u32 q5, q5, q8
473	vadd.u32 q3, q3, q8
474	vadd.u32 q7, q7, q8
475
476	vld1.8	{q8-q9}, [r1]!	/* load plaintext bytes [0:32) */
477
478	veor	q0, q0, q8	/* compute ciphertext bytes [0:32) */
479	veor	q1, q1, q9
480
481	vld1.8	{q8-q9}, [sp, :256]	/* restore q8-q9 */
482
483	vst1.8	{q0-q1}, [r0]!	/* store ciphertext bytes [0:32) */
484	vld1.8	{q0}, [r4]	/* q0 := key[16:32) */
485	mov	r3, #0		/* q1 = (0, nonce[0:4), ..., nonce[8:12)) */
486	vmov	d2, r3, r6
487	vmov	d3, r8, r10
488
489	vzip.32	q8, q9
490	vzip.32	q10, q11
491	vzip.32	q12, q13
492	vzip.32	q14, q15
493
494	vswp	d19, d22
495	vswp	d25, d28
496	vswp	d17, d20
497	vswp	d27, d30
498
499	vswp	q9, q12		/* free up q9 earlier for consecutive q8-q9 */
500	vswp	q11, q14
501
502	vadd.u32 q8, q8, q0
503	vadd.u32 q12, q12, q0
504	vadd.u32 q10, q10, q0
505	vadd.u32 q14, q14, q0
506
507	vadd.u32 q9, q9, q1
508	vadd.u32 q13, q13, q1
509	vadd.u32 q11, q11, q1
510	vadd.u32 q15, q15, q1
511
512	vld1.8	{q0-q1}, [r1]!	/* load plaintext bytes [32:64) */
513
514	veor	q0, q0, q8	/* compute ciphertext bytes [32:64) */
515	veor	q1, q1, q9
516
517	vld1.8	{q8-q9}, [r1]!	/* load plaintext bytes [64:96) */
518	vst1.8	{q0-q1}, [r0]!	/* store ciphertext bytes [32:64) */
519	vld1.8	{q0-q1}, [r1]!	/* load plaintext bytes [96:128) */
520
521	veor	q2, q2, q8	/* compute ciphertext bytes [64:96) */
522	veor	q3, q3, q9
523
524	vld1.8	{q8-q9}, [r1]!	/* load plaintext bytes [128:160) */
525	vst1.8	{q2-q3}, [r0]!	/* store ciphertext bytes [64:80) */
526
527	veor	q10, q10, q0	/* compute ciphertext bytes [96:128) */
528	veor	q11, q11, q1
529
530	vld1.8	{q0-q1}, [r1]!	/* load plaintext bytes [160:192) */
531	vst1.8	{q10-q11}, [r0]!	/* store ciphertext bytes [80:96) */
532
533	veor	q4, q4, q8	/* compute ciphertext bytes [128:160) */
534	veor	q5, q5, q9
535
536	vld1.8	{q8-q9}, [r1]!	/* load plaintext bytes [192:224) */
537	vst1.8	{q4-q5}, [r0]!	/* store ciphertext bytes [96:112) */
538
539	veor	q12, q12, q0	/* compute ciphertext bytes [160:192) */
540	veor	q13, q13, q1
541
542	vld1.8	{q0-q1}, [r1]	/* load plaintext bytes [224:256) */
543	vst1.8	{q12-q13}, [r0]!	/* store ciphertext bytes [112:128) */
544
545	veor	q6, q6, q8	/* compute ciphertext bytes [192:224) */
546	veor	q7, q7, q9
547
548	vst1.8	{q6-q7}, [r0]!	/* store ciphertext bytes [192:224) */
549
550	veor	q14, q14, q0	/* compute ciphertext bytes [224:256) */
551	veor	q15, q15, q1
552
553	vst1.8	{q14-q15}, [r0]	/* store ciphertext bytes [224:256) */
554
555	/* zero temporary space on the stack */
556	vmov.i32 q0, #0
557	vmov.i32 q1, #0
558	vst1.8	{q0-q1}, [sp, :256]
559
560	/* restore callee-saves registers and stack */
561	mov	sp, fp
562	vpop	{d8-d15}
563	pop	{r4, r5, r6, r7, r8, r10, fp, lr}
564	bx	lr
565END(chacha_stream_xor256_neon)
566
567	.section .rodata
568	.p2align 4
569.Lconstants:
570
571	.type	v0123,%object
572v0123:
573	.long	0, 1, 2, 3
574END(v0123)
575
576	.type	rot8,%object
577rot8:
578	.byte	3,0,1,2, 7,4,5,6
579END(rot8)
580