/* serpent_asm.S */
/*
    This file is part of the Crypto-avr-lib/microcrypt-lib.
    Copyright (C) 2008  Daniel Otte (daniel.otte@rub.de)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* 
 * File:        serpent_sboxes.S
 * Author:      Daniel Otte
 * Date:        2008-08-07
 * License:     GPLv3 or later
 * Description: Implementation of the serpent sbox function.
 * 
 */
 
#include <avr/io.h>
#include "avr-asm-macros.S"

/*
static void serpent_lt(uint8_t *b){
	X0 = rotl32(X0, 13);
	X2 = rotl32(X2,  3);
	X1 ^= X0 ^ X2;
	X3 ^= X2 ^ (X0 << 3);
	X1 = rotl32(X1, 1);
	X3 = rotl32(X3, 7);
	X0 ^= X1 ^ X3;
	X2 ^= X3 ^ (X1 << 7);
	X0 = rotl32(X0, 5);
	X2 = rotr32(X2, 10);
}
*/

#if 0
A0 =  4
A1 =  5
A2 =  6
A3 =  7
B0 =  8
B1 =  9
B2 = 10
B3 = 11
C0 = 12
C1 = 13
C2 = 14
C3 = 15
D0 = 16
D1 = 17
D2 = 18
D3 = 19
T0 = 20
T1 = 21
T2 = 22
T3 = 23

serpent_lt:
	push_range 4, 17
	movw r26, r24
	ld A2, X+
	ld A3, X+
	ld A0, X+
	ld A1, X+
	ldi r20, 3
	mov r0, A0
1:	
	lsr r0
	ror A3
	ror A2
	ror A1
	ror A0
	dec r20
	brne 1b
	ld B0, X+
	ld B1, X+
	ld B2, X+
	ld B3, X+
	
	ld C2, X+
	ld C3, X+
	ld C0, X+
	ld C1, X+
	ldi r20, 3
	mov r0, C0
1:	
	lsr r0
	ror C3
	ror C2
	ror C1
	ror C0
	dec r20
	brne 1b

	ld D0, X+
	ld D1, X+
	ld D2, X+
	ld D3, X+
	/* X1 ^= X0 ^ X2; */
	eor B0, A0
	eor B0, C0
	eor B1, A1
	eor B1, C1
	eor B2, A2
	eor B2, C2
	eor B3, A3
	eor B3, C3
	/* X3 ^= X2 ^ (X0 << 3); */
	mov T0, A0
	mov T1, A1
	mov T2, A2
	mov T3, A3
	ldi r24, 3
1:
	lsl T0
	rol T1
	rol T2
	rol T3
	dec r24
	brne 1b
	eor C0, B0
	eor C0, T0
	eor C1, B1
	eor C1, T1
	eor C2, B2
	eor C2, T2
	eor C3, B3
	eor C3, T3
	/*	X1 = rotl32(X1, 1); */
	mov r0, B3
	lsl r0
	rol B0
	rol B1
	rol B2
	rol B3
	/* X3 = rotl32(X3, 7); */
	mov r0, D3
	mov D3, D2
	mov D2, D1
	mov D1, D0
	mov D0, r0
	lsr r0
	ror D3
	ror D2
	ror D1
	ror D0
	/* 	X0 ^= X1 ^ X3; */
	eor A0, B0
	eor A0, D0
	eor A1, B1
	eor A1, D1
	eor A2, B2
	eor A2, D2
	eor A3, B3
	eor A3, D3
	/*  X2 ^= X3 ^ (X1 << 7); */
	mov T1, B0
	mov T2, B1
	mov T3, B2
	clr T0
	mov r0, B3
	lsr r0
	ror T2
	ror T1
	ror T0 
	eor C0, D0
	eor C0, T0
	eor C1, D1
	eor C1, T1
	eor C2, D2
	eor C2, T2
	eor C3, D3
	eor C3, T3
	/* 	X0 = rotl32(X0, 5); */
	ldi r24, 5
	mov r0, A3
1:	
	lsl r0
	rol A0
	rol A1
	rol A2
	rol A3
	dec r24
	brne 1b
	/* X2 = rotr32(X2, 10); */
	mov r0, C0
	mov C0, C1
	mov C1, C2
	mov C2, C3	
	mov C3, r0
	ldi r24, 2
1:
	lsr r0
	ror C2
	ror C1
	ror C0
	ror C3	
	dec r24
	brne 1b
	
	clr r31
	ldi r30, D3+1
	ldi r24, 16
1:
	ld r0, -Z
	st -X, r0	
	dec r24
	brne 1b
	
	pop_range 4, 17
	ret
#endif

T0 = 22
T1 = 23
T2 = 24
T3 = 25
TT = 21
/* rotate the data word (4 byte) pointed to by X by r20 bits to the right */
memrotr32:
	ld T0, X+
	ld T1, X+
	ld T2, X+
	ld T3, X+
	mov TT, T0
1:
	lsr TT
	ror T3
	ror T2
	ror T1
	ror T0
	dec r20
	brne 1b
	st -X, T3
	st -X, T2
	st -X, T1
	st -X, T0
	ret
	
/* rotate the data word (4 byte) pointed to by X by r20 bits to the left */
memrotl32:
	ld T0, X+
	ld T1, X+
	ld T2, X+
	ld T3, X+
	mov TT, T3
1:
	lsl TT
	rol T0
	rol T1
	rol T2
	rol T3
	dec r20
	brne 1b
	st -X, T3
	st -X, T2
	st -X, T1
	st -X, T0
	ret

/* xor the dataword (4 byte) pointed by Z into X */	
memeor32:
  ldi T2, 4
1:  
  ld T0, X		
  ld T1, Z+
  eor T0, T1
  st X+, T0
  dec T2
  brne 1b
  ret

serpent_lt:
	 /* X0 := X0 <<< 13 */
	movw r26, r24
	ldi r20, 7
	rcall memrotl32
	ldi r20, 6
	rcall memrotl32
	/* X2 := X2 <<< 3 */
	adiw r26, 8
	ldi r20, 3
	rcall memrotl32
	/* X1 ^= X2 */
	movw r30, r26
	sbiw r26, 4
	rcall memeor32
	/* X1 ^= X0 */
	sbiw r26, 4
	sbiw r30, 12
	rcall memeor32
	/* X3 ^= X2 */
	movw r30, r26
	adiw r26, 4
	rcall memeor32
	/* T := X0 */
	sbiw r26, 16
	ld r18, X+
	ld r19, X+
	ld r20, X+
	ld r21, X+
	/* T := T<<3 */
	ldi r22, 3
1:
	lsl r18
	rol r19
	rol r20
	rol r21
	dec r22
	brne 1b
	clr r31 
	/* X3 ^= T */
	adiw r26, 8
	ldi r30, 18
	rcall memeor32
	/* X1 := X1<<<1 */
	sbiw r26, 12
	ldi r20, 1
	rcall memrotl32
	/* X3 := X3<<<7 */
	adiw r26, 8
	ldi r20, 7
	rcall memrotl32
	/* X0 ^= X3 */
	movw r30, r26
	sbiw r26, 12
	rcall memeor32
	/* X0 ^= X1 */
	movw r30, r26
	sbiw r26, 4
	rcall memeor32
	/* X2 ^= X3 */
	adiw r26, 4
	adiw r30, 4
	rcall memeor32
	/* T := X1<<<8 */
	sbiw r26, 8
	ld r19, X+
	ld r20, X+
	ld r21, X+
	ld r18, X+
	/* T := T>>>1; T&=0xfffffff8 */
	lsr r18
	ror r21
	ror r20
	ror r19
	clr r18
	ror r18
	clr r31
	ldi r30, 18
	/* X2 ^= T */
	rcall memeor32
	/* X0 := X0 <<< 5 */
	sbiw r26, 12
	ldi r20, 5
	rcall memrotl32
	/* X3 := X3 >>> 10 */
	adiw r26, 8
	ldi r20, 7
	rcall memrotr32
	ldi r20, 3
	rcall memrotr32
	ret

serpent_inv_lt:
	 /* X0 := X0 >>> 5 */
	movw r26, r24
	ldi r20, 5
	rcall memrotr32
	/* X2 := X2 <<< 10 */
	adiw r26, 8
	ldi r20, 7
	rcall memrotl32
	ldi r20, 3
	rcall memrotl32
	/* X2 ^= X3 */
	movw r30, r26
	adiw r30, 4
	rcall memeor32
	sbiw r26, 4
	sbiw r30, 12
	/* T := X1<<7 */
	ld r19, Z+
	ld r20, Z+
	ld r21, Z+
	ld r18, Z+
	lsr r18
	ror r21
	ror r20
	ror r19
	clr r18
	ror r18
    clr r31
    /* X2 ^= T */
    ldi r30, 18
    rcall memeor32
    /* X0 ^= X1 */
    sbiw r26, 12
    movw r30, r26
    adiw r30, 4
    rcall memeor32
    /* X0 ^= X3 */
    sbiw r26, 4
    adiw r30, 4
    rcall memeor32
    /* X1 := X1>>>1 */
    ldi r20, 1
	rcall memrotr32
	/* X3 := X3>>>7 */
	adiw r26, 8
	ldi r20, 7
	rcall memrotr32
	/* X3 ^= X2 */
	sbiw r30, 8
	rcall memeor32
	sbiw r26, 4
	/* T:= X0<<3 */
	sbiw r30, 12
	ld r18, Z+
	ld r19, Z+
	ld r20, Z+
	ld r21, Z+
	ldi r24, 3
1:
	lsl r18
	rol r19
	rol r20
	rol r21
	dec r24
	brne 1b
	/* X3 ^= T */
	clr r31
	ldi r30, 18
	rcall memeor32
	/* X1 ^= X0 */
	sbiw r26, 12
	movw r30, r26
	sbiw r30, 4
	rcall memeor32
	/* X1 ^= X2 */
	movw r26, r30
	adiw r30, 4
	rcall memeor32
	/* X2 := X2 >>> 3 */
	ldi r20, 3
	rcall memrotr32
	/* X0 := X0 >>> 13 */
	sbiw r26, 8
	ldi r20, 7
	rcall memrotr32
	ldi r20, 6
	rcall memrotr32
	ret

/*
#define GOLDEN_RATIO 0x9e3779b9l

static uint32_t serpent_gen_w(uint32_t * b, uint8_t i){
	uint32_t ret;
	ret = b[0] ^ b[3] ^ b[5] ^ b[7] ^ GOLDEN_RATIO ^ (uint32_t)i;
	ret = rotl32(ret, 11);
	return ret;
}
*/
/*
 * param b is passed in r24:r25
 * param i is passed in r22
 * return value is returned in r22.r23.r24.r25
 */
 /* trashes:
  *  r20-r25, r30-r31
  */
serpent_gen_w:
	movw r30, r24
	/* ^i^b[0]*/
    ld r21, Z+
    eor r22, r21
    ld r23, Z+
    ld r24, Z+
    ld r25, Z+
    /* ^b[3]^b[5]^[b7] */
    adiw r30, 4
    ldi r20, 3
1:    
    adiw r30, 4
    ld r21, Z+
    eor r22, r21
    ld r21, Z+
    eor r23, r21
    ld r21, Z+
    eor r24, r21
    ld r21, Z+
    eor r25, r21
	dec r20
	brne 1b
	/* ^0x9e3779b9l */
	ldi r21, 0xb9
	eor r22, r21
	ldi r21, 0x79
	eor r23, r21
	ldi r21, 0x37
	eor r24, r21
	ldi r21, 0x9e
	eor r25, r21
	/* <<<11 */
	mov r21, r25
	mov r25, r24
	mov r24, r23
	mov r23, r22
	mov r22, r21
	mov r21, r25
	ldi r20, 3
1:
	lsl r21
	rol r22
	rol r23
	rol r24
	rol r25
	dec r20
	brne 1b
	ret

/*
 * void serpent_init(const void* key, uint16_t keysize_b, serpent_ctx_t* ctx)
 */
/*
 * param key     is passed in r24:r25
 * param keysize is passed in r22:r23
 * param ctx     is passed in r20:r21
 */
.global serpent_init
serpent_init:
    stack_alloc 32
    adiw r30, 1
	push_ r30, r31
    movw r26, r22
    adiw r26, 7
    tst r27
    breq 1f
	ldi r26, 32
	rjmp 2f
1:
	lsr r26
	lsr r26
	lsr r26
2:	
	mov r22, r26
	bst r22, 5 /* store in T if we have to do the "append 1 thing"*/
	ldi r27, 32
3:	/* set buffer to zero */
	st Z+, r1
	dec r27
	brne 3b
	
	movw r26, r24 /* X points to the key */
	sbiw r30, 32
	tst r22
	breq 5f /* if keylength_b==0 */
4:	/* copy keybytes to buffer */
	ld r19, X+
	st Z+, r19
	dec r22
	brne 4b
5:
	brts 7f /* if keylength_b == 256 */
	ldi r18, 0x01
	andi r22, 0x07
	brne 6f
	st Z, r18
	rjmp 7f
6:	/* shift the one to the right position */
	lsl r18
	dec r22
	brne 6b
	or r18, r19
	st -Z, r18
7: /* post "appending 1 thing" buffer is ready for subkey generation */
	movw r26, r20  /* X points to the context */
	
	pop_ r19, r18 /* r18:r19 points to the buffer */
	push r16
	clr r16
8:
	movw r24, r18
	mov  r22, r16
	rcall serpent_gen_w
	movw r30, r18
	ldi r20, 7*4
1: /* the memmove */
	ldd r0, Z+4
	st Z+, r0
	dec r20
	brne 1b
  /* store new word in buffer and context */	
	st Z+, r22
	st Z+, r23
	st Z+, r24
	st Z+, r25
	st X+, r22
	st X+, r23
	st X+, r24
	st X+, r25
	
	inc r16
	cpi r16, 132
	brne 8b	
	
	push_ r28, r29
	movw r28, r26
	subi r28, lo8(132*4)
	sbci r29, hi8(132*4)
	ldi r16, 33
2:
	movw r24, r28
	adiw r28, 16
	ldi r22, 2
	add r22, r16
	rcall sbox128
	dec r16
	brne 2b
	pop_ r29, r28, r16
	stack_free 32
	ret

/*
 * void serpent_enc(void* buffer, const serpent_ctx_t* ctx){
 */
/*
 * param buffer is passed in r24:r25
 * param ctx    is passed in r22:r23
 */
.global serpent_enc
serpent_enc:

	push_ r12, r13, r14, r15, r16 
	clr r16
	movw r14, r24
	movw r12, r22
1:
	movw r24, r14
	movw r22, r12
	ldi r20, 16
	add r12, r20
	adc r13, r1
	clr r21
	rcall memxor
	movw r24, r14
	mov r22, r16
	rcall sbox128
	movw r24, r14
	rcall serpent_lt
	
	inc r16
	cpi r16, 31
	brne 1b
	
	movw r24, r14
	movw r22, r12
	ldi r20, 16
	add r12, r20
	adc r13, r1
	clr r21
	rcall memxor
	movw r24, r14
	mov r22, r16
	rcall sbox128
	
	inc r16
	movw r24, r14
	movw r22, r12
	ldi r20, 16
	clr r21
	pop_ r16, r15, r14, r13, r12
	rjmp memxor

/*
 * void serpent_dec(void* buffer, const serpent_ctx_t* ctx){
 */
/*
 * param buffer is passed in r24:r25
 * param ctx    is passed in r22:r23
 */
.global serpent_dec
serpent_dec:
	push_ r12, r13, r14, r15, r16 
	movw r14, r24
//	ldi r16, lo8(32*16)
//	add r22, r16
	ldi r16, hi8(32*16)
	add r23, r16
	movw r12, r22
	ldi r20, 16
	clr r21
	rcall memxor
	
	movw r24, r14
	ldi r22, 31
	rcall inv_sbox128
	
	movw r24, r14
	ldi r20, 16
	sub r12, r20
	sbc r13, r1
	movw r22, r12
	clr r21
	rcall memxor
	ldi r16, 31
1:
	dec r16
	movw r24, r14
	rcall serpent_inv_lt
	movw r24, r14
	mov r22, r16
	rcall inv_sbox128
	movw r24, r14
	ldi r20, 16
	sub r12, r20
	sbc r13, r1
	movw r22, r12
	clr r21
	rcall memxor
	
	tst r16
	brne 1b
	pop_ r16, r15, r14, r13, r12
	ret	
	
	
	














