#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <emmintrin.h>
#include <math.h>
struct md5x4_context {
__m128i k[64];
__m128i iv[4];
__m128i ff;
__m128i a, b, c, d;
};
void md5x4_pre_init(struct md5x4_context* ctx) {
for (uint32_t i = 0; i < 64; ++i) {
uint32_t x
= floor(fabs(sin(i
+ 1)) * (double)0x100000000ull
); ctx->k[i] = _mm_set1_epi32(x);
}
ctx->iv[0] = _mm_set1_epi32(0x67452301);
ctx->iv[1] = _mm_set1_epi32(0xefcdab89);
ctx->iv[2] = _mm_set1_epi32(0x98badcfe);
ctx->iv[3] = _mm_set1_epi32(0x10325476);
ctx->ff = _mm_set1_epi32(0xFFFFFFFF);
}
void md5x4_init(struct md5x4_context* ctx) {
ctx->a = ctx->iv[0];
ctx->b = ctx->iv[1];
ctx->c = ctx->iv[2];
ctx->d = ctx->iv[3];
}
inline __m128i md5x4_fx(int s, __m128i a, __m128i b, __m128i k, __m128i x, __m128i f) {
f = _mm_add_epi32(_mm_add_epi32(f, a), _mm_add_epi32(k, x));
return _mm_add_epi32(b, _mm_or_si128(_mm_slli_epi32(f, s), _mm_srli_epi32(f, 32 - s)));
}
inline __m128i md5x4_f1(int s, __m128i a, __m128i b, __m128i c, __m128i d, __m128i k, __m128i x) {
return md5x4_fx(s, a, b, k, x, _mm_or_si128(_mm_and_si128(b, c), _mm_andnot_si128(b, d)));
}
inline __m128i md5x4_f2(int s, __m128i a, __m128i b, __m128i c, __m128i d, __m128i k, __m128i x) {
return md5x4_fx(s, a, b, k, x, _mm_or_si128(_mm_and_si128(d, b), _mm_andnot_si128(d, c)));
}
inline __m128i md5x4_f3(int s, __m128i a, __m128i b, __m128i c, __m128i d, __m128i k, __m128i x) {
return md5x4_fx(s, a, b, k, x, _mm_xor_si128(_mm_xor_si128(b, c), d));
}
inline __m128i md5x4_f4(int s, __m128i a, __m128i b, __m128i c, __m128i d, __m128i k, __m128i x) {
return md5x4_fx(s, a, b, k, x, _mm_xor_si128(c, _mm_or_si128(b, _mm_xor_si128(d, _mm_set1_epi32(0xFFFFFFFF)))));
}
void md5x4_raw_update(struct md5x4_context* ctx, const uint8_t blocks[4][64])
{
__m128i x[16];
for (size_t i = 0; i < 4; ++i) {
__m128 x0 = _mm_loadu_ps((const float*)blocks[0] + i * 4);
__m128 x1 = _mm_loadu_ps((const float*)blocks[1] + i * 4);
__m128 x2 = _mm_loadu_ps((const float*)blocks[2] + i * 4);
__m128 x3 = _mm_loadu_ps((const float*)blocks[3] + i * 4);
__m128 t0 = _mm_unpacklo_ps(x0, x1);
__m128 t1 = _mm_unpackhi_ps(x0, x1);
__m128 t2 = _mm_unpacklo_ps(x2, x3);
__m128 t3 = _mm_unpackhi_ps(x2, x3);
x[i * 4 + 0] = _mm_castps_si128(_mm_movelh_ps(t0, t2));
x[i * 4 + 1] = _mm_castps_si128(_mm_movehl_ps(t2, t0));
x[i * 4 + 2] = _mm_castps_si128(_mm_movelh_ps(t1, t3));
x[i * 4 + 3] = _mm_castps_si128(_mm_movehl_ps(t3, t1));
}
__m128i a = ctx->a;
__m128i b = ctx->b;
__m128i c = ctx->c;
__m128i d = ctx->d;
a = md5x4_f1(7, a, b, c, d, ctx->k[0], x[0]);
d = md5x4_f1(12, d, a, b, c, ctx->k[1], x[1]);
c = md5x4_f1(17, c, d, a, b, ctx->k[2], x[2]);
b = md5x4_f1(22, b, c, d, a, ctx->k[3], x[3]);
a = md5x4_f1(7, a, b, c, d, ctx->k[4], x[4]);
d = md5x4_f1(12, d, a, b, c, ctx->k[5], x[5]);
c = md5x4_f1(17, c, d, a, b, ctx->k[6], x[6]);
b = md5x4_f1(22, b, c, d, a, ctx->k[7], x[7]);
a = md5x4_f1(7, a, b, c, d, ctx->k[8], x[8]);
d = md5x4_f1(12, d, a, b, c, ctx->k[9], x[9]);
c = md5x4_f1(17, c, d, a, b, ctx->k[10], x[10]);
b = md5x4_f1(22, b, c, d, a, ctx->k[11], x[11]);
a = md5x4_f1(7, a, b, c, d, ctx->k[12], x[12]);
d = md5x4_f1(12, d, a, b, c, ctx->k[13], x[13]);
c = md5x4_f1(17, c, d, a, b, ctx->k[14], x[14]);
b = md5x4_f1(22, b, c, d, a, ctx->k[15], x[15]);
a = md5x4_f2(5, a, b, c, d, ctx->k[16], x[1]);
d = md5x4_f2(9, d, a, b, c, ctx->k[17], x[6]);
c = md5x4_f2(14, c, d, a, b, ctx->k[18], x[11]);
b = md5x4_f2(20, b, c, d, a, ctx->k[19], x[0]);
a = md5x4_f2(5, a, b, c, d, ctx->k[20], x[5]);
d = md5x4_f2(9, d, a, b, c, ctx->k[21], x[10]);
c = md5x4_f2(14, c, d, a, b, ctx->k[22], x[15]);
b = md5x4_f2(20, b, c, d, a, ctx->k[23], x[4]);
a = md5x4_f2(5, a, b, c, d, ctx->k[24], x[9]);
d = md5x4_f2(9, d, a, b, c, ctx->k[25], x[14]);
c = md5x4_f2(14, c, d, a, b, ctx->k[26], x[3]);
b = md5x4_f2(20, b, c, d, a, ctx->k[27], x[8]);
a = md5x4_f2(5, a, b, c, d, ctx->k[28], x[13]);
d = md5x4_f2(9, d, a, b, c, ctx->k[29], x[2]);
c = md5x4_f2(14, c, d, a, b, ctx->k[30], x[7]);
b = md5x4_f2(20, b, c, d, a, ctx->k[31], x[12]);
a = md5x4_f3(4, a, b, c, d, ctx->k[32], x[5]);
d = md5x4_f3(11, d, a, b, c, ctx->k[33], x[8]);
c = md5x4_f3(16, c, d, a, b, ctx->k[34], x[11]);
b = md5x4_f3(23, b, c, d, a, ctx->k[35], x[14]);
a = md5x4_f3(4, a, b, c, d, ctx->k[36], x[1]);
d = md5x4_f3(11, d, a, b, c, ctx->k[37], x[4]);
c = md5x4_f3(16, c, d, a, b, ctx->k[38], x[7]);
b = md5x4_f3(23, b, c, d, a, ctx->k[39], x[10]);
a = md5x4_f3(4, a, b, c, d, ctx->k[40], x[13]);
d = md5x4_f3(11, d, a, b, c, ctx->k[41], x[0]);
c = md5x4_f3(16, c, d, a, b, ctx->k[42], x[3]);
b = md5x4_f3(23, b, c, d, a, ctx->k[43], x[6]);
a = md5x4_f3(4, a, b, c, d, ctx->k[44], x[9]);
d = md5x4_f3(11, d, a, b, c, ctx->k[45], x[12]);
c = md5x4_f3(16, c, d, a, b, ctx->k[46], x[15]);
b = md5x4_f3(23, b, c, d, a, ctx->k[47], x[2]);
a = md5x4_f4(6, a, b, c, d, ctx->k[48], x[0]);
d = md5x4_f4(10, d, a, b, c, ctx->k[49], x[7]);
c = md5x4_f4(15, c, d, a, b, ctx->k[50], x[14]);
b = md5x4_f4(21, b, c, d, a, ctx->k[51], x[5]);
a = md5x4_f4(6, a, b, c, d, ctx->k[52], x[12]);
d = md5x4_f4(10, d, a, b, c, ctx->k[53], x[3]);
c = md5x4_f4(15, c, d, a, b, ctx->k[54], x[10]);
b = md5x4_f4(21, b, c, d, a, ctx->k[55], x[1]);
a = md5x4_f4(6, a, b, c, d, ctx->k[56], x[8]);
d = md5x4_f4(10, d, a, b, c, ctx->k[57], x[15]);
c = md5x4_f4(15, c, d, a, b, ctx->k[58], x[6]);
b = md5x4_f4(21, b, c, d, a, ctx->k[59], x[13]);
a = md5x4_f4(6, a, b, c, d, ctx->k[60], x[4]);
d = md5x4_f4(10, d, a, b, c, ctx->k[61], x[11]);
c = md5x4_f4(15, c, d, a, b, ctx->k[62], x[2]);
b = md5x4_f4(21, b, c, d, a, ctx->k[63], x[9]);
ctx->a = _mm_add_epi32(ctx->a, a);
ctx->b = _mm_add_epi32(ctx->b, b);
ctx->c = _mm_add_epi32(ctx->c, c);
ctx->d = _mm_add_epi32(ctx->d, d);
}
void md5x4_final(struct md5x4_context* ctx, uint8_t out[4][16]) {
__m128 a = _mm_castsi128_ps(ctx->a);
__m128 b = _mm_castsi128_ps(ctx->b);
__m128 c = _mm_castsi128_ps(ctx->c);
__m128 d = _mm_castsi128_ps(ctx->d);
__m128 t0 = _mm_unpacklo_ps(a, b);
__m128 t1 = _mm_unpackhi_ps(a, b);
__m128 t2 = _mm_unpacklo_ps(c, d);
__m128 t3 = _mm_unpackhi_ps(c, d);
_mm_storeu_ps((float*)out[0], _mm_movelh_ps(t0, t2));
_mm_storeu_ps((float*)out[1], _mm_movehl_ps(t2, t0));
_mm_storeu_ps((float*)out[2], _mm_movelh_ps(t1, t3));
_mm_storeu_ps((float*)out[3], _mm_movehl_ps(t3, t1));
}
void unsafe_pad_block(uint8_t block[64], size_t length) {
block[length] = 0x80;
*(uint64_t*)(block + 56) = length * 8;
}
int main() {
struct md5x4_context ctx;
md5x4_pre_init(&ctx);
uint8_t data[4][64] = {
"We are the others",
"We are the cast-outs",
"We're the outsiders",
"But you can't hide us",
};
unsafe_pad_block(data[0], 17);
unsafe_pad_block(data[1], 20);
unsafe_pad_block(data[2], 19);
unsafe_pad_block(data[3], 21);
uint8_t digests[4][16] = {0};
md5x4_init(&ctx);
md5x4_raw_update(&ctx, data);
md5x4_final(&ctx, digests);
for (size_t i = 0; i < 4; ++i) {
for (size_t j = 0; j < 16; ++j)
printf("%02X ", digests
[i
][j
]); }
return 0;
}
I2luY2x1ZGUgPHN0ZGludC5oPgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8ZW1taW50cmluLmg+CiNpbmNsdWRlIDxtYXRoLmg+CgpzdHJ1Y3QgbWQ1eDRfY29udGV4dCB7CiAgICBfX20xMjhpIGtbNjRdOwogICAgX19tMTI4aSBpdls0XTsKICAgIF9fbTEyOGkgZmY7CgogICAgX19tMTI4aSBhLCBiLCBjLCBkOwp9OwoKdm9pZCBtZDV4NF9wcmVfaW5pdChzdHJ1Y3QgbWQ1eDRfY29udGV4dCogY3R4KSB7CiAgICBmb3IgKHVpbnQzMl90IGkgPSAwOyBpIDwgNjQ7ICsraSkgewogICAgICAgIHVpbnQzMl90IHggPSBmbG9vcihmYWJzKHNpbihpICsgMSkpICogKGRvdWJsZSkweDEwMDAwMDAwMHVsbCk7CiAgICAgICAgY3R4LT5rW2ldID0gX21tX3NldDFfZXBpMzIoeCk7CiAgICB9CiAgICBjdHgtPml2WzBdID0gX21tX3NldDFfZXBpMzIoMHg2NzQ1MjMwMSk7CiAgICBjdHgtPml2WzFdID0gX21tX3NldDFfZXBpMzIoMHhlZmNkYWI4OSk7CiAgICBjdHgtPml2WzJdID0gX21tX3NldDFfZXBpMzIoMHg5OGJhZGNmZSk7CiAgICBjdHgtPml2WzNdID0gX21tX3NldDFfZXBpMzIoMHgxMDMyNTQ3Nik7CiAgICBjdHgtPmZmID0gX21tX3NldDFfZXBpMzIoMHhGRkZGRkZGRik7Cn0KCnZvaWQgbWQ1eDRfaW5pdChzdHJ1Y3QgbWQ1eDRfY29udGV4dCogY3R4KSB7CiAgICBjdHgtPmEgPSBjdHgtPml2WzBdOwogICAgY3R4LT5iID0gY3R4LT5pdlsxXTsKICAgIGN0eC0+YyA9IGN0eC0+aXZbMl07CiAgICBjdHgtPmQgPSBjdHgtPml2WzNdOwp9CgppbmxpbmUgX19tMTI4aSBtZDV4NF9meChpbnQgcywgX19tMTI4aSBhLCBfX20xMjhpIGIsIF9fbTEyOGkgaywgX19tMTI4aSB4LCBfX20xMjhpIGYpIHsKICAgIGYgPSBfbW1fYWRkX2VwaTMyKF9tbV9hZGRfZXBpMzIoZiwgYSksIF9tbV9hZGRfZXBpMzIoaywgeCkpOwogICAgcmV0dXJuIF9tbV9hZGRfZXBpMzIoYiwgX21tX29yX3NpMTI4KF9tbV9zbGxpX2VwaTMyKGYsIHMpLCBfbW1fc3JsaV9lcGkzMihmLCAzMiAtIHMpKSk7Cn0KCmlubGluZSBfX20xMjhpIG1kNXg0X2YxKGludCBzLCBfX20xMjhpIGEsIF9fbTEyOGkgYiwgX19tMTI4aSBjLCBfX20xMjhpIGQsIF9fbTEyOGkgaywgX19tMTI4aSB4KSB7CiAgICByZXR1cm4gbWQ1eDRfZngocywgYSwgYiwgaywgeCwgX21tX29yX3NpMTI4KF9tbV9hbmRfc2kxMjgoYiwgYyksIF9tbV9hbmRub3Rfc2kxMjgoYiwgZCkpKTsKfQoKaW5saW5lIF9fbTEyOGkgbWQ1eDRfZjIoaW50IHMsIF9fbTEyOGkgYSwgX19tMTI4aSBiLCBfX20xMjhpIGMsIF9fbTEyOGkgZCwgX19tMTI4aSBrLCBfX20xMjhpIHgpIHsKICAgIHJldHVybiBtZDV4NF9meChzLCBhLCBiLCBrLCB4LCBfbW1fb3Jfc2kxMjgoX21tX2FuZF9zaTEyOChkLCBiKSwgX21tX2FuZG5vdF9zaTEyOChkLCBjKSkpOwp9CgppbmxpbmUgX19tMTI4aSBtZDV4NF9mMyhpbnQgcywgX19tMTI4aSBhLCBfX20xMjhpIGIsIF9fbTEyOGkgYywgX19tMTI4aSBkLCBfX20xMjhpIGssIF9fbTEyOGkgeCkgewogICAgcmV0dXJuIG1kNXg0X2Z4KHMsIGEsIGIsIGssIHgsIF9tbV94b3Jfc2kxMjgoX21tX3hvcl9zaTEyOChiLCBjKSwgZCkpOwp9CgppbmxpbmUgX19tMTI4aSBtZDV4NF9mNChpbnQgcywgX19tMTI4aSBhLCBfX20xMjhpIGIsIF9fbTEyOGkgYywgX19tMTI4aSBkLCBfX20xMjhpIGssIF9fbTEyOGkgeCkgewogICAgcmV0dXJuIG1kNXg0X2Z4KHMsIGEsIGIsIGssIHgsIF9tbV94b3Jfc2kxMjgoYywgX21tX29yX3NpMTI4KGIsIF9tbV94b3Jfc2kxMjgoZCwgX21tX3NldDFfZXBpMzIoMHhGRkZGRkZGRikpKSkpOwp9Cgp2b2lkIG1kNXg0X3Jhd191cGRhdGUoc3RydWN0IG1kNXg0X2NvbnRleHQqIGN0eCwgY29uc3QgdWludDhfdCBibG9ja3NbNF1bNjRdKQp7CiAgICBfX20xMjhpIHhbMTZdOwogICAgZm9yIChzaXplX3QgaSA9IDA7IGkgPCA0OyArK2kpIHsKICAgICAgICBfX20xMjggeDAgPSBfbW1fbG9hZHVfcHMoKGNvbnN0IGZsb2F0KilibG9ja3NbMF0gKyBpICogNCk7CiAgICAgICAgX19tMTI4IHgxID0gX21tX2xvYWR1X3BzKChjb25zdCBmbG9hdCopYmxvY2tzWzFdICsgaSAqIDQpOwogICAgICAgIF9fbTEyOCB4MiA9IF9tbV9sb2FkdV9wcygoY29uc3QgZmxvYXQqKWJsb2Nrc1syXSArIGkgKiA0KTsKICAgICAgICBfX20xMjggeDMgPSBfbW1fbG9hZHVfcHMoKGNvbnN0IGZsb2F0KilibG9ja3NbM10gKyBpICogNCk7CgogICAgICAgIF9fbTEyOCB0MCA9IF9tbV91bnBhY2tsb19wcyh4MCwgeDEpOwogICAgICAgIF9fbTEyOCB0MSA9IF9tbV91bnBhY2toaV9wcyh4MCwgeDEpOwogICAgICAgIF9fbTEyOCB0MiA9IF9tbV91bnBhY2tsb19wcyh4MiwgeDMpOwogICAgICAgIF9fbTEyOCB0MyA9IF9tbV91bnBhY2toaV9wcyh4MiwgeDMpOwoKICAgICAgICB4W2kgKiA0ICsgMF0gPSBfbW1fY2FzdHBzX3NpMTI4KF9tbV9tb3ZlbGhfcHModDAsIHQyKSk7CiAgICAgICAgeFtpICogNCArIDFdID0gX21tX2Nhc3Rwc19zaTEyOChfbW1fbW92ZWhsX3BzKHQyLCB0MCkpOwogICAgICAgIHhbaSAqIDQgKyAyXSA9IF9tbV9jYXN0cHNfc2kxMjgoX21tX21vdmVsaF9wcyh0MSwgdDMpKTsKICAgICAgICB4W2kgKiA0ICsgM10gPSBfbW1fY2FzdHBzX3NpMTI4KF9tbV9tb3ZlaGxfcHModDMsIHQxKSk7CiAgICB9CgogICAgX19tMTI4aSBhID0gY3R4LT5hOwogICAgX19tMTI4aSBiID0gY3R4LT5iOwogICAgX19tMTI4aSBjID0gY3R4LT5jOwogICAgX19tMTI4aSBkID0gY3R4LT5kOwoKICAgIGEgPSBtZDV4NF9mMSg3LCBhLCBiLCBjLCBkLCBjdHgtPmtbMF0sIHhbMF0pOwogICAgZCA9IG1kNXg0X2YxKDEyLCBkLCBhLCBiLCBjLCBjdHgtPmtbMV0sIHhbMV0pOwogICAgYyA9IG1kNXg0X2YxKDE3LCBjLCBkLCBhLCBiLCBjdHgtPmtbMl0sIHhbMl0pOwogICAgYiA9IG1kNXg0X2YxKDIyLCBiLCBjLCBkLCBhLCBjdHgtPmtbM10sIHhbM10pOwogICAgYSA9IG1kNXg0X2YxKDcsIGEsIGIsIGMsIGQsIGN0eC0+a1s0XSwgeFs0XSk7CiAgICBkID0gbWQ1eDRfZjEoMTIsIGQsIGEsIGIsIGMsIGN0eC0+a1s1XSwgeFs1XSk7CiAgICBjID0gbWQ1eDRfZjEoMTcsIGMsIGQsIGEsIGIsIGN0eC0+a1s2XSwgeFs2XSk7CiAgICBiID0gbWQ1eDRfZjEoMjIsIGIsIGMsIGQsIGEsIGN0eC0+a1s3XSwgeFs3XSk7CiAgICBhID0gbWQ1eDRfZjEoNywgYSwgYiwgYywgZCwgY3R4LT5rWzhdLCB4WzhdKTsKICAgIGQgPSBtZDV4NF9mMSgxMiwgZCwgYSwgYiwgYywgY3R4LT5rWzldLCB4WzldKTsKICAgIGMgPSBtZDV4NF9mMSgxNywgYywgZCwgYSwgYiwgY3R4LT5rWzEwXSwgeFsxMF0pOwogICAgYiA9IG1kNXg0X2YxKDIyLCBiLCBjLCBkLCBhLCBjdHgtPmtbMTFdLCB4WzExXSk7CiAgICBhID0gbWQ1eDRfZjEoNywgYSwgYiwgYywgZCwgY3R4LT5rWzEyXSwgeFsxMl0pOwogICAgZCA9IG1kNXg0X2YxKDEyLCBkLCBhLCBiLCBjLCBjdHgtPmtbMTNdLCB4WzEzXSk7CiAgICBjID0gbWQ1eDRfZjEoMTcsIGMsIGQsIGEsIGIsIGN0eC0+a1sxNF0sIHhbMTRdKTsKICAgIGIgPSBtZDV4NF9mMSgyMiwgYiwgYywgZCwgYSwgY3R4LT5rWzE1XSwgeFsxNV0pOwoKICAgIGEgPSBtZDV4NF9mMig1LCBhLCBiLCBjLCBkLCBjdHgtPmtbMTZdLCB4WzFdKTsKICAgIGQgPSBtZDV4NF9mMig5LCBkLCBhLCBiLCBjLCBjdHgtPmtbMTddLCB4WzZdKTsKICAgIGMgPSBtZDV4NF9mMigxNCwgYywgZCwgYSwgYiwgY3R4LT5rWzE4XSwgeFsxMV0pOwogICAgYiA9IG1kNXg0X2YyKDIwLCBiLCBjLCBkLCBhLCBjdHgtPmtbMTldLCB4WzBdKTsKICAgIGEgPSBtZDV4NF9mMig1LCBhLCBiLCBjLCBkLCBjdHgtPmtbMjBdLCB4WzVdKTsKICAgIGQgPSBtZDV4NF9mMig5LCBkLCBhLCBiLCBjLCBjdHgtPmtbMjFdLCB4WzEwXSk7CiAgICBjID0gbWQ1eDRfZjIoMTQsIGMsIGQsIGEsIGIsIGN0eC0+a1syMl0sIHhbMTVdKTsKICAgIGIgPSBtZDV4NF9mMigyMCwgYiwgYywgZCwgYSwgY3R4LT5rWzIzXSwgeFs0XSk7CiAgICBhID0gbWQ1eDRfZjIoNSwgYSwgYiwgYywgZCwgY3R4LT5rWzI0XSwgeFs5XSk7CiAgICBkID0gbWQ1eDRfZjIoOSwgZCwgYSwgYiwgYywgY3R4LT5rWzI1XSwgeFsxNF0pOwogICAgYyA9IG1kNXg0X2YyKDE0LCBjLCBkLCBhLCBiLCBjdHgtPmtbMjZdLCB4WzNdKTsKICAgIGIgPSBtZDV4NF9mMigyMCwgYiwgYywgZCwgYSwgY3R4LT5rWzI3XSwgeFs4XSk7CiAgICBhID0gbWQ1eDRfZjIoNSwgYSwgYiwgYywgZCwgY3R4LT5rWzI4XSwgeFsxM10pOwogICAgZCA9IG1kNXg0X2YyKDksIGQsIGEsIGIsIGMsIGN0eC0+a1syOV0sIHhbMl0pOwogICAgYyA9IG1kNXg0X2YyKDE0LCBjLCBkLCBhLCBiLCBjdHgtPmtbMzBdLCB4WzddKTsKICAgIGIgPSBtZDV4NF9mMigyMCwgYiwgYywgZCwgYSwgY3R4LT5rWzMxXSwgeFsxMl0pOwoKICAgIGEgPSBtZDV4NF9mMyg0LCBhLCBiLCBjLCBkLCBjdHgtPmtbMzJdLCB4WzVdKTsKICAgIGQgPSBtZDV4NF9mMygxMSwgZCwgYSwgYiwgYywgY3R4LT5rWzMzXSwgeFs4XSk7CiAgICBjID0gbWQ1eDRfZjMoMTYsIGMsIGQsIGEsIGIsIGN0eC0+a1szNF0sIHhbMTFdKTsKICAgIGIgPSBtZDV4NF9mMygyMywgYiwgYywgZCwgYSwgY3R4LT5rWzM1XSwgeFsxNF0pOwogICAgYSA9IG1kNXg0X2YzKDQsIGEsIGIsIGMsIGQsIGN0eC0+a1szNl0sIHhbMV0pOwogICAgZCA9IG1kNXg0X2YzKDExLCBkLCBhLCBiLCBjLCBjdHgtPmtbMzddLCB4WzRdKTsKICAgIGMgPSBtZDV4NF9mMygxNiwgYywgZCwgYSwgYiwgY3R4LT5rWzM4XSwgeFs3XSk7CiAgICBiID0gbWQ1eDRfZjMoMjMsIGIsIGMsIGQsIGEsIGN0eC0+a1szOV0sIHhbMTBdKTsKICAgIGEgPSBtZDV4NF9mMyg0LCBhLCBiLCBjLCBkLCBjdHgtPmtbNDBdLCB4WzEzXSk7CiAgICBkID0gbWQ1eDRfZjMoMTEsIGQsIGEsIGIsIGMsIGN0eC0+a1s0MV0sIHhbMF0pOwogICAgYyA9IG1kNXg0X2YzKDE2LCBjLCBkLCBhLCBiLCBjdHgtPmtbNDJdLCB4WzNdKTsKICAgIGIgPSBtZDV4NF9mMygyMywgYiwgYywgZCwgYSwgY3R4LT5rWzQzXSwgeFs2XSk7CiAgICBhID0gbWQ1eDRfZjMoNCwgYSwgYiwgYywgZCwgY3R4LT5rWzQ0XSwgeFs5XSk7CiAgICBkID0gbWQ1eDRfZjMoMTEsIGQsIGEsIGIsIGMsIGN0eC0+a1s0NV0sIHhbMTJdKTsKICAgIGMgPSBtZDV4NF9mMygxNiwgYywgZCwgYSwgYiwgY3R4LT5rWzQ2XSwgeFsxNV0pOwogICAgYiA9IG1kNXg0X2YzKDIzLCBiLCBjLCBkLCBhLCBjdHgtPmtbNDddLCB4WzJdKTsKCiAgICBhID0gbWQ1eDRfZjQoNiwgYSwgYiwgYywgZCwgY3R4LT5rWzQ4XSwgeFswXSk7CiAgICBkID0gbWQ1eDRfZjQoMTAsIGQsIGEsIGIsIGMsIGN0eC0+a1s0OV0sIHhbN10pOwogICAgYyA9IG1kNXg0X2Y0KDE1LCBjLCBkLCBhLCBiLCBjdHgtPmtbNTBdLCB4WzE0XSk7CiAgICBiID0gbWQ1eDRfZjQoMjEsIGIsIGMsIGQsIGEsIGN0eC0+a1s1MV0sIHhbNV0pOwogICAgYSA9IG1kNXg0X2Y0KDYsIGEsIGIsIGMsIGQsIGN0eC0+a1s1Ml0sIHhbMTJdKTsKICAgIGQgPSBtZDV4NF9mNCgxMCwgZCwgYSwgYiwgYywgY3R4LT5rWzUzXSwgeFszXSk7CiAgICBjID0gbWQ1eDRfZjQoMTUsIGMsIGQsIGEsIGIsIGN0eC0+a1s1NF0sIHhbMTBdKTsKICAgIGIgPSBtZDV4NF9mNCgyMSwgYiwgYywgZCwgYSwgY3R4LT5rWzU1XSwgeFsxXSk7CiAgICBhID0gbWQ1eDRfZjQoNiwgYSwgYiwgYywgZCwgY3R4LT5rWzU2XSwgeFs4XSk7CiAgICBkID0gbWQ1eDRfZjQoMTAsIGQsIGEsIGIsIGMsIGN0eC0+a1s1N10sIHhbMTVdKTsKICAgIGMgPSBtZDV4NF9mNCgxNSwgYywgZCwgYSwgYiwgY3R4LT5rWzU4XSwgeFs2XSk7CiAgICBiID0gbWQ1eDRfZjQoMjEsIGIsIGMsIGQsIGEsIGN0eC0+a1s1OV0sIHhbMTNdKTsKICAgIGEgPSBtZDV4NF9mNCg2LCBhLCBiLCBjLCBkLCBjdHgtPmtbNjBdLCB4WzRdKTsKICAgIGQgPSBtZDV4NF9mNCgxMCwgZCwgYSwgYiwgYywgY3R4LT5rWzYxXSwgeFsxMV0pOwogICAgYyA9IG1kNXg0X2Y0KDE1LCBjLCBkLCBhLCBiLCBjdHgtPmtbNjJdLCB4WzJdKTsKICAgIGIgPSBtZDV4NF9mNCgyMSwgYiwgYywgZCwgYSwgY3R4LT5rWzYzXSwgeFs5XSk7CgogICAgY3R4LT5hID0gX21tX2FkZF9lcGkzMihjdHgtPmEsIGEpOwogICAgY3R4LT5iID0gX21tX2FkZF9lcGkzMihjdHgtPmIsIGIpOwogICAgY3R4LT5jID0gX21tX2FkZF9lcGkzMihjdHgtPmMsIGMpOwogICAgY3R4LT5kID0gX21tX2FkZF9lcGkzMihjdHgtPmQsIGQpOwp9Cgp2b2lkIG1kNXg0X2ZpbmFsKHN0cnVjdCBtZDV4NF9jb250ZXh0KiBjdHgsIHVpbnQ4X3Qgb3V0WzRdWzE2XSkgewogICAgX19tMTI4IGEgPSBfbW1fY2FzdHNpMTI4X3BzKGN0eC0+YSk7CiAgICBfX20xMjggYiA9IF9tbV9jYXN0c2kxMjhfcHMoY3R4LT5iKTsKICAgIF9fbTEyOCBjID0gX21tX2Nhc3RzaTEyOF9wcyhjdHgtPmMpOwogICAgX19tMTI4IGQgPSBfbW1fY2FzdHNpMTI4X3BzKGN0eC0+ZCk7CgogICAgX19tMTI4IHQwID0gX21tX3VucGFja2xvX3BzKGEsIGIpOwogICAgX19tMTI4IHQxID0gX21tX3VucGFja2hpX3BzKGEsIGIpOwogICAgX19tMTI4IHQyID0gX21tX3VucGFja2xvX3BzKGMsIGQpOwogICAgX19tMTI4IHQzID0gX21tX3VucGFja2hpX3BzKGMsIGQpOwoKICAgIF9tbV9zdG9yZXVfcHMoKGZsb2F0KilvdXRbMF0sIF9tbV9tb3ZlbGhfcHModDAsIHQyKSk7CiAgICBfbW1fc3RvcmV1X3BzKChmbG9hdCopb3V0WzFdLCBfbW1fbW92ZWhsX3BzKHQyLCB0MCkpOwogICAgX21tX3N0b3JldV9wcygoZmxvYXQqKW91dFsyXSwgX21tX21vdmVsaF9wcyh0MSwgdDMpKTsKICAgIF9tbV9zdG9yZXVfcHMoKGZsb2F0KilvdXRbM10sIF9tbV9tb3ZlaGxfcHModDMsIHQxKSk7Cn0KCgp2b2lkIHVuc2FmZV9wYWRfYmxvY2sodWludDhfdCBibG9ja1s2NF0sIHNpemVfdCBsZW5ndGgpIHsKICAgIGJsb2NrW2xlbmd0aF0gPSAweDgwOwogICAgKih1aW50NjRfdCopKGJsb2NrICsgNTYpID0gbGVuZ3RoICogODsKfQoKaW50IG1haW4oKSB7CiAgICBzdHJ1Y3QgbWQ1eDRfY29udGV4dCBjdHg7CiAgICBtZDV4NF9wcmVfaW5pdCgmY3R4KTsKCiAgICB1aW50OF90IGRhdGFbNF1bNjRdID0gewogICAgICAgICJXZSBhcmUgdGhlIG90aGVycyIsCiAgICAgICAgIldlIGFyZSB0aGUgY2FzdC1vdXRzIiwKICAgICAgICAiV2UncmUgdGhlIG91dHNpZGVycyIsCiAgICAgICAgIkJ1dCB5b3UgY2FuJ3QgaGlkZSB1cyIsCiAgICB9OwoKICAgIHVuc2FmZV9wYWRfYmxvY2soZGF0YVswXSwgMTcpOwogICAgdW5zYWZlX3BhZF9ibG9jayhkYXRhWzFdLCAyMCk7CiAgICB1bnNhZmVfcGFkX2Jsb2NrKGRhdGFbMl0sIDE5KTsKICAgIHVuc2FmZV9wYWRfYmxvY2soZGF0YVszXSwgMjEpOwoKICAgIHVpbnQ4X3QgZGlnZXN0c1s0XVsxNl0gPSB7MH07CgogICAgbWQ1eDRfaW5pdCgmY3R4KTsKICAgIG1kNXg0X3Jhd191cGRhdGUoJmN0eCwgZGF0YSk7CiAgICBtZDV4NF9maW5hbCgmY3R4LCBkaWdlc3RzKTsKCiAgICBmb3IgKHNpemVfdCBpID0gMDsgaSA8IDQ7ICsraSkgewogICAgICAgIGZvciAoc2l6ZV90IGogPSAwOyBqIDwgMTY7ICsraikKICAgICAgICAgICAgcHJpbnRmKCIlMDJYICIsIGRpZ2VzdHNbaV1bal0pOwogICAgICAgIHByaW50ZigiXG4iKTsKICAgIH0KCiAgICByZXR1cm4gMDsKfQ==