#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> > 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);
template <class I> static unsigned long long execute(const unsigned long long& data, const I& begin, const I& end);
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->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->subkeys->at(i) = choice<unsigned long long>(c << 28 | d, 56, PC_2_TABLE, 48);
}
}
unsigned long long DES::encipher(const unsigned long long& plane_data) {
return execute(plane_data, this->subkeys->begin(), this->subkeys->end());
}
unsigned long long DES::decipher(const unsigned long long& cipher_data) {
return execute(cipher_data, this->subkeys->rbegin(), this->subkeys->rend());
}
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;
}
template <class I> unsigned long long DES::execute(const unsigned long long& data, const I& begin, const I& end) {
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 (auto iter = begin; iter != end; iter++) {
unsigned long t = r;
r = l ^ f(r, *iter);
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() {
cout << hex;
{
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+IHN1YmtleXM7CglERVMoY29uc3QgREVTJiBkZXMpOwoJREVTJiBvcGVyYXRvciA9KGNvbnN0IERFUyYgZGVzKTsKCXN0YXRpYyBjb25zdCB1bnNpZ25lZCBpbnQgUENfMUNfVEFCTEVbMjhdOwoJc3RhdGljIGNvbnN0IHVuc2lnbmVkIGludCBQQ18xRF9UQUJMRVsyOF07CglzdGF0aWMgY29uc3QgdW5zaWduZWQgaW50IFBDXzJfVEFCTEVbNDhdOwoJc3RhdGljIGNvbnN0IHVuc2lnbmVkIGludCBTVUJLRVlfU0hJRlRfQU1PVU5UU1sxNl07CglzdGF0aWMgY29uc3QgdW5zaWduZWQgaW50IElQX1RBQkxFWzY0XTsKCXN0YXRpYyBjb25zdCB1bnNpZ25lZCBpbnQgSUlQX1RBQkxFWzY0XTsKCXN0YXRpYyBjb25zdCB1bnNpZ25lZCBpbnQgRV9UQUJMRVs0OF07CglzdGF0aWMgY29uc3QgdW5zaWduZWQgaW50IFNfVEFCTEVbOF1bNF1bMTZdOwoJc3RhdGljIGNvbnN0IHVuc2lnbmVkIGludCBQX1RBQkxFWzMyXTsKCXN0YXRpYyB1bnNpZ25lZCBsb25nIGxvbmcgYXBwZW5kUGFyaXR5Qml0cyhjb25zdCB1bnNpZ25lZCBsb25nIGxvbmcmIGtleSk7Cgl0ZW1wbGF0ZSA8Y2xhc3MgST4gc3RhdGljIHVuc2lnbmVkIGxvbmcgbG9uZyBleGVjdXRlKGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYgZGF0YSwgY29uc3QgSSYgYmVnaW4sIGNvbnN0IEkmIGVuZCk7CglzdGF0aWMgdW5zaWduZWQgbG9uZyBmKGNvbnN0IHVuc2lnbmVkIGxvbmcmIHIsIGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYgc3Via2V5KTsKCXN0YXRpYyB1bnNpZ25lZCBjaGFyIHMoY29uc3QgdW5zaWduZWQgY2hhciYgdCwgY29uc3QgdW5zaWduZWQgaW50IHRhYls0XVsxNl0pOwoJdGVtcGxhdGUgPGNsYXNzIEQsIGNsYXNzIFM+IHN0YXRpYyBEIGNob2ljZShjb25zdCBTJiBzcmMsIGNvbnN0IHVuc2lnbmVkIGludCYgc3JjX2xlbiwgY29uc3QgdW5zaWduZWQgaW50KiB0YWIsIGNvbnN0IHVuc2lnbmVkIGludCYgdGFiX2xlbik7Cn07Cgp0ZW1wbGF0ZSA8Y2xhc3MgWD4gWCByb3RhdGVMZWZ0KGNvbnN0IFgmIHgsIGNvbnN0IHVuc2lnbmVkIGludCYgbiwgY29uc3QgdW5zaWduZWQgaW50JiB3ID0gKHNpemVvZihYKSA8PCAzKSk7CgojZGVmaW5lIEFTU0VSVChwcmVkKSBhc3NlcnQoI3ByZWQsIHByZWQpOwoKZXh0ZXJuIHZvaWQgYXNzZXJ0KGNvbnN0IGNoYXIqIHByZWRfc3RyLCBjb25zdCBib29sJiBwcmVkX3Jlcyk7Cgpjb25zdCB1bnNpZ25lZCBpbnQgREVTOjpQQ18xQ19UQUJMRVsyOF0gPSB7Cgk1NywgNDksIDQxLCAzMywgMjUsIDE3LCAgOSwgCgkgMSwgNTgsIDUwLCA0MiwgMzQsIDI2LCAxOCwgCgkxMCwgIDIsIDU5LCA1MSwgNDMsIDM1LCAyNywgCgkxOSwgMTEsICAzLCA2MCwgNTIsIDQ0LCAzNiwgCn07Cgpjb25zdCB1bnNpZ25lZCBpbnQgREVTOjpQQ18xRF9UQUJMRVsyOF0gPSB7Cgk2MywgNTUsIDQ3LCAzOSwgMzEsIDIzLCAxNSwgCgkgNywgNjIsIDU0LCA0NiwgMzgsIDMwLCAyMiwgCgkxNCwgIDYsIDYxLCA1MywgNDUsIDM3LCAyOSwgCgkyMSwgMTMsICA1LCAyOCwgMjAsIDEyLCAgNCwgCn07Cgpjb25zdCB1bnNpZ25lZCBpbnQgREVTOjpQQ18yX1RBQkxFWzQ4XSA9IHsKCTE0LCAxNywgMTEsIDI0LCAgMSwgIDUsIAoJIDMsIDI4LCAxNSwgIDYsIDIxLCAxMCwgCgkyMywgMTksIDEyLCAgNCwgMjYsICA4LCAKCTE2LCAgNywgMjcsIDIwLCAxMywgIDIsIAoJNDEsIDUyLCAzMSwgMzcsIDQ3LCA1NSwgCgkzMCwgNDAsIDUxLCA0NSwgMzMsIDQ4LCAKCTQ0LCA0OSwgMzksIDU2LCAzNCwgNTMsIAoJNDYsIDQyLCA1MCwgMzYsIDI5LCAzMiwgCn07Cgpjb25zdCB1bnNpZ25lZCBpbnQgREVTOjpTVUJLRVlfU0hJRlRfQU1PVU5UU1sxNl0gPSB7CgkxLCAxLCAyLCAyLCAyLCAyLCAyLCAyLCAxLCAyLCAyLCAyLCAyLCAyLCAyLCAxLCAKfTsKCmNvbnN0IHVuc2lnbmVkIGludCBERVM6OklQX1RBQkxFWzY0XSA9IHsKCTU4LCA1MCwgNDIsIDM0LCAyNiwgMTgsIDEwLCAgMiwgCgk2MCwgNTIsIDQ0LCAzNiwgMjgsIDIwLCAxMiwgIDQsIAoJNjIsIDU0LCA0NiwgMzgsIDMwLCAyMiwgMTQsICA2LCAKCTY0LCA1NiwgNDgsIDQwLCAzMiwgMjQsIDE2LCAgOCwgCgk1NywgNDksIDQxLCAzMywgMjUsIDE3LCAgOSwgIDEsIAoJNTksIDUxLCA0MywgMzUsIDI3LCAxOSwgMTEsICAzLCAKCTYxLCA1MywgNDUsIDM3LCAyOSwgMjEsIDEzLCAgNSwgCgk2MywgNTUsIDQ3LCAzOSwgMzEsIDIzLCAxNSwgIDcsIAp9OwoKY29uc3QgdW5zaWduZWQgaW50IERFUzo6SUlQX1RBQkxFWzY0XSA9IHsKCTQwLCA4LCA0OCwgMTYsIDU2LCAyNCwgNjQsIDMyLCAKCTM5LCA3LCA0NywgMTUsIDU1LCAyMywgNjMsIDMxLCAKCTM4LCA2LCA0NiwgMTQsIDU0LCAyMiwgNjIsIDMwLCAKCTM3LCA1LCA0NSwgMTMsIDUzLCAyMSwgNjEsIDI5LCAKCTM2LCA0LCA0NCwgMTIsIDUyLCAyMCwgNjAsIDI4LCAKCTM1LCAzLCA0MywgMTEsIDUxLCAxOSwgNTksIDI3LCAKCTM0LCAyLCA0MiwgMTAsIDUwLCAxOCwgNTgsIDI2LCAKCTMzLCAxLCA0MSwgIDksIDQ5LCAxNywgNTcsIDI1LCAKfTsKCmNvbnN0IHVuc2lnbmVkIGludCBERVM6OkVfVEFCTEVbNDhdID0gewoJMzIsICAxLCAgMiwgIDMsICA0LCAgNSwgCgkgNCwgIDUsICA2LCAgNywgIDgsICA5LCAKCSA4LCAgOSwgMTAsIDExLCAxMiwgMTMsIAoJMTIsIDEzLCAxNCwgMTUsIDE2LCAxNywgCgkxNiwgMTcsIDE4LCAxOSwgMjAsIDIxLCAKCTIwLCAyMSwgMjIsIDIzLCAyNCwgMjUsIAoJMjQsIDI1LCAyNiwgMjcsIDI4LCAyOSwgCgkyOCwgMjksIDMwLCAzMSwgMzIsICAxLCAKfTsKCmNvbnN0IHVuc2lnbmVkIGludCBERVM6OlNfVEFCTEVbOF1bNF1bMTZdID0gewoJewoJCXsxNCwgIDQsIDEzLCAgMSwgIDIsIDE1LCAxMSwgIDgsICAzLCAxMCwgIDYsIDEyLCAgNSwgIDksICAwLCAgNywgfSwgCgkJeyAwLCAxNSwgIDcsICA0LCAxNCwgIDIsIDEzLCAgMSwgMTAsICA2LCAxMiwgMTEsICA5LCAgNSwgIDMsICA4LCB9LCAKCQl7IDQsICAxLCAxNCwgIDgsIDEzLCAgNiwgIDIsIDExLCAxNSwgMTIsICA5LCAgNywgIDMsIDEwLCAgNSwgIDAsIH0sIAoJCXsxNSwgMTIsICA4LCAgMiwgIDQsICA5LCAgMSwgIDcsICA1LCAxMSwgIDMsIDE0LCAxMCwgIDAsICA2LCAxMywgfSwgCgl9LCAKCXsKCQl7MTUsICAxLCAgOCwgMTQsICA2LCAxMSwgIDMsICA0LCAgOSwgIDcsICAyLCAxMywgMTIsICAwLCAgNSwgMTAsIH0sIAoJCXsgMywgMTMsICA0LCAgNywgMTUsICAyLCAgOCwgMTQsIDEyLCAgMCwgIDEsIDEwLCAgNiwgIDksIDExLCAgNSwgfSwgCgkJeyAwLCAxNCwgIDcsIDExLCAxMCwgIDQsIDEzLCAgMSwgIDUsICA4LCAxMiwgIDYsICA5LCAgMywgIDIsIDE1LCB9LCAKCQl7MTMsICA4LCAxMCwgIDEsICAzLCAxNSwgIDQsICAyLCAxMSwgIDYsICA3LCAxMiwgIDAsICA1LCAxNCwgIDksIH0sIAoJfSwgCgl7CgkJezEwLCAgMCwgIDksIDE0LCAgNiwgIDMsIDE1LCAgNSwgIDEsIDEzLCAxMiwgIDcsIDExLCAgNCwgIDIsICA4LCB9LCAKCQl7MTMsICA3LCAgMCwgIDksICAzLCAgNCwgIDYsIDEwLCAgMiwgIDgsICA1LCAxNCwgMTIsIDExLCAxNSwgIDEsIH0sIAoJCXsxMywgIDYsICA0LCAgOSwgIDgsIDE1LCAgMywgIDAsIDExLCAgMSwgIDIsIDEyLCAgNSwgMTAsIDE0LCAgNywgfSwgCgkJeyAxLCAxMCwgMTMsICAwLCAgNiwgIDksICA4LCAgNywgIDQsIDE1LCAxNCwgIDMsIDExLCAgNSwgIDIsIDEyLCB9LCAKCX0sIAoJewoJCXs3ICwgMTMsIDE0LCAgMywgIDAsICA2LCAgOSwgMTAsICAxLCAgMiwgIDgsICA1LCAxMSwgMTIsICA0LCAxNSwgfSwgCgkJezEzLCAgOCwgMTEsICA1LCAgNiwgMTUsICAwLCAgMywgIDQsICA3LCAgMiwgMTIsICAxLCAxMCwgMTQsICA5LCB9LCAKCQl7MTAsICA2LCAgOSwgIDAsIDEyLCAxMSwgIDcsIDEzLCAxNSwgIDEsICAzLCAxNCwgIDUsICAyLCAgOCwgIDQsIH0sIAoJCXsgMywgMTUsICAwLCAgNiwgMTAsICAxLCAxMywgIDgsICA5LCAgNCwgIDUsIDExLCAxMiwgIDcsICAyLCAxNCwgfSwgCgl9LAoJewoJCXsgMiwgMTIsICA0LCAgMSwgIDcsIDEwLCAxMSwgIDYsICA4LCAgNSwgIDMsIDE1LCAxMywgIDAsIDE0LCAgOSwgfSwgCgkJezE0LCAxMSwgIDIsIDEyLCAgNCwgIDcsIDEzLCAgMSwgIDUsICAwLCAxNSwgMTAsICAzLCAgOSwgIDgsICA2LCB9LCAKCQl7IDQsICAyLCAgMSwgMTEsIDEwLCAxMywgIDcsICA4LCAxNSwgIDksIDEyLCAgNSwgIDYsICAzLCAgMCwgMTQsIH0sIAoJCXsxMSwgIDgsIDEyLCAgNywgIDEsIDE0LCAgMiwgMTMsICA2LCAxNSwgIDAsICA5LCAxMCwgIDQsICA1LCAgMywgfSwgCgl9LCAKCXsKCQl7MTIsICAxLCAxMCwgMTUsICA5LCAgMiwgIDYsICA4LCAgMCwgMTMsICAzLCAgNCwgMTQsICA3LCAgNSwgMTEsIH0sIAoJCXsxMCwgMTUsICA0LCAgMiwgIDcsIDEyLCAgOSwgIDUsICA2LCAgMSwgMTMsIDE0LCAgMCwgMTEsICAzLCAgOCwgfSwgCgkJeyA5LCAxNCwgMTUsICA1LCAgMiwgIDgsIDEyLCAgMywgIDcsICAwLCAgNCwgMTAsICAxLCAxMywgMTEsICA2LCB9LCAKCQl7IDQsICAzLCAgMiwgMTIsICA5LCAgNSwgMTUsIDEwLCAxMSwgMTQsICAxLCAgNywgIDYsICAwLCAgOCwgMTMsIH0sIAoJfSwgCgl7CgkJeyA0LCAxMSwgIDIsIDE0LCAxNSwgIDAsICA4LCAxMywgIDMsIDEyLCAgOSwgIDcsICA1LCAxMCwgIDYsICAxLCB9LCAKCQl7MTMsICAwLCAxMSwgIDcsICA0LCAgOSwgIDEsIDEwLCAxNCwgIDMsICA1LCAxMiwgIDIsIDE1LCAgOCwgIDYsIH0sIAoJCXsgMSwgIDQsIDExLCAxMywgMTIsICAzLCAgNywgMTQsIDEwLCAxNSwgIDYsICA4LCAgMCwgIDUsICA5LCAgMiwgfSwgCgkJeyA2LCAxMSwgMTMsICA4LCAgMSwgIDQsIDEwLCAgNywgIDksICA1LCAgMCwgMTUsIDE0LCAgMiwgIDMsIDEyLCB9LCAKCX0sIAoJewoJCXsxMywgIDIsICA4LCAgNCwgIDYsIDE1LCAxMSwgIDEsIDEwLCAgOSwgIDMsIDE0LCAgNSwgIDAsIDEyLCAgNywgfSwgCgkJeyAxLCAxNSwgMTMsICA4LCAxMCwgIDMsICA3LCAgNCwgMTIsICA1LCAgNiwgMTEsICAwLCAxNCwgIDksICAyLCB9LCAKCQl7IDcsIDExLCAgNCwgIDEsICA5LCAxMiwgMTQsICAyLCAgMCwgIDYsIDEwLCAxMywgMTUsICAzLCAgNSwgIDgsIH0sIAoJCXsgMiwgIDEsIDE0LCAgNywgIDQsIDEwLCAgOCwgMTMsIDE1LCAxMiwgIDksICAwLCAgMywgIDUsICA2LCAxMSwgfSwgCgl9LCAKfTsKCmNvbnN0IHVuc2lnbmVkIGludCBERVM6OlBfVEFCTEVbMzJdID0gewoJMTYsICA3LCAyMCwgMjEsCgkyOSwgMTIsIDI4LCAxNywKCSAxLCAxNSwgMjMsIDI2LAoJIDUsIDE4LCAzMSwgMTAsCgkgMiwgIDgsIDI0LCAxNCwKCTMyLCAyNywgIDMsICA5LAoJMTksIDEzLCAzMCwgIDYsCgkyMiwgMTEsICA0LCAyNSwKfTsKCkRFUzo6REVTKGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYga2V5KSB7Cgl1bnNpZ25lZCBsb25nIGxvbmcgYWN0X2tleSA9IGFwcGVuZFBhcml0eUJpdHMoa2V5KTsKCXRoaXMtPnN1YmtleXMucmVzZXQobmV3IGFycmF5PHVuc2lnbmVkIGxvbmcgbG9uZywgMTY+KTsKCXVuc2lnbmVkIGxvbmcgYyA9IGNob2ljZTx1bnNpZ25lZCBsb25nPihhY3Rfa2V5LCA2NCwgUENfMUNfVEFCTEUsIDI4KTsKCXVuc2lnbmVkIGxvbmcgZCA9IGNob2ljZTx1bnNpZ25lZCBsb25nPihhY3Rfa2V5LCA2NCwgUENfMURfVEFCTEUsIDI4KTsKCWZvciAodW5zaWduZWQgaW50IGkgPSAwOyBpIDwgMTY7IGkrKykgewoJCWMgPSByb3RhdGVMZWZ0KGMsIFNVQktFWV9TSElGVF9BTU9VTlRTW2ldLCAyOCk7CgkJZCA9IHJvdGF0ZUxlZnQoZCwgU1VCS0VZX1NISUZUX0FNT1VOVFNbaV0sIDI4KTsKCQl0aGlzLT5zdWJrZXlzLT5hdChpKSA9IGNob2ljZTx1bnNpZ25lZCBsb25nIGxvbmc+KGMgPDwgMjggfCBkLCA1NiwgUENfMl9UQUJMRSwgNDgpOwoJfQp9Cgp1bnNpZ25lZCBsb25nIGxvbmcgREVTOjplbmNpcGhlcihjb25zdCB1bnNpZ25lZCBsb25nIGxvbmcmIHBsYW5lX2RhdGEpIHsKCXJldHVybiBleGVjdXRlKHBsYW5lX2RhdGEsIHRoaXMtPnN1YmtleXMtPmJlZ2luKCksIHRoaXMtPnN1YmtleXMtPmVuZCgpKTsKfQoKdW5zaWduZWQgbG9uZyBsb25nIERFUzo6ZGVjaXBoZXIoY29uc3QgdW5zaWduZWQgbG9uZyBsb25nJiBjaXBoZXJfZGF0YSkgewoJcmV0dXJuIGV4ZWN1dGUoY2lwaGVyX2RhdGEsIHRoaXMtPnN1YmtleXMtPnJiZWdpbigpLCB0aGlzLT5zdWJrZXlzLT5yZW5kKCkpOwp9Cgp1bnNpZ25lZCBsb25nIGxvbmcgREVTOjphcHBlbmRQYXJpdHlCaXRzKGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYga2V5KSB7Cgl1bnNpZ25lZCBsb25nIGxvbmcgcmVzID0gMDsKCXVuc2lnbmVkIGludCBwYXJfYml0ID0gMTsKCWZvciAodW5zaWduZWQgaW50IGkgPSAwOyBpIDwgNTY7IGkrKykgewoJCXJlcyA8PD0gMTsKCQl1bnNpZ25lZCBpbnQgYml0ID0gKGtleSA+PiAoNTYgLSAxIC0gaSkpICYgMTsKCQlyZXMgfD0gYml0OwoJCXBhcl9iaXQgXj0gYml0OwoJCWlmICgoaSArIDEpICUgNyA9PSAwKSB7CgkJCXJlcyA8PD0gMTsKCQkJcmVzIHw9IHBhcl9iaXQ7CgkJCXBhcl9iaXQgPSAxOwoJCX0KCX0KCXJldHVybiByZXM7Cn0KCnRlbXBsYXRlIDxjbGFzcyBJPiB1bnNpZ25lZCBsb25nIGxvbmcgREVTOjpleGVjdXRlKGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYgZGF0YSwgY29uc3QgSSYgYmVnaW4sIGNvbnN0IEkmIGVuZCkgewoJdW5zaWduZWQgbG9uZyBsb25nIGlwX2RhdGEgPSBjaG9pY2U8dW5zaWduZWQgbG9uZyBsb25nPihkYXRhLCA2NCwgSVBfVEFCTEUsIDY0KTsKCXVuc2lnbmVkIGxvbmcgbCA9IGlwX2RhdGEgPj4gMzI7Cgl1bnNpZ25lZCBsb25nIHIgPSBpcF9kYXRhICYgMHhmZmZmZmZmZjsKCWZvciAoYXV0byBpdGVyID0gYmVnaW47IGl0ZXIgIT0gZW5kOyBpdGVyKyspIHsKCQl1bnNpZ25lZCBsb25nIHQgPSByOwoJCXIgPSBsIF4gZihyLCAqaXRlcik7CgkJbCA9IHQ7Cgl9CglyZXR1cm4gY2hvaWNlPHVuc2lnbmVkIGxvbmcgbG9uZz4oKCh1bnNpZ25lZCBsb25nIGxvbmcpciA8PCAzMikgfCBsLCA2NCwgSUlQX1RBQkxFLCA2NCk7Cn0KCnVuc2lnbmVkIGxvbmcgREVTOjpmKGNvbnN0IHVuc2lnbmVkIGxvbmcmIHIsIGNvbnN0IHVuc2lnbmVkIGxvbmcgbG9uZyYgc3Via2V5KSB7Cgl1bnNpZ25lZCBsb25nIGxvbmcgdCA9IGNob2ljZTx1bnNpZ25lZCBsb25nIGxvbmc+KHIsIDMyLCBFX1RBQkxFLCA0OCkgXiBzdWJrZXk7Cgl1bnNpZ25lZCBsb25nIGxvbmcgdSA9IDA7Cglmb3IgKHVuc2lnbmVkIGludCBpID0gMDsgaSA8IDg7IGkrKykgewoJCXUgPDw9IDQ7CgkJdSB8PSBzKCh0ID4+ICg0OCAtIDYgKiAoaSArIDEpKSkgJiAweDNmLCBTX1RBQkxFW2ldKTsKCX0KCXJldHVybiBjaG9pY2U8dW5zaWduZWQgbG9uZz4odSwgMzIsIFBfVEFCTEUsIDMyKTsKfQoKdW5zaWduZWQgY2hhciBERVM6OnMoY29uc3QgdW5zaWduZWQgY2hhciYgdCwgY29uc3QgdW5zaWduZWQgaW50IHRhYls0XVsxNl0pIHsKCXVuc2lnbmVkIGludCByb3cgPSAoKHQgPj4gKDYgLSAxKSkgPDwgMSkgfCAodCAmIDEpOwoJdW5zaWduZWQgaW50IGNvbCA9ICh0ID4+ICgyIC0gMSkpICYgMHhmOwoJcmV0dXJuIHRhYltyb3ddW2NvbF07Cn0KCnRlbXBsYXRlIDxjbGFzcyBELCBjbGFzcyBTPiBEIERFUzo6Y2hvaWNlKGNvbnN0IFMmIHNyYywgY29uc3QgdW5zaWduZWQgaW50JiBzcmNfbGVuLCBjb25zdCB1bnNpZ25lZCBpbnQqIHRhYiwgY29uc3QgdW5zaWduZWQgaW50JiB0YWJfbGVuKSB7CglEIGRlc3QgPSAwOwoJZm9yICh1bnNpZ25lZCBpbnQgaSA9IDA7IGkgPCB0YWJfbGVuOyBpKyspIHsKCQlkZXN0IDw8PSAxOwoJCWRlc3QgfD0gKHNyYyA+PiAoc3JjX2xlbiAtIHRhYltpXSkpICYgMTsKCX0KCXJldHVybiBkZXN0Owp9Cgp0ZW1wbGF0ZSA8Y2xhc3MgWD4gWCAgcm90YXRlTGVmdChjb25zdCBYJiB4LCBjb25zdCB1bnNpZ25lZCBpbnQmIG4sIGNvbnN0IHVuc2lnbmVkIGludCYgdykgewoJcmV0dXJuICh4IDw8IG4pIHwgKHggPj4gKHcgLSBuKSk7Cn0KCnZvaWQgYXNzZXJ0KGNvbnN0IGNoYXIqIHByZWRfc3RyLCBjb25zdCBib29sJiBwcmVkX3JlcykgewoJaWYgKHByZWRfcmVzKSB7CgkJY291dCA8PCAi44Ki44K144O844OI5oiQ5YqfOiAiIDw8IHByZWRfc3RyIDw8IGVuZGw7Cgl9CgllbHNlIHsKCQljZXJyIDw8ICLjgqLjgrXjg7zjg4jlpLHmlZc6ICIgPDwgcHJlZF9zdHIgPDwgZW5kbDsKCQlleGl0KDEpOwoJfQp9CgppbnQgbWFpbigpIHsKCWNvdXQgPDwgaGV4OwoJewoJCURFUyBkZXMoMHgxMjM0NTY3ODEyMzQ1Njc4KTsKCQlBU1NFUlQoZGVzLmVuY2lwaGVyKDB4MTIzNDU2NzgxMjM0NTY3OCkgPT0gMHg5NDFlZGRkODgyNzE0ZDk4KQoJCUFTU0VSVChkZXMuZGVjaXBoZXIoMHg5NDFlZGRkODgyNzE0ZDk4KSA9PSAweDEyMzQ1Njc4MTIzNDU2NzgpCgkJQVNTRVJUKGRlcy5lbmNpcGhlcigweDg3NjU0MzIxODc2NTQzMjEpID09IDB4MDg0Y2Q5NzU0ZTVmMzA1OCkKCQlBU1NFUlQoZGVzLmRlY2lwaGVyKDB4MDg0Y2Q5NzU0ZTVmMzA1OCkgPT0gMHg4NzY1NDMyMTg3NjU0MzIxKQoJfQoJewoJCURFUyBkZXMoMHg4NzY1NDMyMTg3NjU0MzIxKTsKCQlBU1NFUlQoZGVzLmVuY2lwaGVyKDB4MTIzNDU2NzgxMjM0NTY3OCkgPT0gMHg1YjNhMWVmM2YyOTA4OWExKQoJCUFTU0VSVChkZXMuZGVjaXBoZXIoMHg1YjNhMWVmM2YyOTA4OWExKSA9PSAweDEyMzQ1Njc4MTIzNDU2NzgpCgkJQVNTRVJUKGRlcy5lbmNpcGhlcigweDg3NjU0MzIxODc2NTQzMjEpID09IDB4NDZmNGE3MGU2ZmY3MTY2YykKCQlBU1NFUlQoZGVzLmRlY2lwaGVyKDB4NDZmNGE3MGU2ZmY3MTY2YykgPT0gMHg4NzY1NDMyMTg3NjU0MzIxKQoJfQoJcmV0dXJuIDA7Cn0K