1/***************************************************************************
2*   Copyright (C) 2006 by Joachim Fritschi, <jfritschi@freenet.de>        *
3*                                                                         *
4*   This program is free software; you can redistribute it and/or modify  *
5*   it under the terms of the GNU General Public License as published by  *
6*   the Free Software Foundation; either version 2 of the License, or     *
7*   (at your option) any later version.                                   *
8*                                                                         *
9*   This program is distributed in the hope that it will be useful,       *
10*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12*   GNU General Public License for more details.                          *
13*                                                                         *
14*   You should have received a copy of the GNU General Public License     *
15*   along with this program; if not, write to the                         *
16*   Free Software Foundation, Inc.,                                       *
17*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18***************************************************************************/
19
20.file "twofish-x86_64-asm.S"
21.text
22
23#include <linux/linkage.h>
24#include <asm/asm-offsets.h>
25
26#define a_offset	0
27#define b_offset	4
28#define c_offset	8
29#define d_offset	12
30
31/* Structure of the crypto context struct*/
32
33#define s0	0	/* S0 Array 256 Words each */
34#define s1	1024	/* S1 Array */
35#define s2	2048	/* S2 Array */
36#define s3	3072	/* S3 Array */
37#define w	4096	/* 8 whitening keys (word) */
38#define k	4128	/* key 1-32 ( word ) */
39
40/* define a few register aliases to allow macro substitution */
41
42#define R0     %rax
43#define R0D    %eax
44#define R0B    %al
45#define R0H    %ah
46
47#define R1     %rbx
48#define R1D    %ebx
49#define R1B    %bl
50#define R1H    %bh
51
52#define R2     %rcx
53#define R2D    %ecx
54#define R2B    %cl
55#define R2H    %ch
56
57#define R3     %rdx
58#define R3D    %edx
59#define R3B    %dl
60#define R3H    %dh
61
62
63/* performs input whitening */
64#define input_whitening(src,context,offset)\
65	xor	w+offset(context),	src;
66
67/* performs input whitening */
68#define output_whitening(src,context,offset)\
69	xor	w+16+offset(context),	src;
70
71
72/*
73 * a input register containing a (rotated 16)
74 * b input register containing b
75 * c input register containing c
76 * d input register containing d (already rol $1)
77 * operations on a and b are interleaved to increase performance
78 */
79#define encrypt_round(a,b,c,d,round)\
80	movzx	b ## B,		%edi;\
81	mov	s1(%r11,%rdi,4),%r8d;\
82	movzx	a ## B,		%edi;\
83	mov	s2(%r11,%rdi,4),%r9d;\
84	movzx	b ## H,		%edi;\
85	ror	$16,		b ## D;\
86	xor	s2(%r11,%rdi,4),%r8d;\
87	movzx	a ## H,		%edi;\
88	ror	$16,		a ## D;\
89	xor	s3(%r11,%rdi,4),%r9d;\
90	movzx	b ## B,		%edi;\
91	xor	s3(%r11,%rdi,4),%r8d;\
92	movzx	a ## B,		%edi;\
93	xor	(%r11,%rdi,4),	%r9d;\
94	movzx	b ## H,		%edi;\
95	ror	$15,		b ## D;\
96	xor	(%r11,%rdi,4),	%r8d;\
97	movzx	a ## H,		%edi;\
98	xor	s1(%r11,%rdi,4),%r9d;\
99	add	%r8d,		%r9d;\
100	add	%r9d,		%r8d;\
101	add	k+round(%r11),	%r9d;\
102	xor	%r9d,		c ## D;\
103	rol	$15,		c ## D;\
104	add	k+4+round(%r11),%r8d;\
105	xor	%r8d,		d ## D;
106
107/*
108 * a input register containing a(rotated 16)
109 * b input register containing b
110 * c input register containing c
111 * d input register containing d (already rol $1)
112 * operations on a and b are interleaved to increase performance
113 * during the round a and b are prepared for the output whitening
114 */
115#define encrypt_last_round(a,b,c,d,round)\
116	mov	b ## D,		%r10d;\
117	shl	$32,		%r10;\
118	movzx	b ## B,		%edi;\
119	mov	s1(%r11,%rdi,4),%r8d;\
120	movzx	a ## B,		%edi;\
121	mov	s2(%r11,%rdi,4),%r9d;\
122	movzx	b ## H,		%edi;\
123	ror	$16,		b ## D;\
124	xor	s2(%r11,%rdi,4),%r8d;\
125	movzx	a ## H,		%edi;\
126	ror	$16,		a ## D;\
127	xor	s3(%r11,%rdi,4),%r9d;\
128	movzx	b ## B,		%edi;\
129	xor	s3(%r11,%rdi,4),%r8d;\
130	movzx	a ## B,		%edi;\
131	xor	(%r11,%rdi,4),	%r9d;\
132	xor	a,		%r10;\
133	movzx	b ## H,		%edi;\
134	xor	(%r11,%rdi,4),	%r8d;\
135	movzx	a ## H,		%edi;\
136	xor	s1(%r11,%rdi,4),%r9d;\
137	add	%r8d,		%r9d;\
138	add	%r9d,		%r8d;\
139	add	k+round(%r11),	%r9d;\
140	xor	%r9d,		c ## D;\
141	ror	$1,		c ## D;\
142	add	k+4+round(%r11),%r8d;\
143	xor	%r8d,		d ## D
144
145/*
146 * a input register containing a
147 * b input register containing b (rotated 16)
148 * c input register containing c (already rol $1)
149 * d input register containing d
150 * operations on a and b are interleaved to increase performance
151 */
152#define decrypt_round(a,b,c,d,round)\
153	movzx	a ## B,		%edi;\
154	mov	(%r11,%rdi,4),	%r9d;\
155	movzx	b ## B,		%edi;\
156	mov	s3(%r11,%rdi,4),%r8d;\
157	movzx	a ## H,		%edi;\
158	ror	$16,		a ## D;\
159	xor	s1(%r11,%rdi,4),%r9d;\
160	movzx	b ## H,		%edi;\
161	ror	$16,		b ## D;\
162	xor	(%r11,%rdi,4),	%r8d;\
163	movzx	a ## B,		%edi;\
164	xor	s2(%r11,%rdi,4),%r9d;\
165	movzx	b ## B,		%edi;\
166	xor	s1(%r11,%rdi,4),%r8d;\
167	movzx	a ## H,		%edi;\
168	ror	$15,		a ## D;\
169	xor	s3(%r11,%rdi,4),%r9d;\
170	movzx	b ## H,		%edi;\
171	xor	s2(%r11,%rdi,4),%r8d;\
172	add	%r8d,		%r9d;\
173	add	%r9d,		%r8d;\
174	add	k+round(%r11),	%r9d;\
175	xor	%r9d,		c ## D;\
176	add	k+4+round(%r11),%r8d;\
177	xor	%r8d,		d ## D;\
178	rol	$15,		d ## D;
179
180/*
181 * a input register containing a
182 * b input register containing b
183 * c input register containing c (already rol $1)
184 * d input register containing d
185 * operations on a and b are interleaved to increase performance
186 * during the round a and b are prepared for the output whitening
187 */
188#define decrypt_last_round(a,b,c,d,round)\
189	movzx	a ## B,		%edi;\
190	mov	(%r11,%rdi,4),	%r9d;\
191	movzx	b ## B,		%edi;\
192	mov	s3(%r11,%rdi,4),%r8d;\
193	movzx	b ## H,		%edi;\
194	ror	$16,		b ## D;\
195	xor	(%r11,%rdi,4),	%r8d;\
196	movzx	a ## H,		%edi;\
197	mov	b ## D,		%r10d;\
198	shl	$32,		%r10;\
199	xor	a,		%r10;\
200	ror	$16,		a ## D;\
201	xor	s1(%r11,%rdi,4),%r9d;\
202	movzx	b ## B,		%edi;\
203	xor	s1(%r11,%rdi,4),%r8d;\
204	movzx	a ## B,		%edi;\
205	xor	s2(%r11,%rdi,4),%r9d;\
206	movzx	b ## H,		%edi;\
207	xor	s2(%r11,%rdi,4),%r8d;\
208	movzx	a ## H,		%edi;\
209	xor	s3(%r11,%rdi,4),%r9d;\
210	add	%r8d,		%r9d;\
211	add	%r9d,		%r8d;\
212	add	k+round(%r11),	%r9d;\
213	xor	%r9d,		c ## D;\
214	add	k+4+round(%r11),%r8d;\
215	xor	%r8d,		d ## D;\
216	ror	$1,		d ## D;
217
218ENTRY(twofish_enc_blk)
219	pushq    R1
220
221	/* %rdi contains the ctx address */
222	/* %rsi contains the output address */
223	/* %rdx contains the input address */
224	/* ctx address is moved to free one non-rex register
225	as target for the 8bit high operations */
226	mov	%rdi,		%r11
227
228	movq	(R3),	R1
229	movq	8(R3),	R3
230	input_whitening(R1,%r11,a_offset)
231	input_whitening(R3,%r11,c_offset)
232	mov	R1D,	R0D
233	rol	$16,	R0D
234	shr	$32,	R1
235	mov	R3D,	R2D
236	shr	$32,	R3
237	rol	$1,	R3D
238
239	encrypt_round(R0,R1,R2,R3,0);
240	encrypt_round(R2,R3,R0,R1,8);
241	encrypt_round(R0,R1,R2,R3,2*8);
242	encrypt_round(R2,R3,R0,R1,3*8);
243	encrypt_round(R0,R1,R2,R3,4*8);
244	encrypt_round(R2,R3,R0,R1,5*8);
245	encrypt_round(R0,R1,R2,R3,6*8);
246	encrypt_round(R2,R3,R0,R1,7*8);
247	encrypt_round(R0,R1,R2,R3,8*8);
248	encrypt_round(R2,R3,R0,R1,9*8);
249	encrypt_round(R0,R1,R2,R3,10*8);
250	encrypt_round(R2,R3,R0,R1,11*8);
251	encrypt_round(R0,R1,R2,R3,12*8);
252	encrypt_round(R2,R3,R0,R1,13*8);
253	encrypt_round(R0,R1,R2,R3,14*8);
254	encrypt_last_round(R2,R3,R0,R1,15*8);
255
256
257	output_whitening(%r10,%r11,a_offset)
258	movq	%r10,	(%rsi)
259
260	shl	$32,	R1
261	xor	R0,	R1
262
263	output_whitening(R1,%r11,c_offset)
264	movq	R1,	8(%rsi)
265
266	popq	R1
267	movq	$1,%rax
268	ret
269ENDPROC(twofish_enc_blk)
270
271ENTRY(twofish_dec_blk)
272	pushq    R1
273
274	/* %rdi contains the ctx address */
275	/* %rsi contains the output address */
276	/* %rdx contains the input address */
277	/* ctx address is moved to free one non-rex register
278	as target for the 8bit high operations */
279	mov	%rdi,		%r11
280
281	movq	(R3),	R1
282	movq	8(R3),	R3
283	output_whitening(R1,%r11,a_offset)
284	output_whitening(R3,%r11,c_offset)
285	mov	R1D,	R0D
286	shr	$32,	R1
287	rol	$16,	R1D
288	mov	R3D,	R2D
289	shr	$32,	R3
290	rol	$1,	R2D
291
292	decrypt_round(R0,R1,R2,R3,15*8);
293	decrypt_round(R2,R3,R0,R1,14*8);
294	decrypt_round(R0,R1,R2,R3,13*8);
295	decrypt_round(R2,R3,R0,R1,12*8);
296	decrypt_round(R0,R1,R2,R3,11*8);
297	decrypt_round(R2,R3,R0,R1,10*8);
298	decrypt_round(R0,R1,R2,R3,9*8);
299	decrypt_round(R2,R3,R0,R1,8*8);
300	decrypt_round(R0,R1,R2,R3,7*8);
301	decrypt_round(R2,R3,R0,R1,6*8);
302	decrypt_round(R0,R1,R2,R3,5*8);
303	decrypt_round(R2,R3,R0,R1,4*8);
304	decrypt_round(R0,R1,R2,R3,3*8);
305	decrypt_round(R2,R3,R0,R1,2*8);
306	decrypt_round(R0,R1,R2,R3,1*8);
307	decrypt_last_round(R2,R3,R0,R1,0);
308
309	input_whitening(%r10,%r11,a_offset)
310	movq	%r10,	(%rsi)
311
312	shl	$32,	R1
313	xor	R0,	R1
314
315	input_whitening(R1,%r11,c_offset)
316	movq	R1,	8(%rsi)
317
318	popq	R1
319	movq	$1,%rax
320	ret
321ENDPROC(twofish_dec_blk)
322