#include <stdio.h>
#include <string.h>

#define ROUNDS 2

int INVKEYS[] = {
	0, 1, 9, 6, 13, 7, 3, 5, 15, 2, 12, 14, 10, 4, 11, 8
};

int xor(int a, int b)
{
	return (a ^ b) % 16;
}

int add(int a, int b)
{
	return (a + b) % 16;
}

int mul(int a, int b)
{
	int temp = 0;

	if (a == 0) {
		if (b == 0) {
			temp = 1;
		} else {
			temp = 17 - b;
		}
	} else {
		if (b == 0) {
			temp = 17 - a;
		} else {
			temp = (a * b) % 17;
		}
	}
	if (temp == 16) return 0;
	else return temp;
}

void round(int state[], int keys[])
{
	int a,b,c,d,e,f,g,h,i,j;
	
	a = mul(state[0], keys[0]);
	b = add(state[1], keys[1]);
	c = add(state[2], keys[2]);
	d = mul(state[3], keys[3]);
	
	e = xor(a, c);
	f = xor(b, d);
	
	g = mul(e, keys[4]);
	h = add(f, g);
	
	j = mul(h, keys[5]);
	i = add(g, j);
	
	state[0] = xor(a, j);
	state[1] = xor(c, j);
	state[2] = xor(b, i);
	state[3] = xor(d, i);
}

void encrypt(int state[], int keys[][6])
{
	int i;
	for (i = 0; i < ROUNDS; i++) round(state, keys[i]);
}

void invround(int state[], int keys[])
{
	int a,b,c,d,e,f,g,h,i,j;
	
	e = xor(state[0], state[1]);
	f = xor(state[2], state[3]);
	
	g = mul(e, keys[4]);
	h = add(f, g);
	j = mul(h, keys[5]);
	i = add(g, j);

	a = xor(state[0], j);
	c = xor(state[1], j);
	b = xor(state[2], i);
	d = xor(state[3], i);

	state[0] = mul(a, INVKEYS[keys[0]]);
	state[1] = add(b, 16 - keys[1]);
	state[2] = add(c, 16 - keys[2]);
	state[3] = mul(d, INVKEYS[keys[3]]);
}

void decrypt(int state[], int keys[][6])
{
	int i;
	for (i = ROUNDS-1; i >= 0; i--) invround(state, keys[i]);
}

int main(int argc, char *argv[])
{
	int i;
	unsigned short s;
	int decr = 0;
	int state[] = { 0x00, 0x00, 0x00, 0x00 };
	int keys[][6] = {
		{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 },
		{ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c },
	};
	
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-d") == 0) decr = 1;
	}

	while (1) {
		i = fread(&s, 2, 1, stdin);
		if (i == 0) break;
		
		state[0] = (s >> 12) & 0x0f;
		state[1] = (s >> 8) & 0x0f;
		state[2] = (s >> 4) & 0x0f;
		state[3] = s & 0x0f;
		
		if (decr) decrypt(state, keys);
		else encrypt(state, keys);
		
		s = (((((state[0] << 4) | state[1]) << 4) | state[2]) << 4) | state[3];
		
		fwrite(&s, 2, 1, stdout);
	}

/* test operacie nasobenia */
/*
	int i, j;

	printf("    ");
	for (i = 0; i < 16; i++) {
		printf("%2d  ", i);
	}
	printf("\n\n");

	for (i = 0; i < 16; i++) {
		printf("%2d: ", i);
		for (j = 0; j < 16; j++) {
			printf("%2d  ", mul(i,j));
		}
		printf("\n");
	}

	for (i = 0; i < 16; i++) {
		printf("%2d * %2d = %2d\n", i, INVKEYS[i], mul(i, INVKEYS[i]));
	}
*/

	return 0;
}
