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