11a59d1b8SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */
29c201942SThomas Gleixner/***************************************************************************
39c201942SThomas Gleixner*   Copyright (C) 2006 by Joachim Fritschi, <jfritschi@freenet.de>        *
49c201942SThomas Gleixner*                                                                         *
59c201942SThomas Gleixner***************************************************************************/
69c201942SThomas Gleixner
79c201942SThomas Gleixner.file "twofish-i586-asm.S"
89c201942SThomas Gleixner.text
99c201942SThomas Gleixner
10d3f5188dSJussi Kivilinna#include <linux/linkage.h>
119c201942SThomas Gleixner#include <asm/asm-offsets.h>
129c201942SThomas Gleixner
133ad2f3fbSDaniel Mack/* return address at 0 */
149c201942SThomas Gleixner
159c201942SThomas Gleixner#define in_blk    12  /* input byte array address parameter*/
169c201942SThomas Gleixner#define out_blk   8  /* output byte array address parameter*/
1791d41f15SJussi Kivilinna#define ctx       4  /* Twofish context structure */
189c201942SThomas Gleixner
199c201942SThomas Gleixner#define a_offset	0
209c201942SThomas Gleixner#define b_offset	4
219c201942SThomas Gleixner#define c_offset	8
229c201942SThomas Gleixner#define d_offset	12
239c201942SThomas Gleixner
249c201942SThomas Gleixner/* Structure of the crypto context struct*/
259c201942SThomas Gleixner
269c201942SThomas Gleixner#define s0	0	/* S0 Array 256 Words each */
279c201942SThomas Gleixner#define s1	1024	/* S1 Array */
289c201942SThomas Gleixner#define s2	2048	/* S2 Array */
299c201942SThomas Gleixner#define s3	3072	/* S3 Array */
309c201942SThomas Gleixner#define w	4096	/* 8 whitening keys (word) */
319c201942SThomas Gleixner#define k	4128	/* key 1-32 ( word ) */
329c201942SThomas Gleixner
339c201942SThomas Gleixner/* define a few register aliases to allow macro substitution */
349c201942SThomas Gleixner
359c201942SThomas Gleixner#define R0D    %eax
369c201942SThomas Gleixner#define R0B    %al
379c201942SThomas Gleixner#define R0H    %ah
389c201942SThomas Gleixner
399c201942SThomas Gleixner#define R1D    %ebx
409c201942SThomas Gleixner#define R1B    %bl
419c201942SThomas Gleixner#define R1H    %bh
429c201942SThomas Gleixner
439c201942SThomas Gleixner#define R2D    %ecx
449c201942SThomas Gleixner#define R2B    %cl
459c201942SThomas Gleixner#define R2H    %ch
469c201942SThomas Gleixner
479c201942SThomas Gleixner#define R3D    %edx
489c201942SThomas Gleixner#define R3B    %dl
499c201942SThomas Gleixner#define R3H    %dh
509c201942SThomas Gleixner
519c201942SThomas Gleixner
529c201942SThomas Gleixner/* performs input whitening */
539c201942SThomas Gleixner#define input_whitening(src,context,offset)\
549c201942SThomas Gleixner	xor	w+offset(context),	src;
559c201942SThomas Gleixner
569c201942SThomas Gleixner/* performs input whitening */
579c201942SThomas Gleixner#define output_whitening(src,context,offset)\
589c201942SThomas Gleixner	xor	w+16+offset(context),	src;
599c201942SThomas Gleixner
609c201942SThomas Gleixner/*
619c201942SThomas Gleixner * a input register containing a (rotated 16)
629c201942SThomas Gleixner * b input register containing b
639c201942SThomas Gleixner * c input register containing c
649c201942SThomas Gleixner * d input register containing d (already rol $1)
659c201942SThomas Gleixner * operations on a and b are interleaved to increase performance
669c201942SThomas Gleixner */
679c201942SThomas Gleixner#define encrypt_round(a,b,c,d,round)\
689c201942SThomas Gleixner	push	d ## D;\
699c201942SThomas Gleixner	movzx	b ## B,		%edi;\
709c201942SThomas Gleixner	mov	s1(%ebp,%edi,4),d ## D;\
719c201942SThomas Gleixner	movzx	a ## B,		%edi;\
729c201942SThomas Gleixner	mov	s2(%ebp,%edi,4),%esi;\
739c201942SThomas Gleixner	movzx	b ## H,		%edi;\
749c201942SThomas Gleixner	ror	$16,		b ## D;\
759c201942SThomas Gleixner	xor	s2(%ebp,%edi,4),d ## D;\
769c201942SThomas Gleixner	movzx	a ## H,		%edi;\
779c201942SThomas Gleixner	ror	$16,		a ## D;\
789c201942SThomas Gleixner	xor	s3(%ebp,%edi,4),%esi;\
799c201942SThomas Gleixner	movzx	b ## B,		%edi;\
809c201942SThomas Gleixner	xor	s3(%ebp,%edi,4),d ## D;\
819c201942SThomas Gleixner	movzx	a ## B,		%edi;\
829c201942SThomas Gleixner	xor	(%ebp,%edi,4),	%esi;\
839c201942SThomas Gleixner	movzx	b ## H,		%edi;\
849c201942SThomas Gleixner	ror	$15,		b ## D;\
859c201942SThomas Gleixner	xor	(%ebp,%edi,4),	d ## D;\
869c201942SThomas Gleixner	movzx	a ## H,		%edi;\
879c201942SThomas Gleixner	xor	s1(%ebp,%edi,4),%esi;\
889c201942SThomas Gleixner	pop	%edi;\
899c201942SThomas Gleixner	add	d ## D,		%esi;\
909c201942SThomas Gleixner	add	%esi,		d ## D;\
919c201942SThomas Gleixner	add	k+round(%ebp),	%esi;\
929c201942SThomas Gleixner	xor	%esi,		c ## D;\
939c201942SThomas Gleixner	rol	$15,		c ## D;\
949c201942SThomas Gleixner	add	k+4+round(%ebp),d ## D;\
959c201942SThomas Gleixner	xor	%edi,		d ## D;
969c201942SThomas Gleixner
979c201942SThomas Gleixner/*
989c201942SThomas Gleixner * a input register containing a (rotated 16)
999c201942SThomas Gleixner * b input register containing b
1009c201942SThomas Gleixner * c input register containing c
1019c201942SThomas Gleixner * d input register containing d (already rol $1)
1029c201942SThomas Gleixner * operations on a and b are interleaved to increase performance
1039c201942SThomas Gleixner * last round has different rotations for the output preparation
1049c201942SThomas Gleixner */
1059c201942SThomas Gleixner#define encrypt_last_round(a,b,c,d,round)\
1069c201942SThomas Gleixner	push	d ## D;\
1079c201942SThomas Gleixner	movzx	b ## B,		%edi;\
1089c201942SThomas Gleixner	mov	s1(%ebp,%edi,4),d ## D;\
1099c201942SThomas Gleixner	movzx	a ## B,		%edi;\
1109c201942SThomas Gleixner	mov	s2(%ebp,%edi,4),%esi;\
1119c201942SThomas Gleixner	movzx	b ## H,		%edi;\
1129c201942SThomas Gleixner	ror	$16,		b ## D;\
1139c201942SThomas Gleixner	xor	s2(%ebp,%edi,4),d ## D;\
1149c201942SThomas Gleixner	movzx	a ## H,		%edi;\
1159c201942SThomas Gleixner	ror	$16,		a ## D;\
1169c201942SThomas Gleixner	xor	s3(%ebp,%edi,4),%esi;\
1179c201942SThomas Gleixner	movzx	b ## B,		%edi;\
1189c201942SThomas Gleixner	xor	s3(%ebp,%edi,4),d ## D;\
1199c201942SThomas Gleixner	movzx	a ## B,		%edi;\
1209c201942SThomas Gleixner	xor	(%ebp,%edi,4),	%esi;\
1219c201942SThomas Gleixner	movzx	b ## H,		%edi;\
1229c201942SThomas Gleixner	ror	$16,		b ## D;\
1239c201942SThomas Gleixner	xor	(%ebp,%edi,4),	d ## D;\
1249c201942SThomas Gleixner	movzx	a ## H,		%edi;\
1259c201942SThomas Gleixner	xor	s1(%ebp,%edi,4),%esi;\
1269c201942SThomas Gleixner	pop	%edi;\
1279c201942SThomas Gleixner	add	d ## D,		%esi;\
1289c201942SThomas Gleixner	add	%esi,		d ## D;\
1299c201942SThomas Gleixner	add	k+round(%ebp),	%esi;\
1309c201942SThomas Gleixner	xor	%esi,		c ## D;\
1319c201942SThomas Gleixner	ror	$1,		c ## D;\
1329c201942SThomas Gleixner	add	k+4+round(%ebp),d ## D;\
1339c201942SThomas Gleixner	xor	%edi,		d ## D;
1349c201942SThomas Gleixner
1359c201942SThomas Gleixner/*
1369c201942SThomas Gleixner * a input register containing a
1379c201942SThomas Gleixner * b input register containing b (rotated 16)
1389c201942SThomas Gleixner * c input register containing c
1399c201942SThomas Gleixner * d input register containing d (already rol $1)
1409c201942SThomas Gleixner * operations on a and b are interleaved to increase performance
1419c201942SThomas Gleixner */
1429c201942SThomas Gleixner#define decrypt_round(a,b,c,d,round)\
1439c201942SThomas Gleixner	push	c ## D;\
1449c201942SThomas Gleixner	movzx	a ## B,		%edi;\
1459c201942SThomas Gleixner	mov	(%ebp,%edi,4),	c ## D;\
1469c201942SThomas Gleixner	movzx	b ## B,		%edi;\
1479c201942SThomas Gleixner	mov	s3(%ebp,%edi,4),%esi;\
1489c201942SThomas Gleixner	movzx	a ## H,		%edi;\
1499c201942SThomas Gleixner	ror	$16,		a ## D;\
1509c201942SThomas Gleixner	xor	s1(%ebp,%edi,4),c ## D;\
1519c201942SThomas Gleixner	movzx	b ## H,		%edi;\
1529c201942SThomas Gleixner	ror	$16,		b ## D;\
1539c201942SThomas Gleixner	xor	(%ebp,%edi,4),	%esi;\
1549c201942SThomas Gleixner	movzx	a ## B,		%edi;\
1559c201942SThomas Gleixner	xor	s2(%ebp,%edi,4),c ## D;\
1569c201942SThomas Gleixner	movzx	b ## B,		%edi;\
1579c201942SThomas Gleixner	xor	s1(%ebp,%edi,4),%esi;\
1589c201942SThomas Gleixner	movzx	a ## H,		%edi;\
1599c201942SThomas Gleixner	ror	$15,		a ## D;\
1609c201942SThomas Gleixner	xor	s3(%ebp,%edi,4),c ## D;\
1619c201942SThomas Gleixner	movzx	b ## H,		%edi;\
1629c201942SThomas Gleixner	xor	s2(%ebp,%edi,4),%esi;\
1639c201942SThomas Gleixner	pop	%edi;\
1649c201942SThomas Gleixner	add	%esi,		c ## D;\
1659c201942SThomas Gleixner	add	c ## D,		%esi;\
1669c201942SThomas Gleixner	add	k+round(%ebp),	c ## D;\
1679c201942SThomas Gleixner	xor	%edi,		c ## D;\
1689c201942SThomas Gleixner	add	k+4+round(%ebp),%esi;\
1699c201942SThomas Gleixner	xor	%esi,		d ## D;\
1709c201942SThomas Gleixner	rol	$15,		d ## D;
1719c201942SThomas Gleixner
1729c201942SThomas Gleixner/*
1739c201942SThomas Gleixner * a input register containing a
1749c201942SThomas Gleixner * b input register containing b (rotated 16)
1759c201942SThomas Gleixner * c input register containing c
1769c201942SThomas Gleixner * d input register containing d (already rol $1)
1779c201942SThomas Gleixner * operations on a and b are interleaved to increase performance
1789c201942SThomas Gleixner * last round has different rotations for the output preparation
1799c201942SThomas Gleixner */
1809c201942SThomas Gleixner#define decrypt_last_round(a,b,c,d,round)\
1819c201942SThomas Gleixner	push	c ## D;\
1829c201942SThomas Gleixner	movzx	a ## B,		%edi;\
1839c201942SThomas Gleixner	mov	(%ebp,%edi,4),	c ## D;\
1849c201942SThomas Gleixner	movzx	b ## B,		%edi;\
1859c201942SThomas Gleixner	mov	s3(%ebp,%edi,4),%esi;\
1869c201942SThomas Gleixner	movzx	a ## H,		%edi;\
1879c201942SThomas Gleixner	ror	$16,		a ## D;\
1889c201942SThomas Gleixner	xor	s1(%ebp,%edi,4),c ## D;\
1899c201942SThomas Gleixner	movzx	b ## H,		%edi;\
1909c201942SThomas Gleixner	ror	$16,		b ## D;\
1919c201942SThomas Gleixner	xor	(%ebp,%edi,4),	%esi;\
1929c201942SThomas Gleixner	movzx	a ## B,		%edi;\
1939c201942SThomas Gleixner	xor	s2(%ebp,%edi,4),c ## D;\
1949c201942SThomas Gleixner	movzx	b ## B,		%edi;\
1959c201942SThomas Gleixner	xor	s1(%ebp,%edi,4),%esi;\
1969c201942SThomas Gleixner	movzx	a ## H,		%edi;\
1979c201942SThomas Gleixner	ror	$16,		a ## D;\
1989c201942SThomas Gleixner	xor	s3(%ebp,%edi,4),c ## D;\
1999c201942SThomas Gleixner	movzx	b ## H,		%edi;\
2009c201942SThomas Gleixner	xor	s2(%ebp,%edi,4),%esi;\
2019c201942SThomas Gleixner	pop	%edi;\
2029c201942SThomas Gleixner	add	%esi,		c ## D;\
2039c201942SThomas Gleixner	add	c ## D,		%esi;\
2049c201942SThomas Gleixner	add	k+round(%ebp),	c ## D;\
2059c201942SThomas Gleixner	xor	%edi,		c ## D;\
2069c201942SThomas Gleixner	add	k+4+round(%ebp),%esi;\
2079c201942SThomas Gleixner	xor	%esi,		d ## D;\
2089c201942SThomas Gleixner	ror	$1,		d ## D;
2099c201942SThomas Gleixner
2106d685e53SJiri SlabySYM_FUNC_START(twofish_enc_blk)
2119c201942SThomas Gleixner	push	%ebp			/* save registers according to calling convention*/
2129c201942SThomas Gleixner	push    %ebx
2139c201942SThomas Gleixner	push    %esi
2149c201942SThomas Gleixner	push    %edi
2159c201942SThomas Gleixner
21691d41f15SJussi Kivilinna	mov	ctx + 16(%esp),	%ebp	/* abuse the base pointer: set new base
21791d41f15SJussi Kivilinna					 * pointer to the ctx address */
2183ad2f3fbSDaniel Mack	mov     in_blk+16(%esp),%edi	/* input address in edi */
2199c201942SThomas Gleixner
2209c201942SThomas Gleixner	mov	(%edi),		%eax
2219c201942SThomas Gleixner	mov	b_offset(%edi),	%ebx
2229c201942SThomas Gleixner	mov	c_offset(%edi),	%ecx
2239c201942SThomas Gleixner	mov	d_offset(%edi),	%edx
2249c201942SThomas Gleixner	input_whitening(%eax,%ebp,a_offset)
2259c201942SThomas Gleixner	ror	$16,	%eax
2269c201942SThomas Gleixner	input_whitening(%ebx,%ebp,b_offset)
2279c201942SThomas Gleixner	input_whitening(%ecx,%ebp,c_offset)
2289c201942SThomas Gleixner	input_whitening(%edx,%ebp,d_offset)
2299c201942SThomas Gleixner	rol	$1,	%edx
2309c201942SThomas Gleixner
2319c201942SThomas Gleixner	encrypt_round(R0,R1,R2,R3,0);
2329c201942SThomas Gleixner	encrypt_round(R2,R3,R0,R1,8);
2339c201942SThomas Gleixner	encrypt_round(R0,R1,R2,R3,2*8);
2349c201942SThomas Gleixner	encrypt_round(R2,R3,R0,R1,3*8);
2359c201942SThomas Gleixner	encrypt_round(R0,R1,R2,R3,4*8);
2369c201942SThomas Gleixner	encrypt_round(R2,R3,R0,R1,5*8);
2379c201942SThomas Gleixner	encrypt_round(R0,R1,R2,R3,6*8);
2389c201942SThomas Gleixner	encrypt_round(R2,R3,R0,R1,7*8);
2399c201942SThomas Gleixner	encrypt_round(R0,R1,R2,R3,8*8);
2409c201942SThomas Gleixner	encrypt_round(R2,R3,R0,R1,9*8);
2419c201942SThomas Gleixner	encrypt_round(R0,R1,R2,R3,10*8);
2429c201942SThomas Gleixner	encrypt_round(R2,R3,R0,R1,11*8);
2439c201942SThomas Gleixner	encrypt_round(R0,R1,R2,R3,12*8);
2449c201942SThomas Gleixner	encrypt_round(R2,R3,R0,R1,13*8);
2459c201942SThomas Gleixner	encrypt_round(R0,R1,R2,R3,14*8);
2469c201942SThomas Gleixner	encrypt_last_round(R2,R3,R0,R1,15*8);
2479c201942SThomas Gleixner
2489c201942SThomas Gleixner	output_whitening(%eax,%ebp,c_offset)
2499c201942SThomas Gleixner	output_whitening(%ebx,%ebp,d_offset)
2509c201942SThomas Gleixner	output_whitening(%ecx,%ebp,a_offset)
2519c201942SThomas Gleixner	output_whitening(%edx,%ebp,b_offset)
2529c201942SThomas Gleixner	mov	out_blk+16(%esp),%edi;
2539c201942SThomas Gleixner	mov	%eax,		c_offset(%edi)
2549c201942SThomas Gleixner	mov	%ebx,		d_offset(%edi)
2559c201942SThomas Gleixner	mov	%ecx,		(%edi)
2569c201942SThomas Gleixner	mov	%edx,		b_offset(%edi)
2579c201942SThomas Gleixner
2589c201942SThomas Gleixner	pop	%edi
2599c201942SThomas Gleixner	pop	%esi
2609c201942SThomas Gleixner	pop	%ebx
2619c201942SThomas Gleixner	pop	%ebp
2629c201942SThomas Gleixner	mov	$1,	%eax
263*14b476e0SPeter Zijlstra	RET
2646d685e53SJiri SlabySYM_FUNC_END(twofish_enc_blk)
2659c201942SThomas Gleixner
2666d685e53SJiri SlabySYM_FUNC_START(twofish_dec_blk)
2679c201942SThomas Gleixner	push	%ebp			/* save registers according to calling convention*/
2689c201942SThomas Gleixner	push    %ebx
2699c201942SThomas Gleixner	push    %esi
2709c201942SThomas Gleixner	push    %edi
2719c201942SThomas Gleixner
2729c201942SThomas Gleixner
27391d41f15SJussi Kivilinna	mov	ctx + 16(%esp),	%ebp	/* abuse the base pointer: set new base
27491d41f15SJussi Kivilinna					 * pointer to the ctx address */
2753ad2f3fbSDaniel Mack	mov     in_blk+16(%esp),%edi	/* input address in edi */
2769c201942SThomas Gleixner
2779c201942SThomas Gleixner	mov	(%edi),		%eax
2789c201942SThomas Gleixner	mov	b_offset(%edi),	%ebx
2799c201942SThomas Gleixner	mov	c_offset(%edi),	%ecx
2809c201942SThomas Gleixner	mov	d_offset(%edi),	%edx
2819c201942SThomas Gleixner	output_whitening(%eax,%ebp,a_offset)
2829c201942SThomas Gleixner	output_whitening(%ebx,%ebp,b_offset)
2839c201942SThomas Gleixner	ror	$16,	%ebx
2849c201942SThomas Gleixner	output_whitening(%ecx,%ebp,c_offset)
2859c201942SThomas Gleixner	output_whitening(%edx,%ebp,d_offset)
2869c201942SThomas Gleixner	rol	$1,	%ecx
2879c201942SThomas Gleixner
2889c201942SThomas Gleixner	decrypt_round(R0,R1,R2,R3,15*8);
2899c201942SThomas Gleixner	decrypt_round(R2,R3,R0,R1,14*8);
2909c201942SThomas Gleixner	decrypt_round(R0,R1,R2,R3,13*8);
2919c201942SThomas Gleixner	decrypt_round(R2,R3,R0,R1,12*8);
2929c201942SThomas Gleixner	decrypt_round(R0,R1,R2,R3,11*8);
2939c201942SThomas Gleixner	decrypt_round(R2,R3,R0,R1,10*8);
2949c201942SThomas Gleixner	decrypt_round(R0,R1,R2,R3,9*8);
2959c201942SThomas Gleixner	decrypt_round(R2,R3,R0,R1,8*8);
2969c201942SThomas Gleixner	decrypt_round(R0,R1,R2,R3,7*8);
2979c201942SThomas Gleixner	decrypt_round(R2,R3,R0,R1,6*8);
2989c201942SThomas Gleixner	decrypt_round(R0,R1,R2,R3,5*8);
2999c201942SThomas Gleixner	decrypt_round(R2,R3,R0,R1,4*8);
3009c201942SThomas Gleixner	decrypt_round(R0,R1,R2,R3,3*8);
3019c201942SThomas Gleixner	decrypt_round(R2,R3,R0,R1,2*8);
3029c201942SThomas Gleixner	decrypt_round(R0,R1,R2,R3,1*8);
3039c201942SThomas Gleixner	decrypt_last_round(R2,R3,R0,R1,0);
3049c201942SThomas Gleixner
3059c201942SThomas Gleixner	input_whitening(%eax,%ebp,c_offset)
3069c201942SThomas Gleixner	input_whitening(%ebx,%ebp,d_offset)
3079c201942SThomas Gleixner	input_whitening(%ecx,%ebp,a_offset)
3089c201942SThomas Gleixner	input_whitening(%edx,%ebp,b_offset)
3099c201942SThomas Gleixner	mov	out_blk+16(%esp),%edi;
3109c201942SThomas Gleixner	mov	%eax,		c_offset(%edi)
3119c201942SThomas Gleixner	mov	%ebx,		d_offset(%edi)
3129c201942SThomas Gleixner	mov	%ecx,		(%edi)
3139c201942SThomas Gleixner	mov	%edx,		b_offset(%edi)
3149c201942SThomas Gleixner
3159c201942SThomas Gleixner	pop	%edi
3169c201942SThomas Gleixner	pop	%esi
3179c201942SThomas Gleixner	pop	%ebx
3189c201942SThomas Gleixner	pop	%ebp
3199c201942SThomas Gleixner	mov	$1,	%eax
320*14b476e0SPeter Zijlstra	RET
3216d685e53SJiri SlabySYM_FUNC_END(twofish_dec_blk)
322