#include <array>
#include <cstdlib>
#include <iostream>
#include <memory>
using namespace std;
class DES;
class DES {
public:
DES(const unsigned long long& key);
unsigned long long encipher(const unsigned long long& plane_data);
unsigned long long decipher(const unsigned long long& cipher_data);
protected:
shared_ptr<array<unsigned long long, 16> > en_subkeys;
shared_ptr<array<unsigned long long, 16> > de_subkeys;
DES(const DES& des);
DES& operator =(const DES& des);
static const unsigned int PC_1C_TABLE[28];
static const unsigned int PC_1D_TABLE[28];
static const unsigned int PC_2_TABLE[48];
static const unsigned int SUBKEY_SHIFT_AMOUNTS[16];
static const unsigned int IP_TABLE[64];
static const unsigned int IIP_TABLE[64];
static const unsigned int E_TABLE[48];
static const unsigned int S_TABLE[8][4][16];
static const unsigned int P_TABLE[32];
static unsigned long long appendParityBits(const unsigned long long& key);
static unsigned long long execute(const unsigned long long& data, const shared_ptr<array<unsigned long long, 16> >& subkeys);
static unsigned long f(const unsigned long& r, const unsigned long long& subkey);
static unsigned char s(const unsigned char& t, const unsigned int tab[4][16]);
template <class D, class S> static D choice(const S& src, const unsigned int& src_len, const unsigned int* tab, const unsigned int& tab_len);
};
template <class X> X rotateLeft(const X& x, const unsigned int& n, const unsigned int& w = (sizeof(X) << 3));
#define ASSERT(pred) assert(#pred, pred);
extern void assert(const char* pred_str, const bool& pred_res);
const unsigned int DES::PC_1C_TABLE[28] = {
57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
};
const unsigned int DES::PC_1D_TABLE[28] = {
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4,
};
const unsigned int DES::PC_2_TABLE[48] = {
14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32,
};
const unsigned int DES::SUBKEY_SHIFT_AMOUNTS[16] = {
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
};
const unsigned int DES::IP_TABLE[64] = {
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7,
};
const unsigned int DES::IIP_TABLE[64] = {
40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25,
};
const unsigned int DES::E_TABLE[48] = {
32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1,
};
const unsigned int DES::S_TABLE[8][4][16] = {
{
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, },
{ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, },
{ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, },
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, },
},
{
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, },
{ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, },
{ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, },
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, },
},
{
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, },
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, },
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, },
{ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, },
},
{
{7 , 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, },
{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, },
{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, },
{ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, },
},
{
{ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, },
{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, },
{ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, },
{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, },
},
{
{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, },
{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, },
{ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, },
{ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, },
},
{
{ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, },
{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, },
{ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, },
{ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, },
},
{
{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, },
{ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, },
{ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, },
{ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11, },
},
};
const unsigned int DES::P_TABLE[32] = {
16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25,
};
DES::DES(const unsigned long long& key) {
unsigned long long act_key = appendParityBits(key);
this->en_subkeys.reset(new array<unsigned long long, 16>);
this->de_subkeys.reset(new array<unsigned long long, 16>);
unsigned long c = choice<unsigned long>(act_key, 64, PC_1C_TABLE, 28);
unsigned long d = choice<unsigned long>(act_key, 64, PC_1D_TABLE, 28);
for (unsigned int i = 0; i < 16; i++) {
c = rotateLeft(c, SUBKEY_SHIFT_AMOUNTS[i], 28);
d = rotateLeft(d, SUBKEY_SHIFT_AMOUNTS[i], 28);
this->en_subkeys->at(i) = choice<unsigned long long>(c << 28 | d, 56, PC_2_TABLE, 48);
this->de_subkeys->at(16 - 1 - i) = this->en_subkeys->at(i);
}
}
unsigned long long DES::encipher(const unsigned long long& plane_data) {
return execute(plane_data, this->en_subkeys);
}
unsigned long long DES::decipher(const unsigned long long& cipher_data) {
return execute(cipher_data, this->de_subkeys);
}
unsigned long long DES::appendParityBits(const unsigned long long& key) {
unsigned long long res = 0;
unsigned int par_bit = 1;
for (unsigned int i = 0; i < 56; i++) {
res <<= 1;
unsigned int bit = (key >> (56 - 1 - i)) & 1;
res |= bit;
par_bit ^= bit;
if ((i + 1) % 7 == 0) {
res <<= 1;
res |= par_bit;
par_bit = 1;
}
}
return res;
}
unsigned long long DES::execute(const unsigned long long& data, const shared_ptr<array<unsigned long long, 16> >& subkeys) {
unsigned long long ip_data = choice<unsigned long long>(data, 64, IP_TABLE, 64);
unsigned long l = ip_data >> 32;
unsigned long r = ip_data & 0xffffffff;
for (unsigned int i = 0; i < 16; i++) {
unsigned long t = r;
r = l ^ f(r, subkeys->at(i));
l = t;
}
return choice<unsigned long long>(((unsigned long long)r << 32) | l, 64, IIP_TABLE, 64);
}
unsigned long DES::f(const unsigned long& r, const unsigned long long& subkey) {
unsigned long long t = choice<unsigned long long>(r, 32, E_TABLE, 48) ^ subkey;
unsigned long long u = 0;
for (unsigned int i = 0; i < 8; i++) {
u <<= 4;
u |= s((t >> (48 - 6 * (i + 1))) & 0x3f, S_TABLE[i]);
}
return choice<unsigned long>(u, 32, P_TABLE, 32);
}
unsigned char DES::s(const unsigned char& t, const unsigned int tab[4][16]) {
unsigned int row = ((t >> (6 - 1)) << 1) | (t & 1);
unsigned int col = (t >> (2 - 1)) & 0xf;
return tab[row][col];
}
template <class D, class S> D DES::choice(const S& src, const unsigned int& src_len, const unsigned int* tab, const unsigned int& tab_len) {
D dest = 0;
for (unsigned int i = 0; i < tab_len; i++) {
dest <<= 1;
dest |= (src >> (src_len - tab[i])) & 1;
}
return dest;
}
template <class X> X rotateLeft(const X& x, const unsigned int& n, const unsigned int& w) {
return (x << n) | (x >> (w - n));
}
void assert(const char* pred_str, const bool& pred_res) {
if (pred_res) {
cout << "アサート成功: " << pred_str << endl;
}
else {
cerr << "アサート失敗: " << pred_str << endl;
exit(1);
}
}
int main() {
{
DES des(0x1234567812345678);
ASSERT(des.encipher(0x1234567812345678) == 0x941eddd882714d98)
ASSERT(des.decipher(0x941eddd882714d98) == 0x1234567812345678)
ASSERT(des.encipher(0x8765432187654321) == 0x084cd9754e5f3058)
ASSERT(des.decipher(0x084cd9754e5f3058) == 0x8765432187654321)
}
{
DES des(0x8765432187654321);
ASSERT(des.encipher(0x1234567812345678) == 0x5b3a1ef3f29089a1)
ASSERT(des.decipher(0x5b3a1ef3f29089a1) == 0x1234567812345678)
ASSERT(des.encipher(0x8765432187654321) == 0x46f4a70e6ff7166c)
ASSERT(des.decipher(0x46f4a70e6ff7166c) == 0x8765432187654321)
}
return 0;
}
I2luY2x1ZGUgPGFycmF5PgojaW5jbHVkZSA8Y3N0ZGxpYj4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8bWVtb3J5PgoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCmNsYXNzIERFUzsKCmNsYXNzIERFUyB7CnB1YmxpYzoKICAgIERFUyhjb25zdCB1bnNpZ25lZCBsb25nIGxvbmcmIGtleSk7Cgl1bnNpZ25lZCBsb25nIGxvbmcgZW5jaXBoZXIoY29uc3QgdW5zaWduZWQgbG9uZyBsb25nJiBwbGFuZV9kYXRhKTsKCXVuc2lnbmVkIGxvbmcgbG9uZyBkZWNpcGhlcihjb25zdCB1bnNpZ25lZCBsb25nIGxvbmcmIGNpcGhlcl9kYXRhKTsKcHJvdGVjdGVkOgoJc2hhcmVkX3B0cjxhcnJheTx1bnNpZ25lZCBsb25nIGxvbmcsIDE2PiA+IGVuX3N1YmtleXM7CglzaGFyZWRfcHRyPGFycmF5PHVuc2lnbmVkIGxvbmcgbG9uZywgMTY+ID4gZGVfc3Via2V5czsKCURFUyhjb25zdCBERVMmIGRlcyk7CglERVMmIG9wZXJhdG9yID0oY29uc3QgREVTJiBkZXMpOwoJc3RhdGljIGNvbnN0IHVuc2lnbmVkIGludCBQQ18xQ19UQUJMRVsyOF07CglzdGF0aWMgY29uc3QgdW5zaWduZWQgaW50IFBDXzFEX1RBQkxFWzI4XTsKCXN0YXRpYyBjb25zdCB1bnNpZ25lZCBpbnQgUENfMl9UQUJMRVs0OF07CglzdGF0aWMgY29uc3QgdW5zaWduZWQgaW50IFNVQktFWV9TSElGVF9BTU9VTlRTWzE2XTsKCXN0YXRpYyBjb25zdCB1bnNpZ25lZCBpbnQgSVBfVEFCTEVbNjRdOwoJc3RhdGljIGNvbnN0IHVuc2lnbmVkIGludCBJSVBfVEFCTEVbNjRdOwoJc3RhdGljIGNvbnN0IHVuc2lnbmVkIGludCBFX1RBQkxFWzQ4XTsKCXN0YXRpYyBjb25zdCB1bnNpZ25lZCBpbnQgU19UQUJMRVs4XVs0XVsxNl07CglzdGF0aWMgY29uc3QgdW5zaWduZWQgaW50IFBfVEFCTEVbMzJdOwoJc3RhdGljIHVuc2lnbmVkIGxvbmcgbG9uZyBhcHBlbmRQYXJpdHlCaXRzKGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYga2V5KTsKCXN0YXRpYyB1bnNpZ25lZCBsb25nIGxvbmcgZXhlY3V0ZShjb25zdCB1bnNpZ25lZCBsb25nIGxvbmcmIGRhdGEsIGNvbnN0IHNoYXJlZF9wdHI8YXJyYXk8dW5zaWduZWQgbG9uZyBsb25nLCAxNj4gPiYgc3Via2V5cyk7CglzdGF0aWMgdW5zaWduZWQgbG9uZyBmKGNvbnN0IHVuc2lnbmVkIGxvbmcmIHIsIGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYgc3Via2V5KTsKCXN0YXRpYyB1bnNpZ25lZCBjaGFyIHMoY29uc3QgdW5zaWduZWQgY2hhciYgdCwgY29uc3QgdW5zaWduZWQgaW50IHRhYls0XVsxNl0pOwoJdGVtcGxhdGUgPGNsYXNzIEQsIGNsYXNzIFM+IHN0YXRpYyBEIGNob2ljZShjb25zdCBTJiBzcmMsIGNvbnN0IHVuc2lnbmVkIGludCYgc3JjX2xlbiwgY29uc3QgdW5zaWduZWQgaW50KiB0YWIsIGNvbnN0IHVuc2lnbmVkIGludCYgdGFiX2xlbik7Cn07Cgp0ZW1wbGF0ZSA8Y2xhc3MgWD4gWCByb3RhdGVMZWZ0KGNvbnN0IFgmIHgsIGNvbnN0IHVuc2lnbmVkIGludCYgbiwgY29uc3QgdW5zaWduZWQgaW50JiB3ID0gKHNpemVvZihYKSA8PCAzKSk7CgojZGVmaW5lIEFTU0VSVChwcmVkKSBhc3NlcnQoI3ByZWQsIHByZWQpOwoKZXh0ZXJuIHZvaWQgYXNzZXJ0KGNvbnN0IGNoYXIqIHByZWRfc3RyLCBjb25zdCBib29sJiBwcmVkX3Jlcyk7Cgpjb25zdCB1bnNpZ25lZCBpbnQgREVTOjpQQ18xQ19UQUJMRVsyOF0gPSB7Cgk1NywgNDksIDQxLCAzMywgMjUsIDE3LCAgOSwgCgkgMSwgNTgsIDUwLCA0MiwgMzQsIDI2LCAxOCwgCgkxMCwgIDIsIDU5LCA1MSwgNDMsIDM1LCAyNywgCgkxOSwgMTEsICAzLCA2MCwgNTIsIDQ0LCAzNiwgCn07Cgpjb25zdCB1bnNpZ25lZCBpbnQgREVTOjpQQ18xRF9UQUJMRVsyOF0gPSB7Cgk2MywgNTUsIDQ3LCAzOSwgMzEsIDIzLCAxNSwgCgkgNywgNjIsIDU0LCA0NiwgMzgsIDMwLCAyMiwgCgkxNCwgIDYsIDYxLCA1MywgNDUsIDM3LCAyOSwgCgkyMSwgMTMsICA1LCAyOCwgMjAsIDEyLCAgNCwgCn07Cgpjb25zdCB1bnNpZ25lZCBpbnQgREVTOjpQQ18yX1RBQkxFWzQ4XSA9IHsKCTE0LCAxNywgMTEsIDI0LCAgMSwgIDUsIAoJIDMsIDI4LCAxNSwgIDYsIDIxLCAxMCwgCgkyMywgMTksIDEyLCAgNCwgMjYsICA4LCAKCTE2LCAgNywgMjcsIDIwLCAxMywgIDIsIAoJNDEsIDUyLCAzMSwgMzcsIDQ3LCA1NSwgCgkzMCwgNDAsIDUxLCA0NSwgMzMsIDQ4LCAKCTQ0LCA0OSwgMzksIDU2LCAzNCwgNTMsIAoJNDYsIDQyLCA1MCwgMzYsIDI5LCAzMiwgCn07Cgpjb25zdCB1bnNpZ25lZCBpbnQgREVTOjpTVUJLRVlfU0hJRlRfQU1PVU5UU1sxNl0gPSB7CgkxLCAxLCAyLCAyLCAyLCAyLCAyLCAyLCAxLCAyLCAyLCAyLCAyLCAyLCAyLCAxLCAKfTsKCmNvbnN0IHVuc2lnbmVkIGludCBERVM6OklQX1RBQkxFWzY0XSA9IHsKCTU4LCA1MCwgNDIsIDM0LCAyNiwgMTgsIDEwLCAgMiwgCgk2MCwgNTIsIDQ0LCAzNiwgMjgsIDIwLCAxMiwgIDQsIAoJNjIsIDU0LCA0NiwgMzgsIDMwLCAyMiwgMTQsICA2LCAKCTY0LCA1NiwgNDgsIDQwLCAzMiwgMjQsIDE2LCAgOCwgCgk1NywgNDksIDQxLCAzMywgMjUsIDE3LCAgOSwgIDEsIAoJNTksIDUxLCA0MywgMzUsIDI3LCAxOSwgMTEsICAzLCAKCTYxLCA1MywgNDUsIDM3LCAyOSwgMjEsIDEzLCAgNSwgCgk2MywgNTUsIDQ3LCAzOSwgMzEsIDIzLCAxNSwgIDcsIAp9OwoKY29uc3QgdW5zaWduZWQgaW50IERFUzo6SUlQX1RBQkxFWzY0XSA9IHsKCTQwLCA4LCA0OCwgMTYsIDU2LCAyNCwgNjQsIDMyLCAKCTM5LCA3LCA0NywgMTUsIDU1LCAyMywgNjMsIDMxLCAKCTM4LCA2LCA0NiwgMTQsIDU0LCAyMiwgNjIsIDMwLCAKCTM3LCA1LCA0NSwgMTMsIDUzLCAyMSwgNjEsIDI5LCAKCTM2LCA0LCA0NCwgMTIsIDUyLCAyMCwgNjAsIDI4LCAKCTM1LCAzLCA0MywgMTEsIDUxLCAxOSwgNTksIDI3LCAKCTM0LCAyLCA0MiwgMTAsIDUwLCAxOCwgNTgsIDI2LCAKCTMzLCAxLCA0MSwgIDksIDQ5LCAxNywgNTcsIDI1LCAKfTsKCmNvbnN0IHVuc2lnbmVkIGludCBERVM6OkVfVEFCTEVbNDhdID0gewoJMzIsICAxLCAgMiwgIDMsICA0LCAgNSwgCgkgNCwgIDUsICA2LCAgNywgIDgsICA5LCAKCSA4LCAgOSwgMTAsIDExLCAxMiwgMTMsIAoJMTIsIDEzLCAxNCwgMTUsIDE2LCAxNywgCgkxNiwgMTcsIDE4LCAxOSwgMjAsIDIxLCAKCTIwLCAyMSwgMjIsIDIzLCAyNCwgMjUsIAoJMjQsIDI1LCAyNiwgMjcsIDI4LCAyOSwgCgkyOCwgMjksIDMwLCAzMSwgMzIsICAxLCAKfTsKCmNvbnN0IHVuc2lnbmVkIGludCBERVM6OlNfVEFCTEVbOF1bNF1bMTZdID0gewoJewoJCXsxNCwgIDQsIDEzLCAgMSwgIDIsIDE1LCAxMSwgIDgsICAzLCAxMCwgIDYsIDEyLCAgNSwgIDksICAwLCAgNywgfSwgCgkJeyAwLCAxNSwgIDcsICA0LCAxNCwgIDIsIDEzLCAgMSwgMTAsICA2LCAxMiwgMTEsICA5LCAgNSwgIDMsICA4LCB9LCAKCQl7IDQsICAxLCAxNCwgIDgsIDEzLCAgNiwgIDIsIDExLCAxNSwgMTIsICA5LCAgNywgIDMsIDEwLCAgNSwgIDAsIH0sIAoJCXsxNSwgMTIsICA4LCAgMiwgIDQsICA5LCAgMSwgIDcsICA1LCAxMSwgIDMsIDE0LCAxMCwgIDAsICA2LCAxMywgfSwgCgl9LCAKCXsKCQl7MTUsICAxLCAgOCwgMTQsICA2LCAxMSwgIDMsICA0LCAgOSwgIDcsICAyLCAxMywgMTIsICAwLCAgNSwgMTAsIH0sIAoJCXsgMywgMTMsICA0LCAgNywgMTUsICAyLCAgOCwgMTQsIDEyLCAgMCwgIDEsIDEwLCAgNiwgIDksIDExLCAgNSwgfSwgCgkJeyAwLCAxNCwgIDcsIDExLCAxMCwgIDQsIDEzLCAgMSwgIDUsICA4LCAxMiwgIDYsICA5LCAgMywgIDIsIDE1LCB9LCAKCQl7MTMsICA4LCAxMCwgIDEsICAzLCAxNSwgIDQsICAyLCAxMSwgIDYsICA3LCAxMiwgIDAsICA1LCAxNCwgIDksIH0sIAoJfSwgCgl7CgkJezEwLCAgMCwgIDksIDE0LCAgNiwgIDMsIDE1LCAgNSwgIDEsIDEzLCAxMiwgIDcsIDExLCAgNCwgIDIsICA4LCB9LCAKCQl7MTMsICA3LCAgMCwgIDksICAzLCAgNCwgIDYsIDEwLCAgMiwgIDgsICA1LCAxNCwgMTIsIDExLCAxNSwgIDEsIH0sIAoJCXsxMywgIDYsICA0LCAgOSwgIDgsIDE1LCAgMywgIDAsIDExLCAgMSwgIDIsIDEyLCAgNSwgMTAsIDE0LCAgNywgfSwgCgkJeyAxLCAxMCwgMTMsICAwLCAgNiwgIDksICA4LCAgNywgIDQsIDE1LCAxNCwgIDMsIDExLCAgNSwgIDIsIDEyLCB9LCAKCX0sIAoJewoJCXs3ICwgMTMsIDE0LCAgMywgIDAsICA2LCAgOSwgMTAsICAxLCAgMiwgIDgsICA1LCAxMSwgMTIsICA0LCAxNSwgfSwgCgkJezEzLCAgOCwgMTEsICA1LCAgNiwgMTUsICAwLCAgMywgIDQsICA3LCAgMiwgMTIsICAxLCAxMCwgMTQsICA5LCB9LCAKCQl7MTAsICA2LCAgOSwgIDAsIDEyLCAxMSwgIDcsIDEzLCAxNSwgIDEsICAzLCAxNCwgIDUsICAyLCAgOCwgIDQsIH0sIAoJCXsgMywgMTUsICAwLCAgNiwgMTAsICAxLCAxMywgIDgsICA5LCAgNCwgIDUsIDExLCAxMiwgIDcsICAyLCAxNCwgfSwgCgl9LAoJewoJCXsgMiwgMTIsICA0LCAgMSwgIDcsIDEwLCAxMSwgIDYsICA4LCAgNSwgIDMsIDE1LCAxMywgIDAsIDE0LCAgOSwgfSwgCgkJezE0LCAxMSwgIDIsIDEyLCAgNCwgIDcsIDEzLCAgMSwgIDUsICAwLCAxNSwgMTAsICAzLCAgOSwgIDgsICA2LCB9LCAKCQl7IDQsICAyLCAgMSwgMTEsIDEwLCAxMywgIDcsICA4LCAxNSwgIDksIDEyLCAgNSwgIDYsICAzLCAgMCwgMTQsIH0sIAoJCXsxMSwgIDgsIDEyLCAgNywgIDEsIDE0LCAgMiwgMTMsICA2LCAxNSwgIDAsICA5LCAxMCwgIDQsICA1LCAgMywgfSwgCgl9LCAKCXsKCQl7MTIsICAxLCAxMCwgMTUsICA5LCAgMiwgIDYsICA4LCAgMCwgMTMsICAzLCAgNCwgMTQsICA3LCAgNSwgMTEsIH0sIAoJCXsxMCwgMTUsICA0LCAgMiwgIDcsIDEyLCAgOSwgIDUsICA2LCAgMSwgMTMsIDE0LCAgMCwgMTEsICAzLCAgOCwgfSwgCgkJeyA5LCAxNCwgMTUsICA1LCAgMiwgIDgsIDEyLCAgMywgIDcsICAwLCAgNCwgMTAsICAxLCAxMywgMTEsICA2LCB9LCAKCQl7IDQsICAzLCAgMiwgMTIsICA5LCAgNSwgMTUsIDEwLCAxMSwgMTQsICAxLCAgNywgIDYsICAwLCAgOCwgMTMsIH0sIAoJfSwgCgl7CgkJeyA0LCAxMSwgIDIsIDE0LCAxNSwgIDAsICA4LCAxMywgIDMsIDEyLCAgOSwgIDcsICA1LCAxMCwgIDYsICAxLCB9LCAKCQl7MTMsICAwLCAxMSwgIDcsICA0LCAgOSwgIDEsIDEwLCAxNCwgIDMsICA1LCAxMiwgIDIsIDE1LCAgOCwgIDYsIH0sIAoJCXsgMSwgIDQsIDExLCAxMywgMTIsICAzLCAgNywgMTQsIDEwLCAxNSwgIDYsICA4LCAgMCwgIDUsICA5LCAgMiwgfSwgCgkJeyA2LCAxMSwgMTMsICA4LCAgMSwgIDQsIDEwLCAgNywgIDksICA1LCAgMCwgMTUsIDE0LCAgMiwgIDMsIDEyLCB9LCAKCX0sIAoJewoJCXsxMywgIDIsICA4LCAgNCwgIDYsIDE1LCAxMSwgIDEsIDEwLCAgOSwgIDMsIDE0LCAgNSwgIDAsIDEyLCAgNywgfSwgCgkJeyAxLCAxNSwgMTMsICA4LCAxMCwgIDMsICA3LCAgNCwgMTIsICA1LCAgNiwgMTEsICAwLCAxNCwgIDksICAyLCB9LCAKCQl7IDcsIDExLCAgNCwgIDEsICA5LCAxMiwgMTQsICAyLCAgMCwgIDYsIDEwLCAxMywgMTUsICAzLCAgNSwgIDgsIH0sIAoJCXsgMiwgIDEsIDE0LCAgNywgIDQsIDEwLCAgOCwgMTMsIDE1LCAxMiwgIDksICAwLCAgMywgIDUsICA2LCAxMSwgfSwgCgl9LCAKfTsKCmNvbnN0IHVuc2lnbmVkIGludCBERVM6OlBfVEFCTEVbMzJdID0gewoJMTYsICA3LCAyMCwgMjEsCgkyOSwgMTIsIDI4LCAxNywKCSAxLCAxNSwgMjMsIDI2LAoJIDUsIDE4LCAzMSwgMTAsCgkgMiwgIDgsIDI0LCAxNCwKCTMyLCAyNywgIDMsICA5LAoJMTksIDEzLCAzMCwgIDYsCgkyMiwgMTEsICA0LCAyNSwKfTsKCkRFUzo6REVTKGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYga2V5KSB7Cgl1bnNpZ25lZCBsb25nIGxvbmcgYWN0X2tleSA9IGFwcGVuZFBhcml0eUJpdHMoa2V5KTsKCXRoaXMtPmVuX3N1YmtleXMucmVzZXQobmV3IGFycmF5PHVuc2lnbmVkIGxvbmcgbG9uZywgMTY+KTsKCXRoaXMtPmRlX3N1YmtleXMucmVzZXQobmV3IGFycmF5PHVuc2lnbmVkIGxvbmcgbG9uZywgMTY+KTsKCXVuc2lnbmVkIGxvbmcgYyA9IGNob2ljZTx1bnNpZ25lZCBsb25nPihhY3Rfa2V5LCA2NCwgUENfMUNfVEFCTEUsIDI4KTsKCXVuc2lnbmVkIGxvbmcgZCA9IGNob2ljZTx1bnNpZ25lZCBsb25nPihhY3Rfa2V5LCA2NCwgUENfMURfVEFCTEUsIDI4KTsKCWZvciAodW5zaWduZWQgaW50IGkgPSAwOyBpIDwgMTY7IGkrKykgewoJCWMgPSByb3RhdGVMZWZ0KGMsIFNVQktFWV9TSElGVF9BTU9VTlRTW2ldLCAyOCk7CgkJZCA9IHJvdGF0ZUxlZnQoZCwgU1VCS0VZX1NISUZUX0FNT1VOVFNbaV0sIDI4KTsKCQl0aGlzLT5lbl9zdWJrZXlzLT5hdChpKSA9IGNob2ljZTx1bnNpZ25lZCBsb25nIGxvbmc+KGMgPDwgMjggfCBkLCA1NiwgUENfMl9UQUJMRSwgNDgpOwoJCXRoaXMtPmRlX3N1YmtleXMtPmF0KDE2IC0gMSAtIGkpID0gdGhpcy0+ZW5fc3Via2V5cy0+YXQoaSk7Cgl9Cn0KCnVuc2lnbmVkIGxvbmcgbG9uZyBERVM6OmVuY2lwaGVyKGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYgcGxhbmVfZGF0YSkgewoJcmV0dXJuIGV4ZWN1dGUocGxhbmVfZGF0YSwgdGhpcy0+ZW5fc3Via2V5cyk7Cn0KCnVuc2lnbmVkIGxvbmcgbG9uZyBERVM6OmRlY2lwaGVyKGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYgY2lwaGVyX2RhdGEpIHsKCXJldHVybiBleGVjdXRlKGNpcGhlcl9kYXRhLCB0aGlzLT5kZV9zdWJrZXlzKTsKfQoKdW5zaWduZWQgbG9uZyBsb25nIERFUzo6YXBwZW5kUGFyaXR5Qml0cyhjb25zdCB1bnNpZ25lZCBsb25nIGxvbmcmIGtleSkgewoJdW5zaWduZWQgbG9uZyBsb25nIHJlcyA9IDA7Cgl1bnNpZ25lZCBpbnQgcGFyX2JpdCA9IDE7Cglmb3IgKHVuc2lnbmVkIGludCBpID0gMDsgaSA8IDU2OyBpKyspIHsKCQlyZXMgPDw9IDE7CgkJdW5zaWduZWQgaW50IGJpdCA9IChrZXkgPj4gKDU2IC0gMSAtIGkpKSAmIDE7CgkJcmVzIHw9IGJpdDsKCQlwYXJfYml0IF49IGJpdDsKCQlpZiAoKGkgKyAxKSAlIDcgPT0gMCkgewoJCQlyZXMgPDw9IDE7CgkJCXJlcyB8PSBwYXJfYml0OwoJCQlwYXJfYml0ID0gMTsKCQl9Cgl9CglyZXR1cm4gcmVzOwp9Cgp1bnNpZ25lZCBsb25nIGxvbmcgREVTOjpleGVjdXRlKGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYgZGF0YSwgY29uc3Qgc2hhcmVkX3B0cjxhcnJheTx1bnNpZ25lZCBsb25nIGxvbmcsIDE2PiA+JiBzdWJrZXlzKSB7Cgl1bnNpZ25lZCBsb25nIGxvbmcgaXBfZGF0YSA9IGNob2ljZTx1bnNpZ25lZCBsb25nIGxvbmc+KGRhdGEsIDY0LCBJUF9UQUJMRSwgNjQpOwoJdW5zaWduZWQgbG9uZyBsID0gaXBfZGF0YSA+PiAzMjsKCXVuc2lnbmVkIGxvbmcgciA9IGlwX2RhdGEgJiAweGZmZmZmZmZmOwoJZm9yICh1bnNpZ25lZCBpbnQgaSA9IDA7IGkgPCAxNjsgaSsrKSB7CgkJdW5zaWduZWQgbG9uZyB0ID0gcjsKCQlyID0gbCBeIGYociwgc3Via2V5cy0+YXQoaSkpOwoJCWwgPSB0OwoJfQoJcmV0dXJuIGNob2ljZTx1bnNpZ25lZCBsb25nIGxvbmc+KCgodW5zaWduZWQgbG9uZyBsb25nKXIgPDwgMzIpIHwgbCwgNjQsIElJUF9UQUJMRSwgNjQpOwp9Cgp1bnNpZ25lZCBsb25nIERFUzo6Zihjb25zdCB1bnNpZ25lZCBsb25nJiByLCBjb25zdCB1bnNpZ25lZCBsb25nIGxvbmcmIHN1YmtleSkgewoJdW5zaWduZWQgbG9uZyBsb25nIHQgPSBjaG9pY2U8dW5zaWduZWQgbG9uZyBsb25nPihyLCAzMiwgRV9UQUJMRSwgNDgpIF4gc3Via2V5OwoJdW5zaWduZWQgbG9uZyBsb25nIHUgPSAwOwoJZm9yICh1bnNpZ25lZCBpbnQgaSA9IDA7IGkgPCA4OyBpKyspIHsKCQl1IDw8PSA0OwoJCXUgfD0gcygodCA+PiAoNDggLSA2ICogKGkgKyAxKSkpICYgMHgzZiwgU19UQUJMRVtpXSk7Cgl9CglyZXR1cm4gY2hvaWNlPHVuc2lnbmVkIGxvbmc+KHUsIDMyLCBQX1RBQkxFLCAzMik7Cn0KCnVuc2lnbmVkIGNoYXIgREVTOjpzKGNvbnN0IHVuc2lnbmVkIGNoYXImIHQsIGNvbnN0IHVuc2lnbmVkIGludCB0YWJbNF1bMTZdKSB7Cgl1bnNpZ25lZCBpbnQgcm93ID0gKCh0ID4+ICg2IC0gMSkpIDw8IDEpIHwgKHQgJiAxKTsKCXVuc2lnbmVkIGludCBjb2wgPSAodCA+PiAoMiAtIDEpKSAmIDB4ZjsKCXJldHVybiB0YWJbcm93XVtjb2xdOwp9Cgp0ZW1wbGF0ZSA8Y2xhc3MgRCwgY2xhc3MgUz4gRCBERVM6OmNob2ljZShjb25zdCBTJiBzcmMsIGNvbnN0IHVuc2lnbmVkIGludCYgc3JjX2xlbiwgY29uc3QgdW5zaWduZWQgaW50KiB0YWIsIGNvbnN0IHVuc2lnbmVkIGludCYgdGFiX2xlbikgewoJRCBkZXN0ID0gMDsKCWZvciAodW5zaWduZWQgaW50IGkgPSAwOyBpIDwgdGFiX2xlbjsgaSsrKSB7CgkJZGVzdCA8PD0gMTsKCQlkZXN0IHw9IChzcmMgPj4gKHNyY19sZW4gLSB0YWJbaV0pKSAmIDE7Cgl9CglyZXR1cm4gZGVzdDsKfQoKdGVtcGxhdGUgPGNsYXNzIFg+IFggIHJvdGF0ZUxlZnQoY29uc3QgWCYgeCwgY29uc3QgdW5zaWduZWQgaW50JiBuLCBjb25zdCB1bnNpZ25lZCBpbnQmIHcpIHsKCXJldHVybiAoeCA8PCBuKSB8ICh4ID4+ICh3IC0gbikpOwp9Cgp2b2lkIGFzc2VydChjb25zdCBjaGFyKiBwcmVkX3N0ciwgY29uc3QgYm9vbCYgcHJlZF9yZXMpIHsKCWlmIChwcmVkX3JlcykgewoJCWNvdXQgPDwgIuOCouOCteODvOODiOaIkOWKnzogIiA8PCBwcmVkX3N0ciA8PCBlbmRsOwoJfQoJZWxzZSB7CgkJY2VyciA8PCAi44Ki44K144O844OI5aSx5pWXOiAiIDw8IHByZWRfc3RyIDw8IGVuZGw7CgkJZXhpdCgxKTsKCX0KfQoKaW50IG1haW4oKSB7Cgl7CgkJREVTIGRlcygweDEyMzQ1Njc4MTIzNDU2NzgpOwoJCUFTU0VSVChkZXMuZW5jaXBoZXIoMHgxMjM0NTY3ODEyMzQ1Njc4KSA9PSAweDk0MWVkZGQ4ODI3MTRkOTgpCgkJQVNTRVJUKGRlcy5kZWNpcGhlcigweDk0MWVkZGQ4ODI3MTRkOTgpID09IDB4MTIzNDU2NzgxMjM0NTY3OCkKCQlBU1NFUlQoZGVzLmVuY2lwaGVyKDB4ODc2NTQzMjE4NzY1NDMyMSkgPT0gMHgwODRjZDk3NTRlNWYzMDU4KQoJCUFTU0VSVChkZXMuZGVjaXBoZXIoMHgwODRjZDk3NTRlNWYzMDU4KSA9PSAweDg3NjU0MzIxODc2NTQzMjEpCgl9Cgl7CgkJREVTIGRlcygweDg3NjU0MzIxODc2NTQzMjEpOwoJCUFTU0VSVChkZXMuZW5jaXBoZXIoMHgxMjM0NTY3ODEyMzQ1Njc4KSA9PSAweDViM2ExZWYzZjI5MDg5YTEpCgkJQVNTRVJUKGRlcy5kZWNpcGhlcigweDViM2ExZWYzZjI5MDg5YTEpID09IDB4MTIzNDU2NzgxMjM0NTY3OCkKCQlBU1NFUlQoZGVzLmVuY2lwaGVyKDB4ODc2NTQzMjE4NzY1NDMyMSkgPT0gMHg0NmY0YTcwZTZmZjcxNjZjKQoJCUFTU0VSVChkZXMuZGVjaXBoZXIoMHg0NmY0YTcwZTZmZjcxNjZjKSA9PSAweDg3NjU0MzIxODc2NTQzMjEpCgl9CglyZXR1cm4gMDsKfQo=