// license:BSD-3-Clause
// copyright-holders:Andreas Naive

#ifndef MAME_MACHINE_NS10CRYPT_H
#define MAME_MACHINE_NS10CRYPT_H

#include <cstdint>

class ns10_decrypter_device : public device_t
{
public:
	void activate(int iv);
	void deactivate();
	bool is_active()const;

	virtual uint16_t decrypt(uint16_t cipherword)=0;
	virtual ~ns10_decrypter_device();

protected:
	ns10_decrypter_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	virtual void init(int iv)=0;
	virtual void device_start()override=0;

	bool _active;
};

class ns10_type1_decrypter_device : public ns10_decrypter_device
{
public:
	// with just only type-1 game known, we cannot say which parts of the crypto_logic is common, if any,
	// and which is game-specific. In practice, this class is just an alias for the decrypter device of mrdrilr2
	uint16_t decrypt(uint16_t cipherword)override;

protected:
	ns10_type1_decrypter_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

private:
	uint16_t _mask;
	uint8_t _counter;
	static const int initSbox[16];

	void init(int iv)override;
	void device_start()override;
};


class ns10_type2_decrypter_device : public ns10_decrypter_device
{
public:
	uint16_t decrypt(uint16_t cipherword)override;

protected:
	class gf2_reducer  // helper class
	{
	public:
		gf2_reducer();
		int gf2_reduce(uint64_t num)const;
	private:
		int _gf2Reduction[0x10000];
	};

	// this encodes the decryption logic, which varies per game
	// and is probably hard-coded into the CPLD
	struct ns10_crypto_logic
	{
		uint64_t eMask[16];
		uint64_t dMask[16];
		uint16_t xMask;
		uint16_t(*nonlinear_calculation)(uint64_t, uint64_t, const gf2_reducer&);  // preliminary encoding; need research
	};

	ns10_type2_decrypter_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const ns10_crypto_logic &logic);

private:
	uint16_t _mask;
	uint64_t _previous_cipherwords;
	uint64_t _previous_plainwords;
	const ns10_crypto_logic& _logic;
	std::unique_ptr<const gf2_reducer>_reducer;
	static const int initSbox[16];

	void init(int iv)override;
	void device_start()override;
};



// game-specific devices

class mrdrilr2_decrypter_device : public ns10_type1_decrypter_device
{
public:
	mrdrilr2_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};

class chocovdr_decrypter_device : public ns10_type2_decrypter_device
{
public:
	chocovdr_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
private:
	static uint16_t nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer &reducer);
	static const ns10_crypto_logic crypto_logic;
};

class gamshara_decrypter_device : public ns10_type2_decrypter_device
{
public:
	gamshara_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
private:
	static uint16_t nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer &reducer);
	static const ns10_crypto_logic crypto_logic;
};

class gjspace_decrypter_device : public ns10_type2_decrypter_device
{
public:
	gjspace_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
private:
	static uint16_t nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer &reducer);
	static const ns10_crypto_logic crypto_logic;
};

class knpuzzle_decrypter_device : public ns10_type2_decrypter_device
{
public:
	knpuzzle_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
private:
	static uint16_t nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer &reducer);
	static const ns10_crypto_logic crypto_logic;
};

class konotako_decrypter_device : public ns10_type2_decrypter_device
{
public:
	konotako_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
private:
	static uint16_t nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer &reducer);
	static const ns10_crypto_logic crypto_logic;
};

class nflclsfb_decrypter_device : public ns10_type2_decrypter_device
{
public:
	nflclsfb_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
private:
	static uint16_t nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer &reducer);
	static const ns10_crypto_logic crypto_logic;
};

class startrgn_decrypter_device : public ns10_type2_decrypter_device
{
public:
	startrgn_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
private:
	static uint16_t nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer &reducer);
	static const ns10_crypto_logic crypto_logic;
};


DECLARE_DEVICE_TYPE(CHOCOVDR_DECRYPTER, chocovdr_decrypter_device)
DECLARE_DEVICE_TYPE(GAMSHARA_DECRYPTER, gamshara_decrypter_device)
DECLARE_DEVICE_TYPE(GJSPACE_DECRYPTER,  gjspace_decrypter_device)
DECLARE_DEVICE_TYPE(KNPUZZLE_DECRYPTER, knpuzzle_decrypter_device)
DECLARE_DEVICE_TYPE(KONOTAKO_DECRYPTER, konotako_decrypter_device)
DECLARE_DEVICE_TYPE(MRDRILR2_DECRYPTER, mrdrilr2_decrypter_device)
DECLARE_DEVICE_TYPE(NFLCLSFB_DECRYPTER, nflclsfb_decrypter_device)
DECLARE_DEVICE_TYPE(STARTRGN_DECRYPTER, startrgn_decrypter_device)

#endif // MAME_MACHINE_NS10CRYPT_H
