1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * ChaCha 256-bit cipher algorithm, x64 AVX-512VL functions
4 *
5 * Copyright (C) 2018 Martin Willi
6 */
7
8#include <linux/linkage.h>
9
10.section	.rodata.cst32.CTR2BL, "aM", @progbits, 32
11.align 32
12CTR2BL:	.octa 0x00000000000000000000000000000000
13	.octa 0x00000000000000000000000000000001
14
15.section	.rodata.cst32.CTR4BL, "aM", @progbits, 32
16.align 32
17CTR4BL:	.octa 0x00000000000000000000000000000002
18	.octa 0x00000000000000000000000000000003
19
20.section	.rodata.cst32.CTR8BL, "aM", @progbits, 32
21.align 32
22CTR8BL:	.octa 0x00000003000000020000000100000000
23	.octa 0x00000007000000060000000500000004
24
25.text
26
27ENTRY(chacha_2block_xor_avx512vl)
28	# %rdi: Input state matrix, s
29	# %rsi: up to 2 data blocks output, o
30	# %rdx: up to 2 data blocks input, i
31	# %rcx: input/output length in bytes
32	# %r8d: nrounds
33
34	# This function encrypts two ChaCha blocks by loading the state
35	# matrix twice across four AVX registers. It performs matrix operations
36	# on four words in each matrix in parallel, but requires shuffling to
37	# rearrange the words after each round.
38
39	vzeroupper
40
41	# x0..3[0-2] = s0..3
42	vbroadcasti128	0x00(%rdi),%ymm0
43	vbroadcasti128	0x10(%rdi),%ymm1
44	vbroadcasti128	0x20(%rdi),%ymm2
45	vbroadcasti128	0x30(%rdi),%ymm3
46
47	vpaddd		CTR2BL(%rip),%ymm3,%ymm3
48
49	vmovdqa		%ymm0,%ymm8
50	vmovdqa		%ymm1,%ymm9
51	vmovdqa		%ymm2,%ymm10
52	vmovdqa		%ymm3,%ymm11
53
54.Ldoubleround:
55
56	# x0 += x1, x3 = rotl32(x3 ^ x0, 16)
57	vpaddd		%ymm1,%ymm0,%ymm0
58	vpxord		%ymm0,%ymm3,%ymm3
59	vprold		$16,%ymm3,%ymm3
60
61	# x2 += x3, x1 = rotl32(x1 ^ x2, 12)
62	vpaddd		%ymm3,%ymm2,%ymm2
63	vpxord		%ymm2,%ymm1,%ymm1
64	vprold		$12,%ymm1,%ymm1
65
66	# x0 += x1, x3 = rotl32(x3 ^ x0, 8)
67	vpaddd		%ymm1,%ymm0,%ymm0
68	vpxord		%ymm0,%ymm3,%ymm3
69	vprold		$8,%ymm3,%ymm3
70
71	# x2 += x3, x1 = rotl32(x1 ^ x2, 7)
72	vpaddd		%ymm3,%ymm2,%ymm2
73	vpxord		%ymm2,%ymm1,%ymm1
74	vprold		$7,%ymm1,%ymm1
75
76	# x1 = shuffle32(x1, MASK(0, 3, 2, 1))
77	vpshufd		$0x39,%ymm1,%ymm1
78	# x2 = shuffle32(x2, MASK(1, 0, 3, 2))
79	vpshufd		$0x4e,%ymm2,%ymm2
80	# x3 = shuffle32(x3, MASK(2, 1, 0, 3))
81	vpshufd		$0x93,%ymm3,%ymm3
82
83	# x0 += x1, x3 = rotl32(x3 ^ x0, 16)
84	vpaddd		%ymm1,%ymm0,%ymm0
85	vpxord		%ymm0,%ymm3,%ymm3
86	vprold		$16,%ymm3,%ymm3
87
88	# x2 += x3, x1 = rotl32(x1 ^ x2, 12)
89	vpaddd		%ymm3,%ymm2,%ymm2
90	vpxord		%ymm2,%ymm1,%ymm1
91	vprold		$12,%ymm1,%ymm1
92
93	# x0 += x1, x3 = rotl32(x3 ^ x0, 8)
94	vpaddd		%ymm1,%ymm0,%ymm0
95	vpxord		%ymm0,%ymm3,%ymm3
96	vprold		$8,%ymm3,%ymm3
97
98	# x2 += x3, x1 = rotl32(x1 ^ x2, 7)
99	vpaddd		%ymm3,%ymm2,%ymm2
100	vpxord		%ymm2,%ymm1,%ymm1
101	vprold		$7,%ymm1,%ymm1
102
103	# x1 = shuffle32(x1, MASK(2, 1, 0, 3))
104	vpshufd		$0x93,%ymm1,%ymm1
105	# x2 = shuffle32(x2, MASK(1, 0, 3, 2))
106	vpshufd		$0x4e,%ymm2,%ymm2
107	# x3 = shuffle32(x3, MASK(0, 3, 2, 1))
108	vpshufd		$0x39,%ymm3,%ymm3
109
110	sub		$2,%r8d
111	jnz		.Ldoubleround
112
113	# o0 = i0 ^ (x0 + s0)
114	vpaddd		%ymm8,%ymm0,%ymm7
115	cmp		$0x10,%rcx
116	jl		.Lxorpart2
117	vpxord		0x00(%rdx),%xmm7,%xmm6
118	vmovdqu		%xmm6,0x00(%rsi)
119	vextracti128	$1,%ymm7,%xmm0
120	# o1 = i1 ^ (x1 + s1)
121	vpaddd		%ymm9,%ymm1,%ymm7
122	cmp		$0x20,%rcx
123	jl		.Lxorpart2
124	vpxord		0x10(%rdx),%xmm7,%xmm6
125	vmovdqu		%xmm6,0x10(%rsi)
126	vextracti128	$1,%ymm7,%xmm1
127	# o2 = i2 ^ (x2 + s2)
128	vpaddd		%ymm10,%ymm2,%ymm7
129	cmp		$0x30,%rcx
130	jl		.Lxorpart2
131	vpxord		0x20(%rdx),%xmm7,%xmm6
132	vmovdqu		%xmm6,0x20(%rsi)
133	vextracti128	$1,%ymm7,%xmm2
134	# o3 = i3 ^ (x3 + s3)
135	vpaddd		%ymm11,%ymm3,%ymm7
136	cmp		$0x40,%rcx
137	jl		.Lxorpart2
138	vpxord		0x30(%rdx),%xmm7,%xmm6
139	vmovdqu		%xmm6,0x30(%rsi)
140	vextracti128	$1,%ymm7,%xmm3
141
142	# xor and write second block
143	vmovdqa		%xmm0,%xmm7
144	cmp		$0x50,%rcx
145	jl		.Lxorpart2
146	vpxord		0x40(%rdx),%xmm7,%xmm6
147	vmovdqu		%xmm6,0x40(%rsi)
148
149	vmovdqa		%xmm1,%xmm7
150	cmp		$0x60,%rcx
151	jl		.Lxorpart2
152	vpxord		0x50(%rdx),%xmm7,%xmm6
153	vmovdqu		%xmm6,0x50(%rsi)
154
155	vmovdqa		%xmm2,%xmm7
156	cmp		$0x70,%rcx
157	jl		.Lxorpart2
158	vpxord		0x60(%rdx),%xmm7,%xmm6
159	vmovdqu		%xmm6,0x60(%rsi)
160
161	vmovdqa		%xmm3,%xmm7
162	cmp		$0x80,%rcx
163	jl		.Lxorpart2
164	vpxord		0x70(%rdx),%xmm7,%xmm6
165	vmovdqu		%xmm6,0x70(%rsi)
166
167.Ldone2:
168	vzeroupper
169	ret
170
171.Lxorpart2:
172	# xor remaining bytes from partial register into output
173	mov		%rcx,%rax
174	and		$0xf,%rcx
175	jz		.Ldone8
176	mov		%rax,%r9
177	and		$~0xf,%r9
178
179	mov		$1,%rax
180	shld		%cl,%rax,%rax
181	sub		$1,%rax
182	kmovq		%rax,%k1
183
184	vmovdqu8	(%rdx,%r9),%xmm1{%k1}{z}
185	vpxord		%xmm7,%xmm1,%xmm1
186	vmovdqu8	%xmm1,(%rsi,%r9){%k1}
187
188	jmp		.Ldone2
189
190ENDPROC(chacha_2block_xor_avx512vl)
191
192ENTRY(chacha_4block_xor_avx512vl)
193	# %rdi: Input state matrix, s
194	# %rsi: up to 4 data blocks output, o
195	# %rdx: up to 4 data blocks input, i
196	# %rcx: input/output length in bytes
197	# %r8d: nrounds
198
199	# This function encrypts four ChaCha blocks by loading the state
200	# matrix four times across eight AVX registers. It performs matrix
201	# operations on four words in two matrices in parallel, sequentially
202	# to the operations on the four words of the other two matrices. The
203	# required word shuffling has a rather high latency, we can do the
204	# arithmetic on two matrix-pairs without much slowdown.
205
206	vzeroupper
207
208	# x0..3[0-4] = s0..3
209	vbroadcasti128	0x00(%rdi),%ymm0
210	vbroadcasti128	0x10(%rdi),%ymm1
211	vbroadcasti128	0x20(%rdi),%ymm2
212	vbroadcasti128	0x30(%rdi),%ymm3
213
214	vmovdqa		%ymm0,%ymm4
215	vmovdqa		%ymm1,%ymm5
216	vmovdqa		%ymm2,%ymm6
217	vmovdqa		%ymm3,%ymm7
218
219	vpaddd		CTR2BL(%rip),%ymm3,%ymm3
220	vpaddd		CTR4BL(%rip),%ymm7,%ymm7
221
222	vmovdqa		%ymm0,%ymm11
223	vmovdqa		%ymm1,%ymm12
224	vmovdqa		%ymm2,%ymm13
225	vmovdqa		%ymm3,%ymm14
226	vmovdqa		%ymm7,%ymm15
227
228.Ldoubleround4:
229
230	# x0 += x1, x3 = rotl32(x3 ^ x0, 16)
231	vpaddd		%ymm1,%ymm0,%ymm0
232	vpxord		%ymm0,%ymm3,%ymm3
233	vprold		$16,%ymm3,%ymm3
234
235	vpaddd		%ymm5,%ymm4,%ymm4
236	vpxord		%ymm4,%ymm7,%ymm7
237	vprold		$16,%ymm7,%ymm7
238
239	# x2 += x3, x1 = rotl32(x1 ^ x2, 12)
240	vpaddd		%ymm3,%ymm2,%ymm2
241	vpxord		%ymm2,%ymm1,%ymm1
242	vprold		$12,%ymm1,%ymm1
243
244	vpaddd		%ymm7,%ymm6,%ymm6
245	vpxord		%ymm6,%ymm5,%ymm5
246	vprold		$12,%ymm5,%ymm5
247
248	# x0 += x1, x3 = rotl32(x3 ^ x0, 8)
249	vpaddd		%ymm1,%ymm0,%ymm0
250	vpxord		%ymm0,%ymm3,%ymm3
251	vprold		$8,%ymm3,%ymm3
252
253	vpaddd		%ymm5,%ymm4,%ymm4
254	vpxord		%ymm4,%ymm7,%ymm7
255	vprold		$8,%ymm7,%ymm7
256
257	# x2 += x3, x1 = rotl32(x1 ^ x2, 7)
258	vpaddd		%ymm3,%ymm2,%ymm2
259	vpxord		%ymm2,%ymm1,%ymm1
260	vprold		$7,%ymm1,%ymm1
261
262	vpaddd		%ymm7,%ymm6,%ymm6
263	vpxord		%ymm6,%ymm5,%ymm5
264	vprold		$7,%ymm5,%ymm5
265
266	# x1 = shuffle32(x1, MASK(0, 3, 2, 1))
267	vpshufd		$0x39,%ymm1,%ymm1
268	vpshufd		$0x39,%ymm5,%ymm5
269	# x2 = shuffle32(x2, MASK(1, 0, 3, 2))
270	vpshufd		$0x4e,%ymm2,%ymm2
271	vpshufd		$0x4e,%ymm6,%ymm6
272	# x3 = shuffle32(x3, MASK(2, 1, 0, 3))
273	vpshufd		$0x93,%ymm3,%ymm3
274	vpshufd		$0x93,%ymm7,%ymm7
275
276	# x0 += x1, x3 = rotl32(x3 ^ x0, 16)
277	vpaddd		%ymm1,%ymm0,%ymm0
278	vpxord		%ymm0,%ymm3,%ymm3
279	vprold		$16,%ymm3,%ymm3
280
281	vpaddd		%ymm5,%ymm4,%ymm4
282	vpxord		%ymm4,%ymm7,%ymm7
283	vprold		$16,%ymm7,%ymm7
284
285	# x2 += x3, x1 = rotl32(x1 ^ x2, 12)
286	vpaddd		%ymm3,%ymm2,%ymm2
287	vpxord		%ymm2,%ymm1,%ymm1
288	vprold		$12,%ymm1,%ymm1
289
290	vpaddd		%ymm7,%ymm6,%ymm6
291	vpxord		%ymm6,%ymm5,%ymm5
292	vprold		$12,%ymm5,%ymm5
293
294	# x0 += x1, x3 = rotl32(x3 ^ x0, 8)
295	vpaddd		%ymm1,%ymm0,%ymm0
296	vpxord		%ymm0,%ymm3,%ymm3
297	vprold		$8,%ymm3,%ymm3
298
299	vpaddd		%ymm5,%ymm4,%ymm4
300	vpxord		%ymm4,%ymm7,%ymm7
301	vprold		$8,%ymm7,%ymm7
302
303	# x2 += x3, x1 = rotl32(x1 ^ x2, 7)
304	vpaddd		%ymm3,%ymm2,%ymm2
305	vpxord		%ymm2,%ymm1,%ymm1
306	vprold		$7,%ymm1,%ymm1
307
308	vpaddd		%ymm7,%ymm6,%ymm6
309	vpxord		%ymm6,%ymm5,%ymm5
310	vprold		$7,%ymm5,%ymm5
311
312	# x1 = shuffle32(x1, MASK(2, 1, 0, 3))
313	vpshufd		$0x93,%ymm1,%ymm1
314	vpshufd		$0x93,%ymm5,%ymm5
315	# x2 = shuffle32(x2, MASK(1, 0, 3, 2))
316	vpshufd		$0x4e,%ymm2,%ymm2
317	vpshufd		$0x4e,%ymm6,%ymm6
318	# x3 = shuffle32(x3, MASK(0, 3, 2, 1))
319	vpshufd		$0x39,%ymm3,%ymm3
320	vpshufd		$0x39,%ymm7,%ymm7
321
322	sub		$2,%r8d
323	jnz		.Ldoubleround4
324
325	# o0 = i0 ^ (x0 + s0), first block
326	vpaddd		%ymm11,%ymm0,%ymm10
327	cmp		$0x10,%rcx
328	jl		.Lxorpart4
329	vpxord		0x00(%rdx),%xmm10,%xmm9
330	vmovdqu		%xmm9,0x00(%rsi)
331	vextracti128	$1,%ymm10,%xmm0
332	# o1 = i1 ^ (x1 + s1), first block
333	vpaddd		%ymm12,%ymm1,%ymm10
334	cmp		$0x20,%rcx
335	jl		.Lxorpart4
336	vpxord		0x10(%rdx),%xmm10,%xmm9
337	vmovdqu		%xmm9,0x10(%rsi)
338	vextracti128	$1,%ymm10,%xmm1
339	# o2 = i2 ^ (x2 + s2), first block
340	vpaddd		%ymm13,%ymm2,%ymm10
341	cmp		$0x30,%rcx
342	jl		.Lxorpart4
343	vpxord		0x20(%rdx),%xmm10,%xmm9
344	vmovdqu		%xmm9,0x20(%rsi)
345	vextracti128	$1,%ymm10,%xmm2
346	# o3 = i3 ^ (x3 + s3), first block
347	vpaddd		%ymm14,%ymm3,%ymm10
348	cmp		$0x40,%rcx
349	jl		.Lxorpart4
350	vpxord		0x30(%rdx),%xmm10,%xmm9
351	vmovdqu		%xmm9,0x30(%rsi)
352	vextracti128	$1,%ymm10,%xmm3
353
354	# xor and write second block
355	vmovdqa		%xmm0,%xmm10
356	cmp		$0x50,%rcx
357	jl		.Lxorpart4
358	vpxord		0x40(%rdx),%xmm10,%xmm9
359	vmovdqu		%xmm9,0x40(%rsi)
360
361	vmovdqa		%xmm1,%xmm10
362	cmp		$0x60,%rcx
363	jl		.Lxorpart4
364	vpxord		0x50(%rdx),%xmm10,%xmm9
365	vmovdqu		%xmm9,0x50(%rsi)
366
367	vmovdqa		%xmm2,%xmm10
368	cmp		$0x70,%rcx
369	jl		.Lxorpart4
370	vpxord		0x60(%rdx),%xmm10,%xmm9
371	vmovdqu		%xmm9,0x60(%rsi)
372
373	vmovdqa		%xmm3,%xmm10
374	cmp		$0x80,%rcx
375	jl		.Lxorpart4
376	vpxord		0x70(%rdx),%xmm10,%xmm9
377	vmovdqu		%xmm9,0x70(%rsi)
378
379	# o0 = i0 ^ (x0 + s0), third block
380	vpaddd		%ymm11,%ymm4,%ymm10
381	cmp		$0x90,%rcx
382	jl		.Lxorpart4
383	vpxord		0x80(%rdx),%xmm10,%xmm9
384	vmovdqu		%xmm9,0x80(%rsi)
385	vextracti128	$1,%ymm10,%xmm4
386	# o1 = i1 ^ (x1 + s1), third block
387	vpaddd		%ymm12,%ymm5,%ymm10
388	cmp		$0xa0,%rcx
389	jl		.Lxorpart4
390	vpxord		0x90(%rdx),%xmm10,%xmm9
391	vmovdqu		%xmm9,0x90(%rsi)
392	vextracti128	$1,%ymm10,%xmm5
393	# o2 = i2 ^ (x2 + s2), third block
394	vpaddd		%ymm13,%ymm6,%ymm10
395	cmp		$0xb0,%rcx
396	jl		.Lxorpart4
397	vpxord		0xa0(%rdx),%xmm10,%xmm9
398	vmovdqu		%xmm9,0xa0(%rsi)
399	vextracti128	$1,%ymm10,%xmm6
400	# o3 = i3 ^ (x3 + s3), third block
401	vpaddd		%ymm15,%ymm7,%ymm10
402	cmp		$0xc0,%rcx
403	jl		.Lxorpart4
404	vpxord		0xb0(%rdx),%xmm10,%xmm9
405	vmovdqu		%xmm9,0xb0(%rsi)
406	vextracti128	$1,%ymm10,%xmm7
407
408	# xor and write fourth block
409	vmovdqa		%xmm4,%xmm10
410	cmp		$0xd0,%rcx
411	jl		.Lxorpart4
412	vpxord		0xc0(%rdx),%xmm10,%xmm9
413	vmovdqu		%xmm9,0xc0(%rsi)
414
415	vmovdqa		%xmm5,%xmm10
416	cmp		$0xe0,%rcx
417	jl		.Lxorpart4
418	vpxord		0xd0(%rdx),%xmm10,%xmm9
419	vmovdqu		%xmm9,0xd0(%rsi)
420
421	vmovdqa		%xmm6,%xmm10
422	cmp		$0xf0,%rcx
423	jl		.Lxorpart4
424	vpxord		0xe0(%rdx),%xmm10,%xmm9
425	vmovdqu		%xmm9,0xe0(%rsi)
426
427	vmovdqa		%xmm7,%xmm10
428	cmp		$0x100,%rcx
429	jl		.Lxorpart4
430	vpxord		0xf0(%rdx),%xmm10,%xmm9
431	vmovdqu		%xmm9,0xf0(%rsi)
432
433.Ldone4:
434	vzeroupper
435	ret
436
437.Lxorpart4:
438	# xor remaining bytes from partial register into output
439	mov		%rcx,%rax
440	and		$0xf,%rcx
441	jz		.Ldone8
442	mov		%rax,%r9
443	and		$~0xf,%r9
444
445	mov		$1,%rax
446	shld		%cl,%rax,%rax
447	sub		$1,%rax
448	kmovq		%rax,%k1
449
450	vmovdqu8	(%rdx,%r9),%xmm1{%k1}{z}
451	vpxord		%xmm10,%xmm1,%xmm1
452	vmovdqu8	%xmm1,(%rsi,%r9){%k1}
453
454	jmp		.Ldone4
455
456ENDPROC(chacha_4block_xor_avx512vl)
457
458ENTRY(chacha_8block_xor_avx512vl)
459	# %rdi: Input state matrix, s
460	# %rsi: up to 8 data blocks output, o
461	# %rdx: up to 8 data blocks input, i
462	# %rcx: input/output length in bytes
463	# %r8d: nrounds
464
465	# This function encrypts eight consecutive ChaCha blocks by loading
466	# the state matrix in AVX registers eight times. Compared to AVX2, this
467	# mostly benefits from the new rotate instructions in VL and the
468	# additional registers.
469
470	vzeroupper
471
472	# x0..15[0-7] = s[0..15]
473	vpbroadcastd	0x00(%rdi),%ymm0
474	vpbroadcastd	0x04(%rdi),%ymm1
475	vpbroadcastd	0x08(%rdi),%ymm2
476	vpbroadcastd	0x0c(%rdi),%ymm3
477	vpbroadcastd	0x10(%rdi),%ymm4
478	vpbroadcastd	0x14(%rdi),%ymm5
479	vpbroadcastd	0x18(%rdi),%ymm6
480	vpbroadcastd	0x1c(%rdi),%ymm7
481	vpbroadcastd	0x20(%rdi),%ymm8
482	vpbroadcastd	0x24(%rdi),%ymm9
483	vpbroadcastd	0x28(%rdi),%ymm10
484	vpbroadcastd	0x2c(%rdi),%ymm11
485	vpbroadcastd	0x30(%rdi),%ymm12
486	vpbroadcastd	0x34(%rdi),%ymm13
487	vpbroadcastd	0x38(%rdi),%ymm14
488	vpbroadcastd	0x3c(%rdi),%ymm15
489
490	# x12 += counter values 0-3
491	vpaddd		CTR8BL(%rip),%ymm12,%ymm12
492
493	vmovdqa64	%ymm0,%ymm16
494	vmovdqa64	%ymm1,%ymm17
495	vmovdqa64	%ymm2,%ymm18
496	vmovdqa64	%ymm3,%ymm19
497	vmovdqa64	%ymm4,%ymm20
498	vmovdqa64	%ymm5,%ymm21
499	vmovdqa64	%ymm6,%ymm22
500	vmovdqa64	%ymm7,%ymm23
501	vmovdqa64	%ymm8,%ymm24
502	vmovdqa64	%ymm9,%ymm25
503	vmovdqa64	%ymm10,%ymm26
504	vmovdqa64	%ymm11,%ymm27
505	vmovdqa64	%ymm12,%ymm28
506	vmovdqa64	%ymm13,%ymm29
507	vmovdqa64	%ymm14,%ymm30
508	vmovdqa64	%ymm15,%ymm31
509
510.Ldoubleround8:
511	# x0 += x4, x12 = rotl32(x12 ^ x0, 16)
512	vpaddd		%ymm0,%ymm4,%ymm0
513	vpxord		%ymm0,%ymm12,%ymm12
514	vprold		$16,%ymm12,%ymm12
515	# x1 += x5, x13 = rotl32(x13 ^ x1, 16)
516	vpaddd		%ymm1,%ymm5,%ymm1
517	vpxord		%ymm1,%ymm13,%ymm13
518	vprold		$16,%ymm13,%ymm13
519	# x2 += x6, x14 = rotl32(x14 ^ x2, 16)
520	vpaddd		%ymm2,%ymm6,%ymm2
521	vpxord		%ymm2,%ymm14,%ymm14
522	vprold		$16,%ymm14,%ymm14
523	# x3 += x7, x15 = rotl32(x15 ^ x3, 16)
524	vpaddd		%ymm3,%ymm7,%ymm3
525	vpxord		%ymm3,%ymm15,%ymm15
526	vprold		$16,%ymm15,%ymm15
527
528	# x8 += x12, x4 = rotl32(x4 ^ x8, 12)
529	vpaddd		%ymm12,%ymm8,%ymm8
530	vpxord		%ymm8,%ymm4,%ymm4
531	vprold		$12,%ymm4,%ymm4
532	# x9 += x13, x5 = rotl32(x5 ^ x9, 12)
533	vpaddd		%ymm13,%ymm9,%ymm9
534	vpxord		%ymm9,%ymm5,%ymm5
535	vprold		$12,%ymm5,%ymm5
536	# x10 += x14, x6 = rotl32(x6 ^ x10, 12)
537	vpaddd		%ymm14,%ymm10,%ymm10
538	vpxord		%ymm10,%ymm6,%ymm6
539	vprold		$12,%ymm6,%ymm6
540	# x11 += x15, x7 = rotl32(x7 ^ x11, 12)
541	vpaddd		%ymm15,%ymm11,%ymm11
542	vpxord		%ymm11,%ymm7,%ymm7
543	vprold		$12,%ymm7,%ymm7
544
545	# x0 += x4, x12 = rotl32(x12 ^ x0, 8)
546	vpaddd		%ymm0,%ymm4,%ymm0
547	vpxord		%ymm0,%ymm12,%ymm12
548	vprold		$8,%ymm12,%ymm12
549	# x1 += x5, x13 = rotl32(x13 ^ x1, 8)
550	vpaddd		%ymm1,%ymm5,%ymm1
551	vpxord		%ymm1,%ymm13,%ymm13
552	vprold		$8,%ymm13,%ymm13
553	# x2 += x6, x14 = rotl32(x14 ^ x2, 8)
554	vpaddd		%ymm2,%ymm6,%ymm2
555	vpxord		%ymm2,%ymm14,%ymm14
556	vprold		$8,%ymm14,%ymm14
557	# x3 += x7, x15 = rotl32(x15 ^ x3, 8)
558	vpaddd		%ymm3,%ymm7,%ymm3
559	vpxord		%ymm3,%ymm15,%ymm15
560	vprold		$8,%ymm15,%ymm15
561
562	# x8 += x12, x4 = rotl32(x4 ^ x8, 7)
563	vpaddd		%ymm12,%ymm8,%ymm8
564	vpxord		%ymm8,%ymm4,%ymm4
565	vprold		$7,%ymm4,%ymm4
566	# x9 += x13, x5 = rotl32(x5 ^ x9, 7)
567	vpaddd		%ymm13,%ymm9,%ymm9
568	vpxord		%ymm9,%ymm5,%ymm5
569	vprold		$7,%ymm5,%ymm5
570	# x10 += x14, x6 = rotl32(x6 ^ x10, 7)
571	vpaddd		%ymm14,%ymm10,%ymm10
572	vpxord		%ymm10,%ymm6,%ymm6
573	vprold		$7,%ymm6,%ymm6
574	# x11 += x15, x7 = rotl32(x7 ^ x11, 7)
575	vpaddd		%ymm15,%ymm11,%ymm11
576	vpxord		%ymm11,%ymm7,%ymm7
577	vprold		$7,%ymm7,%ymm7
578
579	# x0 += x5, x15 = rotl32(x15 ^ x0, 16)
580	vpaddd		%ymm0,%ymm5,%ymm0
581	vpxord		%ymm0,%ymm15,%ymm15
582	vprold		$16,%ymm15,%ymm15
583	# x1 += x6, x12 = rotl32(x12 ^ x1, 16)
584	vpaddd		%ymm1,%ymm6,%ymm1
585	vpxord		%ymm1,%ymm12,%ymm12
586	vprold		$16,%ymm12,%ymm12
587	# x2 += x7, x13 = rotl32(x13 ^ x2, 16)
588	vpaddd		%ymm2,%ymm7,%ymm2
589	vpxord		%ymm2,%ymm13,%ymm13
590	vprold		$16,%ymm13,%ymm13
591	# x3 += x4, x14 = rotl32(x14 ^ x3, 16)
592	vpaddd		%ymm3,%ymm4,%ymm3
593	vpxord		%ymm3,%ymm14,%ymm14
594	vprold		$16,%ymm14,%ymm14
595
596	# x10 += x15, x5 = rotl32(x5 ^ x10, 12)
597	vpaddd		%ymm15,%ymm10,%ymm10
598	vpxord		%ymm10,%ymm5,%ymm5
599	vprold		$12,%ymm5,%ymm5
600	# x11 += x12, x6 = rotl32(x6 ^ x11, 12)
601	vpaddd		%ymm12,%ymm11,%ymm11
602	vpxord		%ymm11,%ymm6,%ymm6
603	vprold		$12,%ymm6,%ymm6
604	# x8 += x13, x7 = rotl32(x7 ^ x8, 12)
605	vpaddd		%ymm13,%ymm8,%ymm8
606	vpxord		%ymm8,%ymm7,%ymm7
607	vprold		$12,%ymm7,%ymm7
608	# x9 += x14, x4 = rotl32(x4 ^ x9, 12)
609	vpaddd		%ymm14,%ymm9,%ymm9
610	vpxord		%ymm9,%ymm4,%ymm4
611	vprold		$12,%ymm4,%ymm4
612
613	# x0 += x5, x15 = rotl32(x15 ^ x0, 8)
614	vpaddd		%ymm0,%ymm5,%ymm0
615	vpxord		%ymm0,%ymm15,%ymm15
616	vprold		$8,%ymm15,%ymm15
617	# x1 += x6, x12 = rotl32(x12 ^ x1, 8)
618	vpaddd		%ymm1,%ymm6,%ymm1
619	vpxord		%ymm1,%ymm12,%ymm12
620	vprold		$8,%ymm12,%ymm12
621	# x2 += x7, x13 = rotl32(x13 ^ x2, 8)
622	vpaddd		%ymm2,%ymm7,%ymm2
623	vpxord		%ymm2,%ymm13,%ymm13
624	vprold		$8,%ymm13,%ymm13
625	# x3 += x4, x14 = rotl32(x14 ^ x3, 8)
626	vpaddd		%ymm3,%ymm4,%ymm3
627	vpxord		%ymm3,%ymm14,%ymm14
628	vprold		$8,%ymm14,%ymm14
629
630	# x10 += x15, x5 = rotl32(x5 ^ x10, 7)
631	vpaddd		%ymm15,%ymm10,%ymm10
632	vpxord		%ymm10,%ymm5,%ymm5
633	vprold		$7,%ymm5,%ymm5
634	# x11 += x12, x6 = rotl32(x6 ^ x11, 7)
635	vpaddd		%ymm12,%ymm11,%ymm11
636	vpxord		%ymm11,%ymm6,%ymm6
637	vprold		$7,%ymm6,%ymm6
638	# x8 += x13, x7 = rotl32(x7 ^ x8, 7)
639	vpaddd		%ymm13,%ymm8,%ymm8
640	vpxord		%ymm8,%ymm7,%ymm7
641	vprold		$7,%ymm7,%ymm7
642	# x9 += x14, x4 = rotl32(x4 ^ x9, 7)
643	vpaddd		%ymm14,%ymm9,%ymm9
644	vpxord		%ymm9,%ymm4,%ymm4
645	vprold		$7,%ymm4,%ymm4
646
647	sub		$2,%r8d
648	jnz		.Ldoubleround8
649
650	# x0..15[0-3] += s[0..15]
651	vpaddd		%ymm16,%ymm0,%ymm0
652	vpaddd		%ymm17,%ymm1,%ymm1
653	vpaddd		%ymm18,%ymm2,%ymm2
654	vpaddd		%ymm19,%ymm3,%ymm3
655	vpaddd		%ymm20,%ymm4,%ymm4
656	vpaddd		%ymm21,%ymm5,%ymm5
657	vpaddd		%ymm22,%ymm6,%ymm6
658	vpaddd		%ymm23,%ymm7,%ymm7
659	vpaddd		%ymm24,%ymm8,%ymm8
660	vpaddd		%ymm25,%ymm9,%ymm9
661	vpaddd		%ymm26,%ymm10,%ymm10
662	vpaddd		%ymm27,%ymm11,%ymm11
663	vpaddd		%ymm28,%ymm12,%ymm12
664	vpaddd		%ymm29,%ymm13,%ymm13
665	vpaddd		%ymm30,%ymm14,%ymm14
666	vpaddd		%ymm31,%ymm15,%ymm15
667
668	# interleave 32-bit words in state n, n+1
669	vpunpckldq	%ymm1,%ymm0,%ymm16
670	vpunpckhdq	%ymm1,%ymm0,%ymm17
671	vpunpckldq	%ymm3,%ymm2,%ymm18
672	vpunpckhdq	%ymm3,%ymm2,%ymm19
673	vpunpckldq	%ymm5,%ymm4,%ymm20
674	vpunpckhdq	%ymm5,%ymm4,%ymm21
675	vpunpckldq	%ymm7,%ymm6,%ymm22
676	vpunpckhdq	%ymm7,%ymm6,%ymm23
677	vpunpckldq	%ymm9,%ymm8,%ymm24
678	vpunpckhdq	%ymm9,%ymm8,%ymm25
679	vpunpckldq	%ymm11,%ymm10,%ymm26
680	vpunpckhdq	%ymm11,%ymm10,%ymm27
681	vpunpckldq	%ymm13,%ymm12,%ymm28
682	vpunpckhdq	%ymm13,%ymm12,%ymm29
683	vpunpckldq	%ymm15,%ymm14,%ymm30
684	vpunpckhdq	%ymm15,%ymm14,%ymm31
685
686	# interleave 64-bit words in state n, n+2
687	vpunpcklqdq	%ymm18,%ymm16,%ymm0
688	vpunpcklqdq	%ymm19,%ymm17,%ymm1
689	vpunpckhqdq	%ymm18,%ymm16,%ymm2
690	vpunpckhqdq	%ymm19,%ymm17,%ymm3
691	vpunpcklqdq	%ymm22,%ymm20,%ymm4
692	vpunpcklqdq	%ymm23,%ymm21,%ymm5
693	vpunpckhqdq	%ymm22,%ymm20,%ymm6
694	vpunpckhqdq	%ymm23,%ymm21,%ymm7
695	vpunpcklqdq	%ymm26,%ymm24,%ymm8
696	vpunpcklqdq	%ymm27,%ymm25,%ymm9
697	vpunpckhqdq	%ymm26,%ymm24,%ymm10
698	vpunpckhqdq	%ymm27,%ymm25,%ymm11
699	vpunpcklqdq	%ymm30,%ymm28,%ymm12
700	vpunpcklqdq	%ymm31,%ymm29,%ymm13
701	vpunpckhqdq	%ymm30,%ymm28,%ymm14
702	vpunpckhqdq	%ymm31,%ymm29,%ymm15
703
704	# interleave 128-bit words in state n, n+4
705	# xor/write first four blocks
706	vmovdqa64	%ymm0,%ymm16
707	vperm2i128	$0x20,%ymm4,%ymm0,%ymm0
708	cmp		$0x0020,%rcx
709	jl		.Lxorpart8
710	vpxord		0x0000(%rdx),%ymm0,%ymm0
711	vmovdqu64	%ymm0,0x0000(%rsi)
712	vmovdqa64	%ymm16,%ymm0
713	vperm2i128	$0x31,%ymm4,%ymm0,%ymm4
714
715	vperm2i128	$0x20,%ymm12,%ymm8,%ymm0
716	cmp		$0x0040,%rcx
717	jl		.Lxorpart8
718	vpxord		0x0020(%rdx),%ymm0,%ymm0
719	vmovdqu64	%ymm0,0x0020(%rsi)
720	vperm2i128	$0x31,%ymm12,%ymm8,%ymm12
721
722	vperm2i128	$0x20,%ymm6,%ymm2,%ymm0
723	cmp		$0x0060,%rcx
724	jl		.Lxorpart8
725	vpxord		0x0040(%rdx),%ymm0,%ymm0
726	vmovdqu64	%ymm0,0x0040(%rsi)
727	vperm2i128	$0x31,%ymm6,%ymm2,%ymm6
728
729	vperm2i128	$0x20,%ymm14,%ymm10,%ymm0
730	cmp		$0x0080,%rcx
731	jl		.Lxorpart8
732	vpxord		0x0060(%rdx),%ymm0,%ymm0
733	vmovdqu64	%ymm0,0x0060(%rsi)
734	vperm2i128	$0x31,%ymm14,%ymm10,%ymm14
735
736	vperm2i128	$0x20,%ymm5,%ymm1,%ymm0
737	cmp		$0x00a0,%rcx
738	jl		.Lxorpart8
739	vpxord		0x0080(%rdx),%ymm0,%ymm0
740	vmovdqu64	%ymm0,0x0080(%rsi)
741	vperm2i128	$0x31,%ymm5,%ymm1,%ymm5
742
743	vperm2i128	$0x20,%ymm13,%ymm9,%ymm0
744	cmp		$0x00c0,%rcx
745	jl		.Lxorpart8
746	vpxord		0x00a0(%rdx),%ymm0,%ymm0
747	vmovdqu64	%ymm0,0x00a0(%rsi)
748	vperm2i128	$0x31,%ymm13,%ymm9,%ymm13
749
750	vperm2i128	$0x20,%ymm7,%ymm3,%ymm0
751	cmp		$0x00e0,%rcx
752	jl		.Lxorpart8
753	vpxord		0x00c0(%rdx),%ymm0,%ymm0
754	vmovdqu64	%ymm0,0x00c0(%rsi)
755	vperm2i128	$0x31,%ymm7,%ymm3,%ymm7
756
757	vperm2i128	$0x20,%ymm15,%ymm11,%ymm0
758	cmp		$0x0100,%rcx
759	jl		.Lxorpart8
760	vpxord		0x00e0(%rdx),%ymm0,%ymm0
761	vmovdqu64	%ymm0,0x00e0(%rsi)
762	vperm2i128	$0x31,%ymm15,%ymm11,%ymm15
763
764	# xor remaining blocks, write to output
765	vmovdqa64	%ymm4,%ymm0
766	cmp		$0x0120,%rcx
767	jl		.Lxorpart8
768	vpxord		0x0100(%rdx),%ymm0,%ymm0
769	vmovdqu64	%ymm0,0x0100(%rsi)
770
771	vmovdqa64	%ymm12,%ymm0
772	cmp		$0x0140,%rcx
773	jl		.Lxorpart8
774	vpxord		0x0120(%rdx),%ymm0,%ymm0
775	vmovdqu64	%ymm0,0x0120(%rsi)
776
777	vmovdqa64	%ymm6,%ymm0
778	cmp		$0x0160,%rcx
779	jl		.Lxorpart8
780	vpxord		0x0140(%rdx),%ymm0,%ymm0
781	vmovdqu64	%ymm0,0x0140(%rsi)
782
783	vmovdqa64	%ymm14,%ymm0
784	cmp		$0x0180,%rcx
785	jl		.Lxorpart8
786	vpxord		0x0160(%rdx),%ymm0,%ymm0
787	vmovdqu64	%ymm0,0x0160(%rsi)
788
789	vmovdqa64	%ymm5,%ymm0
790	cmp		$0x01a0,%rcx
791	jl		.Lxorpart8
792	vpxord		0x0180(%rdx),%ymm0,%ymm0
793	vmovdqu64	%ymm0,0x0180(%rsi)
794
795	vmovdqa64	%ymm13,%ymm0
796	cmp		$0x01c0,%rcx
797	jl		.Lxorpart8
798	vpxord		0x01a0(%rdx),%ymm0,%ymm0
799	vmovdqu64	%ymm0,0x01a0(%rsi)
800
801	vmovdqa64	%ymm7,%ymm0
802	cmp		$0x01e0,%rcx
803	jl		.Lxorpart8
804	vpxord		0x01c0(%rdx),%ymm0,%ymm0
805	vmovdqu64	%ymm0,0x01c0(%rsi)
806
807	vmovdqa64	%ymm15,%ymm0
808	cmp		$0x0200,%rcx
809	jl		.Lxorpart8
810	vpxord		0x01e0(%rdx),%ymm0,%ymm0
811	vmovdqu64	%ymm0,0x01e0(%rsi)
812
813.Ldone8:
814	vzeroupper
815	ret
816
817.Lxorpart8:
818	# xor remaining bytes from partial register into output
819	mov		%rcx,%rax
820	and		$0x1f,%rcx
821	jz		.Ldone8
822	mov		%rax,%r9
823	and		$~0x1f,%r9
824
825	mov		$1,%rax
826	shld		%cl,%rax,%rax
827	sub		$1,%rax
828	kmovq		%rax,%k1
829
830	vmovdqu8	(%rdx,%r9),%ymm1{%k1}{z}
831	vpxord		%ymm0,%ymm1,%ymm1
832	vmovdqu8	%ymm1,(%rsi,%r9){%k1}
833
834	jmp		.Ldone8
835
836ENDPROC(chacha_8block_xor_avx512vl)
837