]>
Commit | Line | Data |
---|---|---|
afaf712e AB |
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 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 | ||
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 |