// NKRYPT enigma implementation
// Copyright Glenn McIntosh 2013
// licensed under the GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
// compilation: g++ -O3 -std=c++11 -c enigma.cpp

// include files
#include <cstddef>
#include <cstdint>

// definitions
constexpr int N = 26;

// enigma engine
class Enigma
{
	public:
		// initialize rotor tables
		Enigma();

		// set rotor positions
		void set(int8_t s1, int8_t s2, int8_t s3, int8_t s4);
		void rot(int8_t i1, int8_t i2, int8_t i3, int8_t i4);

		// encrypt
		int8_t en(int8_t c) const;
	private:
		// rotors
		int8_t r1d[N], r2d[N], r3d[N], r4d[N];
		int8_t r5r[N];
		int8_t r4u[N], r3u[N], r2u[N], r1u[N];

		// setting
		int8_t o1, o2, o3, o4;
};

// initialize rotor tables
Enigma::Enigma()
{
	for (int i = 0; i < N; ++i)
	{
		r1d[i] = "udbcfgejhilmktsnopqrwxyzav"[i]-'a';
		r2d[i] = "bzcxwhifglmjkvupsqrtonedya"[i]-'a';
		r3d[i] = "zadefgchmijklopqrnwstuvbxy"[i]-'a';
		r4d[i] = "bdfcegijklsmaznhopqrtvxuwy"[i]-'a';
		r5r[i] = "zyvmlihgfkjedurqpotsncxwba"[i]-'a';
		r4u[i] = "madbecfpghijloqrstkuxvywzn"[i]-'a';
		r3u[i] = "bxgcdefhjklmirnopqtuvwsyza"[i]-'a';
		r2u[i] = "zacxwhifglmjkvuprsqtonedyb"[i]-'a';
		r1u[i] = "ycdbgefijhmklpqrstonazuvwx"[i]-'a';
	}
	o1 = o2 = o3 = o4 = 0;
}

// set rotor position
void Enigma::set(int8_t s1, int8_t s2, int8_t s3, int8_t s4)
{
	o1 = s1;
	o2 = s2;
	o3 = s3;
	o4 = s4;
}

// rotate rotor position
void Enigma::rot(int8_t i1, int8_t i2, int8_t i3, int8_t i4)
{
	// increment
	o1 += i1+N; o1 %= N;
	o2 += i2+N; o2 %= N;
	o3 += i3+N; o3 %= N;
	o4 += i4+N; o4 %= N;
}

// encrypt/decrypt
int8_t Enigma::en(int8_t c) const
{
	c -= 'A';
	c += N-o1; c = r1d[c%N]; c += o1;
	c += N-o2; c = r2d[c%N]; c += o2;
	c += N-o3; c = r3d[c%N]; c += o3;
	c += N-o4; c = r4d[c%N]; c += o4;
	c = r5r[c%N];
	c += N-o4; c = r4u[c%N]; c += o4;
	c += N-o3; c = r3u[c%N]; c += o3;
	c += N-o2; c = r2u[c%N]; c += o2;
	c += N-o1; c = r1u[c%N]; c += o1;
	c %= N;
	c += 'a';
	return c;
}
