Home | History | Annotate | Line # | Download | only in arm
      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 
     31 RCSID("$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  */
    159 ENTRY(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
    210 1:	ROUNDLD	q0,q1,q2,q3, q5,q6,q7,q4, q10,q11,q8,q9, q15,q12,q13,q14
    211 2:	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
    365 END(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  */
    375 ENTRY(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
    426 1:	ROUNDLD	q0,q1,q2,q3, q5,q6,q7,q4, q10,q11,q8,q9, q15,q12,q13,q14
    427 2:	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
    565 END(chacha_stream_xor256_neon)
    566 
    567 	.section .rodata
    568 	.p2align 4
    569 .Lconstants:
    570 
    571 	.type	v0123,%object
    572 v0123:
    573 	.long	0, 1, 2, 3
    574 END(v0123)
    575 
    576 	.type	rot8,%object
    577 rot8:
    578 	.byte	3,0,1,2, 7,4,5,6
    579 END(rot8)
    580