0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 #include <linux/linkage.h>
0050 #include <asm/cache.h>
0051
0052 .text
0053 .fpu neon
0054 .align 5
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 chacha_permute:
0068
0069 adr ip, .Lrol8_table
0070 vld1.8 {d10}, [ip, :64]
0071
0072 .Ldoubleround:
0073 // x0 += x1, x3 = rotl32(x3 ^ x0, 16)
0074 vadd.i32 q0, q0, q1
0075 veor q3, q3, q0
0076 vrev32.16 q3, q3
0077
0078 // x2 += x3, x1 = rotl32(x1 ^ x2, 12)
0079 vadd.i32 q2, q2, q3
0080 veor q4, q1, q2
0081 vshl.u32 q1, q4, #12
0082 vsri.u32 q1, q4, #20
0083
0084 // x0 += x1, x3 = rotl32(x3 ^ x0, 8)
0085 vadd.i32 q0, q0, q1
0086 veor q3, q3, q0
0087 vtbl.8 d6, {d6}, d10
0088 vtbl.8 d7, {d7}, d10
0089
0090 // x2 += x3, x1 = rotl32(x1 ^ x2, 7)
0091 vadd.i32 q2, q2, q3
0092 veor q4, q1, q2
0093 vshl.u32 q1, q4, #7
0094 vsri.u32 q1, q4, #25
0095
0096 // x1 = shuffle32(x1, MASK(0, 3, 2, 1))
0097 vext.8 q1, q1, q1, #4
0098 // x2 = shuffle32(x2, MASK(1, 0, 3, 2))
0099 vext.8 q2, q2, q2, #8
0100 // x3 = shuffle32(x3, MASK(2, 1, 0, 3))
0101 vext.8 q3, q3, q3, #12
0102
0103 // x0 += x1, x3 = rotl32(x3 ^ x0, 16)
0104 vadd.i32 q0, q0, q1
0105 veor q3, q3, q0
0106 vrev32.16 q3, q3
0107
0108 // x2 += x3, x1 = rotl32(x1 ^ x2, 12)
0109 vadd.i32 q2, q2, q3
0110 veor q4, q1, q2
0111 vshl.u32 q1, q4, #12
0112 vsri.u32 q1, q4, #20
0113
0114 // x0 += x1, x3 = rotl32(x3 ^ x0, 8)
0115 vadd.i32 q0, q0, q1
0116 veor q3, q3, q0
0117 vtbl.8 d6, {d6}, d10
0118 vtbl.8 d7, {d7}, d10
0119
0120 // x2 += x3, x1 = rotl32(x1 ^ x2, 7)
0121 vadd.i32 q2, q2, q3
0122 veor q4, q1, q2
0123 vshl.u32 q1, q4, #7
0124 vsri.u32 q1, q4, #25
0125
0126 // x1 = shuffle32(x1, MASK(2, 1, 0, 3))
0127 vext.8 q1, q1, q1, #12
0128 // x2 = shuffle32(x2, MASK(1, 0, 3, 2))
0129 vext.8 q2, q2, q2, #8
0130 // x3 = shuffle32(x3, MASK(0, 3, 2, 1))
0131 vext.8 q3, q3, q3, #4
0132
0133 subs r3, r3, #2
0134 bne .Ldoubleround
0135
0136 bx lr
0137 ENDPROC(chacha_permute)
0138
0139 ENTRY(chacha_block_xor_neon)
0140 // r0: Input state matrix, s
0141 // r1: 1 data block output, o
0142 // r2: 1 data block input, i
0143 // r3: nrounds
0144 push {lr}
0145
0146 // x0..3 = s0..3
0147 add ip, r0, #0x20
0148 vld1.32 {q0-q1}, [r0]
0149 vld1.32 {q2-q3}, [ip]
0150
0151 vmov q8, q0
0152 vmov q9, q1
0153 vmov q10, q2
0154 vmov q11, q3
0155
0156 bl chacha_permute
0157
0158 add ip, r2, #0x20
0159 vld1.8 {q4-q5}, [r2]
0160 vld1.8 {q6-q7}, [ip]
0161
0162 // o0 = i0 ^ (x0 + s0)
0163 vadd.i32 q0, q0, q8
0164 veor q0, q0, q4
0165
0166 // o1 = i1 ^ (x1 + s1)
0167 vadd.i32 q1, q1, q9
0168 veor q1, q1, q5
0169
0170 // o2 = i2 ^ (x2 + s2)
0171 vadd.i32 q2, q2, q10
0172 veor q2, q2, q6
0173
0174 // o3 = i3 ^ (x3 + s3)
0175 vadd.i32 q3, q3, q11
0176 veor q3, q3, q7
0177
0178 add ip, r1, #0x20
0179 vst1.8 {q0-q1}, [r1]
0180 vst1.8 {q2-q3}, [ip]
0181
0182 pop {pc}
0183 ENDPROC(chacha_block_xor_neon)
0184
0185 ENTRY(hchacha_block_neon)
0186 // r0: Input state matrix, s
0187 // r1: output (8 32-bit words)
0188 // r2: nrounds
0189 push {lr}
0190
0191 vld1.32 {q0-q1}, [r0]!
0192 vld1.32 {q2-q3}, [r0]
0193
0194 mov r3, r2
0195 bl chacha_permute
0196
0197 vst1.32 {q0}, [r1]!
0198 vst1.32 {q3}, [r1]
0199
0200 pop {pc}
0201 ENDPROC(hchacha_block_neon)
0202
0203 .align 4
0204 .Lctrinc: .word 0, 1, 2, 3
0205 .Lrol8_table: .byte 3, 0, 1, 2, 7, 4, 5, 6
0206
0207 .align 5
0208 ENTRY(chacha_4block_xor_neon)
0209 push {r4, lr}
0210 mov r4, sp // preserve the stack pointer
0211 sub ip, sp, #0x20 // allocate a 32 byte buffer
0212 bic ip, ip, #0x1f // aligned to 32 bytes
0213 mov sp, ip
0214
0215 // r0: Input state matrix, s
0216 // r1: 4 data blocks output, o
0217 // r2: 4 data blocks input, i
0218 // r3: nrounds
0219
0220 //
0221 // This function encrypts four consecutive ChaCha blocks by loading
0222 // the state matrix in NEON registers four times. The algorithm performs
0223 // each operation on the corresponding word of each state matrix, hence
0224 // requires no word shuffling. The words are re-interleaved before the
0225 // final addition of the original state and the XORing step.
0226 //
0227
0228 // x0..15[0-3] = s0..15[0-3]
0229 add ip, r0, #0x20
0230 vld1.32 {q0-q1}, [r0]
0231 vld1.32 {q2-q3}, [ip]
0232
0233 adr lr, .Lctrinc
0234 vdup.32 q15, d7[1]
0235 vdup.32 q14, d7[0]
0236 vld1.32 {q4}, [lr, :128]
0237 vdup.32 q13, d6[1]
0238 vdup.32 q12, d6[0]
0239 vdup.32 q11, d5[1]
0240 vdup.32 q10, d5[0]
0241 vadd.u32 q12, q12, q4 // x12 += counter values 0-3
0242 vdup.32 q9, d4[1]
0243 vdup.32 q8, d4[0]
0244 vdup.32 q7, d3[1]
0245 vdup.32 q6, d3[0]
0246 vdup.32 q5, d2[1]
0247 vdup.32 q4, d2[0]
0248 vdup.32 q3, d1[1]
0249 vdup.32 q2, d1[0]
0250 vdup.32 q1, d0[1]
0251 vdup.32 q0, d0[0]
0252
0253 adr ip, .Lrol8_table
0254 b 1f
0255
0256 .Ldoubleround4:
0257 vld1.32 {q8-q9}, [sp, :256]
0258 1:
0259 // x0 += x4, x12 = rotl32(x12 ^ x0, 16)
0260 // x1 += x5, x13 = rotl32(x13 ^ x1, 16)
0261 // x2 += x6, x14 = rotl32(x14 ^ x2, 16)
0262 // x3 += x7, x15 = rotl32(x15 ^ x3, 16)
0263 vadd.i32 q0, q0, q4
0264 vadd.i32 q1, q1, q5
0265 vadd.i32 q2, q2, q6
0266 vadd.i32 q3, q3, q7
0267
0268 veor q12, q12, q0
0269 veor q13, q13, q1
0270 veor q14, q14, q2
0271 veor q15, q15, q3
0272
0273 vrev32.16 q12, q12
0274 vrev32.16 q13, q13
0275 vrev32.16 q14, q14
0276 vrev32.16 q15, q15
0277
0278 // x8 += x12, x4 = rotl32(x4 ^ x8, 12)
0279 // x9 += x13, x5 = rotl32(x5 ^ x9, 12)
0280 // x10 += x14, x6 = rotl32(x6 ^ x10, 12)
0281 // x11 += x15, x7 = rotl32(x7 ^ x11, 12)
0282 vadd.i32 q8, q8, q12
0283 vadd.i32 q9, q9, q13
0284 vadd.i32 q10, q10, q14
0285 vadd.i32 q11, q11, q15
0286
0287 vst1.32 {q8-q9}, [sp, :256]
0288
0289 veor q8, q4, q8
0290 veor q9, q5, q9
0291 vshl.u32 q4, q8, #12
0292 vshl.u32 q5, q9, #12
0293 vsri.u32 q4, q8, #20
0294 vsri.u32 q5, q9, #20
0295
0296 veor q8, q6, q10
0297 veor q9, q7, q11
0298 vshl.u32 q6, q8, #12
0299 vshl.u32 q7, q9, #12
0300 vsri.u32 q6, q8, #20
0301 vsri.u32 q7, q9, #20
0302
0303 // x0 += x4, x12 = rotl32(x12 ^ x0, 8)
0304 // x1 += x5, x13 = rotl32(x13 ^ x1, 8)
0305 // x2 += x6, x14 = rotl32(x14 ^ x2, 8)
0306 // x3 += x7, x15 = rotl32(x15 ^ x3, 8)
0307 vld1.8 {d16}, [ip, :64]
0308 vadd.i32 q0, q0, q4
0309 vadd.i32 q1, q1, q5
0310 vadd.i32 q2, q2, q6
0311 vadd.i32 q3, q3, q7
0312
0313 veor q12, q12, q0
0314 veor q13, q13, q1
0315 veor q14, q14, q2
0316 veor q15, q15, q3
0317
0318 vtbl.8 d24, {d24}, d16
0319 vtbl.8 d25, {d25}, d16
0320 vtbl.8 d26, {d26}, d16
0321 vtbl.8 d27, {d27}, d16
0322 vtbl.8 d28, {d28}, d16
0323 vtbl.8 d29, {d29}, d16
0324 vtbl.8 d30, {d30}, d16
0325 vtbl.8 d31, {d31}, d16
0326
0327 vld1.32 {q8-q9}, [sp, :256]
0328
0329 // x8 += x12, x4 = rotl32(x4 ^ x8, 7)
0330 // x9 += x13, x5 = rotl32(x5 ^ x9, 7)
0331 // x10 += x14, x6 = rotl32(x6 ^ x10, 7)
0332 // x11 += x15, x7 = rotl32(x7 ^ x11, 7)
0333 vadd.i32 q8, q8, q12
0334 vadd.i32 q9, q9, q13
0335 vadd.i32 q10, q10, q14
0336 vadd.i32 q11, q11, q15
0337
0338 vst1.32 {q8-q9}, [sp, :256]
0339
0340 veor q8, q4, q8
0341 veor q9, q5, q9
0342 vshl.u32 q4, q8, #7
0343 vshl.u32 q5, q9, #7
0344 vsri.u32 q4, q8, #25
0345 vsri.u32 q5, q9, #25
0346
0347 veor q8, q6, q10
0348 veor q9, q7, q11
0349 vshl.u32 q6, q8, #7
0350 vshl.u32 q7, q9, #7
0351 vsri.u32 q6, q8, #25
0352 vsri.u32 q7, q9, #25
0353
0354 vld1.32 {q8-q9}, [sp, :256]
0355
0356 // x0 += x5, x15 = rotl32(x15 ^ x0, 16)
0357 // x1 += x6, x12 = rotl32(x12 ^ x1, 16)
0358 // x2 += x7, x13 = rotl32(x13 ^ x2, 16)
0359 // x3 += x4, x14 = rotl32(x14 ^ x3, 16)
0360 vadd.i32 q0, q0, q5
0361 vadd.i32 q1, q1, q6
0362 vadd.i32 q2, q2, q7
0363 vadd.i32 q3, q3, q4
0364
0365 veor q15, q15, q0
0366 veor q12, q12, q1
0367 veor q13, q13, q2
0368 veor q14, q14, q3
0369
0370 vrev32.16 q15, q15
0371 vrev32.16 q12, q12
0372 vrev32.16 q13, q13
0373 vrev32.16 q14, q14
0374
0375 // x10 += x15, x5 = rotl32(x5 ^ x10, 12)
0376 // x11 += x12, x6 = rotl32(x6 ^ x11, 12)
0377 // x8 += x13, x7 = rotl32(x7 ^ x8, 12)
0378 // x9 += x14, x4 = rotl32(x4 ^ x9, 12)
0379 vadd.i32 q10, q10, q15
0380 vadd.i32 q11, q11, q12
0381 vadd.i32 q8, q8, q13
0382 vadd.i32 q9, q9, q14
0383
0384 vst1.32 {q8-q9}, [sp, :256]
0385
0386 veor q8, q7, q8
0387 veor q9, q4, q9
0388 vshl.u32 q7, q8, #12
0389 vshl.u32 q4, q9, #12
0390 vsri.u32 q7, q8, #20
0391 vsri.u32 q4, q9, #20
0392
0393 veor q8, q5, q10
0394 veor q9, q6, q11
0395 vshl.u32 q5, q8, #12
0396 vshl.u32 q6, q9, #12
0397 vsri.u32 q5, q8, #20
0398 vsri.u32 q6, q9, #20
0399
0400 // x0 += x5, x15 = rotl32(x15 ^ x0, 8)
0401 // x1 += x6, x12 = rotl32(x12 ^ x1, 8)
0402 // x2 += x7, x13 = rotl32(x13 ^ x2, 8)
0403 // x3 += x4, x14 = rotl32(x14 ^ x3, 8)
0404 vld1.8 {d16}, [ip, :64]
0405 vadd.i32 q0, q0, q5
0406 vadd.i32 q1, q1, q6
0407 vadd.i32 q2, q2, q7
0408 vadd.i32 q3, q3, q4
0409
0410 veor q15, q15, q0
0411 veor q12, q12, q1
0412 veor q13, q13, q2
0413 veor q14, q14, q3
0414
0415 vtbl.8 d30, {d30}, d16
0416 vtbl.8 d31, {d31}, d16
0417 vtbl.8 d24, {d24}, d16
0418 vtbl.8 d25, {d25}, d16
0419 vtbl.8 d26, {d26}, d16
0420 vtbl.8 d27, {d27}, d16
0421 vtbl.8 d28, {d28}, d16
0422 vtbl.8 d29, {d29}, d16
0423
0424 vld1.32 {q8-q9}, [sp, :256]
0425
0426 // x10 += x15, x5 = rotl32(x5 ^ x10, 7)
0427 // x11 += x12, x6 = rotl32(x6 ^ x11, 7)
0428 // x8 += x13, x7 = rotl32(x7 ^ x8, 7)
0429 // x9 += x14, x4 = rotl32(x4 ^ x9, 7)
0430 vadd.i32 q10, q10, q15
0431 vadd.i32 q11, q11, q12
0432 vadd.i32 q8, q8, q13
0433 vadd.i32 q9, q9, q14
0434
0435 vst1.32 {q8-q9}, [sp, :256]
0436
0437 veor q8, q7, q8
0438 veor q9, q4, q9
0439 vshl.u32 q7, q8, #7
0440 vshl.u32 q4, q9, #7
0441 vsri.u32 q7, q8, #25
0442 vsri.u32 q4, q9, #25
0443
0444 veor q8, q5, q10
0445 veor q9, q6, q11
0446 vshl.u32 q5, q8, #7
0447 vshl.u32 q6, q9, #7
0448 vsri.u32 q5, q8, #25
0449 vsri.u32 q6, q9, #25
0450
0451 subs r3, r3, #2
0452 bne .Ldoubleround4
0453
0454 // x0..7[0-3] are in q0-q7, x10..15[0-3] are in q10-q15.
0455 // x8..9[0-3] are on the stack.
0456
0457 // Re-interleave the words in the first two rows of each block (x0..7).
0458 // Also add the counter values 0-3 to x12[0-3].
0459 vld1.32 {q8}, [lr, :128] // load counter values 0-3
0460 vzip.32 q0, q1 // => (0 1 0 1) (0 1 0 1)
0461 vzip.32 q2, q3 // => (2 3 2 3) (2 3 2 3)
0462 vzip.32 q4, q5 // => (4 5 4 5) (4 5 4 5)
0463 vzip.32 q6, q7 // => (6 7 6 7) (6 7 6 7)
0464 vadd.u32 q12, q8 // x12 += counter values 0-3
0465 vswp d1, d4
0466 vswp d3, d6
0467 vld1.32 {q8-q9}, [r0]! // load s0..7
0468 vswp d9, d12
0469 vswp d11, d14
0470
0471 // Swap q1 and q4 so that we'll free up consecutive registers (q0-q1)
0472 // after XORing the first 32 bytes.
0473 vswp q1, q4
0474
0475 // First two rows of each block are (q0 q1) (q2 q6) (q4 q5) (q3 q7)
0476
0477 // x0..3[0-3] += s0..3[0-3] (add orig state to 1st row of each block)
0478 vadd.u32 q0, q0, q8
0479 vadd.u32 q2, q2, q8
0480 vadd.u32 q4, q4, q8
0481 vadd.u32 q3, q3, q8
0482
0483 // x4..7[0-3] += s4..7[0-3] (add orig state to 2nd row of each block)
0484 vadd.u32 q1, q1, q9
0485 vadd.u32 q6, q6, q9
0486 vadd.u32 q5, q5, q9
0487 vadd.u32 q7, q7, q9
0488
0489 // XOR first 32 bytes using keystream from first two rows of first block
0490 vld1.8 {q8-q9}, [r2]!
0491 veor q8, q8, q0
0492 veor q9, q9, q1
0493 vst1.8 {q8-q9}, [r1]!
0494
0495 // Re-interleave the words in the last two rows of each block (x8..15).
0496 vld1.32 {q8-q9}, [sp, :256]
0497 mov sp, r4 // restore original stack pointer
0498 ldr r4, [r4, #8] // load number of bytes
0499 vzip.32 q12, q13 // => (12 13 12 13) (12 13 12 13)
0500 vzip.32 q14, q15 // => (14 15 14 15) (14 15 14 15)
0501 vzip.32 q8, q9 // => (8 9 8 9) (8 9 8 9)
0502 vzip.32 q10, q11 // => (10 11 10 11) (10 11 10 11)
0503 vld1.32 {q0-q1}, [r0] // load s8..15
0504 vswp d25, d28
0505 vswp d27, d30
0506 vswp d17, d20
0507 vswp d19, d22
0508
0509 // Last two rows of each block are (q8 q12) (q10 q14) (q9 q13) (q11 q15)
0510
0511 // x8..11[0-3] += s8..11[0-3] (add orig state to 3rd row of each block)
0512 vadd.u32 q8, q8, q0
0513 vadd.u32 q10, q10, q0
0514 vadd.u32 q9, q9, q0
0515 vadd.u32 q11, q11, q0
0516
0517 // x12..15[0-3] += s12..15[0-3] (add orig state to 4th row of each block)
0518 vadd.u32 q12, q12, q1
0519 vadd.u32 q14, q14, q1
0520 vadd.u32 q13, q13, q1
0521 vadd.u32 q15, q15, q1
0522
0523 // XOR the rest of the data with the keystream
0524
0525 vld1.8 {q0-q1}, [r2]!
0526 subs r4, r4, #96
0527 veor q0, q0, q8
0528 veor q1, q1, q12
0529 ble .Lle96
0530 vst1.8 {q0-q1}, [r1]!
0531
0532 vld1.8 {q0-q1}, [r2]!
0533 subs r4, r4, #32
0534 veor q0, q0, q2
0535 veor q1, q1, q6
0536 ble .Lle128
0537 vst1.8 {q0-q1}, [r1]!
0538
0539 vld1.8 {q0-q1}, [r2]!
0540 subs r4, r4, #32
0541 veor q0, q0, q10
0542 veor q1, q1, q14
0543 ble .Lle160
0544 vst1.8 {q0-q1}, [r1]!
0545
0546 vld1.8 {q0-q1}, [r2]!
0547 subs r4, r4, #32
0548 veor q0, q0, q4
0549 veor q1, q1, q5
0550 ble .Lle192
0551 vst1.8 {q0-q1}, [r1]!
0552
0553 vld1.8 {q0-q1}, [r2]!
0554 subs r4, r4, #32
0555 veor q0, q0, q9
0556 veor q1, q1, q13
0557 ble .Lle224
0558 vst1.8 {q0-q1}, [r1]!
0559
0560 vld1.8 {q0-q1}, [r2]!
0561 subs r4, r4, #32
0562 veor q0, q0, q3
0563 veor q1, q1, q7
0564 blt .Llt256
0565 .Lout:
0566 vst1.8 {q0-q1}, [r1]!
0567
0568 vld1.8 {q0-q1}, [r2]
0569 veor q0, q0, q11
0570 veor q1, q1, q15
0571 vst1.8 {q0-q1}, [r1]
0572
0573 pop {r4, pc}
0574
0575 .Lle192:
0576 vmov q4, q9
0577 vmov q5, q13
0578
0579 .Lle160:
0580 // nothing to do
0581
0582 .Lfinalblock:
0583 // Process the final block if processing less than 4 full blocks.
0584 // Entered with 32 bytes of ChaCha cipher stream in q4-q5, and the
0585 // previous 32 byte output block that still needs to be written at
0586 // [r1] in q0-q1.
0587 beq .Lfullblock
0588
0589 .Lpartialblock:
0590 adr lr, .Lpermute + 32
0591 add r2, r2, r4
0592 add lr, lr, r4
0593 add r4, r4, r1
0594
0595 vld1.8 {q2-q3}, [lr]
0596 vld1.8 {q6-q7}, [r2]
0597
0598 add r4, r4, #32
0599
0600 vtbl.8 d4, {q4-q5}, d4
0601 vtbl.8 d5, {q4-q5}, d5
0602 vtbl.8 d6, {q4-q5}, d6
0603 vtbl.8 d7, {q4-q5}, d7
0604
0605 veor q6, q6, q2
0606 veor q7, q7, q3
0607
0608 vst1.8 {q6-q7}, [r4] // overlapping stores
0609 vst1.8 {q0-q1}, [r1]
0610 pop {r4, pc}
0611
0612 .Lfullblock:
0613 vmov q11, q4
0614 vmov q15, q5
0615 b .Lout
0616 .Lle96:
0617 vmov q4, q2
0618 vmov q5, q6
0619 b .Lfinalblock
0620 .Lle128:
0621 vmov q4, q10
0622 vmov q5, q14
0623 b .Lfinalblock
0624 .Lle224:
0625 vmov q4, q3
0626 vmov q5, q7
0627 b .Lfinalblock
0628 .Llt256:
0629 vmov q4, q11
0630 vmov q5, q15
0631 b .Lpartialblock
0632 ENDPROC(chacha_4block_xor_neon)
0633
0634 .align L1_CACHE_SHIFT
0635 .Lpermute:
0636 .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
0637 .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
0638 .byte 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
0639 .byte 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
0640 .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
0641 .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
0642 .byte 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
0643 .byte 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f