blob: 3fecb2124c35a0b35b680a86216be0bd5a27e92d [file] [log] [blame]
Ard Biesheuvelafaf7122017-01-11 16:41:50 +00001/*
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 SSE3 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
27ENTRY(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
142ENDPROC(chacha20_block_xor_neon)
143
144 .align 5
145ENTRY(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]
3930: 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}
520ENDPROC(chacha20_4block_xor_neon)
521
522 .align 4
523CTRINC: .word 0, 1, 2, 3