WiimoteEmu: Implement uDraw GameTablet.

This commit is contained in:
Jordan Woyak 2018-12-14 19:53:20 -06:00
parent 360f2b4a2f
commit 2babbd76d0
26 changed files with 875 additions and 282 deletions

View file

@ -148,6 +148,7 @@ add_library(core
HW/WiimoteEmu/Extension/Drums.cpp
HW/WiimoteEmu/Extension/Guitar.cpp
HW/WiimoteEmu/Extension/Turntable.cpp
HW/WiimoteEmu/Extension/UDrawTablet.cpp
HW/WiimoteReal/WiimoteReal.cpp
HW/WiiSave.cpp
IOS/Device.cpp

View file

@ -182,6 +182,7 @@
<ClCompile Include="HW\WiimoteEmu\Extension\Guitar.cpp" />
<ClCompile Include="HW\WiimoteEmu\Extension\Nunchuk.cpp" />
<ClCompile Include="HW\WiimoteEmu\Extension\Turntable.cpp" />
<ClCompile Include="HW\WiimoteEmu\Extension\UDrawTablet.cpp" />
<ClCompile Include="HW\WiimoteEmu\I2CBus.cpp" />
<ClCompile Include="HW\WiimoteEmu\MotionPlus.cpp" />
<ClCompile Include="HW\WiimoteEmu\Speaker.cpp" />
@ -449,6 +450,7 @@
<ClInclude Include="HW\WiimoteEmu\Extension\Guitar.h" />
<ClInclude Include="HW\WiimoteEmu\Extension\Nunchuk.h" />
<ClInclude Include="HW\WiimoteEmu\Extension\Turntable.h" />
<ClInclude Include="HW\WiimoteEmu\Extension\UDrawTablet.h" />
<ClInclude Include="HW\WiimoteEmu\I2CBus.h" />
<ClInclude Include="HW\WiimoteEmu\MotionPlus.h" />
<ClInclude Include="HW\WiimoteEmu\Speaker.h" />

View file

@ -907,6 +907,9 @@
<ClCompile Include="HW\WiimoteEmu\Extension\Turntable.cpp">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
</ClCompile>
<ClCompile Include="HW\WiimoteEmu\Extension\UDrawTablet.cpp">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
</ClCompile>
<ClCompile Include="HW\WiimoteEmu\Extension\Extension.cpp">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
</ClCompile>
@ -1619,6 +1622,9 @@
<ClInclude Include="HW\WiimoteEmu\Extension\Turntable.h">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
</ClInclude>
<ClInclude Include="HW\WiimoteEmu\Extension\UDrawTablet.h">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
</ClInclude>
<ClInclude Include="HW\WiimoteEmu\Extension\Extension.h">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
</ClInclude>
@ -1628,6 +1634,7 @@
<ClInclude Include="HW\WiimoteCommon\DataReport.h">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Common</Filter>
</ClInclude>
<ClInclude Include="PowerPC\ConditionRegister.h" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />

View file

@ -66,6 +66,12 @@ ControllerEmu::ControlGroup* GetTurntableGroup(int number, WiimoteEmu::Turntable
->GetTurntableGroup(group);
}
ControllerEmu::ControlGroup* GetUDrawTabletGroup(int number, WiimoteEmu::UDrawTabletGroup group)
{
return static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(number))
->GetUDrawTabletGroup(group);
}
void Shutdown()
{
s_config.UnregisterHotplugCallback();

View file

@ -26,6 +26,7 @@ enum class ClassicGroup;
enum class GuitarGroup;
enum class DrumsGroup;
enum class TurntableGroup;
enum class UDrawTabletGroup;
} // namespace WiimoteEmu
enum
@ -78,6 +79,7 @@ ControllerEmu::ControlGroup* GetClassicGroup(int number, WiimoteEmu::ClassicGrou
ControllerEmu::ControlGroup* GetGuitarGroup(int number, WiimoteEmu::GuitarGroup group);
ControllerEmu::ControlGroup* GetDrumsGroup(int number, WiimoteEmu::DrumsGroup group);
ControllerEmu::ControlGroup* GetTurntableGroup(int number, WiimoteEmu::TurntableGroup group);
ControllerEmu::ControlGroup* GetUDrawTabletGroup(int number, WiimoteEmu::UDrawTabletGroup group);
void ControlChannel(int number, u16 channel_id, const void* data, u32 size);
void InterruptChannel(int number, u16 channel_id, const void* data, u32 size);

View file

@ -6,281 +6,512 @@
#include "Core/HW/WiimoteEmu/Encryption.h"
#include <cstring>
#include <algorithm>
#include "Common/CommonTypes.h"
#include "Common/BitUtils.h"
#include "Common/Logging/Log.h"
static const u8 ans_tbl[7][6] = {
{0xA8, 0x77, 0xA6, 0xE0, 0xF7, 0x43}, {0x5A, 0x35, 0x85, 0xE2, 0x72, 0x97},
{0x8F, 0xB7, 0x1A, 0x62, 0x87, 0x38}, {0xD, 0x67, 0xC7, 0xBE, 0x4F, 0x3E},
{0x20, 0x76, 0x37, 0x8F, 0x68, 0xB7}, {0xA9, 0x26, 0x3F, 0x2B, 0x10, 0xE3},
{0x30, 0x7E, 0x90, 0xE, 0x85, 0xA},
};
static const u8 tsbox[256] = {
0x70, 0x51, 3, 0x86, 0x40, 0xD, 0x4F, 0xEB, 0x3E, 0xCC, 0xD1, 0x87, 0x35, 0xBD, 0xF5, 0xB,
0x5E, 0xD0, 0xF8, 0xF2, 0xD5, 0xE2, 0x6C, 0x31, 0xC, 0xAD, 0xFC, 0x21, 0xC3, 0x78, 0xC1, 6,
0xC2, 0x4C, 0x55, 0xE6, 0x4A, 0x34, 0x48, 0x11, 0x1E, 0xDA, 0xE7, 0x1A, 0x84, 0xA0, 0x96, 0xA7,
0xE3, 0x7F, 0xAF, 0x63, 0x9C, 0xFA, 0x23, 0x5B, 0x79, 0xC8, 0x9E, 0xBA, 0xB2, 0xC9, 0x22, 0x12,
0x4B, 0xB3, 0xA1, 0xB6, 0x32, 0x49, 0xA2, 0xE1, 0x89, 0x39, 0x10, 0x66, 0xC5, 7, 0x8F, 0x54,
0xEA, 0x91, 0xCA, 0x3F, 0xF9, 0x19, 0xF0, 0xD7, 0x46, 0xBC, 0x28, 0x1B, 0x61, 0xE8, 0x2F, 0x6A,
0xAE, 0x9D, 0xF6, 0x4E, 9, 0x14, 0x77, 0x4D, 0xDB, 0x1F, 0x2E, 0x7B, 0x7C, 0xF1, 0x43, 0xA3,
0, 0xB8, 0x13, 0x8C, 0x85, 0xB9, 0x29, 0x75, 0x88, 0xFD, 0xD2, 0x56, 0x1C, 0x50, 0x97, 0x41,
0xE5, 0x3B, 0x60, 0xB5, 0xC0, 0x64, 0xEE, 0x98, 0xD6, 0x2D, 0x25, 0xA4, 0xAA, 0xCD, 0x7D, 0xA8,
0x83, 0xC6, 0xAB, 0xBE, 0x44, 0x99, 0x26, 0x3C, 0xCE, 0x9F, 0xBF, 0xD3, 0xCB, 0x76, 0x7A, 0x7E,
0x82, 1, 0x8A, 0x9A, 0x80, 0x1D, 0xE, 0xB0, 0x5C, 0xD4, 0x38, 0x62, 0xF4, 0x30, 0xE0, 0x8E,
0x53, 0xB7, 2, 0x57, 0xAC, 0xA6, 0x52, 0xA, 0x6D, 0x92, 0x65, 0x17, 0x24, 0x33, 0x45, 0x72,
0x74, 0xB1, 0xB4, 0xF7, 0x5D, 0xED, 0x2C, 0xFF, 0x47, 0x37, 0x5A, 0x90, 0xBB, 0xDF, 0x2A, 0x16,
0x59, 0x95, 0xD9, 0xC4, 0x27, 0x67, 0x73, 0xC7, 0x68, 0xFE, 0xA5, 0xDD, 0x6B, 0x5F, 0x93, 0xD8,
0xEC, 5, 0x3A, 0x8D, 0x6E, 0xFB, 0x3D, 0xA9, 0x69, 0x36, 0xF3, 0x94, 0xDE, 0xEF, 0x15, 0x6F,
0x8B, 0x9B, 8, 0xF, 0xDC, 0x81, 0x18, 0x20, 4, 0xE4, 0x71, 0xCF, 0xE9, 0x2B, 0x42, 0x58,
};
static const u8 sboxes[8][256] = {
namespace
{
1, 0xA0, 0xA9, 0x62, 0xD6, 0x3F, 0x85, 0xA7, 0xB6, 0xD4, 0xFA, 0x15, 0x66, 0x17, 9,
0xBD, 0x5D, 0x14, 0x34, 0x26, 0x59, 0x72, 0x91, 0x54, 6, 0x4F, 0xF8, 0xB0, 0x5B, 0x74,
0x93, 0x99, 0x8C, 0xF2, 0x45, 0xCD, 0xEA, 0x4E, 0xAD, 0x10, 0x4A, 0xE5, 0xCA, 0xEE, 0xDF,
0xC6, 0x6F, 0x9F, 0x88, 0x8E, 2, 0xCC, 8, 0xA8, 0x77, 0x94, 0x6D, 0x21, 0xB1, 0x28,
0xE4, 0x39, 0x79, 0x96, 0x60, 0x71, 0x81, 0x16, 0x2E, 0xE6, 0x78, 0xB9, 0xC4, 0x46, 0x9A,
0x42, 0xAE, 0xB7, 0x7C, 0x43, 0xB3, 0x22, 0x1A, 0x86, 0xC2, 0x32, 0x3D, 0x2D, 0x9C, 0xD2,
0x29, 0xE9, 0x63, 0x9B, 0xD1, 0x31, 0x38, 0x5E, 0x1E, 0x36, 0x41, 0xBB, 3, 0x18, 0x2B,
0x3E, 0xBF, 0x68, 0x61, 0xFC, 0x52, 0xC0, 0xDE, 0xE0, 0xA, 0x58, 0x13, 0x5A, 0, 0xBE,
0x1C, 0x90, 0xE, 0x53, 0x12, 0xFD, 0xE2, 0x6E, 0xBA, 0xCE, 0x24, 0x27, 0x44, 0x7F, 0x87,
0xA3, 0xA1, 0xD5, 0x50, 0x40, 0xE3, 0xF9, 0x83, 0xF7, 0xC7, 0xA2, 0x35, 0xC8, 0xDB, 0x19,
0xAB, 0x2F, 0x11, 0x25, 0xED, 0x33, 0x9E, 0x55, 0xE1, 0x48, 0xAF, 0x73, 0x84, 0xDA, 0x2A,
0xAA, 0x51, 0xEB, 0x9D, 0x95, 0xB2, 0xCB, 0xE7, 0x70, 0x80, 0xFE, 0x4C, 0x65, 4, 0xEF,
0xC5, 0xF1, 0xC3, 0x3A, 0xB4, 0xF5, 0x5F, 0x23, 0x89, 0xDD, 0x30, 0xA5, 0x8B, 0xD3, 0xF6,
0xDC, 0x4D, 0x64, 0xD7, 0xF0, 0x8F, 0xEC, 0x56, 0x37, 0x5C, 0xA4, 0xD, 7, 0x76, 0x8A,
0x2C, 0xB, 0xB5, 0xD8, 0xC1, 0x1F, 0xE8, 0x3B, 0xF4, 0x4B, 0x1B, 0x47, 0x6C, 0x49, 0x67,
0x7B, 0x92, 0xCF, 0x75, 0x7E, 0x20, 0xD9, 0x7D, 0x3C, 0x97, 0x7A, 0xD0, 5, 0x6B, 0xF,
0x1D, 0xFB, 0x82, 0x98, 0x57, 0x8D, 0xF3, 0x6A, 0xBC, 0xAC, 0xC9, 0xA6, 0xFF, 0xB8, 0x69,
0xC,
constexpr u8 sboxes[18][256] = {
{
0x70, 0x51, 0x03, 0x86, 0x40, 0x0d, 0x4f, 0xeb, 0x3e, 0xcc, 0xd1, 0x87, 0x35, 0xbd, 0xf5,
0x0b, 0x5e, 0xd0, 0xf8, 0xf2, 0xd5, 0xe2, 0x6c, 0x31, 0x0c, 0xad, 0xfc, 0x21, 0xc3, 0x78,
0xc1, 0x06, 0xc2, 0x4c, 0x55, 0xe6, 0x4a, 0x34, 0x48, 0x11, 0x1e, 0xda, 0xe7, 0x1a, 0x84,
0xa0, 0x96, 0xa7, 0xe3, 0x7f, 0xaf, 0x63, 0x9c, 0xfa, 0x23, 0x5b, 0x79, 0xc8, 0x9e, 0xba,
0xb2, 0xc9, 0x22, 0x12, 0x4b, 0xb3, 0xa1, 0xb6, 0x32, 0x49, 0xa2, 0xe1, 0x89, 0x39, 0x10,
0x66, 0xc5, 0x07, 0x8f, 0x54, 0xea, 0x91, 0xca, 0x3f, 0xf9, 0x19, 0xf0, 0xd7, 0x46, 0xbc,
0x28, 0x1b, 0x61, 0xe8, 0x2f, 0x6a, 0xae, 0x9d, 0xf6, 0x4e, 0x09, 0x14, 0x77, 0x4d, 0xdb,
0x1f, 0x2e, 0x7b, 0x7c, 0xf1, 0x43, 0xa3, 0x00, 0xb8, 0x13, 0x8c, 0x85, 0xb9, 0x29, 0x75,
0x88, 0xfd, 0xd2, 0x56, 0x1c, 0x50, 0x97, 0x41, 0xe5, 0x3b, 0x60, 0xb5, 0xc0, 0x64, 0xee,
0x98, 0xd6, 0x2d, 0x25, 0xa4, 0xaa, 0xcd, 0x7d, 0xa8, 0x83, 0xc6, 0xab, 0xbe, 0x44, 0x99,
0x26, 0x3c, 0xce, 0x9f, 0xbf, 0xd3, 0xcb, 0x76, 0x7a, 0x7e, 0x82, 0x01, 0x8a, 0x9a, 0x80,
0x1d, 0x0e, 0xb0, 0x5c, 0xd4, 0x38, 0x62, 0xf4, 0x30, 0xe0, 0x8e, 0x53, 0xb7, 0x02, 0x57,
0xac, 0xa6, 0x52, 0x0a, 0x6d, 0x92, 0x65, 0x17, 0x24, 0x33, 0x45, 0x72, 0x74, 0xb1, 0xb4,
0xf7, 0x5d, 0xed, 0x2c, 0xff, 0x47, 0x37, 0x5a, 0x90, 0xbb, 0xdf, 0x2a, 0x16, 0x59, 0x95,
0xd9, 0xc4, 0x27, 0x67, 0x73, 0xc7, 0x68, 0xfe, 0xa5, 0xdd, 0x6b, 0x5f, 0x93, 0xd8, 0xec,
0x05, 0x3a, 0x8d, 0x6e, 0xfb, 0x3d, 0xa9, 0x69, 0x36, 0xf3, 0x94, 0xde, 0xef, 0x15, 0x6f,
0x8b, 0x9b, 0x08, 0x0f, 0xdc, 0x81, 0x18, 0x20, 0x04, 0xe4, 0x71, 0xcf, 0xe9, 0x2b, 0x42,
0x58,
},
{
0x4C, 0x4D, 0x72, 7, 0x5A, 0x49, 0x33, 0x8D, 0xA2, 0xAB, 0x46, 0x3D, 0x63, 0xD, 0xA0,
0x97, 0xFF, 0xF0, 0xF5, 0xFA, 0xC0, 0xE9, 0xDB, 0x62, 0xE4, 0xE1, 0x74, 0x43, 0xDC, 0x86,
0x18, 0x29, 0x37, 0xF4, 6, 0xE2, 0xED, 0x6F, 0x90, 0x48, 0x1E, 0x2D, 0x1D, 0xEA, 0x73,
0x94, 0x54, 0xDF, 0x25, 0xF6, 0x47, 0x27, 0xD9, 0x11, 0x77, 0xC9, 0x84, 0x1C, 0x5B, 0x5C,
0x51, 0x81, 0xA6, 0x22, 0x3E, 0x24, 0x96, 0xC8, 0x8A, 0xEC, 0x82, 0x7C, 9, 0xB8, 0x45,
0x4A, 0x57, 0xBB, 0x2F, 0x50, 0x75, 0x8E, 0x61, 0x70, 0x8C, 0x6C, 0xAF, 0xD0, 0xFD, 0xB4,
0x1B, 0xAE, 0xDE, 0xFE, 0x3B, 0xB5, 0x36, 0xBD, 0x55, 1, 0xE, 0x9C, 0x41, 0x56, 0x5F,
0xB3, 0x26, 3, 0x83, 0xBA, 0x13, 0x4B, 0xCA, 0xC5, 0xA, 0xF8, 0x60, 0xA5, 0xB9, 0xC7,
0xC3, 0x98, 0x32, 0xFB, 0x12, 0xF9, 0xA7, 0x92, 0xAA, 0x68, 0xF3, 0x78, 0x7E, 5, 0x20,
0x21, 2, 0xE8, 0xBF, 0xF2, 0xB0, 0x59, 0x8F, 0xD2, 0xCB, 0x87, 0x65, 0x15, 0xF1, 0x1A,
0xB2, 0x30, 0xAD, 0xEE, 0x58, 0xA3, 0x8B, 0x66, 0x1F, 0x2C, 0xD7, 0x5D, 0x19, 0x85, 0xA8,
0xE6, 0xD3, 0x6B, 0xA1, 0xC, 0x91, 0x93, 0x6A, 0x5E, 0xB, 0x79, 0xE3, 0xDD, 0, 0x4F,
0x3C, 0x89, 0x6E, 0x71, 0x69, 0xA9, 0xAC, 0x40, 0xE5, 0x99, 0x28, 0xC6, 0x31, 0x4E, 0x7A,
0xCD, 8, 0x9E, 0x7D, 0xEF, 0x17, 0xFC, 0x88, 0xD8, 0xA4, 0x6D, 0x44, 0x95, 0xD1, 0xB7,
0xD4, 0x9B, 0xBE, 0x2A, 0x34, 0x64, 0x2B, 0xCF, 0x2E, 0xEB, 0x38, 0xCE, 0x23, 0xE0, 0x3A,
0x3F, 0xF7, 0x7B, 0x9F, 0x10, 0x53, 0xBC, 0x52, 0x67, 0x16, 0xE7, 0x80, 0x76, 4, 0xC4,
0xB6, 0xC1, 0xC2, 0x7F, 0x9A, 0xDA, 0xD5, 0x39, 0x42, 0x14, 0x9D, 0xB1, 0xF, 0x35, 0xD6,
0xCC,
0x01, 0xa0, 0xa9, 0x62, 0xd6, 0x3f, 0x85, 0xa7, 0xb6, 0xd4, 0xfa, 0x15, 0x66, 0x17, 0x09,
0xbd, 0x5d, 0x14, 0x34, 0x26, 0x59, 0x72, 0x91, 0x54, 0x06, 0x4f, 0xf8, 0xb0, 0x5b, 0x74,
0x93, 0x99, 0x8c, 0xf2, 0x45, 0xcd, 0xea, 0x4e, 0xad, 0x10, 0x4a, 0xe5, 0xca, 0xee, 0xdf,
0xc6, 0x6f, 0x9f, 0x88, 0x8e, 0x02, 0xcc, 0x08, 0xa8, 0x77, 0x94, 0x6d, 0x21, 0xb1, 0x28,
0xe4, 0x39, 0x79, 0x96, 0x60, 0x71, 0x81, 0x16, 0x2e, 0xe6, 0x78, 0xb9, 0xc4, 0x46, 0x9a,
0x42, 0xae, 0xb7, 0x7c, 0x43, 0xb3, 0x22, 0x1a, 0x86, 0xc2, 0x32, 0x3d, 0x2d, 0x9c, 0xd2,
0x29, 0xe9, 0x63, 0x9b, 0xd1, 0x31, 0x38, 0x5e, 0x1e, 0x36, 0x41, 0xbb, 0x03, 0x18, 0x2b,
0x3e, 0xbf, 0x68, 0x61, 0xfc, 0x52, 0xc0, 0xde, 0xe0, 0x0a, 0x58, 0x13, 0x5a, 0x00, 0xbe,
0x1c, 0x90, 0x0e, 0x53, 0x12, 0xfd, 0xe2, 0x6e, 0xba, 0xce, 0x24, 0x27, 0x44, 0x7f, 0x87,
0xa3, 0xa1, 0xd5, 0x50, 0x40, 0xe3, 0xf9, 0x83, 0xf7, 0xc7, 0xa2, 0x35, 0xc8, 0xdb, 0x19,
0xab, 0x2f, 0x11, 0x25, 0xed, 0x33, 0x9e, 0x55, 0xe1, 0x48, 0xaf, 0x73, 0x84, 0xda, 0x2a,
0xaa, 0x51, 0xeb, 0x9d, 0x95, 0xb2, 0xcb, 0xe7, 0x70, 0x80, 0xfe, 0x4c, 0x65, 0x04, 0xef,
0xc5, 0xf1, 0xc3, 0x3a, 0xb4, 0xf5, 0x5f, 0x23, 0x89, 0xdd, 0x30, 0xa5, 0x8b, 0xd3, 0xf6,
0xdc, 0x4d, 0x64, 0xd7, 0xf0, 0x8f, 0xec, 0x56, 0x37, 0x5c, 0xa4, 0x0d, 0x07, 0x76, 0x8a,
0x2c, 0x0b, 0xb5, 0xd8, 0xc1, 0x1f, 0xe8, 0x3b, 0xf4, 0x4b, 0x1b, 0x47, 0x6c, 0x49, 0x67,
0x7b, 0x92, 0xcf, 0x75, 0x7e, 0x20, 0xd9, 0x7d, 0x3c, 0x97, 0x7a, 0xd0, 0x05, 0x6b, 0x0f,
0x1d, 0xfb, 0x82, 0x98, 0x57, 0x8d, 0xf3, 0x6a, 0xbc, 0xac, 0xc9, 0xa6, 0xff, 0xb8, 0x69,
0x0c,
},
{
0xB9, 0xDA, 0x38, 0xC, 0xA2, 0x9C, 9, 0x1F, 6, 0xB1, 0xB6, 0xFD, 0x1A, 0x69, 0x23,
0x30, 0xC4, 0xDE, 1, 0xD1, 0xF4, 0x58, 0x29, 0x37, 0x1C, 0x7D, 0xD5, 0xBF, 0xFF, 0xBD,
0xC8, 0xC9, 0xCF, 0x65, 0xBE, 0x7B, 0x78, 0x97, 0x98, 0x67, 8, 0xB3, 0x26, 0x57, 0xF7,
0xFA, 0x40, 0xAD, 0x8E, 0x75, 0xA6, 0x7C, 0xDB, 0x91, 0x8B, 0x51, 0x99, 0xD4, 0x17, 0x7A,
0x90, 0x8D, 0xCE, 0x63, 0xCB, 0x4E, 0xA0, 0xAB, 0x18, 0x3A, 0x5B, 0x50, 0x7F, 0x21, 0x74,
0xC1, 0xBB, 0xB8, 0xB7, 0xBA, 0xB, 0x35, 0x95, 0x31, 0x59, 0x9A, 0x4D, 4, 7, 0x1E,
0x5A, 0x76, 0x13, 0xF3, 0x71, 0x83, 0xD0, 0x86, 3, 0xA8, 0x39, 0x42, 0xAA, 0x28, 0xE6,
0xE4, 0xD8, 0x5D, 0xD3, 0xD0, 0x6E, 0x6F, 0x96, 0xFB, 0x5E, 0xBC, 0x56, 0xC2, 0x5F, 0x85,
0x9B, 0xE7, 0xAF, 0xD2, 0x3B, 0x84, 0x6A, 0xA7, 0x53, 0xC5, 0x44, 0x49, 0xA5, 0xF9, 0x36,
0x72, 0x3D, 0x2C, 0xD9, 0x1B, 0xA1, 0xF5, 0x4F, 0x93, 0x9D, 0x68, 0x47, 0x41, 0x16, 0xCA,
0x2A, 0x4C, 0xA3, 0x87, 0xD6, 0xE5, 0x19, 0x2E, 0x77, 0x15, 0x6D, 0x70, 0xC0, 0xDF, 0xB2,
0, 0x46, 0xED, 0xC6, 0x6C, 0x43, 0x60, 0x92, 0x2D, 0xA9, 0x22, 0x45, 0x8F, 0x34, 0x55,
0xAE, 0xA4, 0xA, 0x66, 0x32, 0xE0, 0xDC, 2, 0xAC, 0xE8, 0x20, 0x8C, 0x89, 0x62, 0x4A,
0xFE, 0xEE, 0xC3, 0xE3, 0x3C, 0xF1, 0x79, 5, 0xE9, 0xF6, 0x27, 0x33, 0xCC, 0xF2, 0x9E,
0x11, 0x81, 0x7E, 0x80, 0x10, 0x8A, 0x82, 0x9F, 0x48, 0xD, 0xD7, 0xB4, 0xFC, 0x2F, 0xB5,
0xC7, 0xDD, 0x88, 0x14, 0x6B, 0x2B, 0x54, 0xEA, 0x1D, 0x94, 0x5C, 0xB0, 0xEF, 0x12, 0x24,
0xCD, 0xEB, 0xE1, 0xE2, 0x64, 0x73, 0x3F, 0xE, 0x52, 0x61, 0x25, 0x3E, 0xF8, 0xF, 0x4B,
0xEC,
0x4c, 0x4d, 0x72, 0x07, 0x5a, 0x49, 0x33, 0x8d, 0xa2, 0xab, 0x46, 0x3d, 0x63, 0x0d, 0xa0,
0x97, 0xff, 0xf0, 0xf5, 0xfa, 0xc0, 0xe9, 0xdb, 0x62, 0xe4, 0xe1, 0x74, 0x43, 0xdc, 0x86,
0x18, 0x29, 0x37, 0xf4, 0x06, 0xe2, 0xed, 0x6f, 0x90, 0x48, 0x1e, 0x2d, 0x1d, 0xea, 0x73,
0x94, 0x54, 0xdf, 0x25, 0xf6, 0x47, 0x27, 0xd9, 0x11, 0x77, 0xc9, 0x84, 0x1c, 0x5b, 0x5c,
0x51, 0x81, 0xa6, 0x22, 0x3e, 0x24, 0x96, 0xc8, 0x8a, 0xec, 0x82, 0x7c, 0x09, 0xb8, 0x45,
0x4a, 0x57, 0xbb, 0x2f, 0x50, 0x75, 0x8e, 0x61, 0x70, 0x8c, 0x6c, 0xaf, 0xd0, 0xfd, 0xb4,
0x1b, 0xae, 0xde, 0xfe, 0x3b, 0xb5, 0x36, 0xbd, 0x55, 0x01, 0x0e, 0x9c, 0x41, 0x56, 0x5f,
0xb3, 0x26, 0x03, 0x83, 0xba, 0x13, 0x4b, 0xca, 0xc5, 0x0a, 0xf8, 0x60, 0xa5, 0xb9, 0xc7,
0xc3, 0x98, 0x32, 0xfb, 0x12, 0xf9, 0xa7, 0x92, 0xaa, 0x68, 0xf3, 0x78, 0x7e, 0x05, 0x20,
0x21, 0x02, 0xe8, 0xbf, 0xf2, 0xb0, 0x59, 0x8f, 0xd2, 0xcb, 0x87, 0x65, 0x15, 0xf1, 0x1a,
0xb2, 0x30, 0xad, 0xee, 0x58, 0xa3, 0x8b, 0x66, 0x1f, 0x2c, 0xd7, 0x5d, 0x19, 0x85, 0xa8,
0xe6, 0xd3, 0x6b, 0xa1, 0x0c, 0x91, 0x93, 0x6a, 0x5e, 0x0b, 0x79, 0xe3, 0xdd, 0x00, 0x4f,
0x3c, 0x89, 0x6e, 0x71, 0x69, 0xa9, 0xac, 0x40, 0xe5, 0x99, 0x28, 0xc6, 0x31, 0x4e, 0x7a,
0xcd, 0x08, 0x9e, 0x7d, 0xef, 0x17, 0xfc, 0x88, 0xd8, 0xa4, 0x6d, 0x44, 0x95, 0xd1, 0xb7,
0xd4, 0x9b, 0xbe, 0x2a, 0x34, 0x64, 0x2b, 0xcf, 0x2e, 0xeb, 0x38, 0xce, 0x23, 0xe0, 0x3a,
0x3f, 0xf7, 0x7b, 0x9f, 0x10, 0x53, 0xbc, 0x52, 0x67, 0x16, 0xe7, 0x80, 0x76, 0x04, 0xc4,
0xb6, 0xc1, 0xc2, 0x7f, 0x9a, 0xda, 0xd5, 0x39, 0x42, 0x14, 0x9d, 0xb1, 0x0f, 0x35, 0xd6,
0xcc,
},
{
0xC0, 0, 0x30, 0xF6, 2, 0x49, 0x3D, 0x10, 0x6E, 0x20, 0xC9, 0xA6, 0x2F, 0xFE, 0x2C,
0x2B, 0x75, 0x2E, 0x45, 0x26, 0xAB, 0x48, 0xA9, 0x80, 0xFC, 4, 0xCC, 0xD3, 0xB5, 0xBA,
0xA3, 0x38, 0x31, 0x7D, 1, 0xD9, 0xA7, 0x7B, 0x96, 0xB6, 0x63, 0x69, 0x4E, 0xF7, 0xDE,
0xE0, 0x78, 0xCA, 0x50, 0xAA, 0x41, 0x91, 0x65, 0x88, 0xE4, 0x21, 0x85, 0xDA, 0x3A, 0x27,
0xBE, 0x1C, 0x3E, 0x42, 0x5E, 0x17, 0x52, 0x7F, 0x1F, 0x89, 0x24, 0x6F, 0x8F, 0x5C, 0x67,
0x74, 0xE, 0x12, 0x87, 0x8D, 0xE9, 0x34, 0xED, 0x73, 0xC4, 0xF8, 0x61, 0x5B, 5, 0xDF,
0x59, 0x4C, 0x97, 0x79, 0x83, 0x18, 0xA4, 0x55, 0x95, 0xEB, 0xBD, 0x53, 0xF5, 0xF1, 0x57,
0x66, 0x46, 0x9F, 0xB2, 0x81, 9, 0x51, 0x86, 0x22, 0x16, 0xDD, 0x23, 0x93, 0x76, 0x29,
0xC2, 0xD7, 0x1D, 0xD4, 0xBF, 0x36, 0x3F, 0xEA, 0x4B, 0x11, 0x32, 0xB9, 0x62, 0x54, 0x60,
0xD6, 0x6D, 0x43, 0x9A, 0xD, 0x92, 0x9C, 0xB0, 0xEF, 0x58, 0x6C, 0x9D, 0x77, 0x2D, 0x70,
0xFA, 0xF3, 0xB3, 0xB, 0xE2, 0x40, 0x7E, 0xF4, 0x8A, 0xE5, 0x8C, 0x3C, 0x56, 0x71, 0xD1,
0x64, 0xE1, 0x82, 0xA, 0xCB, 0x13, 0x15, 0x90, 0xEC, 3, 0x99, 0xAF, 0x14, 0x5D, 0xF,
0x33, 0x4A, 0x94, 0xA5, 0xA8, 0x35, 0x1B, 0xE3, 0x6A, 0xC6, 0x28, 0xFF, 0x4D, 0xE7, 0x25,
0x84, 0xAC, 8, 0xAE, 0xC5, 0xA2, 0x2A, 0xB8, 0x37, 0xC, 0x7A, 0xA0, 0xC3, 0xCE, 0xAD,
6, 0x1A, 0x9E, 0x8B, 0xFB, 0xD5, 0xD0, 0xC1, 0x1E, 0xD0, 0xB4, 0x9B, 0xB1, 0x44, 0xF2,
0x47, 0xC7, 0x68, 0xCF, 0x72, 0xBB, 0x4F, 0x5A, 0xF9, 0xDC, 0x6B, 0xDB, 0xD2, 0xE8, 0x7C,
0xC8, 0xEE, 0x98, 0xA1, 0xE6, 0xD8, 0x39, 7, 0x5F, 0xFD, 0x8E, 0x19, 0xB7, 0x3B, 0xBC,
0xCD,
0xb9, 0xda, 0x38, 0x0c, 0xa2, 0x9c, 0x09, 0x1f, 0x06, 0xb1, 0xb6, 0xfd, 0x1a, 0x69, 0x23,
0x30, 0xc4, 0xde, 0x01, 0xd1, 0xf4, 0x58, 0x29, 0x37, 0x1c, 0x7d, 0xd5, 0xbf, 0xff, 0xbd,
0xc8, 0xc9, 0xcf, 0x65, 0xbe, 0x7b, 0x78, 0x97, 0x98, 0x67, 0x08, 0xb3, 0x26, 0x57, 0xf7,
0xfa, 0x40, 0xad, 0x8e, 0x75, 0xa6, 0x7c, 0xdb, 0x91, 0x8b, 0x51, 0x99, 0xd4, 0x17, 0x7a,
0x90, 0x8d, 0xce, 0x63, 0xcb, 0x4e, 0xa0, 0xab, 0x18, 0x3a, 0x5b, 0x50, 0x7f, 0x21, 0x74,
0xc1, 0xbb, 0xb8, 0xb7, 0xba, 0x0b, 0x35, 0x95, 0x31, 0x59, 0x9a, 0x4d, 0x04, 0x07, 0x1e,
0x5a, 0x76, 0x13, 0xf3, 0x71, 0x83, 0xf0, 0x86, 0x03, 0xa8, 0x39, 0x42, 0xaa, 0x28, 0xe6,
0xe4, 0xd8, 0x5d, 0xd3, 0xd0, 0x6e, 0x6f, 0x96, 0xfb, 0x5e, 0xbc, 0x56, 0xc2, 0x5f, 0x85,
0x9b, 0xe7, 0xaf, 0xd2, 0x3b, 0x84, 0x6a, 0xa7, 0x53, 0xc5, 0x44, 0x49, 0xa5, 0xf9, 0x36,
0x72, 0x3d, 0x2c, 0xd9, 0x1b, 0xa1, 0xf5, 0x4f, 0x93, 0x9d, 0x68, 0x47, 0x41, 0x16, 0xca,
0x2a, 0x4c, 0xa3, 0x87, 0xd6, 0xe5, 0x19, 0x2e, 0x77, 0x15, 0x6d, 0x70, 0xc0, 0xdf, 0xb2,
0x00, 0x46, 0xed, 0xc6, 0x6c, 0x43, 0x60, 0x92, 0x2d, 0xa9, 0x22, 0x45, 0x8f, 0x34, 0x55,
0xae, 0xa4, 0x0a, 0x66, 0x32, 0xe0, 0xdc, 0x02, 0xac, 0xe8, 0x20, 0x8c, 0x89, 0x62, 0x4a,
0xfe, 0xee, 0xc3, 0xe3, 0x3c, 0xf1, 0x79, 0x05, 0xe9, 0xf6, 0x27, 0x33, 0xcc, 0xf2, 0x9e,
0x11, 0x81, 0x7e, 0x80, 0x10, 0x8a, 0x82, 0x9f, 0x48, 0x0d, 0xd7, 0xb4, 0xfc, 0x2f, 0xb5,
0xc7, 0xdd, 0x88, 0x14, 0x6b, 0x2b, 0x54, 0xea, 0x1d, 0x94, 0x5c, 0xb0, 0xef, 0x12, 0x24,
0xcd, 0xeb, 0xe1, 0xe2, 0x64, 0x73, 0x3f, 0x0e, 0x52, 0x61, 0x25, 0x3e, 0xf8, 0x0f, 0x4b,
0xec,
},
{
0x7C, 0xE3, 0x81, 0x73, 0xB2, 0x11, 0xBF, 0x6F, 0x20, 0x98, 0xFE, 0x75, 0x96, 0xEF, 0x6C,
0xDA, 0x50, 0xE1, 9, 0x72, 0x54, 0x45, 0xBA, 0x34, 0x80, 0x5B, 0xED, 0x3E, 0x53, 0x2C,
0x87, 0xA4, 0x57, 0xF3, 0x33, 0x3F, 0x3C, 0xB7, 0x67, 0xB4, 0xA3, 0x25, 0x60, 0x4F, 7,
0x6B, 0x1B, 0x47, 0x15, 0xF, 0xE4, 0xA, 0xEA, 0xD1, 0x32, 0x78, 0x36, 0x49, 0x8D, 0x4B,
0xD2, 0xBC, 0xA5, 0xDC, 0x1D, 0xD, 0x4D, 0xCD, 0x9A, 0x82, 0x5F, 0xFC, 0x94, 0x65, 0xBE,
0xE2, 0xF4, 0xC9, 0x1E, 0x44, 0xCB, 0x9E, 0xC, 0x64, 0x71, 0x26, 0x63, 0xB3, 0x14, 0xE8,
0x40, 0x70, 0x8A, 0xE, 0x19, 0x42, 0x6D, 0xAC, 0x88, 0x10, 0x5C, 0xDF, 0x41, 0xA9, 0xAD,
0xE5, 0xFB, 0x74, 0xCC, 0xD5, 6, 0x8E, 0x59, 0x86, 0xCE, 0x1F, 0x3D, 0x76, 0xE0, 0x8F,
0xB9, 0x77, 0x27, 0x7B, 0xA6, 0xD8, 0x29, 0xD3, 0xEC, 0xB8, 0x13, 0xF7, 0xFA, 0xC3, 0x51,
0x6A, 0xDE, 0x4A, 0x5A, 0xEB, 0xC2, 0x8B, 0x23, 0x48, 0x92, 0xCF, 0x62, 0xA8, 0x99, 0xF8,
0xD0, 0x2E, 0x85, 0x61, 0x43, 0xC8, 0xBD, 0xF0, 5, 0x93, 0xCA, 0x4E, 0xF1, 0x7D, 0x30,
0xFD, 0xC4, 0x69, 0x66, 0x2F, 8, 0xB1, 0x52, 0xF9, 0x21, 0xE6, 0x7A, 0x2B, 0xDD, 0x39,
0x84, 0xFF, 0xC0, 0x91, 0xD6, 0x37, 0xD4, 0x7F, 0x2D, 0x9B, 0x5D, 0xA1, 0x3B, 0x6E, 0xB5,
0xC5, 0x46, 4, 0xF5, 0x90, 0xEE, 0x7E, 0x83, 0x1C, 3, 0x56, 0xB6, 0xAA, 0, 0x17,
1, 0x35, 0x55, 0x79, 0xB, 0x12, 0xBB, 0x1A, 0x31, 0xE7, 2, 0x28, 0x16, 0xC1, 0xF6,
0xA2, 0xDB, 0x18, 0x9C, 0x89, 0x68, 0x38, 0x97, 0xAB, 0xC7, 0x2A, 0xD7, 0x3A, 0xF2, 0xC6,
0x24, 0x4C, 0xB0, 0x58, 0xA0, 0x22, 0x5E, 0x9D, 0xD9, 0xA7, 0xE9, 0xAE, 0xAF, 0x8C, 0x95,
0x9F,
0xc0, 0x00, 0x30, 0xf6, 0x02, 0x49, 0x3d, 0x10, 0x6e, 0x20, 0xc9, 0xa6, 0x2f, 0xfe, 0x2c,
0x2b, 0x75, 0x2e, 0x45, 0x26, 0xab, 0x48, 0xa9, 0x80, 0xfc, 0x04, 0xcc, 0xd3, 0xb5, 0xba,
0xa3, 0x38, 0x31, 0x7d, 0x01, 0xd9, 0xa7, 0x7b, 0x96, 0xb6, 0x63, 0x69, 0x4e, 0xf7, 0xde,
0xe0, 0x78, 0xca, 0x50, 0xaa, 0x41, 0x91, 0x65, 0x88, 0xe4, 0x21, 0x85, 0xda, 0x3a, 0x27,
0xbe, 0x1c, 0x3e, 0x42, 0x5e, 0x17, 0x52, 0x7f, 0x1f, 0x89, 0x24, 0x6f, 0x8f, 0x5c, 0x67,
0x74, 0x0e, 0x12, 0x87, 0x8d, 0xe9, 0x34, 0xed, 0x73, 0xc4, 0xf8, 0x61, 0x5b, 0x05, 0xdf,
0x59, 0x4c, 0x97, 0x79, 0x83, 0x18, 0xa4, 0x55, 0x95, 0xeb, 0xbd, 0x53, 0xf5, 0xf1, 0x57,
0x66, 0x46, 0x9f, 0xb2, 0x81, 0x09, 0x51, 0x86, 0x22, 0x16, 0xdd, 0x23, 0x93, 0x76, 0x29,
0xc2, 0xd7, 0x1d, 0xd4, 0xbf, 0x36, 0x3f, 0xea, 0x4b, 0x11, 0x32, 0xb9, 0x62, 0x54, 0x60,
0xd6, 0x6d, 0x43, 0x9a, 0x0d, 0x92, 0x9c, 0xb0, 0xef, 0x58, 0x6c, 0x9d, 0x77, 0x2d, 0x70,
0xfa, 0xf3, 0xb3, 0x0b, 0xe2, 0x40, 0x7e, 0xf4, 0x8a, 0xe5, 0x8c, 0x3c, 0x56, 0x71, 0xd1,
0x64, 0xe1, 0x82, 0x0a, 0xcb, 0x13, 0x15, 0x90, 0xec, 0x03, 0x99, 0xaf, 0x14, 0x5d, 0x0f,
0x33, 0x4a, 0x94, 0xa5, 0xa8, 0x35, 0x1b, 0xe3, 0x6a, 0xc6, 0x28, 0xff, 0x4d, 0xe7, 0x25,
0x84, 0xac, 0x08, 0xae, 0xc5, 0xa2, 0x2a, 0xb8, 0x37, 0x0c, 0x7a, 0xa0, 0xc3, 0xce, 0xad,
0x06, 0x1a, 0x9e, 0x8b, 0xfb, 0xd5, 0xf0, 0xc1, 0x1e, 0xd0, 0xb4, 0x9b, 0xb1, 0x44, 0xf2,
0x47, 0xc7, 0x68, 0xcf, 0x72, 0xbb, 0x4f, 0x5a, 0xf9, 0xdc, 0x6b, 0xdb, 0xd2, 0xe8, 0x7c,
0xc8, 0xee, 0x98, 0xa1, 0xe6, 0xd8, 0x39, 0x07, 0x5f, 0xfd, 0x8e, 0x19, 0xb7, 0x3b, 0xbc,
0xcd,
},
{
0x28, 0xB7, 0x20, 0xD7, 0xB0, 0x30, 0xC3, 9, 0x19, 0xC0, 0x67, 0xD6, 0, 0x3C, 0x7E,
0xE7, 0xE9, 0xF4, 8, 0x5A, 0xF8, 0xB8, 0x2E, 5, 0xA6, 0x25, 0x9E, 0x5C, 0xD8, 0x15,
0xD, 0xE1, 0xF6, 0x11, 0x54, 0x6B, 0xCD, 0x21, 0x46, 0x66, 0x5E, 0x84, 0xAD, 6, 0x38,
0x29, 0x44, 0xC5, 0xA2, 0xCE, 0xF1, 0xAA, 0xC1, 0x40, 0x71, 0x86, 0xB5, 0xEF, 0xFC, 0x36,
0xA8, 0xCB, 0xA, 0x48, 0x27, 0x45, 0x64, 0xA3, 0xAF, 0x8C, 0xB2, 0xC6, 0x9F, 7, 0x89,
0xDC, 0x17, 0xD3, 0x49, 0x79, 0xFB, 0xFE, 0x1D, 0xD0, 0xB9, 0x88, 0x43, 0x52, 0xBC, 1,
0x78, 0x2B, 0x7D, 0x94, 0xC7, 0xE, 0xDE, 0xA5, 0xD5, 0x9B, 0xCC, 0xF7, 0x61, 0x7A, 0xC2,
0x74, 0x81, 0x39, 3, 0xAB, 0x96, 0xA0, 0x37, 0xBD, 0x2D, 0x72, 0x75, 0x3F, 0xC9, 0xD4,
0x8E, 0x6F, 0xF9, 0x8D, 0xED, 0x62, 0xDB, 0x1C, 0xDF, 4, 0xAC, 0x1B, 0x6C, 0x14, 0x4B,
0x63, 0xD0, 0xBF, 0xB4, 0x82, 0xEC, 0x7B, 0x1A, 0x59, 0x92, 0xD2, 0x10, 0x60, 0xB6, 0x3D,
0x5F, 0xE6, 0x80, 0x6E, 0x70, 0xC4, 0xF2, 0x35, 0xD9, 0x7C, 0xEE, 0xE5, 0x41, 0xA4, 0x5B,
0x50, 0xDD, 0xBB, 0x4C, 0xF3, 0x1F, 0x9D, 0x5D, 0x57, 0x55, 0x51, 0x97, 0xE3, 0x58, 0x42,
0x4D, 0x9C, 0x73, 0xBA, 0xC8, 0x77, 0x31, 0x69, 0x26, 0xAE, 0xEA, 0x8A, 0xDA, 0x22, 0xB3,
0x87, 0x56, 0xFA, 0x93, 0xB, 0x34, 0x16, 0x33, 0xE8, 0xE4, 0x53, 0xBE, 0xA9, 0xB1, 0x3A,
0x3E, 0xF5, 0x90, 0x6A, 0xCF, 0x3B, 0x12, 0xFD, 0x8F, 0x9A, 0xA7, 0x47, 0x91, 0x99, 0xEB,
0xF, 0x24, 0xFF, 0x23, 0x18, 0x85, 0x4E, 0x7F, 0xC, 0xE0, 0xA1, 0xD2, 0xD1, 0x2C, 0x2A,
0x4A, 2, 0x4F, 0x1E, 0x95, 0x68, 0x8B, 0x98, 0x83, 0x6D, 0x76, 0xCA, 0x65, 0x32, 0x13,
0x2F,
0x7c, 0xe3, 0x81, 0x73, 0xb2, 0x11, 0xbf, 0x6f, 0x20, 0x98, 0xfe, 0x75, 0x96, 0xef, 0x6c,
0xda, 0x50, 0xe1, 0x09, 0x72, 0x54, 0x45, 0xba, 0x34, 0x80, 0x5b, 0xed, 0x3e, 0x53, 0x2c,
0x87, 0xa4, 0x57, 0xf3, 0x33, 0x3f, 0x3c, 0xb7, 0x67, 0xb4, 0xa3, 0x25, 0x60, 0x4f, 0x07,
0x6b, 0x1b, 0x47, 0x15, 0x0f, 0xe4, 0x0a, 0xea, 0xd1, 0x32, 0x78, 0x36, 0x49, 0x8d, 0x4b,
0xd2, 0xbc, 0xa5, 0xdc, 0x1d, 0x0d, 0x4d, 0xcd, 0x9a, 0x82, 0x5f, 0xfc, 0x94, 0x65, 0xbe,
0xe2, 0xf4, 0xc9, 0x1e, 0x44, 0xcb, 0x9e, 0x0c, 0x64, 0x71, 0x26, 0x63, 0xb3, 0x14, 0xe8,
0x40, 0x70, 0x8a, 0x0e, 0x19, 0x42, 0x6d, 0xac, 0x88, 0x10, 0x5c, 0xdf, 0x41, 0xa9, 0xad,
0xe5, 0xfb, 0x74, 0xcc, 0xd5, 0x06, 0x8e, 0x59, 0x86, 0xce, 0x1f, 0x3d, 0x76, 0xe0, 0x8f,
0xb9, 0x77, 0x27, 0x7b, 0xa6, 0xd8, 0x29, 0xd3, 0xec, 0xb8, 0x13, 0xf7, 0xfa, 0xc3, 0x51,
0x6a, 0xde, 0x4a, 0x5a, 0xeb, 0xc2, 0x8b, 0x23, 0x48, 0x92, 0xcf, 0x62, 0xa8, 0x99, 0xf8,
0xd0, 0x2e, 0x85, 0x61, 0x43, 0xc8, 0xbd, 0xf0, 0x05, 0x93, 0xca, 0x4e, 0xf1, 0x7d, 0x30,
0xfd, 0xc4, 0x69, 0x66, 0x2f, 0x08, 0xb1, 0x52, 0xf9, 0x21, 0xe6, 0x7a, 0x2b, 0xdd, 0x39,
0x84, 0xff, 0xc0, 0x91, 0xd6, 0x37, 0xd4, 0x7f, 0x2d, 0x9b, 0x5d, 0xa1, 0x3b, 0x6e, 0xb5,
0xc5, 0x46, 0x04, 0xf5, 0x90, 0xee, 0x7e, 0x83, 0x1c, 0x03, 0x56, 0xb6, 0xaa, 0x00, 0x17,
0x01, 0x35, 0x55, 0x79, 0x0b, 0x12, 0xbb, 0x1a, 0x31, 0xe7, 0x02, 0x28, 0x16, 0xc1, 0xf6,
0xa2, 0xdb, 0x18, 0x9c, 0x89, 0x68, 0x38, 0x97, 0xab, 0xc7, 0x2a, 0xd7, 0x3a, 0xf2, 0xc6,
0x24, 0x4c, 0xb0, 0x58, 0xa0, 0x22, 0x5e, 0x9d, 0xd9, 0xa7, 0xe9, 0xae, 0xaf, 0x8c, 0x95,
0x9f,
},
{
0xC3, 0x82, 0x9A, 0xA4, 0xBA, 0x81, 0x60, 0x37, 0x34, 0x35, 0xFC, 0x80, 0xA8, 0x51, 0x65,
0x67, 0xED, 0x30, 0x5F, 0x10, 0xD3, 0x4A, 0x27, 0x2F, 0x13, 0xB9, 0x2A, 0xD2, 0xCC, 0xE1,
0xEF, 0xAE, 0xEB, 0xBE, 0xF4, 0xBD, 0xCF, 0x43, 0xB3, 0xC5, 0x88, 0x84, 0xB7, 0xDD, 0x39,
0x40, 0xCE, 0x48, 0x6D, 0x9B, 0x72, 0x61, 0x7E, 0xE7, 0xA1, 0x4E, 0x53, 0x2E, 0x77, 0x3B,
0xE2, 0xC9, 0x36, 0x22, 0x1B, 0x6E, 0x73, 0xB1, 3, 0xB2, 0x4C, 0x87, 0xA9, 0xD4, 0x4D,
0xF, 0xD8, 0x15, 0x6C, 0xAA, 0x18, 0xF6, 0x49, 0x57, 0x5D, 0xFB, 0x7A, 0x14, 0x94, 0x63,
0xA0, 0x11, 0xB0, 0x9E, 0xDE, 5, 0x46, 0xC8, 0xEE, 0x47, 0xDB, 0xDC, 0x24, 0x89, 0x9C,
0x91, 0x97, 0x29, 0xE9, 0x7B, 0xC1, 7, 0x1E, 0xB8, 0xFD, 0xFE, 0xAC, 0xC6, 0x62, 0x98,
0x4F, 0xF1, 0x79, 0xE0, 0xE8, 0x6B, 0x78, 0x56, 0xB6, 0x8D, 4, 0x50, 0x86, 0xCA, 0x6F,
0x20, 0xE6, 0xEA, 0xE5, 0x76, 0x17, 0x1C, 0x74, 0x7F, 0xBC, 0xD, 0x2C, 0x85, 0xF7, 0x66,
0x96, 0xE4, 0x8B, 0x75, 0x3F, 0x4B, 0xD9, 0x38, 0xAF, 0x7C, 0xDA, 0xB, 0x83, 0x2D, 0x31,
0x32, 0xA2, 0xF5, 0x1D, 0x59, 0x41, 0x45, 0xBF, 0x3C, 0x1F, 0xF8, 0xF9, 0x8A, 0xD0, 0x16,
0x25, 0x69, 0x12, 0x99, 0x9D, 0x21, 0x95, 0xAB, 1, 0xA6, 0xD7, 0xB5, 0xC0, 0x7D, 0xFF,
0x58, 0xE, 0x3A, 0x92, 0xD1, 0x55, 0xE3, 8, 0x9F, 0xD6, 0x3E, 0x52, 0x8E, 0xFA, 0xA3,
0xC7, 2, 0xCD, 0xDF, 0x8F, 0x64, 0x19, 0x8C, 0xF3, 0xA7, 0xC, 0x5E, 0xA, 0x6A, 9,
0xF0, 0x93, 0x5B, 0x42, 0xC2, 6, 0x23, 0xEC, 0x71, 0xAD, 0xB4, 0xCB, 0xBB, 0x70, 0x28,
0xD5, 0x1A, 0x5C, 0x33, 0x68, 0x5A, 0, 0x44, 0x90, 0xA5, 0xC4, 0x26, 0x3D, 0x2B, 0xF2,
0x28, 0xb7, 0x20, 0xd7, 0xb0, 0x30, 0xc3, 0x09, 0x19, 0xc0, 0x67, 0xd6, 0x00, 0x3c, 0x7e,
0xe7, 0xe9, 0xf4, 0x08, 0x5a, 0xf8, 0xb8, 0x2e, 0x05, 0xa6, 0x25, 0x9e, 0x5c, 0xd8, 0x15,
0x0d, 0xe1, 0xf6, 0x11, 0x54, 0x6b, 0xcd, 0x21, 0x46, 0x66, 0x5e, 0x84, 0xad, 0x06, 0x38,
0x29, 0x44, 0xc5, 0xa2, 0xce, 0xf1, 0xaa, 0xc1, 0x40, 0x71, 0x86, 0xb5, 0xef, 0xfc, 0x36,
0xa8, 0xcb, 0x0a, 0x48, 0x27, 0x45, 0x64, 0xa3, 0xaf, 0x8c, 0xb2, 0xc6, 0x9f, 0x07, 0x89,
0xdc, 0x17, 0xd3, 0x49, 0x79, 0xfb, 0xfe, 0x1d, 0xd0, 0xb9, 0x88, 0x43, 0x52, 0xbc, 0x01,
0x78, 0x2b, 0x7d, 0x94, 0xc7, 0x0e, 0xde, 0xa5, 0xd5, 0x9b, 0xcc, 0xf7, 0x61, 0x7a, 0xc2,
0x74, 0x81, 0x39, 0x03, 0xab, 0x96, 0xa0, 0x37, 0xbd, 0x2d, 0x72, 0x75, 0x3f, 0xc9, 0xd4,
0x8e, 0x6f, 0xf9, 0x8d, 0xed, 0x62, 0xdb, 0x1c, 0xdf, 0x04, 0xac, 0x1b, 0x6c, 0x14, 0x4b,
0x63, 0xf0, 0xbf, 0xb4, 0x82, 0xec, 0x7b, 0x1a, 0x59, 0x92, 0xd2, 0x10, 0x60, 0xb6, 0x3d,
0x5f, 0xe6, 0x80, 0x6e, 0x70, 0xc4, 0xf2, 0x35, 0xd9, 0x7c, 0xee, 0xe5, 0x41, 0xa4, 0x5b,
0x50, 0xdd, 0xbb, 0x4c, 0xf3, 0x1f, 0x9d, 0x5d, 0x57, 0x55, 0x51, 0x97, 0xe3, 0x58, 0x42,
0x4d, 0x9c, 0x73, 0xba, 0xc8, 0x77, 0x31, 0x69, 0x26, 0xae, 0xea, 0x8a, 0xda, 0x22, 0xb3,
0x87, 0x56, 0xfa, 0x93, 0x0b, 0x34, 0x16, 0x33, 0xe8, 0xe4, 0x53, 0xbe, 0xa9, 0xb1, 0x3a,
0x3e, 0xf5, 0x90, 0x6a, 0xcf, 0x3b, 0x12, 0xfd, 0x8f, 0x9a, 0xa7, 0x47, 0x91, 0x99, 0xeb,
0x0f, 0x24, 0xff, 0x23, 0x18, 0x85, 0x4e, 0x7f, 0x0c, 0xe0, 0xa1, 0xe2, 0xd1, 0x2c, 0x2a,
0x4a, 0x02, 0x4f, 0x1e, 0x95, 0x68, 0x8b, 0x98, 0x83, 0x6d, 0x76, 0xca, 0x65, 0x32, 0x13,
0x2f,
},
{
0xc3, 0x82, 0x9a, 0xa4, 0xba, 0x81, 0x60, 0x37, 0x34, 0x35, 0xfc, 0x80, 0xa8, 0x51, 0x65,
0x67, 0xed, 0x30, 0x5f, 0x10, 0xd3, 0x4a, 0x27, 0x2f, 0x13, 0xb9, 0x2a, 0xd2, 0xcc, 0xe1,
0xef, 0xae, 0xeb, 0xbe, 0xf4, 0xbd, 0xcf, 0x43, 0xb3, 0xc5, 0x88, 0x84, 0xb7, 0xdd, 0x39,
0x40, 0xce, 0x48, 0x6d, 0x9b, 0x72, 0x61, 0x7e, 0xe7, 0xa1, 0x4e, 0x53, 0x2e, 0x77, 0x3b,
0xe2, 0xc9, 0x36, 0x22, 0x1b, 0x6e, 0x73, 0xb1, 0x03, 0xb2, 0x4c, 0x87, 0xa9, 0xd4, 0x4d,
0x0f, 0xd8, 0x15, 0x6c, 0xaa, 0x18, 0xf6, 0x49, 0x57, 0x5d, 0xfb, 0x7a, 0x14, 0x94, 0x63,
0xa0, 0x11, 0xb0, 0x9e, 0xde, 0x05, 0x46, 0xc8, 0xee, 0x47, 0xdb, 0xdc, 0x24, 0x89, 0x9c,
0x91, 0x97, 0x29, 0xe9, 0x7b, 0xc1, 0x07, 0x1e, 0xb8, 0xfd, 0xfe, 0xac, 0xc6, 0x62, 0x98,
0x4f, 0xf1, 0x79, 0xe0, 0xe8, 0x6b, 0x78, 0x56, 0xb6, 0x8d, 0x04, 0x50, 0x86, 0xca, 0x6f,
0x20, 0xe6, 0xea, 0xe5, 0x76, 0x17, 0x1c, 0x74, 0x7f, 0xbc, 0x0d, 0x2c, 0x85, 0xf7, 0x66,
0x96, 0xe4, 0x8b, 0x75, 0x3f, 0x4b, 0xd9, 0x38, 0xaf, 0x7c, 0xda, 0x0b, 0x83, 0x2d, 0x31,
0x32, 0xa2, 0xf5, 0x1d, 0x59, 0x41, 0x45, 0xbf, 0x3c, 0x1f, 0xf8, 0xf9, 0x8a, 0xd0, 0x16,
0x25, 0x69, 0x12, 0x99, 0x9d, 0x21, 0x95, 0xab, 0x01, 0xa6, 0xd7, 0xb5, 0xc0, 0x7d, 0xff,
0x58, 0x0e, 0x3a, 0x92, 0xd1, 0x55, 0xe3, 0x08, 0x9f, 0xd6, 0x3e, 0x52, 0x8e, 0xfa, 0xa3,
0xc7, 0x02, 0xcd, 0xdf, 0x8f, 0x64, 0x19, 0x8c, 0xf3, 0xa7, 0x0c, 0x5e, 0x0a, 0x6a, 0x09,
0xf0, 0x93, 0x5b, 0x42, 0xc2, 0x06, 0x23, 0xec, 0x71, 0xad, 0xb4, 0xcb, 0xbb, 0x70, 0x28,
0xd5, 0x1a, 0x5c, 0x33, 0x68, 0x5a, 0x00, 0x44, 0x90, 0xa5, 0xc4, 0x26, 0x3d, 0x2b, 0xf2,
0x54,
},
{
0x96, 0xAD, 0xDA, 0x1F, 0xED, 0x33, 0xE1, 0x81, 0x69, 8, 0xD, 0xA, 0xDB, 0x35, 0x77,
0x9A, 0x64, 0xD1, 0xFC, 0x78, 0xAA, 0x1B, 0xD0, 0x67, 0xA0, 0xDD, 0xFA, 0x6C, 0x63, 0x71,
5, 0x84, 0x17, 0x6A, 0x89, 0x4F, 0x66, 0x7F, 0xC6, 0x50, 0x55, 0x92, 0x6F, 0xBD, 0xE7,
0xD2, 0x40, 0x72, 0x8D, 0xBB, 0xEC, 6, 0x42, 0x8A, 0xE4, 0x88, 0x9D, 0x7E, 0x7A, 0x82,
0x27, 0x13, 0x41, 0x1A, 0xAF, 0xC8, 0xA4, 0x76, 0xB4, 0xC2, 0xFE, 0x6D, 0x1C, 0xD9, 0x61,
0x30, 0xB3, 0x7C, 0xEA, 0xF7, 0x29, 0xF, 0xF2, 0x3B, 0x51, 0xC1, 0xDE, 0x5F, 0xE5, 0x2A,
0x2F, 0x99, 0xB, 0x5D, 0xA3, 0x2B, 0x4A, 0xAB, 0x95, 0xA5, 0xD3, 0x58, 0x56, 0xEE, 0x28,
0x31, 0, 0xCC, 0x15, 0x46, 0xCA, 0xE6, 0x86, 0x38, 0x3C, 0x65, 0xF5, 0xE3, 0x9F, 0xD6,
0x5B, 9, 0x49, 0x83, 0x70, 0x2D, 0x53, 0xA9, 0x7D, 0xE2, 0xC4, 0xAC, 0x8E, 0x5E, 0xB8,
0x25, 0xF4, 0xB9, 0x57, 0xF3, 0xF1, 0x68, 0x47, 0xB2, 0xA2, 0x59, 0x20, 0xCE, 0x34, 0x79,
0x5C, 0x90, 0xE, 0x1E, 0xBE, 0xD5, 0x22, 0x23, 0xB1, 0xC9, 0x18, 0x62, 0x16, 0x2E, 0x91,
0x3E, 7, 0x8F, 0xD8, 0x3F, 0x93, 0x3D, 0xD4, 0x9B, 0xDF, 0x85, 0x21, 0xFB, 0x11, 0x74,
0x97, 0xC7, 0xD7, 0xDC, 0x4C, 0x19, 0x45, 0x98, 0xE9, 0x43, 2, 0x4B, 0xBC, 0xC3, 4,
0x9C, 0x6B, 0xF0, 0x75, 0x52, 0xA7, 0x26, 0xF6, 0xC5, 0xBA, 0xCF, 0xB0, 0xB7, 0xAE, 0x5A,
0xA1, 0xBF, 3, 0x8B, 0x80, 0x12, 0x6E, 0xC, 0xEB, 0xF9, 0xC0, 0x44, 0x24, 0xEF, 0x10,
0xF8, 0xA8, 0x8C, 0xE8, 0x7B, 0xFF, 0x9E, 0x2C, 0xCD, 0x60, 0x36, 0x87, 0xB5, 0x94, 0xA6,
0x54, 0x73, 0x3A, 0x14, 0x4E, 1, 0x1D, 0xB6, 0xFD, 0x37, 0x48, 0x4D, 0x39, 0xCB, 0xE0,
0x96, 0xad, 0xda, 0x1f, 0xed, 0x33, 0xe1, 0x81, 0x69, 0x08, 0x0d, 0x0a, 0xdb, 0x35, 0x77,
0x9a, 0x64, 0xd1, 0xfc, 0x78, 0xaa, 0x1b, 0xd0, 0x67, 0xa0, 0xdd, 0xfa, 0x6c, 0x63, 0x71,
0x05, 0x84, 0x17, 0x6a, 0x89, 0x4f, 0x66, 0x7f, 0xc6, 0x50, 0x55, 0x92, 0x6f, 0xbd, 0xe7,
0xd2, 0x40, 0x72, 0x8d, 0xbb, 0xec, 0x06, 0x42, 0x8a, 0xe4, 0x88, 0x9d, 0x7e, 0x7a, 0x82,
0x27, 0x13, 0x41, 0x1a, 0xaf, 0xc8, 0xa4, 0x76, 0xb4, 0xc2, 0xfe, 0x6d, 0x1c, 0xd9, 0x61,
0x30, 0xb3, 0x7c, 0xea, 0xf7, 0x29, 0x0f, 0xf2, 0x3b, 0x51, 0xc1, 0xde, 0x5f, 0xe5, 0x2a,
0x2f, 0x99, 0x0b, 0x5d, 0xa3, 0x2b, 0x4a, 0xab, 0x95, 0xa5, 0xd3, 0x58, 0x56, 0xee, 0x28,
0x31, 0x00, 0xcc, 0x15, 0x46, 0xca, 0xe6, 0x86, 0x38, 0x3c, 0x65, 0xf5, 0xe3, 0x9f, 0xd6,
0x5b, 0x09, 0x49, 0x83, 0x70, 0x2d, 0x53, 0xa9, 0x7d, 0xe2, 0xc4, 0xac, 0x8e, 0x5e, 0xb8,
0x25, 0xf4, 0xb9, 0x57, 0xf3, 0xf1, 0x68, 0x47, 0xb2, 0xa2, 0x59, 0x20, 0xce, 0x34, 0x79,
0x5c, 0x90, 0x0e, 0x1e, 0xbe, 0xd5, 0x22, 0x23, 0xb1, 0xc9, 0x18, 0x62, 0x16, 0x2e, 0x91,
0x3e, 0x07, 0x8f, 0xd8, 0x3f, 0x93, 0x3d, 0xd4, 0x9b, 0xdf, 0x85, 0x21, 0xfb, 0x11, 0x74,
0x97, 0xc7, 0xd7, 0xdc, 0x4c, 0x19, 0x45, 0x98, 0xe9, 0x43, 0x02, 0x4b, 0xbc, 0xc3, 0x04,
0x9c, 0x6b, 0xf0, 0x75, 0x52, 0xa7, 0x26, 0xf6, 0xc5, 0xba, 0xcf, 0xb0, 0xb7, 0xae, 0x5a,
0xa1, 0xbf, 0x03, 0x8b, 0x80, 0x12, 0x6e, 0x0c, 0xeb, 0xf9, 0xc0, 0x44, 0x24, 0xef, 0x10,
0xf8, 0xa8, 0x8c, 0xe8, 0x7b, 0xff, 0x9e, 0x2c, 0xcd, 0x60, 0x36, 0x87, 0xb5, 0x94, 0xa6,
0x54, 0x73, 0x3a, 0x14, 0x4e, 0x01, 0x1d, 0xb6, 0xfd, 0x37, 0x48, 0x4d, 0x39, 0xcb, 0xe0,
0x32,
}};
static inline u8 ROR8(const u8 a, const u8 b)
},
{
return (a >> b) | ((a << (8 - b)) & 0xff);
}
static void GenerateKey(const u8* const rand, const u8 idx, u8* const key)
0x54, 0x29, 0x28, 0x4e, 0x0f, 0xfc, 0xa4, 0x6c, 0x87, 0x50, 0x49, 0x3c, 0xf2, 0xb4, 0xb1,
0xf9, 0xc3, 0x58, 0x2e, 0x83, 0x5f, 0x71, 0x8a, 0x9b, 0x82, 0xca, 0xc2, 0xbe, 0xba, 0x75,
0x91, 0x60, 0x78, 0xa8, 0x2a, 0x4c, 0x25, 0x5b, 0x8b, 0xb0, 0xda, 0xaf, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xa4, 0x38, 0x33, 0x69, 0xd4, 0xf5, 0x6a, 0xa8, 0xd7, 0xec, 0x74, 0xa6,
0x7b, 0xc7, 0x3c, 0x41, 0xb7, 0x21, 0x98, 0x4a, 0x8d, 0xc8, 0x28, 0xf3, 0xf8, 0x32, 0x91,
0xab, 0xad, 0x34, 0x86, 0x30, 0x4c, 0xbc, 0xff, 0xce, 0x14, 0x1e, 0x2e, 0xf9, 0x31, 0x59,
0x85, 0x87, 0xfc, 0xc2, 0xfd, 0x3e, 0xbb, 0x56, 0x88, 0x8b, 0xbf, 0x47, 0x61, 0x92, 0xb1,
0x94, 0x7a, 0x51, 0x9c, 0x8f, 0xb0, 0x49, 0x9b, 0xb9, 0x05, 0x36, 0x10, 0x3b, 0xd5, 0xd3,
0x0c, 0x96, 0xcb, 0x79, 0x60, 0x4e, 0xa2, 0xb5, 0xd1, 0xee, 0x17, 0xba, 0x1f, 0x09, 0x78,
0x93, 0xb4, 0x35, 0x3a, 0x9d, 0x1d, 0x39, 0xc9, 0x3f, 0x7c, 0x2f, 0xca, 0x0b, 0x37, 0xe6,
0x1b, 0xd0, 0x67, 0xd9, 0x18, 0x84, 0xe1, 0x42, 0x5a, 0x7e, 0xb8, 0x97, 0xdf, 0x54, 0x70,
0x03, 0x6e, 0xdb, 0x63, 0xae, 0x55, 0x5d, 0xc4, 0x4b, 0x89, 0xcc, 0x13, 0xb3, 0x90, 0xf6,
0xe9, 0xb2, 0xa3, 0xbe, 0x2d, 0x19, 0x73, 0x23, 0x20, 0x7f, 0x40, 0x02, 0x9e, 0xc3, 0x6b,
0x1a, 0x52, 0xda, 0x29, 0x80, 0x0d, 0x5f, 0xd6, 0x8e, 0x0e, 0x22, 0xe3, 0x6d, 0xdc, 0x58,
0x75, 0xe0, 0x01, 0x0a, 0x26, 0x50, 0x08, 0xa9, 0xfe, 0x4d, 0x15, 0xf7, 0x6c, 0xcf, 0x4f,
0xf0, 0x64, 0x5e, 0xc6, 0x68, 0x8a, 0xac, 0xde, 0xb6, 0x48, 0x66, 0xed, 0x6f, 0x71, 0x45,
0x3d, 0xeb, 0x9f, 0x04, 0x25, 0x5c, 0xbd, 0x65, 0xdd, 0x53, 0xcd, 0x24, 0xef, 0x72, 0xe8,
0x9a,
},
{
const u8* const ans = ans_tbl[idx];
u8 t0[10];
for (int i = 0; i < 10; ++i)
t0[i] = tsbox[rand[i]];
key[0] = ((ROR8((ans[0] ^ t0[5]), (t0[2] % 8)) - t0[9]) ^ t0[4]);
key[1] = ((ROR8((ans[1] ^ t0[1]), (t0[0] % 8)) - t0[5]) ^ t0[7]);
key[2] = ((ROR8((ans[2] ^ t0[6]), (t0[8] % 8)) - t0[2]) ^ t0[0]);
key[3] = ((ROR8((ans[3] ^ t0[4]), (t0[7] % 8)) - t0[3]) ^ t0[2]);
key[4] = ((ROR8((ans[4] ^ t0[1]), (t0[6] % 8)) - t0[3]) ^ t0[4]);
key[5] = ((ROR8((ans[5] ^ t0[7]), (t0[8] % 8)) - t0[5]) ^ t0[9]);
}
static void GenerateTables(const u8* const rand, const u8* const key, const u8 idx, u8* const ft,
u8* const sb)
0xe7, 0x16, 0xc1, 0x00, 0x77, 0x2c, 0x7d, 0xa5, 0x2a, 0x44, 0x62, 0x27, 0xf4, 0xc0, 0x07,
0x1c, 0x5b, 0x99, 0x82, 0x57, 0x06, 0xfa, 0xfb, 0x12, 0xaf, 0xa7, 0xd2, 0xaa, 0x2b, 0x8c,
0xf2, 0xd8, 0x83, 0xa0, 0x76, 0x11, 0xc5, 0x43, 0x81, 0x46, 0xe5, 0xf1, 0xea, 0x95, 0xe2,
0xe4, 0x0f, 0xa1, 0x2b, 0xd2, 0xa5, 0x8e, 0x26, 0x09, 0x0f, 0xf7, 0x45, 0x5b, 0x3c, 0xfd,
0x8c, 0x72, 0x22, 0xbf, 0xca, 0xda, 0xe7, 0xaf, 0x16, 0xb2, 0x5e, 0x8a, 0x6f, 0x94, 0xb7,
0xd6, 0x1c, 0xb1, 0x29, 0x4c, 0xb5, 0x43, 0x18, 0x9c, 0x31, 0xce, 0xb6, 0x84, 0x71, 0x60,
0x7f, 0x2a, 0x6e, 0x35, 0xf8, 0xa6, 0x54, 0xea, 0x74, 0x88, 0xac, 0x03, 0x19, 0x1b, 0x3d,
0x79, 0xfc, 0xee, 0x42, 0x9f, 0x93, 0xdb, 0x80, 0xad, 0x8b, 0x15, 0x41, 0x5d, 0x48, 0xcd,
0x7c, 0xa3, 0x2c, 0x32, 0x1f, 0x63, 0xd1, 0xed, 0x4f, 0x04, 0x66, 0x1e, 0x46, 0x9b, 0xbb,
0x38, 0x06, 0x7e, 0x95, 0xc8, 0x5f, 0x4a, 0x51, 0x6b, 0x97, 0xbe, 0x2e, 0x98, 0xbd, 0xec,
0x0e, 0x05, 0x0a, 0xa0, 0x01, 0x52, 0x85, 0xc0, 0xd8, 0x3b, 0xfe, 0x12, 0x64, 0xe1, 0xf3,
0x24, 0x4b, 0xf5, 0x49, 0x7a, 0xe4, 0x4e, 0x34, 0x25, 0x08, 0x53, 0x1a, 0xe3, 0xef, 0x86,
0xdf, 0xf1, 0x91, 0xeb, 0xc6, 0xd9, 0xd3, 0x83, 0x14, 0x1d, 0xb0, 0xa7, 0x0b, 0x10, 0x40,
0x89, 0xb4, 0xd4, 0x3a, 0x02, 0x0c, 0xdd, 0x2f, 0x5a, 0x56, 0x28, 0xae, 0x2d, 0x55, 0xf6,
0xc1, 0xd5, 0xa8, 0x44, 0xcf, 0x58, 0x9d, 0xb3, 0x23, 0xc5, 0xa4, 0x3e, 0x7d, 0x30, 0x13,
0x6a, 0x61, 0xd0, 0xf0, 0x3f, 0x67, 0xcb, 0x0d, 0xff, 0x92, 0x68, 0xe0, 0x81, 0x69, 0x62,
0xab, 0x75, 0x59, 0x11, 0xf2, 0xc9, 0x07, 0xe9, 0xc7, 0xa1, 0xc2, 0x78, 0x33, 0x17, 0x6c,
0xf9,
},
{
ft[0] = sboxes[idx][key[4]] ^ sboxes[(idx + 1) % 8][rand[3]];
ft[1] = sboxes[idx][key[2]] ^ sboxes[(idx + 1) % 8][rand[5]];
ft[2] = sboxes[idx][key[5]] ^ sboxes[(idx + 1) % 8][rand[7]];
ft[3] = sboxes[idx][key[0]] ^ sboxes[(idx + 1) % 8][rand[2]];
ft[4] = sboxes[idx][key[1]] ^ sboxes[(idx + 1) % 8][rand[4]];
ft[5] = sboxes[idx][key[3]] ^ sboxes[(idx + 1) % 8][rand[9]];
ft[6] = sboxes[idx][rand[0]] ^ sboxes[(idx + 1) % 8][rand[6]];
ft[7] = sboxes[idx][rand[1]] ^ sboxes[(idx + 1) % 8][rand[8]];
0xc4, 0xb8, 0xb9, 0xdc, 0x27, 0x90, 0xbc, 0xfb, 0x70, 0xaa, 0xe8, 0x96, 0x73, 0x39, 0xf4,
0xc3, 0x77, 0x87, 0xde, 0x00, 0xa2, 0x9a, 0xe2, 0x7b, 0xfa, 0x36, 0x65, 0x6d, 0x20, 0xd7,
0x57, 0x5c, 0x37, 0x8f, 0x4d, 0x9e, 0x47, 0xa9, 0xe5, 0xcc, 0x99, 0x8d, 0x76, 0x50, 0xba,
0xe6, 0x82, 0x21, 0xb0, 0x0d, 0xeb, 0x75, 0x6d, 0x22, 0xce, 0xe7, 0x63, 0x2c, 0xde, 0xe2,
0xf5, 0x45, 0xba, 0x44, 0x95, 0x1f, 0xe5, 0x39, 0xd7, 0xa5, 0xb5, 0x8d, 0x07, 0x93, 0xfd,
0xbc, 0x62, 0x7e, 0x89, 0xb3, 0x48, 0x59, 0x7f, 0xd3, 0xbe, 0xd0, 0xf2, 0x36, 0x53, 0x9f,
0xe6, 0xb1, 0x82, 0xc0, 0x94, 0xb8, 0x2f, 0x03, 0x24, 0x3c, 0x00, 0x0a, 0x42, 0x65, 0xe8,
0x5c, 0x96, 0xd5, 0xa9, 0x90, 0xb9, 0x85, 0xe9, 0xea, 0x0e, 0x16, 0x7b, 0x84, 0x29, 0x4e,
0x5e, 0x87, 0x9d, 0x35, 0x06, 0x86, 0xe1, 0xe0, 0xe3, 0xec, 0xef, 0xc8, 0x52, 0x5f, 0x64,
0xe4, 0x46, 0x30, 0x5a, 0xcd, 0xed, 0xd1, 0x51, 0x81, 0x0c, 0x3a, 0x66, 0xfe, 0x04, 0x67,
0x1e, 0xd6, 0xf7, 0x8c, 0xbd, 0x33, 0xb2, 0x91, 0xd4, 0xa8, 0x4a, 0x14, 0x0b, 0x79, 0x58,
0x88, 0xb6, 0xc1, 0x19, 0x56, 0xf8, 0x27, 0xac, 0x23, 0x99, 0xb4, 0xc3, 0x12, 0xf3, 0x20,
0x78, 0x34, 0x49, 0xdc, 0xd8, 0x05, 0xbb, 0x55, 0x8a, 0x71, 0x11, 0x21, 0xc7, 0xdb, 0xf1,
0x9b, 0xf6, 0x9e, 0x17, 0xf9, 0xfa, 0xfb, 0xa7, 0x60, 0x8e, 0x6e, 0x8b, 0xca, 0x15, 0xab,
0xdd, 0x3d, 0xa6, 0xc6, 0x80, 0xc2, 0xda, 0x4c, 0x1d, 0x4f, 0x5d, 0x92, 0x69, 0x98, 0xa2,
0x32, 0x9c, 0x2b, 0x6a, 0x41, 0x1a, 0x6c, 0xa3, 0xc5, 0x72, 0xaa, 0xcc, 0x6b, 0x10, 0x5b,
0x4d, 0x57, 0x28, 0x68, 0xee, 0x09, 0x40, 0xf0, 0xad, 0x26, 0x2e, 0x2d, 0x9a, 0xa0, 0x7a,
0xcb,
},
{
0x74, 0x3e, 0x1b, 0x70, 0xfc, 0x43, 0xc4, 0x77, 0x08, 0xb7, 0xcf, 0x1c, 0x7d, 0x18, 0x0f,
0x13, 0x25, 0xbf, 0x61, 0x01, 0x37, 0xae, 0xd2, 0x2a, 0x7c, 0x97, 0xaf, 0x3f, 0x50, 0xdf,
0x6f, 0xa1, 0xa4, 0xff, 0x38, 0xc9, 0x83, 0x8f, 0x54, 0x73, 0x02, 0x47, 0xd9, 0x31, 0x76,
0x3b, 0x4b, 0xf4, 0x9c, 0x49, 0xc7, 0xb6, 0x14, 0x21, 0x5f, 0x52, 0xf3, 0xb7, 0xd5, 0xf2,
0x95, 0xa0, 0x25, 0x54, 0xd9, 0xe7, 0xb0, 0xbf, 0x69, 0x13, 0x78, 0xf0, 0x33, 0xe0, 0x8c,
0x94, 0xdb, 0xe6, 0xa7, 0xb5, 0xec, 0xc2, 0x63, 0xe3, 0x18, 0xb9, 0x4b, 0x74, 0xe5, 0x01,
0x8e, 0xb1, 0x27, 0x35, 0xb4, 0x3d, 0x26, 0x48, 0x1f, 0xfa, 0xbb, 0x90, 0xd3, 0x98, 0xdf,
0xa4, 0x37, 0x67, 0x5d, 0x80, 0xd2, 0x62, 0xe1, 0x6f, 0x96, 0x2d, 0xa8, 0x6a, 0x97, 0x30,
0x89, 0xea, 0x3a, 0xbe, 0x22, 0x19, 0x41, 0xac, 0x79, 0xf1, 0x85, 0xee, 0x70, 0xc0, 0x0a,
0x1b, 0x7f, 0xc1, 0xd0, 0xa6, 0xf4, 0x16, 0xfc, 0xba, 0x4e, 0x4a, 0xc9, 0x12, 0x8a, 0x1a,
0x9d, 0xc5, 0x38, 0xd4, 0xde, 0xad, 0xc4, 0x43, 0x03, 0xb3, 0xf7, 0xa9, 0x59, 0x6d, 0xa3,
0x20, 0x36, 0x4d, 0x86, 0x5b, 0xae, 0x61, 0x17, 0xa5, 0x93, 0xdc, 0x50, 0x2c, 0xef, 0x2a,
0x68, 0x75, 0x7a, 0x8b, 0xd6, 0xfb, 0x00, 0x9e, 0x2e, 0x02, 0xcd, 0xed, 0x47, 0xab, 0x82,
0xbd, 0x71, 0x11, 0xb2, 0x66, 0x5e, 0x3c, 0x7c, 0x08, 0x6e, 0xf6, 0x09, 0x45, 0x3f, 0x5a,
0x0f, 0x84, 0xcc, 0xdd, 0x73, 0x0d, 0xf8, 0x92, 0xe8, 0x0b, 0xe9, 0xcf, 0x4f, 0x1c, 0xda,
0x10, 0x0e, 0x9f, 0xa2, 0x58, 0xff, 0x40, 0x87, 0x77, 0x2f, 0x60, 0x4c, 0xc3, 0x28, 0x88,
0x15, 0x81, 0x06, 0x56, 0xd1, 0x55, 0x8d, 0x9b, 0x57, 0x83, 0x65, 0x91, 0x34, 0xce, 0x53,
0x42,
},
{
0x04, 0x0c, 0x46, 0x7d, 0x07, 0x29, 0xfe, 0x24, 0x2b, 0x6c, 0x05, 0x32, 0xcb, 0x72, 0x1e,
0x7e, 0xaa, 0xe4, 0x99, 0x6b, 0xe2, 0xa1, 0xd8, 0x1d, 0x3e, 0xc6, 0xc8, 0x5c, 0x8f, 0xd7,
0x64, 0x39, 0xb8, 0x44, 0x23, 0x31, 0x7b, 0x51, 0xca, 0x3b, 0xf5, 0xf9, 0xfd, 0x76, 0xeb,
0x9a, 0xaf, 0xbc, 0x94, 0xc5, 0x26, 0x3f, 0xf6, 0xf8, 0x93, 0x6e, 0x73, 0x84, 0x82, 0xe7,
0x54, 0x2c, 0x57, 0xaa, 0x46, 0x6d, 0x7a, 0x7e, 0xf7, 0xe6, 0x9a, 0x9f, 0xd6, 0xed, 0xe1,
0xf0, 0xf5, 0x67, 0xde, 0xf4, 0xd1, 0x41, 0xfc, 0x4a, 0x53, 0xc8, 0x4d, 0x30, 0x4e, 0x36,
0x40, 0x31, 0x8d, 0x98, 0x0c, 0xa2, 0xc0, 0xea, 0x6c, 0x0a, 0x18, 0x58, 0x8f, 0xee, 0x00,
0x62, 0x83, 0xe2, 0x0d, 0x5b, 0x8b, 0xc7, 0xd7, 0x04, 0x90, 0xa1, 0xe9, 0xcd, 0x16, 0x15,
0x56, 0x78, 0x92, 0x77, 0xd5, 0x12, 0xe3, 0xce, 0x19, 0xbe, 0x34, 0x50, 0x51, 0x4b, 0x32,
0xc1, 0x06, 0x07, 0x37, 0x35, 0x60, 0xac, 0xad, 0x2b, 0x27, 0xeb, 0x08, 0x9b, 0xdb, 0x7b,
0x4f, 0x03, 0x79, 0x11, 0x17, 0xd3, 0xf1, 0xd9, 0xa6, 0x66, 0xf3, 0xcf, 0x72, 0x99, 0x3a,
0xca, 0x3d, 0x0b, 0x89, 0x47, 0x24, 0xdf, 0x65, 0x14, 0x38, 0x61, 0xc2, 0x6f, 0x13, 0xaf,
0x91, 0x3e, 0x2a, 0x33, 0xda, 0xe0, 0xa5, 0x3b, 0x1b, 0x1d, 0xa0, 0x22, 0x6a, 0xc4, 0x95,
0xfa, 0xb6, 0xb2, 0x69, 0x9c, 0xf2, 0x80, 0x44, 0x21, 0xef, 0x9d, 0xa7, 0xcb, 0xa9, 0x96,
0x1e, 0x43, 0x76, 0x8a, 0x7f, 0x3c, 0xd0, 0xa8, 0x59, 0x20, 0xdc, 0x81, 0xc9, 0xcc, 0x97,
0xa4, 0xbc, 0xbd, 0x7d, 0xab, 0xa3, 0xb4, 0x52, 0xe4, 0xb0, 0x8c, 0xb9, 0x2f, 0x9e, 0xb7,
0x4c, 0xe8, 0x45, 0x63, 0x09, 0x64, 0x5d, 0x88, 0xd2, 0x1c, 0x74, 0x87, 0x48, 0x5e, 0x55,
0x6b,
},
{
0xb3, 0xec, 0x39, 0x05, 0x2d, 0x28, 0x10, 0xb1, 0xc6, 0xfe, 0x70, 0x29, 0x5a, 0xfb, 0x49,
0x23, 0xdd, 0x86, 0x01, 0xe5, 0xd4, 0x25, 0x42, 0xae, 0x85, 0x75, 0xff, 0x68, 0x2e, 0x5c,
0x1f, 0x02, 0xba, 0xb5, 0xbf, 0x7c, 0xfd, 0x71, 0xf9, 0x8e, 0x5f, 0xb8, 0x0e, 0x0f, 0xc3,
0x1a, 0xbb, 0xd8, 0xaa, 0xf3, 0xc7, 0xa9, 0x43, 0x20, 0xc6, 0xd0, 0xf4, 0x07, 0x00, 0x9f,
0x89, 0x8e, 0xba, 0xe0, 0x5a, 0x24, 0x1f, 0x2a, 0xdd, 0xd4, 0xe3, 0x0d, 0xb0, 0xed, 0xbe,
0xb2, 0x2b, 0x75, 0x2e, 0x66, 0x17, 0x6e, 0x7c, 0x52, 0x76, 0x91, 0x01, 0x59, 0x61, 0x3c,
0x86, 0x2c, 0xfd, 0x2d, 0xf6, 0x0b, 0xab, 0xe5, 0x22, 0x41, 0x67, 0x72, 0xc2, 0xad, 0xbd,
0xfe, 0x96, 0xfa, 0x7b, 0x9e, 0x40, 0x5f, 0x71, 0x98, 0x4c, 0x88, 0xfb, 0xeb, 0x6b, 0xc9,
0xce, 0xbb, 0xc0, 0x03, 0x5b, 0x3a, 0xae, 0x15, 0x3e, 0x56, 0x4d, 0xd8, 0x3b, 0x50, 0x35,
0x84, 0x97, 0x34, 0xc4, 0x54, 0xcc, 0x4e, 0x5e, 0xcd, 0xe6, 0x68, 0x4f, 0xb3, 0xb4, 0x9d,
0x5d, 0xa5, 0xa3, 0x78, 0xe9, 0x38, 0x7e, 0x08, 0x60, 0x6c, 0xdb, 0x7f, 0xbf, 0x82, 0x30,
0xe2, 0x48, 0x19, 0x6d, 0x1a, 0xa2, 0xdf, 0x58, 0x95, 0x69, 0x51, 0x31, 0xda, 0x0c, 0x4b,
0xa4, 0x0a, 0x45, 0x27, 0xd7, 0x1e, 0x65, 0x87, 0x1b, 0xb7, 0xb5, 0x42, 0x8c, 0x26, 0x6f,
0x25, 0xea, 0xfc, 0xef, 0x8a, 0xa7, 0x10, 0xbc, 0xf5, 0xa0, 0x21, 0x44, 0x57, 0x02, 0xd2,
0x2f, 0x63, 0x3d, 0xd5, 0x79, 0x9c, 0x05, 0xf2, 0xe4, 0xcf, 0x29, 0xf1, 0x53, 0x0e, 0x7a,
0xb1, 0x14, 0x12, 0xf9, 0xf7, 0x11, 0x8b, 0x36, 0xa6, 0xb6, 0xd6, 0xa1, 0x18, 0x39, 0xec,
0x04, 0xc1, 0xe8, 0x8d, 0x28, 0x99, 0x73, 0x90, 0x70, 0xd3, 0x1d, 0x8f, 0xcb, 0xf8, 0xf0,
0xb9,
},
{
0xde, 0x77, 0x92, 0x32, 0xe7, 0xee, 0x85, 0x33, 0x13, 0xa8, 0x9a, 0x3f, 0xc8, 0xe1, 0x80,
0x9b, 0x06, 0x23, 0x37, 0x09, 0xd1, 0xff, 0xac, 0x81, 0x94, 0x64, 0xaf, 0x4a, 0x46, 0x7d,
0x16, 0xc3, 0x55, 0x47, 0xca, 0xd9, 0x0f, 0x1c, 0x6a, 0x74, 0xdc, 0x49, 0x83, 0xc5, 0xb8,
0x5c, 0x93, 0x62, 0xdc, 0x2f, 0xd4, 0xf0, 0x86, 0x18, 0xb1, 0x8c, 0x4f, 0xb9, 0xd5, 0x97,
0x1b, 0x43, 0x4c, 0x1d, 0xea, 0x5b, 0xc3, 0x11, 0x82, 0xfc, 0xa2, 0x4a, 0xa0, 0x7f, 0x47,
0xaf, 0xa3, 0x0a, 0x59, 0xad, 0xe5, 0x06, 0x2a, 0x4e, 0x6e, 0xe3, 0x40, 0xdb, 0x53, 0x83,
0x49, 0xb4, 0xba, 0x71, 0x95, 0x9b, 0x51, 0xb3, 0xac, 0xd1, 0xae, 0xc4, 0xcf, 0x4b, 0x4d,
0x69, 0x16, 0xec, 0x0b, 0xa5, 0x91, 0x73, 0x07, 0x3b, 0x19, 0x84, 0xc2, 0x6d, 0x8d, 0xb2,
0xbd, 0x25, 0x48, 0x96, 0xc5, 0x20, 0x1a, 0xa1, 0x8b, 0xc6, 0xe1, 0x3f, 0x28, 0xa7, 0xe7,
0x12, 0x76, 0xb0, 0x1c, 0x8e, 0xd0, 0x45, 0x90, 0xca, 0x98, 0xd6, 0xa6, 0x36, 0x32, 0x72,
0x8a, 0xa8, 0x0d, 0x3a, 0x9f, 0x37, 0x3c, 0x89, 0xdd, 0x67, 0x22, 0x81, 0xe9, 0x15, 0x41,
0x42, 0xf5, 0x2e, 0x66, 0xd2, 0x61, 0x80, 0x0f, 0x54, 0x93, 0xaa, 0xed, 0x5d, 0xe4, 0x7d,
0x30, 0xc9, 0x3d, 0xe0, 0xe2, 0x26, 0xf2, 0x08, 0xa9, 0x63, 0x24, 0x2d, 0x8f, 0x79, 0x9c,
0xda, 0xbf, 0x55, 0x62, 0x5c, 0x00, 0xb6, 0x27, 0x6a, 0x0e, 0x92, 0x01, 0xd7, 0xff, 0xeb,
0x1f, 0x74, 0x14, 0x99, 0xf7, 0x44, 0x87, 0x33, 0x6c, 0x94, 0x13, 0x50, 0x75, 0x68, 0x10,
0x17, 0xbb, 0x2c, 0x6b, 0x04, 0xdf, 0xbc, 0x35, 0x6f, 0xb7, 0xf1, 0x57, 0xc1, 0xe6, 0x7c,
0xb8, 0x77, 0x65, 0x3e, 0x5f, 0xd3, 0x64, 0xcb, 0x02, 0x1e, 0x38, 0xab, 0x88, 0x60, 0x5e,
0x9d,
},
{
0xbe, 0xc8, 0xa4, 0xd8, 0x52, 0x7b, 0x29, 0xf4, 0x05, 0x70, 0xce, 0x78, 0x85, 0x39, 0x23,
0xf3, 0x34, 0x58, 0x9e, 0xfb, 0x31, 0xcc, 0x46, 0xef, 0x9a, 0x5a, 0xfe, 0x7a, 0x56, 0xfd,
0xee, 0xde, 0x0c, 0xf9, 0xcd, 0xc0, 0x2b, 0xd9, 0xb5, 0x09, 0xf6, 0xc7, 0x21, 0xfa, 0xf8,
0x03, 0xe8, 0x7e, 0x9f, 0xbd, 0x79, 0x91, 0xcc, 0x78, 0x7f, 0xd5, 0x1b, 0xee, 0xbb, 0xb7,
0xdc, 0xed, 0x6d, 0x9b, 0xef, 0x58, 0xfb, 0x5d, 0x67, 0x69, 0x1f, 0x4e, 0xaf, 0x62, 0x4b,
0xb8, 0xa8, 0xae, 0x08, 0x60, 0x8c, 0xad, 0x24, 0xa1, 0x48, 0x2f, 0x8a, 0x00, 0x90, 0xb1,
0x53, 0x07, 0x26, 0x12, 0x72, 0x9d, 0x56, 0x1c, 0x51, 0x34, 0x46, 0x2e, 0x81, 0xcf, 0xb3,
0xf3, 0x37, 0xf1, 0xfa, 0x3c, 0xba, 0x06, 0x54, 0x85, 0x14, 0x59, 0x36, 0x5e, 0xa5, 0x55,
0x0c, 0x52, 0x89, 0xcb, 0x97, 0xe2, 0x3b, 0x11, 0xbe, 0xd9, 0x1d, 0xfc, 0x13, 0x7d, 0xa0,
0x05, 0x41, 0xc3, 0xc5, 0xfd, 0x76, 0x33, 0x82, 0xcd, 0x88, 0x16, 0x1a, 0x29, 0x87, 0x1e,
0x40, 0x6f, 0xe8, 0x03, 0x3a, 0x50, 0xa6, 0xe4, 0xf4, 0x4f, 0xd6, 0x98, 0x39, 0x71, 0xd0,
0xf2, 0xf0, 0x3e, 0xea, 0x8d, 0x2c, 0xa2, 0xa9, 0x57, 0x0b, 0x8b, 0x0d, 0xaa, 0xe9, 0x31,
0xc2, 0x35, 0x5c, 0xd1, 0x38, 0xff, 0x01, 0xa7, 0xec, 0x80, 0xf9, 0x23, 0xdf, 0x30, 0xeb,
0x2a, 0xb0, 0x17, 0xd2, 0x19, 0x6e, 0xda, 0x25, 0x9e, 0xb6, 0x4c, 0xc6, 0x93, 0xdb, 0x75,
0x6b, 0x3f, 0x15, 0x73, 0xfe, 0x3d, 0x65, 0x66, 0xb5, 0x7a, 0x9a, 0x32, 0xca, 0x68, 0x8e,
0x22, 0xc0, 0x44, 0x43, 0xa3, 0x0e, 0x21, 0xb9, 0x02, 0x4d, 0xc8, 0xb4, 0x0a, 0xf6, 0xd3,
0x45, 0x96, 0x5a, 0x84, 0x70, 0x18, 0xd4, 0xbf, 0xc4, 0xa4, 0x9c, 0xc1, 0xe0, 0x47, 0xc7,
0xe5,
},
{
0xe6, 0x7e, 0x63, 0xdd, 0x6a, 0xce, 0x28, 0x94, 0xe7, 0x10, 0xbc, 0x5f, 0x04, 0x64, 0x2d,
0x8f, 0x6c, 0xf7, 0x2b, 0x92, 0x83, 0xd8, 0x99, 0xe3, 0xde, 0xd7, 0x5b, 0xab, 0x4a, 0x74,
0x77, 0xc9, 0xf5, 0x7b, 0x0f, 0x20, 0xf8, 0x61, 0x42, 0x86, 0x7c, 0x49, 0x95, 0xac, 0x27,
0xe1, 0x09, 0xb2, 0x0b, 0xd3, 0x6f, 0x0a, 0x39, 0x77, 0x21, 0x17, 0x8f, 0xc7, 0xd5, 0xe5,
0xb5, 0xb9, 0x11, 0xa4, 0xdc, 0xa3, 0xcd, 0xbb, 0x1a, 0x81, 0x8a, 0xb7, 0xd9, 0x5b, 0x47,
0x61, 0x8e, 0x88, 0xb8, 0x0c, 0x3b, 0x3a, 0x9a, 0x54, 0xfd, 0x2d, 0x53, 0xb4, 0xc3, 0x5f,
0x69, 0x60, 0xb1, 0xab, 0x26, 0x56, 0x83, 0x7e, 0xb3, 0x3d, 0x4a, 0x0d, 0x5a, 0x1d, 0x1e,
0x59, 0xd6, 0x35, 0x8c, 0xf3, 0x9b, 0x18, 0x66, 0xbf, 0xe2, 0x62, 0x92, 0x7b, 0xff, 0x2e,
0x5c, 0xcf, 0x25, 0xc4, 0xaf, 0xd2, 0x29, 0x63, 0xa5, 0xb2, 0xf9, 0x6a, 0xc1, 0xfb, 0x14,
0x87, 0x55, 0x73, 0x2c, 0x44, 0x31, 0x79, 0xf4, 0x2a, 0x41, 0x01, 0x24, 0x80, 0x19, 0x65,
0x4d, 0x9d, 0x9c, 0xe8, 0x13, 0xa2, 0xc0, 0xc5, 0xfe, 0x6b, 0xce, 0x50, 0xf8, 0x04, 0x48,
0xa8, 0x06, 0x16, 0xbe, 0x67, 0xba, 0xea, 0xc6, 0x0f, 0xd7, 0x74, 0x85, 0xb6, 0xd8, 0x0e,
0x4c, 0x93, 0x15, 0xbd, 0xe6, 0x78, 0x03, 0x05, 0x32, 0xf7, 0x34, 0xe4, 0xad, 0x30, 0x98,
0xa1, 0x27, 0x9e, 0xf6, 0x43, 0x64, 0x3c, 0x49, 0xbc, 0xf0, 0x99, 0xdd, 0x12, 0xd1, 0xc9,
0x5d, 0x7c, 0x22, 0x75, 0x1f, 0x28, 0x2f, 0x09, 0xc2, 0x84, 0x6d, 0xfa, 0x23, 0x3f, 0x7d,
0x91, 0x89, 0x82, 0x86, 0x58, 0xdf, 0x76, 0xe9, 0xaa, 0xdb, 0xac, 0x2b, 0xf5, 0x90, 0x42,
0x20, 0xe1, 0xa0, 0xed, 0xd4, 0x52, 0x10, 0xef, 0x3e, 0xe3, 0x1c, 0xda, 0x96, 0xb0, 0x72,
0x38,
},
};
sb[0] = sboxes[idx][key[0]] ^ sboxes[(idx + 1) % 8][rand[1]];
sb[1] = sboxes[idx][key[5]] ^ sboxes[(idx + 1) % 8][rand[4]];
sb[2] = sboxes[idx][key[3]] ^ sboxes[(idx + 1) % 8][rand[0]];
sb[3] = sboxes[idx][key[2]] ^ sboxes[(idx + 1) % 8][rand[9]];
sb[4] = sboxes[idx][key[4]] ^ sboxes[(idx + 1) % 8][rand[7]];
sb[5] = sboxes[idx][key[1]] ^ sboxes[(idx + 1) % 8][rand[8]];
sb[6] = sboxes[idx][rand[3]] ^ sboxes[(idx + 1) % 8][rand[5]];
sb[7] = sboxes[idx][rand[2]] ^ sboxes[(idx + 1) % 8][rand[6]];
}
} // namespace
namespace WiimoteEmu
{
// Generate key from the 0x40-0x4c data in g_RegExt
void EncryptionKey::Generate(const u8* const keydata)
void EncryptionKey::GenerateTables(const RandData& rand, const KeyData& key, const u32 idx,
const u8 offset)
{
u8 rand[10];
u8 skey[6];
u8 testkey[6];
int idx;
ft[0] = sboxes[idx][key[4] + offset] ^ sboxes[idx + 1][rand[3] + offset];
ft[1] = sboxes[idx][key[2] + offset] ^ sboxes[idx + 1][rand[5] + offset];
ft[2] = sboxes[idx][key[5] + offset] ^ sboxes[idx + 1][rand[7] + offset];
ft[3] = sboxes[idx][key[0] + offset] ^ sboxes[idx + 1][rand[2] + offset];
ft[4] = sboxes[idx][key[1] + offset] ^ sboxes[idx + 1][rand[4] + offset];
ft[5] = sboxes[idx][key[3] + offset] ^ sboxes[idx + 1][rand[9] + offset];
ft[6] = sboxes[idx][rand[0] + offset] ^ sboxes[idx + 1][rand[6] + offset];
ft[7] = sboxes[idx][rand[1] + offset] ^ sboxes[idx + 1][rand[8] + offset];
for (int i = 0; i < 10; ++i)
rand[9 - i] = keydata[i];
for (int i = 0; i < 6; ++i)
skey[5 - i] = keydata[i + 10];
for (idx = 0; idx < 7; ++idx)
{
GenerateKey(rand, idx, testkey);
if (0 == memcmp(testkey, skey, 6))
break;
}
// default case is idx = 7 which is valid (homebrew uses it for the 0x17 case)
GenerateTables(rand, skey, idx, ft, sb);
// for homebrew, ft and sb are all 0x97 which is equivalent to 0x17
sb[0] = sboxes[idx][key[0] + offset] ^ sboxes[idx + 1][rand[1] + offset];
sb[1] = sboxes[idx][key[5] + offset] ^ sboxes[idx + 1][rand[4] + offset];
sb[2] = sboxes[idx][key[3] + offset] ^ sboxes[idx + 1][rand[0] + offset];
sb[3] = sboxes[idx][key[2] + offset] ^ sboxes[idx + 1][rand[9] + offset];
sb[4] = sboxes[idx][key[4] + offset] ^ sboxes[idx + 1][rand[7] + offset];
sb[5] = sboxes[idx][key[1] + offset] ^ sboxes[idx + 1][rand[8] + offset];
sb[6] = sboxes[idx][rand[3] + offset] ^ sboxes[idx + 1][rand[5] + offset];
sb[7] = sboxes[idx][rand[2] + offset] ^ sboxes[idx + 1][rand[6] + offset];
}
// Question: Is there a reason these can only handle a length of 255?
// Answer: The i2c address space is only 8-bits so it really doesn't need to.
// Also, only 21 bytes are ever encrypted at most (6 in any normal game).
void EncryptionKey::Encrypt(u8* const data, int addr, const u8 len) const
// Generate key from the 0x40-0x4f data in the extension register.
EncryptionKey KeyGen::GenerateFromExtensionKeyData(const ExtKeyData& ext_key) const
{
for (int i = 0; i < len; ++i, ++addr)
EncryptionKey::RandData rand;
std::copy_n(ext_key.begin(), rand.size(), rand.rbegin());
EncryptionKey::KeyData key;
std::copy_n(ext_key.begin() + rand.size(), key.size(), key.rbegin());
// The "key" is generated from "rand" and "idx".
// The tables are generated from "rand" "key" and "idx".
// But "idx" is not sent to the extension.
// We brute force which "idx" (0-6) the Wii used to generate its "key".
for (u32 idx = 0; idx != 7; ++idx)
{
if (GenerateKeyData(rand, idx) == key)
return GenerateTables(rand, key, idx);
}
// Some homebrew apparently sends "ext_key" filled with 0x00.
// On a real extension this produces tables filled with 0x17 or 0x97 (same effect).
// This is not something that the Wii's algorithm is capable of and our brute force will fail.
WARN_LOG(WIIMOTE, "Extension key generation failed. Filling tables with 0x17.");
// There must be some not understood math behind the extension's table generation.
EncryptionKey result;
result.ft.fill(0x17);
result.sb.fill(0x17);
return result;
}
EncryptionKey::KeyData KeyGen1stParty::GenerateKeyData(const EncryptionKey::RandData& rand,
const u32 idx) const
{
constexpr u8 ans_tbl[7][6] = {
{0xa8, 0x77, 0xa6, 0xe0, 0xf7, 0x43}, {0x5a, 0x35, 0x85, 0xe2, 0x72, 0x97},
{0x8f, 0xb7, 0x1a, 0x62, 0x87, 0x38}, {0x0d, 0x67, 0xc7, 0xbe, 0x4f, 0x3e},
{0x20, 0x76, 0x37, 0x8f, 0x68, 0xb7}, {0xa9, 0x26, 0x3f, 0x2b, 0x10, 0xe3},
{0x30, 0x7e, 0x90, 0x0e, 0x85, 0x0a},
};
auto& ans = ans_tbl[idx];
auto& sbox = sboxes[0];
EncryptionKey::RandData t0;
for (std::size_t i = 0; i != t0.size(); ++i)
t0[i] = sbox[rand[i]];
auto& ror8 = Common::RotateRight<u8>;
return {
u8((ror8(ans[0] ^ t0[5], t0[2]) - t0[9]) ^ t0[4]),
u8((ror8(ans[1] ^ t0[1], t0[0]) - t0[5]) ^ t0[7]),
u8((ror8(ans[2] ^ t0[6], t0[8]) - t0[2]) ^ t0[0]),
u8((ror8(ans[3] ^ t0[4], t0[7]) - t0[3]) ^ t0[2]),
u8((ror8(ans[4] ^ t0[1], t0[6]) - t0[3]) ^ t0[4]),
u8((ror8(ans[5] ^ t0[7], t0[8]) - t0[5]) ^ t0[9]),
};
}
EncryptionKey::KeyData KeyGen3rdParty::GenerateKeyData(const EncryptionKey::RandData& rand,
const u32 idx) const
{
auto& sbox = sboxes[9];
EncryptionKey::RandData t0;
for (std::size_t i = 0; i != t0.size(); ++i)
t0[i] = sbox[rand[i] + 0x30];
const auto ans = &sbox[idx * 6];
auto& rol8 = Common::RotateLeft<u8>;
return {
u8(t0[7] ^ t0[6] + rol8(ans[0] ^ t0[0], t0[1])),
u8(t0[1] ^ t0[3] + rol8(ans[1] ^ t0[4], t0[2])),
u8(t0[5] ^ t0[4] + rol8(ans[2] ^ t0[2], t0[8])),
u8(t0[0] ^ t0[7] + rol8(ans[3] ^ t0[6], t0[9])),
u8(t0[1] ^ t0[8] + rol8(ans[4] ^ t0[5], t0[4])),
u8(t0[5] ^ t0[8] + rol8(ans[5] ^ t0[9], t0[3])),
};
}
EncryptionKey KeyGen1stParty::GenerateTables(const EncryptionKey::RandData& rand,
const EncryptionKey::KeyData& key, u32 idx) const
{
EncryptionKey result;
result.GenerateTables(rand, key, idx + 1, 0);
return result;
}
EncryptionKey KeyGen3rdParty::GenerateTables(const EncryptionKey::RandData& rand,
const EncryptionKey::KeyData& key, u32 idx) const
{
EncryptionKey result;
result.GenerateTables(rand, key, idx + 10, 0x30);
return result;
}
void EncryptionKey::Encrypt(u8* const data, u32 addr, const u32 len) const
{
for (u32 i = 0; i != len; ++i, ++addr)
data[i] = (data[i] - ft[addr % 8]) ^ sb[addr % 8];
}
void EncryptionKey::Decrypt(u8* const data, int addr, const u8 len) const
void EncryptionKey::Decrypt(u8* const data, u32 addr, const u32 len) const
{
for (int i = 0; i < len; ++i, ++addr)
for (u32 i = 0; i != len; ++i, ++addr)
data[i] = (data[i] ^ sb[addr % 8]) + ft[addr % 8];
}

View file

@ -6,6 +6,8 @@
#pragma once
#include <array>
#include "Common/CommonTypes.h"
namespace WiimoteEmu
@ -13,14 +15,50 @@ namespace WiimoteEmu
class EncryptionKey
{
public:
void Generate(const u8* keydata);
void Encrypt(u8* data, u32 addr, u32 len) const;
void Decrypt(u8* data, u32 addr, u32 len) const;
void Encrypt(u8* data, int addr, u8 len) const;
void Decrypt(u8* data, int addr, u8 len) const;
using RandData = std::array<u8, 10>;
using KeyData = std::array<u8, 6>;
void GenerateTables(const RandData& rand, const KeyData& key, const u32 idx, const u8 offset);
std::array<u8, 8> ft = {};
std::array<u8, 8> sb = {};
};
class KeyGen
{
public:
virtual ~KeyGen() = default;
using ExtKeyData = std::array<u8, 16>;
EncryptionKey GenerateFromExtensionKeyData(const ExtKeyData& key_data) const;
protected:
virtual EncryptionKey::KeyData GenerateKeyData(const EncryptionKey::RandData& rand,
u32 idx) const = 0;
virtual EncryptionKey GenerateTables(const EncryptionKey::RandData& rand,
const EncryptionKey::KeyData& key, u32 idx) const = 0;
};
class KeyGen1stParty final : public KeyGen
{
private:
u8 ft[8] = {};
u8 sb[8] = {};
EncryptionKey::KeyData GenerateKeyData(const EncryptionKey::RandData& rand,
u32 idx) const final override;
EncryptionKey GenerateTables(const EncryptionKey::RandData& rand,
const EncryptionKey::KeyData& key, u32 idx) const final override;
};
class KeyGen3rdParty final : public KeyGen
{
private:
EncryptionKey::KeyData GenerateKeyData(const EncryptionKey::RandData& rand,
u32 idx) const final override;
EncryptionKey GenerateTables(const EncryptionKey::RandData& rand,
const EncryptionKey::KeyData& key, u32 idx) const final override;
};
} // namespace WiimoteEmu

View file

@ -72,7 +72,7 @@ constexpr std::array<u16, 4> classic_dpad_bitmasks{{
Classic::PAD_RIGHT,
}};
Classic::Classic() : EncryptedExtension(_trans("Classic"))
Classic::Classic() : Extension1stParty(_trans("Classic"))
{
// buttons
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
@ -172,7 +172,8 @@ bool Classic::IsButtonPressed() const
void Classic::Reset()
{
m_reg = {};
EncryptedExtension::Reset();
m_reg.identifier = classic_id;
// Build calibration data:

View file

@ -26,7 +26,7 @@ enum class ClassicGroup
RightStick
};
class Classic : public EncryptedExtension
class Classic : public Extension1stParty
{
public:
union ButtonFormat

View file

@ -44,7 +44,7 @@ constexpr std::array<u16, 2> drum_button_bitmasks{{
Drums::BUTTON_PLUS,
}};
Drums::Drums() : EncryptedExtension(_trans("Drums"))
Drums::Drums() : Extension1stParty(_trans("Drums"))
{
// pads
groups.emplace_back(m_pads = new ControllerEmu::Buttons(_trans("Pads")));
@ -106,7 +106,8 @@ bool Drums::IsButtonPressed() const
void Drums::Reset()
{
m_reg = {};
EncryptedExtension::Reset();
m_reg.identifier = drums_id;
// TODO: Is there calibration data?

View file

@ -22,8 +22,8 @@ enum class DrumsGroup
Stick
};
// TODO: Do the drums ever use encryption?
class Drums : public EncryptedExtension
// The Drums use the "1st-party" extension encryption scheme.
class Drums : public Extension1stParty
{
public:
struct DataFormat

View file

@ -12,6 +12,8 @@
#include "Common/Compiler.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "Common/Logging/Log.h"
namespace WiimoteEmu
{
Extension::Extension(const char* name) : m_name(name)
@ -85,15 +87,16 @@ int EncryptedExtension::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out)
auto const result = RawRead(&m_reg, addr, count, data_out);
// Encrypt data read from extension register
// Encrypt data read from extension register.
if (ENCRYPTION_ENABLED == m_reg.encryption)
{
// INFO_LOG(WIIMOTE, "Encrypted read.");
ext_key.Encrypt(data_out, addr, (u8)count);
}
else
if (m_is_key_dirty)
{
// INFO_LOG(WIIMOTE, "Unencrypted read.");
UpdateEncryptionKey();
m_is_key_dirty = false;
}
ext_key.Encrypt(data_out, addr, count);
}
return result;
@ -106,24 +109,48 @@ int EncryptedExtension::BusWrite(u8 slave_addr, u8 addr, int count, const u8* da
auto const result = RawWrite(&m_reg, addr, count, data_in);
// TODO: make this check less ugly:
if (addr + count > 0x40 && addr < 0x50)
constexpr u8 ENCRYPTION_KEY_DATA_BEGIN = offsetof(Register, encryption_key_data);
constexpr u8 ENCRYPTION_KEY_DATA_END = ENCRYPTION_KEY_DATA_BEGIN + 0x10;
if (addr + count > ENCRYPTION_KEY_DATA_BEGIN && addr < ENCRYPTION_KEY_DATA_END)
{
// Run the key generation on all writes in the key area, it doesn't matter
// that we send it parts of a key, only the last full key will have an effect
ext_key.Generate(m_reg.encryption_key_data);
// FYI: Real extensions seem to require the key data written in specifically sized chunks.
// We just run the key generation on all writes to the key area.
m_is_key_dirty = true;
}
return result;
}
void EncryptedExtension::Reset()
{
// Clear register state.
m_reg = {};
// Clear encryption key state.
ext_key = {};
m_is_key_dirty = true;
}
void EncryptedExtension::DoState(PointerWrap& p)
{
p.Do(m_reg);
// No need to sync this when we can regenerate it:
if (p.GetMode() == PointerWrap::MODE_READ)
ext_key.Generate(m_reg.encryption_key_data);
{
// No need to sync the key when we can just regenerate it.
m_is_key_dirty = true;
}
}
void Extension1stParty::UpdateEncryptionKey()
{
ext_key = KeyGen1stParty().GenerateFromExtensionKeyData(m_reg.encryption_key_data);
}
void Extension3rdParty::UpdateEncryptionKey()
{
ext_key = KeyGen3rdParty().GenerateFromExtensionKeyData(m_reg.encryption_key_data);
}
} // namespace WiimoteEmu

View file

@ -64,7 +64,7 @@ public:
// TODO: This is public for TAS reasons.
// TODO: TAS handles encryption poorly.
WiimoteEmu::EncryptionKey ext_key = {};
EncryptionKey ext_key;
protected:
static constexpr int CALIBRATION_CHECKSUM_BYTES = 2;
@ -82,7 +82,7 @@ protected:
u8 unknown3[0x10];
// address 0x40
u8 encryption_key_data[0x10];
std::array<u8, 0x10> encryption_key_data;
u8 unknown4[0xA0];
// address 0xF0
@ -98,9 +98,14 @@ protected:
Register m_reg = {};
void Reset() override;
void DoState(PointerWrap& p) override;
virtual void UpdateEncryptionKey() = 0;
private:
bool m_is_key_dirty = true;
static constexpr u8 ENCRYPTION_ENABLED = 0xaa;
bool ReadDeviceDetectPin() const override;
@ -109,4 +114,22 @@ private:
int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) override;
};
class Extension1stParty : public EncryptedExtension
{
protected:
using EncryptedExtension::EncryptedExtension;
private:
void UpdateEncryptionKey() final override;
};
class Extension3rdParty : public EncryptedExtension
{
protected:
using EncryptedExtension::EncryptedExtension;
private:
void UpdateEncryptionKey() final override;
};
} // namespace WiimoteEmu

View file

@ -62,7 +62,7 @@ constexpr std::array<u16, 2> guitar_strum_bitmasks{{
Guitar::BAR_DOWN,
}};
Guitar::Guitar() : EncryptedExtension(_trans("Guitar"))
Guitar::Guitar() : Extension1stParty(_trans("Guitar"))
{
// frets
groups.emplace_back(m_frets = new ControllerEmu::Buttons(_trans("Frets")));
@ -152,7 +152,8 @@ bool Guitar::IsButtonPressed() const
void Guitar::Reset()
{
m_reg = {};
EncryptedExtension::Reset();
m_reg.identifier = guitar_id;
// TODO: Is there calibration data?

View file

@ -27,8 +27,8 @@ enum class GuitarGroup
SliderBar
};
// TODO: Does the guitar ever use encryption?
class Guitar : public EncryptedExtension
// The Guitar uses the "1st-party" extension encryption scheme.
class Guitar : public Extension1stParty
{
public:
struct DataFormat

View file

@ -31,7 +31,7 @@ constexpr std::array<u8, 2> nunchuk_button_bitmasks{{
Nunchuk::BUTTON_Z,
}};
Nunchuk::Nunchuk() : EncryptedExtension(_trans("Nunchuk"))
Nunchuk::Nunchuk() : Extension1stParty(_trans("Nunchuk"))
{
// buttons
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
@ -121,7 +121,8 @@ bool Nunchuk::IsButtonPressed() const
void Nunchuk::Reset()
{
m_reg = {};
EncryptedExtension::Reset();
m_reg.identifier = nunchuk_id;
m_swing_state = {};

View file

@ -30,7 +30,7 @@ enum class NunchukGroup
Shake
};
class Nunchuk : public EncryptedExtension
class Nunchuk : public Extension1stParty
{
public:
union ButtonFormat

View file

@ -45,7 +45,7 @@ constexpr std::array<const char*, 6> turntable_button_names{{
_trans("Blue Right"),
}};
Turntable::Turntable() : EncryptedExtension(_trans("Turntable"))
Turntable::Turntable() : Extension1stParty(_trans("Turntable"))
{
// buttons
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
@ -148,7 +148,8 @@ bool Turntable::IsButtonPressed() const
void Turntable::Reset()
{
m_reg = {};
EncryptedExtension::Reset();
m_reg.identifier = turntable_id;
// TODO: Is there calibration data?

View file

@ -27,8 +27,8 @@ enum class TurntableGroup
Crossfade
};
// TODO: Does the turntable ever use encryption?
class Turntable : public EncryptedExtension
// The DJ Hero Turntable uses the "1st-party" extension encryption scheme.
class Turntable : public Extension1stParty
{
public:
struct DataFormat

View file

@ -0,0 +1,147 @@
// Copyright 2019 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h"
#include <array>
#include <cassert>
#include "Common/BitUtils.h"
#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "InputCommon/ControllerEmu/Control/Input.h"
#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
#include "InputCommon/ControllerEmu/ControlGroup/Triggers.h"
namespace WiimoteEmu
{
constexpr std::array<u8, 6> udraw_tablet_id{{0xff, 0x00, 0xa4, 0x20, 0x01, 0x12}};
constexpr std::array<u8, 2> udraw_tablet_button_bitmasks{{
UDrawTablet::BUTTON_ROCKER_UP,
UDrawTablet::BUTTON_ROCKER_DOWN,
}};
constexpr std::array<const char*, 2> udraw_tablet_button_names{{
_trans("Rocker Up"),
_trans("Rocker Down"),
}};
UDrawTablet::UDrawTablet() : Extension3rdParty(_trans("uDraw"))
{
// Buttons
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
for (auto& button_name : udraw_tablet_button_names)
{
m_buttons->controls.emplace_back(
new ControllerEmu::Input(ControllerEmu::Translate, button_name));
}
// Stylus
groups.emplace_back(m_stylus = new ControllerEmu::AnalogStick(
_trans("Stylus"), std::make_unique<ControllerEmu::SquareStickGate>(1.0)));
// Touch
groups.emplace_back(m_touch = new ControllerEmu::Triggers(_trans("Touch")));
m_touch->controls.emplace_back(
new ControllerEmu::Input(ControllerEmu::Translate, _trans("Pressure")));
}
void UDrawTablet::Update()
{
DataFormat tablet_data = {};
// Pressure:
// Min/Max values produced on my device: 0x08, 0xf2
// We're just gonna assume it's an old sensor and use the full byte range:
// Note: Pressure values are valid even when stylus is lifted.
constexpr u8 max_pressure = 0xff;
const auto touch_state = m_touch->GetState();
tablet_data.pressure = static_cast<u8>(touch_state.data[0] * max_pressure);
// Stylus X/Y:
// Min/Max X values (when touched) produced on my device: 0x4f, 0x7B3
// Drawing area edge (approx) X values on my device: 0x56, 0x7a5
// Min/Max Y values (when touched) produced on my device: 0x53, 0x5b4
// Drawing area edge (approx) Y values on my device: 0x5e, 0x5a5
// Calibrated for "uDraw Studio: Instant Artist".
constexpr u16 min_x = 0x56;
constexpr u16 max_x = 0x780;
constexpr u16 min_y = 0x65;
constexpr u16 max_y = 0x5a5;
constexpr double center_x = (max_x + min_x) / 2.0;
constexpr double center_y = (max_y + min_y) / 2.0;
// Neutral (lifted) stylus state:
u16 stylus_x = 0x7ff;
u16 stylus_y = 0x7ff;
// TODO: Expose the lifted stylus state in the UI.
bool is_stylus_lifted = false;
const auto stylus_state = m_stylus->GetState();
if (!is_stylus_lifted)
{
stylus_x = u16(center_x + stylus_state.x * (max_x - center_x));
stylus_y = u16(center_y + stylus_state.y * (max_y - center_y));
}
tablet_data.stylus_x1 = stylus_x & 0xff;
tablet_data.stylus_x2 = stylus_x >> 8;
tablet_data.stylus_y1 = stylus_y & 0xff;
tablet_data.stylus_y2 = stylus_y >> 8;
// Buttons:
m_buttons->GetState(&tablet_data.buttons, udraw_tablet_button_bitmasks.data());
// Flip button bits
constexpr u8 buttons_neutral_state = 0xfb;
tablet_data.buttons ^= buttons_neutral_state;
// Always 0xff
tablet_data.unk = 0xff;
Common::BitCastPtr<DataFormat>(&m_reg.controller_data) = tablet_data;
}
void UDrawTablet::Reset()
{
EncryptedExtension::Reset();
m_reg.identifier = udraw_tablet_id;
// Both 0x20 and 0x30 calibration sections are just filled with 0xff on the real tablet:
m_reg.calibration.fill(0xff);
}
bool UDrawTablet::IsButtonPressed() const
{
u8 buttons = 0;
m_buttons->GetState(&buttons, udraw_tablet_button_bitmasks.data());
return buttons != 0;
}
ControllerEmu::ControlGroup* UDrawTablet::GetGroup(UDrawTabletGroup group)
{
switch (group)
{
case UDrawTabletGroup::Buttons:
return m_buttons;
case UDrawTabletGroup::Stylus:
return m_stylus;
case UDrawTabletGroup::Touch:
return m_touch;
default:
assert(false);
return nullptr;
}
}
} // namespace WiimoteEmu

View file

@ -0,0 +1,68 @@
// Copyright 2019 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Core/HW/WiimoteEmu/Extension/Extension.h"
namespace ControllerEmu
{
class Buttons;
class AnalogStick;
class Triggers;
class ControlGroup;
} // namespace ControllerEmu
namespace WiimoteEmu
{
enum class UDrawTabletGroup
{
Buttons,
Stylus,
Touch,
};
class UDrawTablet : public Extension3rdParty
{
public:
UDrawTablet();
void Update() override;
bool IsButtonPressed() const override;
void Reset() override;
ControllerEmu::ControlGroup* GetGroup(UDrawTabletGroup group);
static constexpr u8 BUTTON_ROCKER_UP = 0x1;
static constexpr u8 BUTTON_ROCKER_DOWN = 0x2;
struct DataFormat
{
// Bytes 0-2 are 0xff when stylus is lifted
// X increases from left to right
// Y increases from bottom to top
u8 stylus_x1;
u8 stylus_y1;
u8 stylus_x2 : 4;
u8 stylus_y2 : 4;
// Valid even when stylus is lifted
u8 pressure;
// Always 0xff
u8 unk;
// Buttons are 0 when pressed
// 0x04 is always unset (neutral state is 0xfb)
u8 buttons;
};
static_assert(6 == sizeof(DataFormat), "Wrong size.");
private:
ControllerEmu::Buttons* m_buttons;
ControllerEmu::AnalogStick* m_stylus;
ControllerEmu::Triggers* m_touch;
};
} // namespace WiimoteEmu

View file

@ -19,6 +19,7 @@ enum ExtensionNumber : u8
GUITAR,
DRUMS,
TURNTABLE,
UDRAW_TABLET,
};
// FYI: An extension must be attached.

View file

@ -30,6 +30,7 @@
#include "Core/HW/WiimoteEmu/Extension/Guitar.h"
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
#include "Core/HW/WiimoteEmu/Extension/Turntable.h"
#include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h"
#include "InputCommon/ControllerEmu/Control/Input.h"
#include "InputCommon/ControllerEmu/Control/Output.h"
@ -165,6 +166,7 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index)
m_attachments->AddAttachment(std::make_unique<WiimoteEmu::Guitar>());
m_attachments->AddAttachment(std::make_unique<WiimoteEmu::Drums>());
m_attachments->AddAttachment(std::make_unique<WiimoteEmu::Turntable>());
m_attachments->AddAttachment(std::make_unique<WiimoteEmu::UDrawTablet>());
m_attachments->AddSetting(&m_motion_plus_setting, {_trans("Attach MotionPlus")}, true);
@ -284,6 +286,13 @@ ControllerEmu::ControlGroup* Wiimote::GetTurntableGroup(TurntableGroup group)
->GetGroup(group);
}
ControllerEmu::ControlGroup* Wiimote::GetUDrawTabletGroup(UDrawTabletGroup group)
{
return static_cast<UDrawTablet*>(
m_attachments->GetAttachmentList()[ExtensionNumber::UDRAW_TABLET].get())
->GetGroup(group);
}
bool Wiimote::ProcessExtensionPortEvent()
{
// WiiBrew: Following a connection or disconnection event on the Extension Port,

View file

@ -55,6 +55,7 @@ enum class ClassicGroup;
enum class GuitarGroup;
enum class DrumsGroup;
enum class TurntableGroup;
enum class UDrawTabletGroup;
template <typename T>
void UpdateCalibrationDataChecksum(T& data, int cksum_bytes)
@ -113,6 +114,7 @@ public:
ControllerEmu::ControlGroup* GetGuitarGroup(GuitarGroup group);
ControllerEmu::ControlGroup* GetDrumsGroup(DrumsGroup group);
ControllerEmu::ControlGroup* GetTurntableGroup(TurntableGroup group);
ControllerEmu::ControlGroup* GetUDrawTabletGroup(UDrawTabletGroup group);
void Update();
void StepDynamics();

View file

@ -15,6 +15,7 @@
#include "Core/HW/WiimoteEmu/Extension/Guitar.h"
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
#include "Core/HW/WiimoteEmu/Extension/Turntable.h"
#include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "InputCommon/InputConfig.h"
@ -27,6 +28,7 @@ WiimoteEmuExtension::WiimoteEmuExtension(MappingWindow* window) : MappingWidget(
CreateNoneLayout();
CreateNunchukLayout();
CreateTurntableLayout();
CreateUDrawTabletLayout();
CreateMainLayout();
ChangeExtensionType(WiimoteEmu::ExtensionNumber::NONE);
@ -181,6 +183,24 @@ void WiimoteEmuExtension::CreateTurntableLayout()
m_turntable_box->setLayout(layout);
}
void WiimoteEmuExtension::CreateUDrawTabletLayout()
{
auto* hbox = new QHBoxLayout();
m_udraw_tablet_box = new QGroupBox(tr("uDraw GameTablet"), this);
hbox->addWidget(CreateGroupBox(
tr("Buttons"),
Wiimote::GetUDrawTabletGroup(GetPort(), WiimoteEmu::UDrawTabletGroup::Buttons)));
hbox->addWidget(CreateGroupBox(
tr("Stylus"), Wiimote::GetUDrawTabletGroup(GetPort(), WiimoteEmu::UDrawTabletGroup::Stylus)));
hbox->addWidget(CreateGroupBox(
tr("Touch"), Wiimote::GetUDrawTabletGroup(GetPort(), WiimoteEmu::UDrawTabletGroup::Touch)));
m_udraw_tablet_box->setLayout(hbox);
}
void WiimoteEmuExtension::CreateMainLayout()
{
m_main_layout = new QHBoxLayout();
@ -191,6 +211,7 @@ void WiimoteEmuExtension::CreateMainLayout()
m_main_layout->addWidget(m_none_box);
m_main_layout->addWidget(m_nunchuk_box);
m_main_layout->addWidget(m_turntable_box);
m_main_layout->addWidget(m_udraw_tablet_box);
setLayout(m_main_layout);
}
@ -220,4 +241,5 @@ void WiimoteEmuExtension::ChangeExtensionType(u32 type)
m_guitar_box->setHidden(type != ExtensionNumber::GUITAR);
m_drums_box->setHidden(type != ExtensionNumber::DRUMS);
m_turntable_box->setHidden(type != ExtensionNumber::TURNTABLE);
m_udraw_tablet_box->setHidden(type != ExtensionNumber::UDRAW_TABLET);
}

View file

@ -31,6 +31,7 @@ private:
void CreateNoneLayout();
void CreateNunchukLayout();
void CreateTurntableLayout();
void CreateUDrawTabletLayout();
void CreateMainLayout();
// Main
@ -41,4 +42,5 @@ private:
QGroupBox* m_none_box;
QGroupBox* m_nunchuk_box;
QGroupBox* m_turntable_box;
QGroupBox* m_udraw_tablet_box;
};