Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: arm/chacha20 - implement NEON version based on SSE3 code

This is a straight port to ARM/NEON of the x86 SSE3 implementation
of the ChaCha20 stream cipher.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Ard Biesheuvel and committed by
Herbert Xu
80966672 8621caa0

+667
+6
arch/arm/crypto/Kconfig
··· 130 130 depends on KERNEL_MODE_NEON && CRC32 131 131 select CRYPTO_HASH 132 132 133 + config CRYPTO_CHACHA20_NEON 134 + tristate "NEON accelerated ChaCha20 symmetric cipher" 135 + depends on KERNEL_MODE_NEON 136 + select CRYPTO_BLKCIPHER 137 + select CRYPTO_CHACHA20 138 + 133 139 endif
+2
arch/arm/crypto/Makefile
··· 8 8 obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o 9 9 obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o 10 10 obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o 11 + obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha20-neon.o 11 12 12 13 ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o 13 14 ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o ··· 41 40 ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o 42 41 crct10dif-arm-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o 43 42 crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o 43 + chacha20-neon-y := chacha20-neon-core.o chacha20-neon-glue.o 44 44 45 45 quiet_cmd_perl = PERL $@ 46 46 cmd_perl = $(PERL) $(<) > $(@)
+523
arch/arm/crypto/chacha20-neon-core.S
··· 1 + /* 2 + * ChaCha20 256-bit cipher algorithm, RFC7539, ARM NEON 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 SNEON3 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 + #include <linux/linkage.h> 22 + 23 + .text 24 + .fpu neon 25 + .align 5 26 + 27 + ENTRY(chacha20_block_xor_neon) 28 + // r0: Input state matrix, s 29 + // r1: 1 data block output, o 30 + // r2: 1 data block input, i 31 + 32 + // 33 + // This function encrypts one ChaCha20 block by loading the state matrix 34 + // in four NEON registers. It performs matrix operation on four words in 35 + // parallel, but requireds shuffling to rearrange the words after each 36 + // round. 37 + // 38 + 39 + // x0..3 = s0..3 40 + add ip, r0, #0x20 41 + vld1.32 {q0-q1}, [r0] 42 + vld1.32 {q2-q3}, [ip] 43 + 44 + vmov q8, q0 45 + vmov q9, q1 46 + vmov q10, q2 47 + vmov q11, q3 48 + 49 + mov r3, #10 50 + 51 + .Ldoubleround: 52 + // x0 += x1, x3 = rotl32(x3 ^ x0, 16) 53 + vadd.i32 q0, q0, q1 54 + veor q4, q3, q0 55 + vshl.u32 q3, q4, #16 56 + vsri.u32 q3, q4, #16 57 + 58 + // x2 += x3, x1 = rotl32(x1 ^ x2, 12) 59 + vadd.i32 q2, q2, q3 60 + veor q4, q1, q2 61 + vshl.u32 q1, q4, #12 62 + vsri.u32 q1, q4, #20 63 + 64 + // x0 += x1, x3 = rotl32(x3 ^ x0, 8) 65 + vadd.i32 q0, q0, q1 66 + veor q4, q3, q0 67 + vshl.u32 q3, q4, #8 68 + vsri.u32 q3, q4, #24 69 + 70 + // x2 += x3, x1 = rotl32(x1 ^ x2, 7) 71 + vadd.i32 q2, q2, q3 72 + veor q4, q1, q2 73 + vshl.u32 q1, q4, #7 74 + vsri.u32 q1, q4, #25 75 + 76 + // x1 = shuffle32(x1, MASK(0, 3, 2, 1)) 77 + vext.8 q1, q1, q1, #4 78 + // x2 = shuffle32(x2, MASK(1, 0, 3, 2)) 79 + vext.8 q2, q2, q2, #8 80 + // x3 = shuffle32(x3, MASK(2, 1, 0, 3)) 81 + vext.8 q3, q3, q3, #12 82 + 83 + // x0 += x1, x3 = rotl32(x3 ^ x0, 16) 84 + vadd.i32 q0, q0, q1 85 + veor q4, q3, q0 86 + vshl.u32 q3, q4, #16 87 + vsri.u32 q3, q4, #16 88 + 89 + // x2 += x3, x1 = rotl32(x1 ^ x2, 12) 90 + vadd.i32 q2, q2, q3 91 + veor q4, q1, q2 92 + vshl.u32 q1, q4, #12 93 + vsri.u32 q1, q4, #20 94 + 95 + // x0 += x1, x3 = rotl32(x3 ^ x0, 8) 96 + vadd.i32 q0, q0, q1 97 + veor q4, q3, q0 98 + vshl.u32 q3, q4, #8 99 + vsri.u32 q3, q4, #24 100 + 101 + // x2 += x3, x1 = rotl32(x1 ^ x2, 7) 102 + vadd.i32 q2, q2, q3 103 + veor q4, q1, q2 104 + vshl.u32 q1, q4, #7 105 + vsri.u32 q1, q4, #25 106 + 107 + // x1 = shuffle32(x1, MASK(2, 1, 0, 3)) 108 + vext.8 q1, q1, q1, #12 109 + // x2 = shuffle32(x2, MASK(1, 0, 3, 2)) 110 + vext.8 q2, q2, q2, #8 111 + // x3 = shuffle32(x3, MASK(0, 3, 2, 1)) 112 + vext.8 q3, q3, q3, #4 113 + 114 + subs r3, r3, #1 115 + bne .Ldoubleround 116 + 117 + add ip, r2, #0x20 118 + vld1.8 {q4-q5}, [r2] 119 + vld1.8 {q6-q7}, [ip] 120 + 121 + // o0 = i0 ^ (x0 + s0) 122 + vadd.i32 q0, q0, q8 123 + veor q0, q0, q4 124 + 125 + // o1 = i1 ^ (x1 + s1) 126 + vadd.i32 q1, q1, q9 127 + veor q1, q1, q5 128 + 129 + // o2 = i2 ^ (x2 + s2) 130 + vadd.i32 q2, q2, q10 131 + veor q2, q2, q6 132 + 133 + // o3 = i3 ^ (x3 + s3) 134 + vadd.i32 q3, q3, q11 135 + veor q3, q3, q7 136 + 137 + add ip, r1, #0x20 138 + vst1.8 {q0-q1}, [r1] 139 + vst1.8 {q2-q3}, [ip] 140 + 141 + bx lr 142 + ENDPROC(chacha20_block_xor_neon) 143 + 144 + .align 5 145 + ENTRY(chacha20_4block_xor_neon) 146 + push {r4-r6, lr} 147 + mov ip, sp // preserve the stack pointer 148 + sub r3, sp, #0x20 // allocate a 32 byte buffer 149 + bic r3, r3, #0x1f // aligned to 32 bytes 150 + mov sp, r3 151 + 152 + // r0: Input state matrix, s 153 + // r1: 4 data blocks output, o 154 + // r2: 4 data blocks input, i 155 + 156 + // 157 + // This function encrypts four consecutive ChaCha20 blocks by loading 158 + // the state matrix in NEON registers four times. The algorithm performs 159 + // each operation on the corresponding word of each state matrix, hence 160 + // requires no word shuffling. For final XORing step we transpose the 161 + // matrix by interleaving 32- and then 64-bit words, which allows us to 162 + // do XOR in NEON registers. 163 + // 164 + 165 + // x0..15[0-3] = s0..3[0..3] 166 + add r3, r0, #0x20 167 + vld1.32 {q0-q1}, [r0] 168 + vld1.32 {q2-q3}, [r3] 169 + 170 + adr r3, CTRINC 171 + vdup.32 q15, d7[1] 172 + vdup.32 q14, d7[0] 173 + vld1.32 {q11}, [r3, :128] 174 + vdup.32 q13, d6[1] 175 + vdup.32 q12, d6[0] 176 + vadd.i32 q12, q12, q11 // x12 += counter values 0-3 177 + vdup.32 q11, d5[1] 178 + vdup.32 q10, d5[0] 179 + vdup.32 q9, d4[1] 180 + vdup.32 q8, d4[0] 181 + vdup.32 q7, d3[1] 182 + vdup.32 q6, d3[0] 183 + vdup.32 q5, d2[1] 184 + vdup.32 q4, d2[0] 185 + vdup.32 q3, d1[1] 186 + vdup.32 q2, d1[0] 187 + vdup.32 q1, d0[1] 188 + vdup.32 q0, d0[0] 189 + 190 + mov r3, #10 191 + 192 + .Ldoubleround4: 193 + // x0 += x4, x12 = rotl32(x12 ^ x0, 16) 194 + // x1 += x5, x13 = rotl32(x13 ^ x1, 16) 195 + // x2 += x6, x14 = rotl32(x14 ^ x2, 16) 196 + // x3 += x7, x15 = rotl32(x15 ^ x3, 16) 197 + vadd.i32 q0, q0, q4 198 + vadd.i32 q1, q1, q5 199 + vadd.i32 q2, q2, q6 200 + vadd.i32 q3, q3, q7 201 + 202 + veor q12, q12, q0 203 + veor q13, q13, q1 204 + veor q14, q14, q2 205 + veor q15, q15, q3 206 + 207 + vrev32.16 q12, q12 208 + vrev32.16 q13, q13 209 + vrev32.16 q14, q14 210 + vrev32.16 q15, q15 211 + 212 + // x8 += x12, x4 = rotl32(x4 ^ x8, 12) 213 + // x9 += x13, x5 = rotl32(x5 ^ x9, 12) 214 + // x10 += x14, x6 = rotl32(x6 ^ x10, 12) 215 + // x11 += x15, x7 = rotl32(x7 ^ x11, 12) 216 + vadd.i32 q8, q8, q12 217 + vadd.i32 q9, q9, q13 218 + vadd.i32 q10, q10, q14 219 + vadd.i32 q11, q11, q15 220 + 221 + vst1.32 {q8-q9}, [sp, :256] 222 + 223 + veor q8, q4, q8 224 + veor q9, q5, q9 225 + vshl.u32 q4, q8, #12 226 + vshl.u32 q5, q9, #12 227 + vsri.u32 q4, q8, #20 228 + vsri.u32 q5, q9, #20 229 + 230 + veor q8, q6, q10 231 + veor q9, q7, q11 232 + vshl.u32 q6, q8, #12 233 + vshl.u32 q7, q9, #12 234 + vsri.u32 q6, q8, #20 235 + vsri.u32 q7, q9, #20 236 + 237 + // x0 += x4, x12 = rotl32(x12 ^ x0, 8) 238 + // x1 += x5, x13 = rotl32(x13 ^ x1, 8) 239 + // x2 += x6, x14 = rotl32(x14 ^ x2, 8) 240 + // x3 += x7, x15 = rotl32(x15 ^ x3, 8) 241 + vadd.i32 q0, q0, q4 242 + vadd.i32 q1, q1, q5 243 + vadd.i32 q2, q2, q6 244 + vadd.i32 q3, q3, q7 245 + 246 + veor q8, q12, q0 247 + veor q9, q13, q1 248 + vshl.u32 q12, q8, #8 249 + vshl.u32 q13, q9, #8 250 + vsri.u32 q12, q8, #24 251 + vsri.u32 q13, q9, #24 252 + 253 + veor q8, q14, q2 254 + veor q9, q15, q3 255 + vshl.u32 q14, q8, #8 256 + vshl.u32 q15, q9, #8 257 + vsri.u32 q14, q8, #24 258 + vsri.u32 q15, q9, #24 259 + 260 + vld1.32 {q8-q9}, [sp, :256] 261 + 262 + // x8 += x12, x4 = rotl32(x4 ^ x8, 7) 263 + // x9 += x13, x5 = rotl32(x5 ^ x9, 7) 264 + // x10 += x14, x6 = rotl32(x6 ^ x10, 7) 265 + // x11 += x15, x7 = rotl32(x7 ^ x11, 7) 266 + vadd.i32 q8, q8, q12 267 + vadd.i32 q9, q9, q13 268 + vadd.i32 q10, q10, q14 269 + vadd.i32 q11, q11, q15 270 + 271 + vst1.32 {q8-q9}, [sp, :256] 272 + 273 + veor q8, q4, q8 274 + veor q9, q5, q9 275 + vshl.u32 q4, q8, #7 276 + vshl.u32 q5, q9, #7 277 + vsri.u32 q4, q8, #25 278 + vsri.u32 q5, q9, #25 279 + 280 + veor q8, q6, q10 281 + veor q9, q7, q11 282 + vshl.u32 q6, q8, #7 283 + vshl.u32 q7, q9, #7 284 + vsri.u32 q6, q8, #25 285 + vsri.u32 q7, q9, #25 286 + 287 + vld1.32 {q8-q9}, [sp, :256] 288 + 289 + // x0 += x5, x15 = rotl32(x15 ^ x0, 16) 290 + // x1 += x6, x12 = rotl32(x12 ^ x1, 16) 291 + // x2 += x7, x13 = rotl32(x13 ^ x2, 16) 292 + // x3 += x4, x14 = rotl32(x14 ^ x3, 16) 293 + vadd.i32 q0, q0, q5 294 + vadd.i32 q1, q1, q6 295 + vadd.i32 q2, q2, q7 296 + vadd.i32 q3, q3, q4 297 + 298 + veor q15, q15, q0 299 + veor q12, q12, q1 300 + veor q13, q13, q2 301 + veor q14, q14, q3 302 + 303 + vrev32.16 q15, q15 304 + vrev32.16 q12, q12 305 + vrev32.16 q13, q13 306 + vrev32.16 q14, q14 307 + 308 + // x10 += x15, x5 = rotl32(x5 ^ x10, 12) 309 + // x11 += x12, x6 = rotl32(x6 ^ x11, 12) 310 + // x8 += x13, x7 = rotl32(x7 ^ x8, 12) 311 + // x9 += x14, x4 = rotl32(x4 ^ x9, 12) 312 + vadd.i32 q10, q10, q15 313 + vadd.i32 q11, q11, q12 314 + vadd.i32 q8, q8, q13 315 + vadd.i32 q9, q9, q14 316 + 317 + vst1.32 {q8-q9}, [sp, :256] 318 + 319 + veor q8, q7, q8 320 + veor q9, q4, q9 321 + vshl.u32 q7, q8, #12 322 + vshl.u32 q4, q9, #12 323 + vsri.u32 q7, q8, #20 324 + vsri.u32 q4, q9, #20 325 + 326 + veor q8, q5, q10 327 + veor q9, q6, q11 328 + vshl.u32 q5, q8, #12 329 + vshl.u32 q6, q9, #12 330 + vsri.u32 q5, q8, #20 331 + vsri.u32 q6, q9, #20 332 + 333 + // x0 += x5, x15 = rotl32(x15 ^ x0, 8) 334 + // x1 += x6, x12 = rotl32(x12 ^ x1, 8) 335 + // x2 += x7, x13 = rotl32(x13 ^ x2, 8) 336 + // x3 += x4, x14 = rotl32(x14 ^ x3, 8) 337 + vadd.i32 q0, q0, q5 338 + vadd.i32 q1, q1, q6 339 + vadd.i32 q2, q2, q7 340 + vadd.i32 q3, q3, q4 341 + 342 + veor q8, q15, q0 343 + veor q9, q12, q1 344 + vshl.u32 q15, q8, #8 345 + vshl.u32 q12, q9, #8 346 + vsri.u32 q15, q8, #24 347 + vsri.u32 q12, q9, #24 348 + 349 + veor q8, q13, q2 350 + veor q9, q14, q3 351 + vshl.u32 q13, q8, #8 352 + vshl.u32 q14, q9, #8 353 + vsri.u32 q13, q8, #24 354 + vsri.u32 q14, q9, #24 355 + 356 + vld1.32 {q8-q9}, [sp, :256] 357 + 358 + // x10 += x15, x5 = rotl32(x5 ^ x10, 7) 359 + // x11 += x12, x6 = rotl32(x6 ^ x11, 7) 360 + // x8 += x13, x7 = rotl32(x7 ^ x8, 7) 361 + // x9 += x14, x4 = rotl32(x4 ^ x9, 7) 362 + vadd.i32 q10, q10, q15 363 + vadd.i32 q11, q11, q12 364 + vadd.i32 q8, q8, q13 365 + vadd.i32 q9, q9, q14 366 + 367 + vst1.32 {q8-q9}, [sp, :256] 368 + 369 + veor q8, q7, q8 370 + veor q9, q4, q9 371 + vshl.u32 q7, q8, #7 372 + vshl.u32 q4, q9, #7 373 + vsri.u32 q7, q8, #25 374 + vsri.u32 q4, q9, #25 375 + 376 + veor q8, q5, q10 377 + veor q9, q6, q11 378 + vshl.u32 q5, q8, #7 379 + vshl.u32 q6, q9, #7 380 + vsri.u32 q5, q8, #25 381 + vsri.u32 q6, q9, #25 382 + 383 + subs r3, r3, #1 384 + beq 0f 385 + 386 + vld1.32 {q8-q9}, [sp, :256] 387 + b .Ldoubleround4 388 + 389 + // x0[0-3] += s0[0] 390 + // x1[0-3] += s0[1] 391 + // x2[0-3] += s0[2] 392 + // x3[0-3] += s0[3] 393 + 0: ldmia r0!, {r3-r6} 394 + vdup.32 q8, r3 395 + vdup.32 q9, r4 396 + vadd.i32 q0, q0, q8 397 + vadd.i32 q1, q1, q9 398 + vdup.32 q8, r5 399 + vdup.32 q9, r6 400 + vadd.i32 q2, q2, q8 401 + vadd.i32 q3, q3, q9 402 + 403 + // x4[0-3] += s1[0] 404 + // x5[0-3] += s1[1] 405 + // x6[0-3] += s1[2] 406 + // x7[0-3] += s1[3] 407 + ldmia r0!, {r3-r6} 408 + vdup.32 q8, r3 409 + vdup.32 q9, r4 410 + vadd.i32 q4, q4, q8 411 + vadd.i32 q5, q5, q9 412 + vdup.32 q8, r5 413 + vdup.32 q9, r6 414 + vadd.i32 q6, q6, q8 415 + vadd.i32 q7, q7, q9 416 + 417 + // interleave 32-bit words in state n, n+1 418 + vzip.32 q0, q1 419 + vzip.32 q2, q3 420 + vzip.32 q4, q5 421 + vzip.32 q6, q7 422 + 423 + // interleave 64-bit words in state n, n+2 424 + vswp d1, d4 425 + vswp d3, d6 426 + vswp d9, d12 427 + vswp d11, d14 428 + 429 + // xor with corresponding input, write to output 430 + vld1.8 {q8-q9}, [r2]! 431 + veor q8, q8, q0 432 + veor q9, q9, q4 433 + vst1.8 {q8-q9}, [r1]! 434 + 435 + vld1.32 {q8-q9}, [sp, :256] 436 + 437 + // x8[0-3] += s2[0] 438 + // x9[0-3] += s2[1] 439 + // x10[0-3] += s2[2] 440 + // x11[0-3] += s2[3] 441 + ldmia r0!, {r3-r6} 442 + vdup.32 q0, r3 443 + vdup.32 q4, r4 444 + vadd.i32 q8, q8, q0 445 + vadd.i32 q9, q9, q4 446 + vdup.32 q0, r5 447 + vdup.32 q4, r6 448 + vadd.i32 q10, q10, q0 449 + vadd.i32 q11, q11, q4 450 + 451 + // x12[0-3] += s3[0] 452 + // x13[0-3] += s3[1] 453 + // x14[0-3] += s3[2] 454 + // x15[0-3] += s3[3] 455 + ldmia r0!, {r3-r6} 456 + vdup.32 q0, r3 457 + vdup.32 q4, r4 458 + adr r3, CTRINC 459 + vadd.i32 q12, q12, q0 460 + vld1.32 {q0}, [r3, :128] 461 + vadd.i32 q13, q13, q4 462 + vadd.i32 q12, q12, q0 // x12 += counter values 0-3 463 + 464 + vdup.32 q0, r5 465 + vdup.32 q4, r6 466 + vadd.i32 q14, q14, q0 467 + vadd.i32 q15, q15, q4 468 + 469 + // interleave 32-bit words in state n, n+1 470 + vzip.32 q8, q9 471 + vzip.32 q10, q11 472 + vzip.32 q12, q13 473 + vzip.32 q14, q15 474 + 475 + // interleave 64-bit words in state n, n+2 476 + vswp d17, d20 477 + vswp d19, d22 478 + vswp d25, d28 479 + vswp d27, d30 480 + 481 + vmov q4, q1 482 + 483 + vld1.8 {q0-q1}, [r2]! 484 + veor q0, q0, q8 485 + veor q1, q1, q12 486 + vst1.8 {q0-q1}, [r1]! 487 + 488 + vld1.8 {q0-q1}, [r2]! 489 + veor q0, q0, q2 490 + veor q1, q1, q6 491 + vst1.8 {q0-q1}, [r1]! 492 + 493 + vld1.8 {q0-q1}, [r2]! 494 + veor q0, q0, q10 495 + veor q1, q1, q14 496 + vst1.8 {q0-q1}, [r1]! 497 + 498 + vld1.8 {q0-q1}, [r2]! 499 + veor q0, q0, q4 500 + veor q1, q1, q5 501 + vst1.8 {q0-q1}, [r1]! 502 + 503 + vld1.8 {q0-q1}, [r2]! 504 + veor q0, q0, q9 505 + veor q1, q1, q13 506 + vst1.8 {q0-q1}, [r1]! 507 + 508 + vld1.8 {q0-q1}, [r2]! 509 + veor q0, q0, q3 510 + veor q1, q1, q7 511 + vst1.8 {q0-q1}, [r1]! 512 + 513 + vld1.8 {q0-q1}, [r2] 514 + veor q0, q0, q11 515 + veor q1, q1, q15 516 + vst1.8 {q0-q1}, [r1] 517 + 518 + mov sp, ip 519 + pop {r4-r6, pc} 520 + ENDPROC(chacha20_4block_xor_neon) 521 + 522 + .align 4 523 + CTRINC: .word 0, 1, 2, 3
+136
arch/arm/crypto/chacha20-neon-glue.c
··· 1 + /* 2 + * ChaCha20 256-bit cipher algorithm, RFC7539, ARM NEON 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, SIMD glue code 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 + #include <crypto/algapi.h> 22 + #include <crypto/chacha20.h> 23 + #include <linux/crypto.h> 24 + #include <linux/kernel.h> 25 + #include <linux/module.h> 26 + 27 + #include <asm/hwcap.h> 28 + #include <asm/neon.h> 29 + #include <asm/simd.h> 30 + 31 + asmlinkage void chacha20_block_xor_neon(u32 *state, u8 *dst, const u8 *src); 32 + asmlinkage void chacha20_4block_xor_neon(u32 *state, u8 *dst, const u8 *src); 33 + 34 + static void chacha20_dosimd(u32 *state, u8 *dst, const u8 *src, 35 + unsigned int bytes) 36 + { 37 + u8 buf[CHACHA20_BLOCK_SIZE]; 38 + 39 + while (bytes >= CHACHA20_BLOCK_SIZE * 4) { 40 + chacha20_4block_xor_neon(state, dst, src); 41 + bytes -= CHACHA20_BLOCK_SIZE * 4; 42 + src += CHACHA20_BLOCK_SIZE * 4; 43 + dst += CHACHA20_BLOCK_SIZE * 4; 44 + state[12] += 4; 45 + } 46 + while (bytes >= CHACHA20_BLOCK_SIZE) { 47 + chacha20_block_xor_neon(state, dst, src); 48 + bytes -= CHACHA20_BLOCK_SIZE; 49 + src += CHACHA20_BLOCK_SIZE; 50 + dst += CHACHA20_BLOCK_SIZE; 51 + state[12]++; 52 + } 53 + if (bytes) { 54 + memcpy(buf, src, bytes); 55 + chacha20_block_xor_neon(state, buf, buf); 56 + memcpy(dst, buf, bytes); 57 + } 58 + } 59 + 60 + static int chacha20_simd(struct blkcipher_desc *desc, struct scatterlist *dst, 61 + struct scatterlist *src, unsigned int nbytes) 62 + { 63 + struct blkcipher_walk walk; 64 + u32 state[16]; 65 + int err; 66 + 67 + if (nbytes <= CHACHA20_BLOCK_SIZE || !may_use_simd()) 68 + return crypto_chacha20_crypt(desc, dst, src, nbytes); 69 + 70 + blkcipher_walk_init(&walk, dst, src, nbytes); 71 + err = blkcipher_walk_virt_block(desc, &walk, CHACHA20_BLOCK_SIZE); 72 + 73 + crypto_chacha20_init(state, crypto_blkcipher_ctx(desc->tfm), walk.iv); 74 + 75 + kernel_neon_begin(); 76 + 77 + while (walk.nbytes >= CHACHA20_BLOCK_SIZE) { 78 + chacha20_dosimd(state, walk.dst.virt.addr, walk.src.virt.addr, 79 + rounddown(walk.nbytes, CHACHA20_BLOCK_SIZE)); 80 + err = blkcipher_walk_done(desc, &walk, 81 + walk.nbytes % CHACHA20_BLOCK_SIZE); 82 + } 83 + 84 + if (walk.nbytes) { 85 + chacha20_dosimd(state, walk.dst.virt.addr, walk.src.virt.addr, 86 + walk.nbytes); 87 + err = blkcipher_walk_done(desc, &walk, 0); 88 + } 89 + 90 + kernel_neon_end(); 91 + 92 + return err; 93 + } 94 + 95 + static struct crypto_alg alg = { 96 + .cra_name = "chacha20", 97 + .cra_driver_name = "chacha20-neon", 98 + .cra_priority = 300, 99 + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 100 + .cra_blocksize = 1, 101 + .cra_type = &crypto_blkcipher_type, 102 + .cra_ctxsize = sizeof(struct chacha20_ctx), 103 + .cra_alignmask = sizeof(u32) - 1, 104 + .cra_module = THIS_MODULE, 105 + .cra_u = { 106 + .blkcipher = { 107 + .min_keysize = CHACHA20_KEY_SIZE, 108 + .max_keysize = CHACHA20_KEY_SIZE, 109 + .ivsize = CHACHA20_IV_SIZE, 110 + .geniv = "seqiv", 111 + .setkey = crypto_chacha20_setkey, 112 + .encrypt = chacha20_simd, 113 + .decrypt = chacha20_simd, 114 + }, 115 + }, 116 + }; 117 + 118 + static int __init chacha20_simd_mod_init(void) 119 + { 120 + if (!(elf_hwcap & HWCAP_NEON)) 121 + return -ENODEV; 122 + 123 + return crypto_register_alg(&alg); 124 + } 125 + 126 + static void __exit chacha20_simd_mod_fini(void) 127 + { 128 + crypto_unregister_alg(&alg); 129 + } 130 + 131 + module_init(chacha20_simd_mod_init); 132 + module_exit(chacha20_simd_mod_fini); 133 + 134 + MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); 135 + MODULE_LICENSE("GPL v2"); 136 + MODULE_ALIAS_CRYPTO("chacha20");