on-the-fly decryption support for mrdrilr2

This commit is contained in:
joseluis 2016-09-16 17:24:11 +02:00
parent 8ab7875e89
commit d501f35e96
3 changed files with 272 additions and 173 deletions

View File

@ -279,12 +279,11 @@ public:
m_maincpu(*this, "maincpu") { }
// memm variant interface
DECLARE_WRITE16_MEMBER(key_w);
DECLARE_WRITE16_MEMBER(crypto_switch_w);
DECLARE_READ16_MEMBER(range_r);
DECLARE_WRITE16_MEMBER(bank_w);
// memn variant interface
DECLARE_WRITE16_MEMBER(crypto_switch_w);
DECLARE_READ16_MEMBER(nand_status_r);
DECLARE_WRITE8_MEMBER(nand_address1_w);
DECLARE_WRITE8_MEMBER(nand_address2_w);
@ -316,7 +315,6 @@ private:
I2CP_RECIEVE_ACK_0
};
UINT16 key;
UINT8 cnt;
UINT32 bank_base;
UINT32 nand_address;
UINT16 block[0x1ff];
@ -369,55 +367,36 @@ ADDRESS_MAP_END
// know until the decryption is done.
//
// bios copies 62000-37ffff from the flash to 80012000 in ram through the
// decryption in range_r then jumps there (and dies horribly, of course)
// decryption in range_r then jumps there
WRITE16_MEMBER(namcos10_state::key_w )
WRITE16_MEMBER(namcos10_state::crypto_switch_w)
{
key = (data >> 15) | (data << 1);
logerror("key_w %04x\n", key);
cnt = 0;
printf("crypto_switch_w: %04x\n", data);
if (decrypter == nullptr)
return;
if (BIT(data, 15) != 0)
decrypter->activate(data & 0xf);
else
decrypter->deactivate();
}
WRITE16_MEMBER(namcos10_state::bank_w)
{
bank_base = 0x80000 * offset;
bank_base = 0x100000 * offset;
}
READ16_MEMBER(namcos10_state::range_r)
{
UINT32 d16 = ((const UINT16 *)(memregion("maincpu:rom")->base()))[offset+bank_base];
UINT16 data = ((const UINT16 *)(memregion("maincpu:rom")->base()))[bank_base+offset];
/* This is not entirely correct, but not entirely incorrect either...
It's also specific to mrdriller2, it seems.
*/
if (decrypter == nullptr)
return data;
UINT16 dd16 = d16 ^ key;
key = d16;
key =
//(( BIT(d16, 3) ^ (BIT(cnt, 0) & !BIT(cnt, 2))) << 15) |
((1 ^ BIT(key, 3) ^ BIT(d16, 0)) << 15) |
((1 ^ BIT(key, 13) ^ BIT(cnt, 0)) << 14) |
((1 ^ BIT(key, 11) ^ BIT(d16, 5) ^ BIT(d16, 2)) << 13) |
(( BIT(key, 9) ^ BIT(cnt, 3)) << 12) |
((1 ^ BIT(key, 2)) << 11) |
(( BIT(key, 10) ^ (BIT(d16, 4) & BIT(cnt, 1))) << 10) |
((1 ^ BIT(key, 6) ^ BIT(cnt, 4)) << 9) |
((1 ^ BIT(d16, 6) ^ BIT(key, 5)) << 8) |
(( BIT(key, 1) ^ (BIT(d16, 5) | BIT(d16, 4))) << 7) |
(( BIT(key, 15)) << 6) |
((1 ^ BIT(key, 4) ^ BIT(cnt, 3) ^ BIT(d16, 2)) << 5) |
((1 ^ BIT(key, 7) ^ BIT(cnt, 5)) << 4) |
((1 ^ BIT(key, 8) ^ (BIT(cnt, 7) | BIT(d16, 3))) << 3) |
(( BIT(key, 14) ^ (BIT(cnt, 1) | BIT(d16, 7))) << 2) |
((1 ^ BIT(key, 12) ^ (BIT(cnt, 7) & BIT(d16, 7))) << 1) |
//(( (BIT(cnt, 0) | BIT(cnt, 2))) << 0);
((1 ^ BIT(key, 0) ^ BIT(cnt, 2)) << 0);
cnt++;
return dd16;
if (decrypter->is_active())
return decrypter->decrypt(data);
else
return data;
}
READ16_MEMBER(namcos10_state::control_r)
@ -556,7 +535,7 @@ void namcos10_state::i2c_update()
}
static ADDRESS_MAP_START( namcos10_memm_map, AS_PROGRAM, 32, namcos10_state )
AM_RANGE(0x1f300000, 0x1f300003) AM_WRITE16(key_w, 0x0000ffff)
AM_RANGE(0x1f300000, 0x1f300003) AM_WRITE16(crypto_switch_w, 0x0000ffff)
AM_RANGE(0x1f400000, 0x1f5fffff) AM_READ16(range_r, 0xffffffff)
AM_RANGE(0x1fb40000, 0x1fb4000f) AM_WRITE16(bank_w, 0xffffffff)
@ -569,18 +548,6 @@ ADDRESS_MAP_END
// Block access to the nand. Something strange is going on with the
// status port. Interaction with the decryption is unclear at best.
WRITE16_MEMBER(namcos10_state::crypto_switch_w)
{
printf("crypto_switch_w: %04x\n", data);
if (decrypter == nullptr)
return;
if (BIT(data, 15) != 0)
decrypter->activate(data & 0xf);
else
decrypter->deactivate();
}
READ16_MEMBER(namcos10_state::nand_status_r )
{
return 0;
@ -703,7 +670,10 @@ static void decrypt_bios( running_machine &machine, const char *regionName, int
DRIVER_INIT_MEMBER(namcos10_state,mrdrilr2)
{
int regSize = machine().root_device().memregion("maincpu:rom")->bytes();
decrypt_bios(machine(), "maincpu:rom", 0, regSize, 0xc, 0xd, 0xf, 0xe, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x4, 0x1, 0x2, 0x5, 0x0, 0x3);
decrypt_bios(machine(), "maincpu:rom", 0, 0x62000, 0xc, 0xd, 0xf, 0xe, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x4, 0x1, 0x2, 0x5, 0x0, 0x3);
decrypt_bios(machine(), "maincpu:rom", 0x380000, regSize, 0xc, 0xd, 0xf, 0xe, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x4, 0x1, 0x2, 0x5, 0x0, 0x3);
decrypter = static_cast<ns10_decrypter_device*>(machine().root_device().subdevice("decrypter"));
}
DRIVER_INIT_MEMBER(namcos10_state,gjspace)
@ -849,6 +819,11 @@ static MACHINE_CONFIG_START( namcos10_memn, namcos10_state )
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED(ns10_mrdrilr2, namcos10_memm)
/* decrypter device (CPLD in hardware?) */
MCFG_DEVICE_ADD("decrypter", MRDRILR2_DECRYPTER, 0)
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED(ns10_chocovdr, namcos10_memn)
/* decrypter device (CPLD in hardware?) */
MCFG_DEVICE_ADD("decrypter", CHOCOVDR_DECRYPTER, 0)
@ -1077,8 +1052,8 @@ ROM_START( konotako )
ROM_END
GAME( 2000, mrdrilr2, 0, namcos10_memm, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Japan, DR21 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
GAME( 2000, mrdrlr2a, mrdrilr2, namcos10_memm, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Asia, DR22 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
GAME( 2000, mrdrilr2, 0, ns10_mrdrilr2, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Japan, DR21 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
GAME( 2000, mrdrlr2a, mrdrilr2, ns10_mrdrilr2, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Asia, DR22 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
GAME( 2000, ptblank3, 0, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Point Blank 3 (Asia, GNN2 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
GAME( 2000, gunbalina, ptblank3, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Gunbalina (Japan, GNN1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
GAME( 2001, gjspace, 0, ns10_gjspace , namcos10, namcos10_state, gjspace, ROT0, "Namco / Metro", "Gekitoride-Jong Space (10011 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )

View File

@ -3,15 +3,17 @@
/****************************************************************************
Namco System 10 decryption emulation
(As of 2015-08, this file is still pretty much a WIP; changes are expected as
out knowledge progress.)
The decryption used by type-2 System10 PCBs (MEM-N) acts on 16-bit words and is
The decryption used by both System10 PCB types act on 16-bit words and is
designed to operate in a serial way: once the decryption is triggered, every
word is XORed with a mask calculated over data taken from the previous words
(both encrypted and decrypted). Type-1 PCBs seem to use a similar
scheme, probably involving the word address too and a bitswap, but his relation
to what is described here needs further investigation.
(both encrypted and decrypted). Type-1 (MEM-M) calculate the mask using the previous
cipherword and plainword, plus the 8 lowest bits of the word address. Type-2 (MEM-N)
boards dropped the use of the word address (maybe due to the serial protocol
used by the K9F2808U0B?), but expanded the number of previous cipherwords and
plainwords used up to three.
The only known type-1 game (mrdrilr2) has the encrypted data contained in them
[0x62000,0x380000] region of the first ROM of the game (1A).
In type-2 PCBs, the encrypted data is always contained in the first ROM of the
game (8E), and it's always stored spanning an integer number of NAND blocks
@ -48,22 +50,26 @@ the end-of-ROM region, in what maybe is an attempt to hinder the
recognition/reconstruction of the encrypted data.
Most games do a single decryption run, so the process is only initialized once;
however, at least three of them (gamshara, mrdrilrg & panikuru) do reinitialize the
internal state of the decrypted several times. As of 2015-08-19, only gamshara shows signs
however, at least four of them (mrdrilr2, gamshara, mrdrilrg & panikuru) do
reinitialize the internal state of the decryption several times. As of 2016-09-16,
only mrdrilr2 (type-1) and gamshara (type-2) show signs
of doing it by writing to the triggering register; how the others two are triggering the
reinitializations is still unclear. gamshara does a reinitialization every 5 NAND blocks
reinitializations is still unclear. mrdrilr2 does a reinitialization every time the address
hits a 0x80000-bytes multiple); gamshara does a reinitialization every 5 NAND blocks
(16 times in total); mrdrilrg does the second one after 0x38000 bytes and then subsequent
ones every 32 blocks (8 times in total); panikuru does one every 2 blocks up to a total
of 16 times.
The calculation of the XOR masks seem to operate this way: most bits are
The calculation of the XOR masks operate in this way: most bits are
calculated by using linear equations over GF(2) taking as input data the bits from
previously processed words; however, one nonlinear calculation is performed
per word processed, and that calculation typically affect just one bit (the only
known exception is mrdrilrg, where the same nonlinear terms are
affecting two of them). Till now, all the formulae seem to depend only on the
per word processed, and that calculation typically affect just one bit. The only
known exceptions are mrdrilr2 (type-1), where the counter is used in nonlinear terms
(but, like in type-2 ones, just one nonlinear term involving previous words is present),
and mrdrilrg (type-2), where the same nonlinear terms are
affecting two of them). Till now, all the formulae for type-2 games seem to depend only on the
previous 3 words, and the first mask after a (re-)initialization is always zero, so
chances are the mask bits are calculated one word in advance, having access to the
chances are that the mask bits are calculated one word in advance, having access to the
current encrypted and decrypted words plus two further words in each sequence, maybe stored
in 32 bits registers. All the nonlinear terms reverse-engineered till now are of the form
A x B, where A and B are linear formulae; thus, as everything else in the schema involves
@ -71,7 +77,7 @@ only linear relations, those nonlinear terms are probably caused by an Y-combina
the resuls of two such linear relations as input, and deciding between both branches based
on another linear formula.
The bits affected by the nonlinear calculations are given below:
The bits affected by the nonlinear calculations in type-2 games are given below:
chocovdr -> #10
gamshara -> #2
gjspace -> none
@ -93,11 +99,10 @@ equivalent datasets, nothing else.
TO-DO:
* If further dumps support the theory of the calculations just depending on 3 previous words,
change the implementation accordingly to reflect that.
* Research how type-1 encryption is related to this.
* If further dumps support the theory of the calculations of type-2 games just depending
on 3 previous words, change the implementation accordingly to reflect that.
Observing the linear equations, there is a keen difference between bits using
Observing the linear equations of type-2 games, there is a keen difference between bits using
just a bunch of previous bits, and others using much more bits from more words;
simplifying the latter ones could be handy, and probably closer to what the
hardware is doing. Two possible simplifications could be:
@ -113,22 +118,21 @@ really exist.
#include "emu.h"
#include "ns10crypt.h"
const device_type CHOCOVDR_DECRYPTER = &device_creator<chocovdr_decrypter_device>;
const device_type GAMSHARA_DECRYPTER = &device_creator<gamshara_decrypter_device>;
const device_type GJSPACE_DECRYPTER = &device_creator<gjspace_decrypter_device>;
const device_type KNPUZZLE_DECRYPTER = &device_creator<knpuzzle_decrypter_device>;
const device_type KONOTAKO_DECRYPTER = &device_creator<konotako_decrypter_device>;
const device_type NFLCLSFB_DECRYPTER = &device_creator<nflclsfb_decrypter_device>;
const device_type STARTRGN_DECRYPTER = &device_creator<startrgn_decrypter_device>;
constexpr device_type CHOCOVDR_DECRYPTER = &device_creator<chocovdr_decrypter_device>;
constexpr device_type GAMSHARA_DECRYPTER = &device_creator<gamshara_decrypter_device>;
constexpr device_type GJSPACE_DECRYPTER = &device_creator<gjspace_decrypter_device>;
constexpr device_type KNPUZZLE_DECRYPTER = &device_creator<knpuzzle_decrypter_device>;
constexpr device_type KONOTAKO_DECRYPTER = &device_creator<konotako_decrypter_device>;
constexpr device_type MRDRILR2_DECRYPTER = &device_creator<mrdrilr2_decrypter_device>;
constexpr device_type NFLCLSFB_DECRYPTER = &device_creator<nflclsfb_decrypter_device>;
constexpr device_type STARTRGN_DECRYPTER = &device_creator<startrgn_decrypter_device>;
// this could perfectly be part of the per-game logic; by now, only gamshara seems to use it, so we keep it global
const int ns10_decrypter_device::initSbox[16] = {0,12,13,6,2,4,9,8,11,1,7,15,10,5,14,3};
// base class
ns10_decrypter_device::ns10_decrypter_device(device_type type, const ns10_crypto_logic &logic, const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
ns10_decrypter_device::ns10_decrypter_device(device_type type, const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, "Namco System 10 Decrypter", tag, owner, clock, "ns10_crypto", __FILE__)
, _active(false)
, _logic(logic)
{
_active = false;
}
void ns10_decrypter_device::activate(int iv)
@ -147,9 +151,77 @@ bool ns10_decrypter_device::is_active()const
return _active;
}
UINT16 ns10_decrypter_device::decrypt(UINT16 cipherword)
ns10_decrypter_device::~ns10_decrypter_device()
{
UINT16 plainword = cipherword ^ _mask;
}
// type-1 decrypter
constexpr int UNKNOWN {16};
constexpr int U {UNKNOWN};
// this could perfectly be part of the per-game logic but, with only one known type-1 game, we cannot say anything definitive
constexpr int ns10_type1_decrypter_device::initSbox[16] {U,U,U,0,4,9,U,U,U,8,U,1,U,9,U,5};
ns10_type1_decrypter_device::ns10_type1_decrypter_device(device_type type, const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_decrypter_device(type, mconfig, tag, owner, clock)
{
}
uint16_t ns10_type1_decrypter_device::decrypt(uint16_t cipherword)
{
uint16_t plainword = _mask ^ bitswap(cipherword,9,13,15,7,14,8,6,10,11,12,3,5,0,1,4,2);
uint16_t nbs =
((BIT(_counter, 4) ) << 15) ^
((BIT(cipherword, 2) ^ BIT(cipherword, 5) ) << 14) ^
((BIT(cipherword, 0) ) << 13) ^
(((BIT(cipherword, 4) | BIT(cipherword, 5))) << 12) ^ // this is the only nonlinear term not involving the counter
((BIT(_counter, 0) ) << 11) ^
((BIT(cipherword, 6) ) << 10) ^
(((BIT(cipherword, 4) & BIT(_counter, 1)) ) << 8) ^
((BIT(_counter, 3) ) << 6) ^
(((BIT(cipherword, 3) | BIT(_counter, 7)) ) << 5) ^
((BIT(cipherword, 2) ^ BIT(_counter, 3) ) << 4) ^
((BIT(_counter, 2) ) << 3) ^
(((BIT(cipherword, 7) & BIT(_counter, 7)) ) << 2) ^
((BIT(_counter, 5) ) << 1) ^
(((BIT(cipherword, 7) | BIT(_counter, 1)) ) << 0);
_mask = nbs
^ bitswap(cipherword, 6,11, 3, 1,13, 5,15,10, 2, 9, 8, 4, 0,12, 7,14)
^ bitswap(plainword , 9, 7, 5, 2,14, 4,13, 8, 0,15,10, 1, 3, 6,12,11)
^ 0xecbe;
++_counter;
return plainword;
}
void ns10_type1_decrypter_device::init(int iv)
{
_mask = initSbox[iv];
_counter = 0;
}
void ns10_type1_decrypter_device::device_start()
{
_active = false;
}
// type-2 decrypter
// this could perfectly be part of the per-game logic; by now, only gamshara seems to use it, so we keep it global
constexpr int ns10_type2_decrypter_device::initSbox[16] {0,12,13,6,2,4,9,8,11,1,7,15,10,5,14,3};
ns10_type2_decrypter_device::ns10_type2_decrypter_device(device_type type, const ns10_crypto_logic &logic, const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_decrypter_device(type, mconfig, tag, owner, clock)
, _logic(logic)
{
}
uint16_t ns10_type2_decrypter_device::decrypt(UINT16 cipherword)
{
uint16_t plainword = cipherword ^ _mask;
_previous_cipherwords <<= 16;
_previous_cipherwords ^= cipherword;
@ -169,20 +241,21 @@ UINT16 ns10_decrypter_device::decrypt(UINT16 cipherword)
return plainword;
}
void ns10_decrypter_device::device_start()
void ns10_type2_decrypter_device::init(int iv)
{
// by now, only gamshara requires non-trivial initialization code; data
// should be moved to the per-game logic in case any other game do it differently
_previous_cipherwords = bitswap(initSbox[iv],3,16,16,2,1,16,16,0,16,16,16,16,16,16,16,16);
_previous_plainwords = 0;
_mask = 0;
}
void ns10_type2_decrypter_device::device_start()
{
_active = false;
_reducer = std::make_unique<gf2_reducer>();
}
void ns10_decrypter_device::init(int iv)
{
// by now, only gamshara requires non-trivial initialization code; data
// should be moved to the per-game logic in case any other game do it differently
_previous_cipherwords = BITSWAP16(initSbox[iv],3,16,16,2,1,16,16,0,16,16,16,16,16,16,16,16);
_previous_plainwords = 0;
_mask = 0;
}
gf2_reducer::gf2_reducer()
{
@ -191,11 +264,13 @@ gf2_reducer::gf2_reducer()
// create a look-up table of GF2 reductions of 16-bits words
for (int i = 0; i < 0x10000; ++i)
{
reduction = 0;
for (int j = 0; j < 16; ++j)
reduction ^= BIT(i, j);
reduction = i;
reduction ^= reduction >> 8;
reduction ^= reduction >> 4;
reduction ^= reduction >> 2;
reduction ^= reduction >> 1;
_gf2Reduction[i] = reduction;
_gf2Reduction[i] = reduction & 1;
}
}
@ -211,25 +286,25 @@ int gf2_reducer::gf2_reduce(UINT64 num)const
// game-specific logic
// static UINT16 mrdrilrg_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer)
// static uint16_t mrdrilrg_nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer& reducer)
// {
// UINT64 previous_masks = previous_cipherwords ^ previous_plainwords;
// uint64_t previous_masks = previous_cipherwords ^ previous_plainwords;
// return (reducer.gf2_reduce(0x00000a00a305c826ull & previous_masks) & reducer.gf2_reduce(0x0000011800020000ull & previous_masks)) * 0x0011;
// }
// static UINT16 panikuru_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer)
// static uint16_t panikuru_nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer& reducer)
// {
// return ((reducer.gf2_reduce(0x0000000088300281ull & previous_cipherwords) ^ reducer.gf2_reduce(0x0000000004600281ull & previous_plainwords))
// & (reducer.gf2_reduce(0x0000a13140090000ull & previous_cipherwords) ^ reducer.gf2_reduce(0x0000806240090000ull & previous_plainwords))) << 2;
// }
static UINT16 chocovdr_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer)
static uint16_t chocovdr_nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer& reducer)
{
UINT64 previous_masks = previous_cipherwords ^ previous_plainwords;
uint64_t previous_masks = previous_cipherwords ^ previous_plainwords;
return ((previous_masks >> 9) & (reducer.gf2_reduce(0x0000000010065810ull & previous_cipherwords) ^ reducer.gf2_reduce(0x0000000021005810ull & previous_plainwords)) & 1) << 10;
}
static const ns10_decrypter_device::ns10_crypto_logic chocovdr_crypto_logic = {
static constexpr ns10_type2_decrypter_device::ns10_crypto_logic chocovdr_crypto_logic = {
{
0x00005239351ec1daull, 0x0000000000008090ull, 0x0000000048264808ull, 0x0000000000004820ull,
0x0000000000000500ull, 0x0000000058ff5a54ull, 0x00000000d8220208ull, 0x00005239351e91d3ull,
@ -245,13 +320,13 @@ static const ns10_decrypter_device::ns10_crypto_logic chocovdr_crypto_logic = {
chocovdr_nonlinear_calc
};
static UINT16 gamshara_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer&)
static uint16_t gamshara_nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer&)
{
UINT64 previous_masks = previous_cipherwords ^ previous_plainwords;
uint64_t previous_masks = previous_cipherwords ^ previous_plainwords;
return ((previous_masks >> 7) & (previous_masks >> 13) & 1) << 2;
}
static const ns10_decrypter_device::ns10_crypto_logic gamshara_crypto_logic = {
static constexpr ns10_type2_decrypter_device::ns10_crypto_logic gamshara_crypto_logic = {
{
0x0000000000000028ull, 0x0000cae83f389fd9ull, 0x0000000000001000ull, 0x0000000042823402ull,
0x0000cae8736a0592ull, 0x0000cae8736a8596ull, 0x000000008b4095b9ull, 0x0000000000002100ull,
@ -267,12 +342,12 @@ static const ns10_decrypter_device::ns10_crypto_logic gamshara_crypto_logic = {
gamshara_nonlinear_calc
};
static UINT16 gjspace_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer&)
static uint16_t gjspace_nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer&)
{
return 0;
}
static const ns10_decrypter_device::ns10_crypto_logic gjspace_crypto_logic = {
static constexpr ns10_type2_decrypter_device::ns10_crypto_logic gjspace_crypto_logic = {
{
0x0000000000000240ull, 0x0000d617eb0f1ab1ull, 0x00000000451111c0ull, 0x00000000013b1f44ull,
0x0000aab0b356abceull, 0x00007ca76b89602aull, 0x0000000000001800ull, 0x00000000031d1303ull,
@ -288,13 +363,13 @@ static const ns10_decrypter_device::ns10_crypto_logic gjspace_crypto_logic = {
gjspace_nonlinear_calc
};
static UINT16 knpuzzle_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer)
static uint16_t knpuzzle_nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer& reducer)
{
UINT64 previous_masks = previous_cipherwords ^ previous_plainwords;
uint64_t previous_masks = previous_cipherwords ^ previous_plainwords;
return ((previous_masks >> 0x13) & (reducer.gf2_reduce(0x0000000014001290ull & previous_cipherwords) ^ reducer.gf2_reduce(0x0000000000021290ull & previous_plainwords)) & 1) << 1;
}
static const ns10_decrypter_device::ns10_crypto_logic knpuzzle_crypto_logic = {
static constexpr ns10_type2_decrypter_device::ns10_crypto_logic knpuzzle_crypto_logic = {
{
0x00000000c0a4208cull, 0x00000000204100a8ull, 0x000000000c0306a0ull, 0x000000000819e944ull,
0x0000000000001400ull, 0x0000000000000061ull, 0x000000000141401cull, 0x0000000000000020ull,
@ -310,13 +385,13 @@ static const ns10_decrypter_device::ns10_crypto_logic knpuzzle_crypto_logic = {
knpuzzle_nonlinear_calc
};
static UINT16 konotako_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer&)
static uint16_t konotako_nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer&)
{
UINT64 previous_masks = previous_cipherwords ^ previous_plainwords;
uint64_t previous_masks = previous_cipherwords ^ previous_plainwords;
return ((previous_masks >> 7) & (previous_masks >> 15) & 1) << 15;
}
static const ns10_decrypter_device::ns10_crypto_logic konotako_crypto_logic = {
static constexpr ns10_type2_decrypter_device::ns10_crypto_logic konotako_crypto_logic = {
{
0x000000000000004cull, 0x00000000d39e3d3dull, 0x0000000000001110ull, 0x0000000000002200ull,
0x000000003680c008ull, 0x0000000000000281ull, 0x0000000000005002ull, 0x00002a7371895a47ull,
@ -332,13 +407,13 @@ static const ns10_decrypter_device::ns10_crypto_logic konotako_crypto_logic = {
konotako_nonlinear_calc
};
static UINT16 nflclsfb_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer& reducer)
static uint16_t nflclsfb_nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer& reducer)
{
UINT64 previous_masks = previous_cipherwords ^ previous_plainwords;
uint64_t previous_masks = previous_cipherwords ^ previous_plainwords;
return ((previous_masks >> 1) & (reducer.gf2_reduce(0x0000000040de8fb3ull & previous_cipherwords) ^ reducer.gf2_reduce(0x0000000088008fb3ull & previous_plainwords)) & 1) << 2;
}
static const ns10_decrypter_device::ns10_crypto_logic nflclsfb_crypto_logic = {
static constexpr ns10_type2_decrypter_device::ns10_crypto_logic nflclsfb_crypto_logic = {
{
0x000034886e281880ull, 0x0000000012c5e7baull, 0x0000000000000200ull, 0x000000002900002aull,
0x00000000000004c0ull, 0x0000000012c5e6baull, 0x00000000e0df8bbbull, 0x000000002011532aull,
@ -354,13 +429,13 @@ static const ns10_decrypter_device::ns10_crypto_logic nflclsfb_crypto_logic = {
nflclsfb_nonlinear_calc
};
static UINT16 startrgn_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords, const gf2_reducer&)
static uint16_t startrgn_nonlinear_calc(uint64_t previous_cipherwords, uint64_t previous_plainwords, const gf2_reducer&)
{
UINT64 previous_masks = previous_cipherwords ^ previous_plainwords;
uint64_t previous_masks = previous_cipherwords ^ previous_plainwords;
return ((previous_masks >> 12) & (previous_masks >> 14) & 1) << 4;
}
static const ns10_decrypter_device::ns10_crypto_logic startrgn_crypto_logic = {
static constexpr ns10_type2_decrypter_device::ns10_crypto_logic startrgn_crypto_logic = {
{
0x00003e4bfe92c6a9ull, 0x000000000000010cull, 0x00003e4b7bd6c4aaull, 0x0000b1a904b8fab8ull,
0x0000000000000080ull, 0x0000000000008c00ull, 0x0000b1a9b2f0b4cdull, 0x000000006c100828ull,
@ -379,37 +454,42 @@ static const ns10_decrypter_device::ns10_crypto_logic startrgn_crypto_logic = {
// game-specific devices
chocovdr_decrypter_device::chocovdr_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ns10_decrypter_device(CHOCOVDR_DECRYPTER, chocovdr_crypto_logic, mconfig, tag, owner, clock)
mrdrilr2_decrypter_device::mrdrilr2_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_type1_decrypter_device(MRDRILR2_DECRYPTER,mconfig, tag, owner, clock)
{
}
gamshara_decrypter_device::gamshara_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ns10_decrypter_device(GAMSHARA_DECRYPTER, gamshara_crypto_logic, mconfig, tag, owner, clock)
chocovdr_decrypter_device::chocovdr_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_type2_decrypter_device(CHOCOVDR_DECRYPTER, chocovdr_crypto_logic, mconfig, tag, owner, clock)
{
}
gjspace_decrypter_device::gjspace_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ns10_decrypter_device(GJSPACE_DECRYPTER, gjspace_crypto_logic, mconfig, tag, owner, clock)
gamshara_decrypter_device::gamshara_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_type2_decrypter_device(GAMSHARA_DECRYPTER, gamshara_crypto_logic, mconfig, tag, owner, clock)
{
}
knpuzzle_decrypter_device::knpuzzle_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ns10_decrypter_device(KNPUZZLE_DECRYPTER, knpuzzle_crypto_logic, mconfig, tag, owner, clock)
gjspace_decrypter_device::gjspace_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_type2_decrypter_device(GJSPACE_DECRYPTER, gjspace_crypto_logic, mconfig, tag, owner, clock)
{
}
konotako_decrypter_device::konotako_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ns10_decrypter_device(KONOTAKO_DECRYPTER, konotako_crypto_logic, mconfig, tag, owner, clock)
knpuzzle_decrypter_device::knpuzzle_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_type2_decrypter_device(KNPUZZLE_DECRYPTER, knpuzzle_crypto_logic, mconfig, tag, owner, clock)
{
}
nflclsfb_decrypter_device::nflclsfb_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ns10_decrypter_device(NFLCLSFB_DECRYPTER, nflclsfb_crypto_logic, mconfig, tag, owner, clock)
konotako_decrypter_device::konotako_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_type2_decrypter_device(KONOTAKO_DECRYPTER, konotako_crypto_logic, mconfig, tag, owner, clock)
{
}
startrgn_decrypter_device::startrgn_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ns10_decrypter_device(STARTRGN_DECRYPTER, startrgn_crypto_logic, mconfig, tag, owner, clock)
nflclsfb_decrypter_device::nflclsfb_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_type2_decrypter_device(NFLCLSFB_DECRYPTER, nflclsfb_crypto_logic, mconfig, tag, owner, clock)
{
}
startrgn_decrypter_device::startrgn_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ns10_type2_decrypter_device(STARTRGN_DECRYPTER, startrgn_crypto_logic, mconfig, tag, owner, clock)
{
}

View File

@ -4,99 +4,143 @@
#ifndef _NS10CRYPT_H_
#define _NS10CRYPT_H_
#include <cstdint>
class gf2_reducer // helper class
{
public:
gf2_reducer();
int gf2_reduce(UINT64 num)const;
int gf2_reduce(uint64_t num)const;
private:
int _gf2Reduction[0x10000];
};
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(device_type type, const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual void init(int iv)=0;
virtual void device_start()=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);
protected:
ns10_type1_decrypter_device(device_type type, const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
private:
uint16_t _mask;
uint8_t _counter;
static const int initSbox[16];
void init(int iv);
void device_start()override;
};
class ns10_type2_decrypter_device : public ns10_decrypter_device
{
public:
// this encodes the decryption logic, which varies per game
// and is probably hard-coded into the CPLD
struct ns10_crypto_logic
{
UINT64 eMask[16];
UINT64 dMask[16];
UINT16 xMask;
UINT16(*nonlinear_calculation)(UINT64, UINT64, const gf2_reducer&); // preliminary encoding; need research
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
};
void activate(int iv);
void deactivate();
bool is_active()const;
UINT16 decrypt(UINT16 cipherword);
uint16_t decrypt(uint16_t cipherword);
protected:
ns10_decrypter_device(
device_type type, const ns10_decrypter_device::ns10_crypto_logic &logic,
ns10_type2_decrypter_device(
device_type type, const ns10_type2_decrypter_device::ns10_crypto_logic &logic,
const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
private:
UINT16 _mask;
UINT64 _previous_cipherwords;
UINT64 _previous_plainwords;
bool _active;
uint16_t _mask;
uint64_t _previous_cipherwords;
uint64_t _previous_plainwords;
const ns10_crypto_logic& _logic;
static const int initSbox[16];
std::unique_ptr<const gf2_reducer>_reducer;
static const int initSbox[16];
void device_start() override;
void init(int iv);
void device_start()override;
};
// game-specific devices
class chocovdr_decrypter_device : public ns10_decrypter_device
class mrdrilr2_decrypter_device : public ns10_type1_decrypter_device
{
public:
chocovdr_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
mrdrilr2_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
class gamshara_decrypter_device : public ns10_decrypter_device
class chocovdr_decrypter_device : public ns10_type2_decrypter_device
{
public:
gamshara_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
chocovdr_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
class gjspace_decrypter_device : public ns10_decrypter_device
class gamshara_decrypter_device : public ns10_type2_decrypter_device
{
public:
gjspace_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
gamshara_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
class knpuzzle_decrypter_device : public ns10_decrypter_device
class gjspace_decrypter_device : public ns10_type2_decrypter_device
{
public:
knpuzzle_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
gjspace_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
class konotako_decrypter_device : public ns10_decrypter_device
class knpuzzle_decrypter_device : public ns10_type2_decrypter_device
{
public:
konotako_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
knpuzzle_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
class nflclsfb_decrypter_device : public ns10_decrypter_device
class konotako_decrypter_device : public ns10_type2_decrypter_device
{
public:
nflclsfb_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
konotako_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
class startrgn_decrypter_device : public ns10_decrypter_device
class nflclsfb_decrypter_device : public ns10_type2_decrypter_device
{
public:
startrgn_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
nflclsfb_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
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);
};
extern const device_type MRDRILR2_DECRYPTER;
extern const device_type CHOCOVDR_DECRYPTER;
extern const device_type GAMSHARA_DECRYPTER;
extern const device_type GJSPACE_DECRYPTER;