1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/***************************************************************************
3*   Copyright (C) 2006 by Joachim Fritschi, <jfritschi@freenet.de>        *
4*                                                                         *
5***************************************************************************/
6
7.file "twofish-i586-asm.S"
8.text
9
10#include <linux/linkage.h>
11#include <asm/asm-offsets.h>
12
13/* return address at 0 */
14
15#define in_blk    12  /* input byte array address parameter*/
16#define out_blk   8  /* output byte array address parameter*/
17#define ctx       4  /* Twofish context structure */
18
19#define a_offset	0
20#define b_offset	4
21#define c_offset	8
22#define d_offset	12
23
24/* Structure of the crypto context struct*/
25
26#define s0	0	/* S0 Array 256 Words each */
27#define s1	1024	/* S1 Array */
28#define s2	2048	/* S2 Array */
29#define s3	3072	/* S3 Array */
30#define w	4096	/* 8 whitening keys (word) */
31#define k	4128	/* key 1-32 ( word ) */
32
33/* define a few register aliases to allow macro substitution */
34
35#define R0D    %eax
36#define R0B    %al
37#define R0H    %ah
38
39#define R1D    %ebx
40#define R1B    %bl
41#define R1H    %bh
42
43#define R2D    %ecx
44#define R2B    %cl
45#define R2H    %ch
46
47#define R3D    %edx
48#define R3B    %dl
49#define R3H    %dh
50
51
52/* performs input whitening */
53#define input_whitening(src,context,offset)\
54	xor	w+offset(context),	src;
55
56/* performs input whitening */
57#define output_whitening(src,context,offset)\
58	xor	w+16+offset(context),	src;
59
60/*
61 * a input register containing a (rotated 16)
62 * b input register containing b
63 * c input register containing c
64 * d input register containing d (already rol $1)
65 * operations on a and b are interleaved to increase performance
66 */
67#define encrypt_round(a,b,c,d,round)\
68	push	d ## D;\
69	movzx	b ## B,		%edi;\
70	mov	s1(%ebp,%edi,4),d ## D;\
71	movzx	a ## B,		%edi;\
72	mov	s2(%ebp,%edi,4),%esi;\
73	movzx	b ## H,		%edi;\
74	ror	$16,		b ## D;\
75	xor	s2(%ebp,%edi,4),d ## D;\
76	movzx	a ## H,		%edi;\
77	ror	$16,		a ## D;\
78	xor	s3(%ebp,%edi,4),%esi;\
79	movzx	b ## B,		%edi;\
80	xor	s3(%ebp,%edi,4),d ## D;\
81	movzx	a ## B,		%edi;\
82	xor	(%ebp,%edi,4),	%esi;\
83	movzx	b ## H,		%edi;\
84	ror	$15,		b ## D;\
85	xor	(%ebp,%edi,4),	d ## D;\
86	movzx	a ## H,		%edi;\
87	xor	s1(%ebp,%edi,4),%esi;\
88	pop	%edi;\
89	add	d ## D,		%esi;\
90	add	%esi,		d ## D;\
91	add	k+round(%ebp),	%esi;\
92	xor	%esi,		c ## D;\
93	rol	$15,		c ## D;\
94	add	k+4+round(%ebp),d ## D;\
95	xor	%edi,		d ## D;
96
97/*
98 * a input register containing a (rotated 16)
99 * b input register containing b
100 * c input register containing c
101 * d input register containing d (already rol $1)
102 * operations on a and b are interleaved to increase performance
103 * last round has different rotations for the output preparation
104 */
105#define encrypt_last_round(a,b,c,d,round)\
106	push	d ## D;\
107	movzx	b ## B,		%edi;\
108	mov	s1(%ebp,%edi,4),d ## D;\
109	movzx	a ## B,		%edi;\
110	mov	s2(%ebp,%edi,4),%esi;\
111	movzx	b ## H,		%edi;\
112	ror	$16,		b ## D;\
113	xor	s2(%ebp,%edi,4),d ## D;\
114	movzx	a ## H,		%edi;\
115	ror	$16,		a ## D;\
116	xor	s3(%ebp,%edi,4),%esi;\
117	movzx	b ## B,		%edi;\
118	xor	s3(%ebp,%edi,4),d ## D;\
119	movzx	a ## B,		%edi;\
120	xor	(%ebp,%edi,4),	%esi;\
121	movzx	b ## H,		%edi;\
122	ror	$16,		b ## D;\
123	xor	(%ebp,%edi,4),	d ## D;\
124	movzx	a ## H,		%edi;\
125	xor	s1(%ebp,%edi,4),%esi;\
126	pop	%edi;\
127	add	d ## D,		%esi;\
128	add	%esi,		d ## D;\
129	add	k+round(%ebp),	%esi;\
130	xor	%esi,		c ## D;\
131	ror	$1,		c ## D;\
132	add	k+4+round(%ebp),d ## D;\
133	xor	%edi,		d ## D;
134
135/*
136 * a input register containing a
137 * b input register containing b (rotated 16)
138 * c input register containing c
139 * d input register containing d (already rol $1)
140 * operations on a and b are interleaved to increase performance
141 */
142#define decrypt_round(a,b,c,d,round)\
143	push	c ## D;\
144	movzx	a ## B,		%edi;\
145	mov	(%ebp,%edi,4),	c ## D;\
146	movzx	b ## B,		%edi;\
147	mov	s3(%ebp,%edi,4),%esi;\
148	movzx	a ## H,		%edi;\
149	ror	$16,		a ## D;\
150	xor	s1(%ebp,%edi,4),c ## D;\
151	movzx	b ## H,		%edi;\
152	ror	$16,		b ## D;\
153	xor	(%ebp,%edi,4),	%esi;\
154	movzx	a ## B,		%edi;\
155	xor	s2(%ebp,%edi,4),c ## D;\
156	movzx	b ## B,		%edi;\
157	xor	s1(%ebp,%edi,4),%esi;\
158	movzx	a ## H,		%edi;\
159	ror	$15,		a ## D;\
160	xor	s3(%ebp,%edi,4),c ## D;\
161	movzx	b ## H,		%edi;\
162	xor	s2(%ebp,%edi,4),%esi;\
163	pop	%edi;\
164	add	%esi,		c ## D;\
165	add	c ## D,		%esi;\
166	add	k+round(%ebp),	c ## D;\
167	xor	%edi,		c ## D;\
168	add	k+4+round(%ebp),%esi;\
169	xor	%esi,		d ## D;\
170	rol	$15,		d ## D;
171
172/*
173 * a input register containing a
174 * b input register containing b (rotated 16)
175 * c input register containing c
176 * d input register containing d (already rol $1)
177 * operations on a and b are interleaved to increase performance
178 * last round has different rotations for the output preparation
179 */
180#define decrypt_last_round(a,b,c,d,round)\
181	push	c ## D;\
182	movzx	a ## B,		%edi;\
183	mov	(%ebp,%edi,4),	c ## D;\
184	movzx	b ## B,		%edi;\
185	mov	s3(%ebp,%edi,4),%esi;\
186	movzx	a ## H,		%edi;\
187	ror	$16,		a ## D;\
188	xor	s1(%ebp,%edi,4),c ## D;\
189	movzx	b ## H,		%edi;\
190	ror	$16,		b ## D;\
191	xor	(%ebp,%edi,4),	%esi;\
192	movzx	a ## B,		%edi;\
193	xor	s2(%ebp,%edi,4),c ## D;\
194	movzx	b ## B,		%edi;\
195	xor	s1(%ebp,%edi,4),%esi;\
196	movzx	a ## H,		%edi;\
197	ror	$16,		a ## D;\
198	xor	s3(%ebp,%edi,4),c ## D;\
199	movzx	b ## H,		%edi;\
200	xor	s2(%ebp,%edi,4),%esi;\
201	pop	%edi;\
202	add	%esi,		c ## D;\
203	add	c ## D,		%esi;\
204	add	k+round(%ebp),	c ## D;\
205	xor	%edi,		c ## D;\
206	add	k+4+round(%ebp),%esi;\
207	xor	%esi,		d ## D;\
208	ror	$1,		d ## D;
209
210SYM_FUNC_START(twofish_enc_blk)
211	push	%ebp			/* save registers according to calling convention*/
212	push    %ebx
213	push    %esi
214	push    %edi
215
216	mov	ctx + 16(%esp),	%ebp	/* abuse the base pointer: set new base
217					 * pointer to the ctx address */
218	mov     in_blk+16(%esp),%edi	/* input address in edi */
219
220	mov	(%edi),		%eax
221	mov	b_offset(%edi),	%ebx
222	mov	c_offset(%edi),	%ecx
223	mov	d_offset(%edi),	%edx
224	input_whitening(%eax,%ebp,a_offset)
225	ror	$16,	%eax
226	input_whitening(%ebx,%ebp,b_offset)
227	input_whitening(%ecx,%ebp,c_offset)
228	input_whitening(%edx,%ebp,d_offset)
229	rol	$1,	%edx
230
231	encrypt_round(R0,R1,R2,R3,0);
232	encrypt_round(R2,R3,R0,R1,8);
233	encrypt_round(R0,R1,R2,R3,2*8);
234	encrypt_round(R2,R3,R0,R1,3*8);
235	encrypt_round(R0,R1,R2,R3,4*8);
236	encrypt_round(R2,R3,R0,R1,5*8);
237	encrypt_round(R0,R1,R2,R3,6*8);
238	encrypt_round(R2,R3,R0,R1,7*8);
239	encrypt_round(R0,R1,R2,R3,8*8);
240	encrypt_round(R2,R3,R0,R1,9*8);
241	encrypt_round(R0,R1,R2,R3,10*8);
242	encrypt_round(R2,R3,R0,R1,11*8);
243	encrypt_round(R0,R1,R2,R3,12*8);
244	encrypt_round(R2,R3,R0,R1,13*8);
245	encrypt_round(R0,R1,R2,R3,14*8);
246	encrypt_last_round(R2,R3,R0,R1,15*8);
247
248	output_whitening(%eax,%ebp,c_offset)
249	output_whitening(%ebx,%ebp,d_offset)
250	output_whitening(%ecx,%ebp,a_offset)
251	output_whitening(%edx,%ebp,b_offset)
252	mov	out_blk+16(%esp),%edi;
253	mov	%eax,		c_offset(%edi)
254	mov	%ebx,		d_offset(%edi)
255	mov	%ecx,		(%edi)
256	mov	%edx,		b_offset(%edi)
257
258	pop	%edi
259	pop	%esi
260	pop	%ebx
261	pop	%ebp
262	mov	$1,	%eax
263	ret
264SYM_FUNC_END(twofish_enc_blk)
265
266SYM_FUNC_START(twofish_dec_blk)
267	push	%ebp			/* save registers according to calling convention*/
268	push    %ebx
269	push    %esi
270	push    %edi
271
272
273	mov	ctx + 16(%esp),	%ebp	/* abuse the base pointer: set new base
274					 * pointer to the ctx address */
275	mov     in_blk+16(%esp),%edi	/* input address in edi */
276
277	mov	(%edi),		%eax
278	mov	b_offset(%edi),	%ebx
279	mov	c_offset(%edi),	%ecx
280	mov	d_offset(%edi),	%edx
281	output_whitening(%eax,%ebp,a_offset)
282	output_whitening(%ebx,%ebp,b_offset)
283	ror	$16,	%ebx
284	output_whitening(%ecx,%ebp,c_offset)
285	output_whitening(%edx,%ebp,d_offset)
286	rol	$1,	%ecx
287
288	decrypt_round(R0,R1,R2,R3,15*8);
289	decrypt_round(R2,R3,R0,R1,14*8);
290	decrypt_round(R0,R1,R2,R3,13*8);
291	decrypt_round(R2,R3,R0,R1,12*8);
292	decrypt_round(R0,R1,R2,R3,11*8);
293	decrypt_round(R2,R3,R0,R1,10*8);
294	decrypt_round(R0,R1,R2,R3,9*8);
295	decrypt_round(R2,R3,R0,R1,8*8);
296	decrypt_round(R0,R1,R2,R3,7*8);
297	decrypt_round(R2,R3,R0,R1,6*8);
298	decrypt_round(R0,R1,R2,R3,5*8);
299	decrypt_round(R2,R3,R0,R1,4*8);
300	decrypt_round(R0,R1,R2,R3,3*8);
301	decrypt_round(R2,R3,R0,R1,2*8);
302	decrypt_round(R0,R1,R2,R3,1*8);
303	decrypt_last_round(R2,R3,R0,R1,0);
304
305	input_whitening(%eax,%ebp,c_offset)
306	input_whitening(%ebx,%ebp,d_offset)
307	input_whitening(%ecx,%ebp,a_offset)
308	input_whitening(%edx,%ebp,b_offset)
309	mov	out_blk+16(%esp),%edi;
310	mov	%eax,		c_offset(%edi)
311	mov	%ebx,		d_offset(%edi)
312	mov	%ecx,		(%edi)
313	mov	%edx,		b_offset(%edi)
314
315	pop	%edi
316	pop	%esi
317	pop	%ebx
318	pop	%ebp
319	mov	$1,	%eax
320	ret
321SYM_FUNC_END(twofish_dec_blk)
322